From e6abb61e057d55a08c263a48648aaf7b776dfcee Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Mon, 9 Mar 2015 14:52:32 -0500 Subject: Upgrade oneit with -r (restart), -3 (send exiting PID values to child), and signal handling. --- lib/lib.h | 1 + lib/xwrap.c | 11 ++++++ toys/other/oneit.c | 99 ++++++++++++++++++++++++++++++++++++------------------ 3 files changed, 79 insertions(+), 32 deletions(-) diff --git a/lib/lib.h b/lib/lib.h index a183fd56..e5667517 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -129,6 +129,7 @@ long xparsetime(char *arg, long units, long *fraction); void xpidfile(char *name); void xregcomp(regex_t *preg, char *rexec, int cflags); char *xtzset(char *new); +void xsignal(int signal, void *handler); // lib.c void verror_msg(char *msg, int err, va_list va); diff --git a/lib/xwrap.c b/lib/xwrap.c index 14703a72..44cd1684 100644 --- a/lib/xwrap.c +++ b/lib/xwrap.c @@ -638,3 +638,14 @@ char *xtzset(char *new) return tz; } + +// Set a signal handler +void xsignal(int signal, void *handler) +{ + struct sigaction *sa = (void *)libbuf; + + memset(sa, 0, sizeof(struct sigaction)); + sa->sa_handler = handler; + + if (sigaction(signal, sa, 0)) perror_exit("xsignal %d", signal); +} diff --git a/toys/other/oneit.c b/toys/other/oneit.c index 72395cce..8e4b7133 100644 --- a/toys/other/oneit.c +++ b/toys/other/oneit.c @@ -2,7 +2,7 @@ * * Copyright 2005, 2007 by Rob Landley . -USE_ONEIT(NEWTOY(oneit, "^<1c:p", TOYFLAG_SBIN)) +USE_ONEIT(NEWTOY(oneit, "^<1nc:p3[!pn]", TOYFLAG_SBIN)) config ONEIT bool "oneit" @@ -10,16 +10,18 @@ config ONEIT help usage: oneit [-p] [-c /dev/tty0] command [...] - A simple init program that runs a single supplied command line with a + Simple init program that runs a single supplied command line with a controlling tty (so CTRL-C can kill it). + -c Which console device to use (/dev/console doesn't do CTRL-C, etc). -p Power off instead of rebooting when command exits. - -c Which console device to use. + -r Restart child when it exits. + -3 Write 32 bit PID of each exiting reparented process to fd 3 of child. + (Blocking writes, child must read to avoid eventual deadlock.) - The oneit command runs the supplied command line as a child process - (because PID 1 has signals blocked), attached to /dev/tty0, in its - own session. Then oneit reaps zombies until the child exits, at - which point it reboots (or with -p, powers off) the system. + Spawns a single child process (because PID 1 has signals blocked) + in its own session, reaps zombies until the child exits, then + reboots the system (or powers off with -p, or restarts the child with -r). */ #define FOR_oneit @@ -40,37 +42,70 @@ GLOBALS( // PID 1 then reaps zombies until the child process it spawned exits, at which // point it calls sync() and reboot(). I could stick a kill -1 in there. +// Perform actions in response to signals. (Only root can send us signals.) +static void oneit_signaled(int signal) +{ + int action = RB_AUTOBOOT; + + toys.signal = signal; + if (signal == SIGUSR1) action = RB_HALT_SYSTEM; + if (signal == SIGUSR2) action = RB_POWER_OFF; + + // PID 1 can't call reboot() because it kills the task that calls it, + // which causes the kernel to panic before the actual reboot happens. + sync(); + if (!vfork()) reboot(action); +} void oneit_main(void) { - int i; - pid_t pid; - - // Create a new child process. - pid = vfork(); - if (pid) { - - // pid 1 just reaps zombies until it gets its child, then halts the system. - while (pid != wait(&i)); - sync(); - - // PID 1 can't call reboot() because it kills the task that calls it, - // which causes the kernel to panic before the actual reboot happens. - if (!vfork()) reboot((toys.optflags & FLAG_p) ? RB_POWER_OFF : RB_AUTOBOOT); - sleep(5); - _exit(1); + int i, pid, pipes[] = {SIGUSR1, SIGUSR2, SIGTERM, SIGINT}; + + if (FLAG_3) { + // Ensure next available filehandle is #3 + while (open("/", 0) < 3); + close(3); + close(4); + if (pipe(pipes)) perror_exit("pipe"); + fcntl(4, F_SETFD, FD_CLOEXEC); } - // Redirect stdio to /dev/tty0, with new session ID, so ctrl-c works. - setsid(); - for (i=0; i<3; i++) { - close(i); - // Remember, O_CLOEXEC is backwards for xopen() - xopen(TT.console ? TT.console : "/dev/tty0", O_RDWR|O_CLOEXEC); + // Setup signal handlers for signals of interest + for (i = 0; i