Browse Source

Merge "shutdown" and "dinit-reboot" functionality into the "shutdown"
executable.

dinit-reboot function (of actually unmounting file systems and performing
shutdown) is accessed using --system argument, which is not expected to
be used by users.

Davin McCall 8 years ago
parent
commit
b0fe89734e
6 changed files with 104 additions and 191 deletions
  1. 1 1
      Makefile
  2. 0 162
      dinit-reboot.cc
  3. 2 2
      dinit.cc
  4. 2 1
      halt
  5. 1 1
      reboot
  6. 98 24
      shutdown.cc

+ 1 - 1
Makefile

@@ -6,7 +6,7 @@ dinit_objects = dinit.o load_service.o service.o control.o dinit-log.o
 
 all: dinit dinit-start
 
-shutdown-utils: shutdown dinit-reboot
+shutdown-utils: shutdown
 
 dinit: $(dinit_objects)
 	$(CXX) -o dinit $(dinit_objects) -lev $(EXTRA_LIBS)

+ 0 - 162
dinit-reboot.cc

@@ -1,162 +0,0 @@
-// #include <netinet/in.h>
-#include <cstddef>
-#include <cstdio>
-#include <csignal>
-#include <unistd.h>
-#include <cstring>
-#include <string>
-#include <iostream>
-
-#include <sys/reboot.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-
-#include "control-cmds.h"
-
-// shutdown:  shut down the system
-// This utility communicates with the dinit daemon via a unix socket (/dev/initctl).
-
-static void unmount_disks();
-static void swap_off();
-
-int main(int argc, char **argv)
-{
-    using namespace std;
-    
-    int sd_type = 0;
-    
-    //bool show_help = argc < 2;
-    bool show_help = false;
-        
-    for (int i = 1; i < argc; i++) {
-        if (argv[i][0] == '-') {
-            if (strcmp(argv[i], "--help") == 0) {
-                show_help = true;
-                break;
-            }
-            else if (strcmp(argv[i], "-r") == 0) {
-                // Reboot
-                sd_type = 1;
-            }
-            else if (strcmp(argv[i], "-p") == 0) {
-                // Power down
-                sd_type = 2;
-            }
-            else if (strcmp(argv[i], "-h") == 0) {
-                // Halt
-                sd_type = 3;
-            }
-            else if (strcmp(argv[i], "-l") == 0) {
-                // Loop
-                sd_type = 0;
-            }
-            else {
-                cerr << "Unrecognized command-line parameter: " << argv[i] << endl;
-                return 1;
-            }
-        }
-        else {
-            // time argument? TODO
-            show_help = true;
-        }
-    }
-
-    if (show_help) {
-        cout << "dinit-shutdown :   shutdown the system" << endl;
-        cout << "  --help           : show this help" << endl;
-        return 1;
-    }
-    
-    if (sd_type == 0) {
-        while (true) {
-            pause();
-        }
-    }
-    
-    int reboot_type = 0;
-    if (sd_type == 1) reboot_type = RB_AUTOBOOT;
-    else if (sd_type == 2) 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:
-    close(STDOUT_FILENO);
-    int consfd = open("/dev/console", O_WRONLY);
-    if (consfd != STDOUT_FILENO) {
-        dup2(consfd, STDOUT_FILENO);
-    }
-    
-    // At this point, util-linux 2.13 shutdown sends SIGTERM to all processes with uid >= 100 and
-    // calls it 'sendiong SIGTERM to mortals'.
-    // Equivalent would probably be to rollback 'loginready' service. However, that will happen as
-    // part of the regular rollback anyway.
-    
-    //cout << "Writing rollback command..." << endl; // DAV
-    
-    //int r = write(socknum, buf, bufsize);
-    //if (r == -1) {
-    //    perror("write");
-    //}
-    
-    cout << "Sending TERM/KILL..." << endl; // DAV
-    
-    // Send TERM/KILL to all (remaining) processes
-    kill(-1, SIGTERM);
-    sleep(1);
-    kill(-1, SIGKILL);
-    
-    cout << "Sending QUIT to init..." << endl; // DAV
-    
-    // Tell init to exec reboot:
-    // TODO what if it's not PID=1? probably should have dinit pass us its PID
-    kill(1, SIGQUIT);
-    
-    // TODO can we wait somehow for above to work?
-    // maybe have a pipe/socket and we read from our end...
-    
-    // TODO: close all ancillary file descriptors.
-    
-    // perform shutdown
-    cout << "Turning off swap..." << endl;
-    swap_off();
-    cout << "Unmounting disks..." << endl;
-    unmount_disks();
-    sync();
-    
-    cout << "Issuing shutdown via kernel..." << endl;
-    reboot(reboot_type);
-    
-    return 0;
-}
-
-static void unmount_disks()
-{
-    pid_t chpid = fork();
-    if (chpid == 0) {
-        // umount -a -r
-        //  -a : all filesystems (except proc)
-        //  -r : mount readonly if can't unmount
-        execl("/bin/umount", "/bin/umount", "-a", "-r", nullptr);
-    }
-    else if (chpid > 0) {
-        int status;
-        waitpid(chpid, &status, 0);
-    }
-}
-
-static void swap_off()
-{
-    pid_t chpid = fork();
-    if (chpid == 0) {
-        // swapoff -a
-        execl("/sbin/swapoff", "/sbin/swapoff", "-a", nullptr);
-    }
-    else if (chpid > 0) {
-        int status;
-        waitpid(chpid, &status, 0);
-    }
-}

