From: Davin McCall Date: Thu, 31 Dec 2015 22:09:51 +0000 (+0000) Subject: Merge "shutdown" and "dinit-reboot" functionality into the "shutdown" X-Git-Tag: v0.01~79 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=b0fe89734e8b60d6926ce18bd74643d50c9d8a23;p=oweals%2Fdinit.git 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. --- diff --git a/Makefile b/Makefile index 245a0b8..fe89883 100644 --- a/Makefile +++ b/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) diff --git a/dinit-reboot.cc b/dinit-reboot.cc deleted file mode 100644 index d57ad31..0000000 --- a/dinit-reboot.cc +++ /dev/null @@ -1,162 +0,0 @@ -// #include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - - -#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); - } -} diff --git a/dinit.cc b/dinit.cc index 0973946..317dffa 100644 --- a/dinit.cc +++ b/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) { diff --git a/halt b/halt index d8ad55c..4987aff 100755 --- a/halt +++ b/halt @@ -1,2 +1,3 @@ #!/bin/sh -shutdown -h +# "halt" command actually executes the more useful "power off". +shutdown -p "$@" diff --git a/reboot b/reboot index 285a393..c607879 100755 --- a/reboot +++ b/reboot @@ -1,2 +1,2 @@ #!/bin/sh -shutdown -r +shutdown -r "$@" diff --git a/shutdown.cc b/shutdown.cc index aa0f6a7..1d46ab2 100644 --- a/shutdown.cc +++ b/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(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); + } +}