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. --- toys/other/oneit.c | 99 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 32 deletions(-) (limited to 'toys') 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