base_process_service: properly clean up in destructor.
[oweals/dinit.git] / src / shutdown.cc
index a9c95a8a3e4bdae06d139e617131770528c6b399..c751fd086fe422a3e9beb877a7cc3abb37aa84c4 100644 (file)
 // shutdown:  shut down the system
 // This utility communicates with the dinit daemon via a unix socket (/dev/initctl).
 
-void do_system_shutdown(ShutdownType shutdown_type);
+void do_system_shutdown(shutdown_type_t shutdown_type);
 static void unmount_disks();
 static void swap_off();
-static void wait_for_reply(CPBuffer<1024> &rbuffer, int fd);
+static void wait_for_reply(cpbuffer<1024> &rbuffer, int fd);
 
 
 class ReadCPException
@@ -41,8 +41,9 @@ int main(int argc, char **argv)
     
     bool show_help = false;
     bool sys_shutdown = false;
+    bool use_passed_cfd = false;
     
-    auto shutdown_type = ShutdownType::POWEROFF;
+    auto shutdown_type = shutdown_type_t::POWEROFF;
         
     for (int i = 1; i < argc; i++) {
         if (argv[i][0] == '-') {
@@ -55,13 +56,16 @@ int main(int argc, char **argv)
                 sys_shutdown = true;
             }
             else if (strcmp(argv[i], "-r") == 0) {
-                shutdown_type = ShutdownType::REBOOT;
+                shutdown_type = shutdown_type_t::REBOOT;
             }
             else if (strcmp(argv[i], "-h") == 0) {
-                shutdown_type = ShutdownType::HALT;
+                shutdown_type = shutdown_type_t::HALT;
             }
             else if (strcmp(argv[i], "-p") == 0) {
-                shutdown_type = ShutdownType::POWEROFF;
+                shutdown_type = shutdown_type_t::POWEROFF;
+            }
+            else if (strcmp(argv[i], "--use-passed-cfd") == 0) {
+                use_passed_cfd = true;
             }
             else {
                 cerr << "Unrecognized command-line parameter: " << argv[i] << endl;
@@ -80,6 +84,8 @@ int main(int argc, char **argv)
         cout << "  -r               : reboot" << endl;
         cout << "  -h               : halt system" << endl;
         cout << "  -p               : power down (default)" << endl;
+        cout << "  --use-passed-cfd : use the socket file descriptor identified by the DINIT_CS_FD" << endl;
+        cout << "                     environment variable to communicate with the init daemon." << endl;
         cout << "  --system         : perform shutdown immediately, instead of issuing shutdown" << endl;
         cout << "                     command to the init program. Not recommended for use" << endl;
         cout << "                     by users." << endl;
@@ -90,32 +96,52 @@ int main(int argc, char **argv)
         do_system_shutdown(shutdown_type);
         return 0;
     }
-    
-    int socknum = socket(AF_UNIX, SOCK_STREAM, 0);
-    if (socknum == -1) {
-        perror("socket");
-        return 1;
-    }
 
     signal(SIGPIPE, SIG_IGN);
     
-    const char *naddr = "/dev/dinitctl";
-    
-    struct sockaddr_un name;
-    name.sun_family = AF_UNIX;
-    strcpy(name.sun_path, naddr);
-    int sunlen = offsetof(struct sockaddr_un, sun_path) + strlen(naddr) + 1; // family, (string), nul
+    int socknum = 0;
     
-    int connr = connect(socknum, (struct sockaddr *) &name, sunlen);
-    if (connr == -1) {
-        perror("connect");
-        return 1;
+    if (use_passed_cfd) {
+        char * dinit_cs_fd_env = getenv("DINIT_CS_FD");
+        if (dinit_cs_fd_env != nullptr) {
+            char * endptr;
+            long int cfdnum = strtol(dinit_cs_fd_env, &endptr, 10);
+            if (endptr != dinit_cs_fd_env) {
+                socknum = (int) cfdnum;
+            }
+            else {
+                use_passed_cfd = false;
+            }
+        }
+        else {
+            use_passed_cfd = false;
+        }
     }
     
+    if (! use_passed_cfd) {
+        socknum = socket(AF_UNIX, SOCK_STREAM, 0);
+        if (socknum == -1) {
+            perror("socket");
+            return 1;
+        }
+        
+        const char *naddr = "/dev/dinitctl";
+        
+        struct sockaddr_un name;
+        name.sun_family = AF_UNIX;
+        strcpy(name.sun_path, naddr);
+        int sunlen = offsetof(struct sockaddr_un, sun_path) + strlen(naddr) + 1; // family, (string), nul
+        
+        int connr = connect(socknum, (struct sockaddr *) &name, sunlen);
+        if (connr == -1) {
+            perror("connect");
+            return 1;
+        }
+    }
+
     // Build buffer;
-    //uint16_t sname_len = strlen(service_name);
-    int bufsize = 2;
-    char * buf = new char[bufsize];
+    constexpr int bufsize = 2;
+    char buf[bufsize];
     
     buf[0] = DINIT_CP_SHUTDOWN;
     buf[1] = static_cast<char>(shutdown_type);
@@ -135,7 +161,7 @@ int main(int argc, char **argv)
     //    cout << "Received acknowledgement. System should now shut down." << endl;
     //}
     
-    CPBuffer<1024> rbuffer;
+    cpbuffer<1024> rbuffer;
     try {
         wait_for_reply(rbuffer, socknum);
         
@@ -162,7 +188,7 @@ int main(int argc, char **argv)
 //     errcode = 0   if end of stream (remote end closed)
 //     errcode = errno   if another error occurred
 // Note that EINTR is ignored (i.e. the read will be re-tried).
-static void fillBufferTo(CPBuffer<1024> *buf, int fd, int rlength)
+static void fillBufferTo(cpbuffer<1024> *buf, int fd, int rlength)
 {
     do {
         int r = buf->fill_to(fd, rlength);
@@ -183,13 +209,13 @@ static void fillBufferTo(CPBuffer<1024> *buf, int fd, int rlength)
 
 // Wait for a reply packet, skipping over any information packets
 // that are received in the meantime.
-static void wait_for_reply(CPBuffer<1024> &rbuffer, int fd)
+static void wait_for_reply(cpbuffer<1024> &rbuffer, int fd)
 {
     fillBufferTo(&rbuffer, fd, 1);
     
     while (rbuffer[0] >= 100) {
         // Information packet; discard.
-        fillBufferTo(&rbuffer, fd, 1);
+        fillBufferTo(&rbuffer, fd, 2);
         int pktlen = (unsigned char) rbuffer[1];
         
         rbuffer.consume(1);  // Consume one byte so we'll read one byte of the next packet
@@ -199,13 +225,18 @@ static void wait_for_reply(CPBuffer<1024> &rbuffer, int fd)
 }
 
 // Actually shut down the system.
-void do_system_shutdown(ShutdownType shutdown_type)
+void do_system_shutdown(shutdown_type_t shutdown_type)
 {
     using namespace std;
     
+    // Mask all signals to prevent death of our parent etc from terminating us
+    sigset_t allsigs;
+    sigfillset(&allsigs);
+    sigprocmask(SIG_SETMASK, &allsigs, nullptr);
+    
     int reboot_type = 0;
-    if (shutdown_type == ShutdownType::REBOOT) reboot_type = RB_AUTOBOOT;
-    else if (shutdown_type == ShutdownType::POWEROFF) reboot_type = RB_POWER_OFF;
+    if (shutdown_type == shutdown_type_t::REBOOT) reboot_type = RB_AUTOBOOT;
+    else if (shutdown_type == shutdown_type_t::POWEROFF) reboot_type = RB_POWER_OFF;
     else reboot_type = RB_HALT_SYSTEM;
     
     // Write to console rather than any terminal, since we lose the terminal it seems:
@@ -215,7 +246,7 @@ void do_system_shutdown(ShutdownType shutdown_type)
         dup2(consfd, STDOUT_FILENO);
     }
     
-    cout << "Sending TERM/KILL to all processes..." << endl; // DAV
+    cout << "Sending TERM/KILL to all processes..." << endl;
     
     // Send TERM/KILL to all (remaining) processes
     kill(-1, SIGTERM);