+ 2 - 2
dinit.cc

@@ -292,8 +292,8 @@ int main(int argc, char **argv)
         }
         
         // Fork and execute dinit-reboot.
-        execl("/usr/libexec/dinit-reboot", "/usr/libexec/dinit-reboot", cmd_arg, nullptr);
-        log(LogLevel::ERROR, "Could not execl() for reboot: ", strerror(errno));
+        execl("/sbin/shutdown", "/sbin/shutdown", "--system", cmd_arg, nullptr);
+        log(LogLevel::ERROR, "Could not execute /sbin/shutdown: ", strerror(errno));
         
         // PID 1 must not actually exit, although we should never reach this point:
         while (true) {

+ 2 - 1
halt

@@ -1,2 +1,3 @@
 #!/bin/sh
-shutdown -h
+# "halt" command actually executes the more useful "power off".
+shutdown -p "$@"

+ 1 - 1
reboot

@@ -1,2 +1,2 @@
 #!/bin/sh
-shutdown -r
+shutdown -r "$@"

+ 98 - 24
shutdown.cc

@@ -21,12 +21,16 @@
 // 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);
+static void unmount_disks();
+static void swap_off();
+
 int main(int argc, char **argv)
 {
     using namespace std;
     
-    //bool show_help = argc < 2;
     bool show_help = false;
+    bool sys_shutdown = false;
     
     auto shutdown_type = ShutdownType::POWEROFF;
         
@@ -36,10 +40,17 @@ int main(int argc, char **argv)
                 show_help = true;
                 break;
             }
+            
+            if (strcmp(argv[i], "--system") == 0) {
+                sys_shutdown = true;
+            }
             else if (strcmp(argv[i], "-r") == 0) {
                 shutdown_type = ShutdownType::REBOOT;
             }
             else if (strcmp(argv[i], "-h") == 0) {
+                shutdown_type = ShutdownType::HALT;
+            }
+            else if (strcmp(argv[i], "-p") == 0) {
                 shutdown_type = ShutdownType::POWEROFF;
             }
             else {
@@ -49,15 +60,27 @@ int main(int argc, char **argv)
         }
         else {
             // time argument? TODO
+            show_help = true;
         }
     }
 
     if (show_help) {
         cout << "dinit-shutdown :   shutdown the system" << endl;
         cout << "  --help           : show this help" << endl;
+        cout << "  -r               : reboot" << endl;
+        cout << "  -h               : halt system" << endl;
+        cout << "  -p               : power down (default)" << 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;
         return 1;
     }
     
