aa0f6a7c1f6a0cbeaf25eebe8ab9ec01fa9cdcf4
[oweals/dinit.git] / shutdown.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 #include "control-cmds.h"
19 #include "service-constants.h"
20
21 // shutdown:  shut down the system
22 // This utility communicates with the dinit daemon via a unix socket (/dev/initctl).
23
24 int main(int argc, char **argv)
25 {
26     using namespace std;
27     
28     //bool show_help = argc < 2;
29     bool show_help = false;
30     
31     auto shutdown_type = ShutdownType::POWEROFF;
32         
33     for (int i = 1; i < argc; i++) {
34         if (argv[i][0] == '-') {
35             if (strcmp(argv[i], "--help") == 0) {
36                 show_help = true;
37                 break;
38             }
39             else if (strcmp(argv[i], "-r") == 0) {
40                 shutdown_type = ShutdownType::REBOOT;
41             }
42             else if (strcmp(argv[i], "-h") == 0) {
43                 shutdown_type = ShutdownType::POWEROFF;
44             }
45             else {
46                 cerr << "Unrecognized command-line parameter: " << argv[i] << endl;
47                 return 1;
48             }
49         }
50         else {
51             // time argument? TODO
52         }
53     }
54
55     if (show_help) {
56         cout << "dinit-shutdown :   shutdown the system" << endl;
57         cout << "  --help           : show this help" << endl;
58         return 1;
59     }
60     
61     int socknum = socket(AF_UNIX, SOCK_STREAM, 0);
62     if (socknum == -1) {
63         perror("socket");
64         return 1;
65     }
66
67     const char *naddr = "/dev/dinitctl";
68     
69     struct sockaddr_un name;
70     name.sun_family = AF_UNIX;
71     strcpy(name.sun_path, naddr);
72     int sunlen = offsetof(struct sockaddr_un, sun_path) + strlen(naddr) + 1; // family, (string), nul
73     
74     int connr = connect(socknum, (struct sockaddr *) &name, sunlen);
75     if (connr == -1) {
76         perror("connect");
77         return 1;
78     }
79     
80     // Build buffer;
81     //uint16_t sname_len = strlen(service_name);
82     int bufsize = 2;
83     char * buf = new char[bufsize];
84     
85     buf[0] = DINIT_CP_SHUTDOWN;
86     buf[1] = static_cast<char>(shutdown_type);
87     
88     //memcpy(buf + 1, &sname_len, 2);
89     //memcpy(buf + 3, service_name, sname_len);
90     
91     // Make sure we can't die due to a signal at this point:
92     //sigset_t sigmask;
93     //sigfillset(&sigmask);
94     //sigprocmask(SIG_BLOCK, &sigmask, nullptr);
95     
96     // Write to console rather than any terminal, since we lose the terminal it seems:
97     //close(STDOUT_FILENO);
98     //int consfd = open("/dev/console", O_WRONLY);
99     //if (consfd != STDOUT_FILENO) {
100     //    dup2(consfd, STDOUT_FILENO);
101     //}
102     
103     // At this point, util-linux 2.13 shutdown sends SIGTERM to all processes with uid >= 100 and
104     // calls it 'sendiong SIGTERM to mortals'.
105     // Equivalent would probably be to rollback 'loginready' service. However, that will happen as
106     // part of the regular rollback anyway.
107     
108     cout << "Writing shutdown command..." << endl; // DAV
109     
110     // TODO make sure to write the whole buffer
111     int r = write(socknum, buf, bufsize);
112     if (r == -1) {
113         perror("write");
114     }
115     
116     cout << "Waiting for ACK..." << endl; // DAV
117     
118     // Wait for ACK/NACK
119     r = read(socknum, buf, 1);
120     // TODO: check result
121     
122     return 0;
123 }