d57ad314ee8830a2faa38973fc8a973fa2fcd3e7
[oweals/dinit.git] / dinit-reboot.cc
1 // #include <netinet/in.h>
2 #include <cstddef>
3 #include <cstdio>
4 #include <csignal>
5 #include <unistd.h>
6 #include <cstring>
7 #include <string>
8 #include <iostream>
9
10 #include <sys/reboot.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <sys/un.h>
14 #include <sys/wait.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17
18
19 #include "control-cmds.h"
20
21 // shutdown:  shut down the system
22 // This utility communicates with the dinit daemon via a unix socket (/dev/initctl).
23
24 static void unmount_disks();
25 static void swap_off();
26
27 int main(int argc, char **argv)
28 {
29     using namespace std;
30     
31     int sd_type = 0;
32     
33     //bool show_help = argc < 2;
34     bool show_help = false;
35         
36     for (int i = 1; i < argc; i++) {
37         if (argv[i][0] == '-') {
38             if (strcmp(argv[i], "--help") == 0) {
39                 show_help = true;
40                 break;
41             }
42             else if (strcmp(argv[i], "-r") == 0) {
43                 // Reboot
44                 sd_type = 1;
45             }
46             else if (strcmp(argv[i], "-p") == 0) {
47                 // Power down
48                 sd_type = 2;
49             }
50             else if (strcmp(argv[i], "-h") == 0) {
51                 // Halt
52                 sd_type = 3;
53             }
54             else if (strcmp(argv[i], "-l") == 0) {
55                 // Loop
56                 sd_type = 0;
57             }
58             else {
59                 cerr << "Unrecognized command-line parameter: " << argv[i] << endl;
60                 return 1;
61             }
62         }
63         else {
64             // time argument? TODO
65             show_help = true;
66         }
67     }
68
69     if (show_help) {
70         cout << "dinit-shutdown :   shutdown the system" << endl;
71         cout << "  --help           : show this help" << endl;
72         return 1;
73     }
74     
75     if (sd_type == 0) {
76         while (true) {
77             pause();
78         }
79     }
80     
81     int reboot_type = 0;
82     if (sd_type == 1) reboot_type = RB_AUTOBOOT;
83     else if (sd_type == 2) reboot_type = RB_POWER_OFF;
84     else reboot_type = RB_HALT_SYSTEM;
85     
86     // Write to console rather than any terminal, since we lose the terminal it seems:
87     close(STDOUT_FILENO);
88     int consfd = open("/dev/console", O_WRONLY);
89     if (consfd != STDOUT_FILENO) {
90         dup2(consfd, STDOUT_FILENO);
91     }
92     
93     // At this point, util-linux 2.13 shutdown sends SIGTERM to all processes with uid >= 100 and
94     // calls it 'sendiong SIGTERM to mortals'.
95     // Equivalent would probably be to rollback 'loginready' service. However, that will happen as
96     // part of the regular rollback anyway.
97     
98     //cout << "Writing rollback command..." << endl; // DAV
99     
100     //int r = write(socknum, buf, bufsize);
101     //if (r == -1) {
102     //    perror("write");
103     //}
104     
105     cout << "Sending TERM/KILL..." << endl; // DAV
106     
107     // Send TERM/KILL to all (remaining) processes
108     kill(-1, SIGTERM);
109     sleep(1);
110     kill(-1, SIGKILL);
111     
112     cout << "Sending QUIT to init..." << endl; // DAV
113     
114     // Tell init to exec reboot:
115     // TODO what if it's not PID=1? probably should have dinit pass us its PID
116     kill(1, SIGQUIT);
117     
118     // TODO can we wait somehow for above to work?
119     // maybe have a pipe/socket and we read from our end...
120     
121     // TODO: close all ancillary file descriptors.
122     
123     // perform shutdown
124     cout << "Turning off swap..." << endl;
125     swap_off();
126     cout << "Unmounting disks..." << endl;
127     unmount_disks();
128     sync();
129     
130     cout << "Issuing shutdown via kernel..." << endl;
131     reboot(reboot_type);
132     
133     return 0;
134 }
135
136 static void unmount_disks()
137 {
138     pid_t chpid = fork();
139     if (chpid == 0) {
140         // umount -a -r
141         //  -a : all filesystems (except proc)
142         //  -r : mount readonly if can't unmount
143         execl("/bin/umount", "/bin/umount", "-a", "-r", nullptr);
144     }
145     else if (chpid > 0) {
146         int status;
147         waitpid(chpid, &status, 0);
148     }
149 }
150
151 static void swap_off()
152 {
153     pid_t chpid = fork();
154     if (chpid == 0) {
155         // swapoff -a
156         execl("/sbin/swapoff", "/sbin/swapoff", "-a", nullptr);
157     }
158     else if (chpid > 0) {
159         int status;
160         waitpid(chpid, &status, 0);
161     }
162 }