Mercurial > hg > aboriginal
diff sources/toys/oneit.c @ 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 | |
children |
line wrap: on
line diff
--- /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); +}