Mercurial > hg > aboriginal
changeset 1133:1ad777637d2d
Migrate oneit out of toybox into sources/toys as a standalone program, and fix it so pid 1 has / as its working directory so we can umount /home if necessary.
author | Rob Landley <rob@landley.net> |
---|---|
date | Sun, 20 Jun 2010 20:32:59 -0500 |
parents | ea4fd1dd8c3b |
children | 7bd052346d86 |
files | simple-root-filesystem.sh sources/native-root/sbin/init.sh sources/sections/toybox.build sources/toys/oneit.c |
diffstat | 4 files changed, 99 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/simple-root-filesystem.sh Sun Jun 20 18:44:46 2010 -0500 +++ b/simple-root-filesystem.sh Sun Jun 20 20:32:59 2010 -0500 @@ -44,6 +44,12 @@ cp "$WORK"/config-busybox "$STAGE_DIR"/src || dienow build_section toybox +# Build the world's simplest init program: spawns one task with a controlling +# TTY, waits (reaping zombies) until it exits, then shuts down the system. + +${ARCH}-cc "$SOURCES/toys/oneit.c" -Os $CFLAGS -o "$STAGE_DIR/sbin/oneit" || + dienow + # Put statically and dynamically linked hello world programs on there for # test purposes.
--- a/sources/native-root/sbin/init.sh Sun Jun 20 18:44:46 2010 -0500 +++ b/sources/native-root/sbin/init.sh Sun Jun 20 20:32:59 2010 -0500 @@ -75,7 +75,7 @@ HANDOFF=/mnt/init fi fi - exec /bin/oneit -c /dev/"$CONSOLE" "$HANDOFF" + exec /sbin/oneit -c /dev/"$CONSOLE" "$HANDOFF" # If we're not PID 1, it's probably a chroot. else
--- a/sources/sections/toybox.build Sun Jun 20 18:44:46 2010 -0500 +++ b/sources/sections/toybox.build Sun Jun 20 20:32:59 2010 -0500 @@ -10,7 +10,6 @@ if [ -z "$USE_TOYBOX" ] then ln -sf toybox "$INSTDIR/patch" && - ln -sf toybox "$INSTDIR/oneit" && ln -sf toybox "$INSTDIR/netcat" || dienow else make install_flat PREFIX="$INSTDIR" || dienow
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sources/toys/oneit.c Sun Jun 20 20:32:59 2010 -0500 @@ -0,0 +1,92 @@ +/* vi: set sw=4 ts=4: + * + * oneit.c, tiny one-process init replacement. + * + * Copyright 2005, 2010 by Rob Landley <rob@landley.net>. + */ + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/reboot.h> + +char *console; +int poweroff; + +// The minimum amount of work necessary to get ctrl-c and such to work is: +// +// - Fork a child (PID 1 is special: can't exit, has various signals blocked). +// - Do a setsid() (so we have our own session). +// - In the child, attach stdio to /dev/tty0 (/dev/console is special) +// - Exec the rest of the command line. +// +// 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. + + +int main(int argc, char *argv[]) +{ + int i, args; + pid_t pid; + + for (args=1; args<argc; args++) { + if (*argv[args]=='-') switch (argv[args][1]) { + case 'c': + console=argv[++args]; + continue; + case 'p': + poweroff++; + continue; + default: + args=argc; + break; + } + break; + } + if (args>=argc) { + fprintf(stderr, + "usage: oneit [-p] [-c /dev/tty0] command [...]\n\n" + "A simple init program that runs a single supplied command line with a\n" + "controlling tty (so CTRL-C can kill it).\n\n" + "-p\tPower off instead of rebooting when command exits.\n" + "-c\tWhich console device to use.\n\n" + "The oneit command runs the supplied command line as a child process\n" + "(because PID 1 has signals blocked), attached to /dev/tty0, in its\n" + "own session. Then oneit reaps zombies until the child exits, at\n" + "which point it reboots (or with -p, powers off) the system.\n"); + exit(1); + } + + // Create a new child process. + pid = vfork(); + if (pid) { + chdir("/"); + + // 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 that syscall kills the task that calls + // it, which causes the kernel to panic before the actual reboot happens. + if (!vfork()) reboot(poweroff ? RB_POWER_OFF : RB_AUTOBOOT); + sleep(5); + _exit(1); + } + + // Redirect stdio to /dev/tty0, with new session ID, so ctrl-c works. + setsid(); + if (!console) console="/dev/tty0"; + for (i=0; i<3; i++) { + close(i); + if(-1==open(console, O_RDWR)) { + fprintf(stderr, "Can't open '%s'\n", console); + exit(1); + } + } + + execvp(argv[args], argv+args); + _exit(127); +}