1 // #include <netinet/in.h>
10 #include <sys/reboot.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
18 #include "control-cmds.h"
19 #include "service-constants.h"
21 // shutdown: shut down the system
22 // This utility communicates with the dinit daemon via a unix socket (/dev/initctl).
24 void do_system_shutdown(ShutdownType shutdown_type);
25 static void unmount_disks();
26 static void swap_off();
28 int main(int argc, char **argv)
32 bool show_help = false;
33 bool sys_shutdown = false;
35 auto shutdown_type = ShutdownType::POWEROFF;
37 for (int i = 1; i < argc; i++) {
38 if (argv[i][0] == '-') {
39 if (strcmp(argv[i], "--help") == 0) {
44 if (strcmp(argv[i], "--system") == 0) {
47 else if (strcmp(argv[i], "-r") == 0) {
48 shutdown_type = ShutdownType::REBOOT;
50 else if (strcmp(argv[i], "-h") == 0) {
51 shutdown_type = ShutdownType::HALT;
53 else if (strcmp(argv[i], "-p") == 0) {
54 shutdown_type = ShutdownType::POWEROFF;
57 cerr << "Unrecognized command-line parameter: " << argv[i] << endl;
62 // time argument? TODO
68 cout << "dinit-shutdown : shutdown the system" << endl;
69 cout << " --help : show this help" << endl;
70 cout << " -r : reboot" << endl;
71 cout << " -h : halt system" << endl;
72 cout << " -p : power down (default)" << endl;
73 cout << " --system : perform shutdown immediately, instead of issuing shutdown" << endl;
74 cout << " command to the init program. Not recommended for use" << endl;
75 cout << " by users." << endl;
80 do_system_shutdown(shutdown_type);
84 int socknum = socket(AF_UNIX, SOCK_STREAM, 0);
90 const char *naddr = "/dev/dinitctl";
92 struct sockaddr_un name;
93 name.sun_family = AF_UNIX;
94 strcpy(name.sun_path, naddr);
95 int sunlen = offsetof(struct sockaddr_un, sun_path) + strlen(naddr) + 1; // family, (string), nul
97 int connr = connect(socknum, (struct sockaddr *) &name, sunlen);
104 //uint16_t sname_len = strlen(service_name);
106 char * buf = new char[bufsize];
108 buf[0] = DINIT_CP_SHUTDOWN;
109 buf[1] = static_cast<char>(shutdown_type);
111 cout << "Issuing shutdown command..." << endl; // DAV
113 // TODO make sure to write the whole buffer
114 int r = write(socknum, buf, bufsize);
120 r = read(socknum, buf, 1);
121 // TODO: check result
126 void do_system_shutdown(ShutdownType shutdown_type)
131 if (shutdown_type == ShutdownType::REBOOT) reboot_type = RB_AUTOBOOT;
132 else if (shutdown_type == ShutdownType::POWEROFF) reboot_type = RB_POWER_OFF;
133 else reboot_type = RB_HALT_SYSTEM;
135 // Write to console rather than any terminal, since we lose the terminal it seems:
136 close(STDOUT_FILENO);
137 int consfd = open("/dev/console", O_WRONLY);
138 if (consfd != STDOUT_FILENO) {
139 dup2(consfd, STDOUT_FILENO);
142 cout << "Sending TERM/KILL to all processes..." << endl; // DAV
144 // Send TERM/KILL to all (remaining) processes
149 // cout << "Sending QUIT to init..." << endl; // DAV
151 // Tell init to exec reboot:
152 // TODO what if it's not PID=1? probably should have dinit pass us its PID
155 // TODO can we wait somehow for above to work?
156 // maybe have a pipe/socket and we read from our end...
158 // TODO: close all ancillary file descriptors.
161 cout << "Turning off swap..." << endl;
163 cout << "Unmounting disks..." << endl;
167 cout << "Issuing shutdown via kernel..." << endl;
171 static void unmount_disks()
173 pid_t chpid = fork();
176 // -a : all filesystems (except proc)
177 // -r : mount readonly if can't unmount
178 execl("/bin/umount", "/bin/umount", "-a", "-r", nullptr);
180 else if (chpid > 0) {
182 waitpid(chpid, &status, 0);
186 static void swap_off()
188 pid_t chpid = fork();
191 execl("/sbin/swapoff", "/sbin/swapoff", "-a", nullptr);
193 else if (chpid > 0) {
195 waitpid(chpid, &status, 0);