+    if (sys_shutdown) {
+        do_system_shutdown(shutdown_type);
+        return 0;
+    }
+    
     int socknum = socket(AF_UNIX, SOCK_STREAM, 0);
     if (socknum == -1) {
         perror("socket");
@@ -85,27 +108,7 @@ int main(int argc, char **argv)
     buf[0] = DINIT_CP_SHUTDOWN;
     buf[1] = static_cast<char>(shutdown_type);
     
-    //memcpy(buf + 1, &sname_len, 2);
-    //memcpy(buf + 3, service_name, sname_len);
-    
-    // Make sure we can't die due to a signal at this point:
-    //sigset_t sigmask;
-    //sigfillset(&sigmask);
-    //sigprocmask(SIG_BLOCK, &sigmask, nullptr);
-    
-    // Write to console rather than any terminal, since we lose the terminal it seems:
-    //close(STDOUT_FILENO);
-    //int consfd = open("/dev/console", O_WRONLY);
-    //if (consfd != STDOUT_FILENO) {
-    //    dup2(consfd, STDOUT_FILENO);
-    //}
-    
-    // At this point, util-linux 2.13 shutdown sends SIGTERM to all processes with uid >= 100 and
-    // calls it 'sendiong SIGTERM to mortals'.
-    // Equivalent would probably be to rollback 'loginready' service. However, that will happen as
-    // part of the regular rollback anyway.
-    
-    cout << "Writing shutdown command..." << endl; // DAV
+    cout << "Issuing shutdown command..." << endl; // DAV
     
     // TODO make sure to write the whole buffer
     int r = write(socknum, buf, bufsize);
@@ -113,11 +116,82 @@ int main(int argc, char **argv)
         perror("write");
     }
     
-    cout << "Waiting for ACK..." << endl; // DAV
-    
     // Wait for ACK/NACK
     r = read(socknum, buf, 1);
     // TODO: check result
     
     return 0;
 }
+
+void do_system_shutdown(ShutdownType shutdown_type)
+{
+    using namespace std;
+    
+    int reboot_type = 0;
+    if (shutdown_type == ShutdownType::REBOOT) reboot_type = RB_AUTOBOOT;
+    else if (shutdown_type == ShutdownType::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:
+    close(STDOUT_FILENO);
+    int consfd = open("/dev/console", O_WRONLY);
+    if (consfd != STDOUT_FILENO) {
+        dup2(consfd, STDOUT_FILENO);
+    }
+    
+    cout << "Sending TERM/KILL to all processes..." << endl; // DAV
+    
+    // Send TERM/KILL to all (remaining) processes
+    kill(-1, SIGTERM);
+    sleep(1);
+    kill(-1, SIGKILL);
+    
+    // cout << "Sending QUIT to init..." << endl; // DAV
+    
+    // Tell init to exec reboot:
+    // TODO what if it's not PID=1? probably should have dinit pass us its PID
+    // kill(1, SIGQUIT);
+    
+    // TODO can we wait somehow for above to work?
+    // maybe have a pipe/socket and we read from our end...
+    
+    // TODO: close all ancillary file descriptors.
+    
+    // perform shutdown
+    cout << "Turning off swap..." << endl;
+    swap_off();
+    cout << "Unmounting disks..." << endl;
+    unmount_disks();
+    sync();
+    
+    cout << "Issuing shutdown via kernel..." << endl;
+    reboot(reboot_type);
+}
+
+static void unmount_disks()
+{
+    pid_t chpid = fork();
+    if (chpid == 0) {
+        // umount -a -r
+        //  -a : all filesystems (except proc)
+        //  -r : mount readonly if can't unmount
+        execl("/bin/umount", "/bin/umount", "-a", "-r", nullptr);
+    }
+    else if (chpid > 0) {
+        int status;
+        waitpid(chpid, &status, 0);
+    }
+}
+
+static void swap_off()
+{
+    pid_t chpid = fork();
+    if (chpid == 0) {
+        // swapoff -a
+        execl("/sbin/swapoff", "/sbin/swapoff", "-a", nullptr);
+    }
+    else if (chpid > 0) {
+        int status;
+        waitpid(chpid, &status, 0);
+    }
+}