Mercurial > hg > toybox
comparison toys/other/oneit.c @ 1725:b2b2d214727a draft
Upgrade oneit with -r (restart), -3 (send exiting PID values to child), and signal handling.
author | Rob Landley <rob@landley.net> |
---|---|
date | Mon, 09 Mar 2015 14:52:32 -0500 |
parents | 8c78a7e5486d |
children |
comparison
equal
deleted
inserted
replaced
1724:81d8a7b20ce9 | 1725:b2b2d214727a |
---|---|
1 /* oneit.c - tiny init replacement to launch a single child process. | 1 /* oneit.c - tiny init replacement to launch a single child process. |
2 * | 2 * |
3 * Copyright 2005, 2007 by Rob Landley <rob@landley.net>. | 3 * Copyright 2005, 2007 by Rob Landley <rob@landley.net>. |
4 | 4 |
5 USE_ONEIT(NEWTOY(oneit, "^<1c:p", TOYFLAG_SBIN)) | 5 USE_ONEIT(NEWTOY(oneit, "^<1nc:p3[!pn]", TOYFLAG_SBIN)) |
6 | 6 |
7 config ONEIT | 7 config ONEIT |
8 bool "oneit" | 8 bool "oneit" |
9 default y | 9 default y |
10 help | 10 help |
11 usage: oneit [-p] [-c /dev/tty0] command [...] | 11 usage: oneit [-p] [-c /dev/tty0] command [...] |
12 | 12 |
13 A simple init program that runs a single supplied command line with a | 13 Simple init program that runs a single supplied command line with a |
14 controlling tty (so CTRL-C can kill it). | 14 controlling tty (so CTRL-C can kill it). |
15 | 15 |
16 -c Which console device to use (/dev/console doesn't do CTRL-C, etc). | |
16 -p Power off instead of rebooting when command exits. | 17 -p Power off instead of rebooting when command exits. |
17 -c Which console device to use. | 18 -r Restart child when it exits. |
19 -3 Write 32 bit PID of each exiting reparented process to fd 3 of child. | |
20 (Blocking writes, child must read to avoid eventual deadlock.) | |
18 | 21 |
19 The oneit command runs the supplied command line as a child process | 22 Spawns a single child process (because PID 1 has signals blocked) |
20 (because PID 1 has signals blocked), attached to /dev/tty0, in its | 23 in its own session, reaps zombies until the child exits, then |
21 own session. Then oneit reaps zombies until the child exits, at | 24 reboots the system (or powers off with -p, or restarts the child with -r). |
22 which point it reboots (or with -p, powers off) the system. | |
23 */ | 25 */ |
24 | 26 |
25 #define FOR_oneit | 27 #define FOR_oneit |
26 #include "toys.h" | 28 #include "toys.h" |
27 #include <sys/reboot.h> | 29 #include <sys/reboot.h> |
38 // - Exec the rest of the command line. | 40 // - Exec the rest of the command line. |
39 // | 41 // |
40 // PID 1 then reaps zombies until the child process it spawned exits, at which | 42 // PID 1 then reaps zombies until the child process it spawned exits, at which |
41 // point it calls sync() and reboot(). I could stick a kill -1 in there. | 43 // point it calls sync() and reboot(). I could stick a kill -1 in there. |
42 | 44 |
45 // Perform actions in response to signals. (Only root can send us signals.) | |
46 static void oneit_signaled(int signal) | |
47 { | |
48 int action = RB_AUTOBOOT; | |
49 | |
50 toys.signal = signal; | |
51 if (signal == SIGUSR1) action = RB_HALT_SYSTEM; | |
52 if (signal == SIGUSR2) action = RB_POWER_OFF; | |
53 | |
54 // PID 1 can't call reboot() because it kills the task that calls it, | |
55 // which causes the kernel to panic before the actual reboot happens. | |
56 sync(); | |
57 if (!vfork()) reboot(action); | |
58 } | |
43 | 59 |
44 void oneit_main(void) | 60 void oneit_main(void) |
45 { | 61 { |
46 int i; | 62 int i, pid, pipes[] = {SIGUSR1, SIGUSR2, SIGTERM, SIGINT}; |
47 pid_t pid; | |
48 | 63 |
49 // Create a new child process. | 64 if (FLAG_3) { |
50 pid = vfork(); | 65 // Ensure next available filehandle is #3 |
51 if (pid) { | 66 while (open("/", 0) < 3); |
52 | 67 close(3); |
53 // pid 1 just reaps zombies until it gets its child, then halts the system. | 68 close(4); |
54 while (pid != wait(&i)); | 69 if (pipe(pipes)) perror_exit("pipe"); |
55 sync(); | 70 fcntl(4, F_SETFD, FD_CLOEXEC); |
56 | |
57 // PID 1 can't call reboot() because it kills the task that calls it, | |
58 // which causes the kernel to panic before the actual reboot happens. | |
59 if (!vfork()) reboot((toys.optflags & FLAG_p) ? RB_POWER_OFF : RB_AUTOBOOT); | |
60 sleep(5); | |
61 _exit(1); | |
62 } | 71 } |
63 | 72 |
64 // Redirect stdio to /dev/tty0, with new session ID, so ctrl-c works. | 73 // Setup signal handlers for signals of interest |
65 setsid(); | 74 for (i = 0; i<ARRAY_LEN(pipes); i++) xsignal(pipes[i], oneit_signaled); |
66 for (i=0; i<3; i++) { | 75 |
67 close(i); | 76 while (!toys.signal) { |
68 // Remember, O_CLOEXEC is backwards for xopen() | 77 |
69 xopen(TT.console ? TT.console : "/dev/tty0", O_RDWR|O_CLOEXEC); | 78 // Create a new child process. |
79 pid = vfork(); | |
80 if (pid) { | |
81 | |
82 // pid 1 reaps zombies until it gets its child, then halts system. | |
83 // We ignore the return value of write (what would we do with it?) | |
84 // but save it in a variable we never read to make fortify shut up. | |
85 // (Real problem is if pid2 never reads, write() fills pipe and blocks.) | |
86 while (pid != wait(&i)) if (FLAG_3) i = write(4, &pid, 4); | |
87 if (toys.optflags & FLAG_n) continue; | |
88 | |
89 oneit_signaled((toys.optflags & FLAG_p) ? SIGUSR2 : SIGTERM); | |
90 } else { | |
91 // Redirect stdio to /dev/tty0, with new session ID, so ctrl-c works. | |
92 setsid(); | |
93 for (i=0; i<3; i++) { | |
94 close(i); | |
95 // Remember, O_CLOEXEC is backwards for xopen() | |
96 xopen(TT.console ? TT.console : "/dev/tty0", O_RDWR|O_CLOEXEC); | |
97 } | |
98 | |
99 // Can't xexec() here, we vforked so we don't want to error_exit(). | |
100 toy_exec(toys.optargs); | |
101 execvp(*toys.optargs, toys.optargs); | |
102 perror_msg("%s not in PATH=%s", *toys.optargs, getenv("PATH")); | |
103 | |
104 break; | |
105 } | |
70 } | 106 } |
71 | 107 |
72 // Can't xexec() here, because we vforked so we don't want to error_exit(). | 108 // Give reboot() time to kick in, or avoid rapid spinning if exec failed |
73 toy_exec(toys.optargs); | 109 sleep(5); |
74 execvp(*toys.optargs, toys.optargs); | |
75 _exit(127); | 110 _exit(127); |
76 } | 111 } |