--- busybox.orig/runit/runsvdir.c Thu Sep 24 23:41:41 2009 +++ busybox/runit/runsvdir.c Mon Nov 2 21:34:47 2009 @@ -28,11 +28,11 @@ /* Busyboxed by Denys Vlasenko */ /* TODO: depends on runit_lib.c - review and reduce/eliminate */ -#include -#include #include "libbb.h" #include "runit_lib.h" +#include + #define MAXSERVICES 1000 /* Should be not needed - all dirs are on same FS, right? */ @@ -208,6 +208,14 @@ return need_rescan; } +static void killall(smallint signo) +{ + int i; + for (i = 0; i < svnum; i++) + if (sv[i].pid) + kill(sv[i].pid, signo); +} + int runsvdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int runsvdir_main(int argc UNUSED_PARAM, char **argv) { @@ -223,14 +231,12 @@ unsigned stampcheck; int i; int need_rescan = 1; - char *opt_s_argv[3]; + bool is_init = (getpid() == 1); INIT_G(); opt_complementary = "-1"; - opt_s_argv[0] = NULL; - opt_s_argv[2] = NULL; - getopt32(argv, "Ps:", &opt_s_argv[0]); + getopt32(argv, "P"); argv += optind; bb_signals(0 @@ -239,12 +245,8 @@ /* For busybox's init, SIGTERM == reboot, * SIGUSR1 == halt * SIGUSR2 == poweroff - * so we need to intercept SIGUSRn too. - * Note that we do not implement actual reboot - * (killall(TERM) + umount, etc), we just pause - * respawing and avoid exiting (-> making kernel oops). - * The user is responsible for the rest. */ - | (getpid() == 1 ? ((1 << SIGUSR1) | (1 << SIGUSR2)) : 0) + * so we need to intercept SIGUSRn too. */ + | (is_init ? ((1 << SIGUSR1) | (1 << SIGUSR2)) : 0) , record_signo); svdir = *argv++; @@ -359,35 +361,57 @@ } } #endif - if (!bb_got_signal) - continue; + if (bb_got_signal) { + // init signalled -> sync and wait a while + if (is_init) { + sync(); sleep(3); + // vanilla runsvdir, any signal causes exit + // just go on exiting + } else + break; - /* -s SCRIPT: useful if we are init. - * In this case typically script never returns, - * it halts/powers off/reboots the system. */ - if (opt_s_argv[0]) { - /* Single parameter: signal# */ - opt_s_argv[1] = utoa(bb_got_signal); - pid = spawn(opt_s_argv); - if (pid > 0) { - /* Remembering to wait for _any_ children, - * not just pid */ - while (wait(NULL) != pid) - continue; + // N.B. we are here if we are init + + // SIGHUP means go on serving + if (SIGHUP == bb_got_signal) + bb_got_signal = 0; + + // kill all services + killall(SIGTERM); + killall(SIGCONT); + // let services exit cleanly + sync(); sleep(5); sync(); + + // kill survived services + killall(SIGKILL); + sync(); sleep(3); sync(); + + // SIGHUP means go on serving + if (SIGHUP == bb_got_signal) + continue; + + // we surely have to halt/poweroff/reboot if we are here + + // mimic umount -a + { + // echo u >/proc/sysrq-trigger + int fd = open("/proc/sysrq-trigger", O_WRONLY); + if (fd != -1) { + write(fd, "u", 1); + close(fd); + sleep(3); + } } - } - if (bb_got_signal == SIGHUP) { - for (i = 0; i < svnum; i++) - if (sv[i].pid) - kill(sv[i].pid, SIGTERM); + // SIGUSR1 means halt + // SIGUSR2 means poweroff + // SIGTERM means reboot + reboot( + (SIGUSR1 == bb_got_signal) ? RB_HALT_SYSTEM : + (SIGUSR2 == bb_got_signal) ? RB_POWER_OFF : RB_AUTOBOOT + ); } - /* SIGHUP or SIGTERM (or SIGUSRn if we are init) */ - /* Exit unless we are init */ - if (getpid() != 1) - return (SIGHUP == bb_got_signal) ? 111 : EXIT_SUCCESS; - - /* init continues to monitor services forever */ - bb_got_signal = 0; } /* for (;;) */ + + return (SIGHUP == bb_got_signal) ? 111 : EXIT_SUCCESS; }