diff options
author | Glenn L McGrath <bug1@ihug.co.nz> | 2003-05-11 14:52:39 +0000 |
---|---|---|
committer | Glenn L McGrath <bug1@ihug.co.nz> | 2003-05-11 14:52:39 +0000 |
commit | 1e11c34be4decfef8fbda8a8e01cd60def8232e5 (patch) | |
tree | 6e93956fef2bcd4c1db18031dc081dcaf689f2d1 | |
parent | 8c6887c855460ee9e688e2a51e29f99faa2a2d8c (diff) | |
download | busybox-w32-1e11c34be4decfef8fbda8a8e01cd60def8232e5.tar.gz busybox-w32-1e11c34be4decfef8fbda8a8e01cd60def8232e5.tar.bz2 busybox-w32-1e11c34be4decfef8fbda8a8e01cd60def8232e5.zip |
minit, a Minimal init system.
-rw-r--r-- | include/applets.h | 9 | ||||
-rw-r--r-- | include/usage.h | 29 | ||||
-rw-r--r-- | init/Config.in | 20 | ||||
-rw-r--r-- | init/Makefile.in | 3 | ||||
-rw-r--r-- | init/minit.c | 612 | ||||
-rw-r--r-- | init/msvc.c | 300 | ||||
-rw-r--r-- | init/pidfilehack.c | 78 |
7 files changed, 1051 insertions, 0 deletions
diff --git a/include/applets.h b/include/applets.h index 668c84914..6697be5ee 100644 --- a/include/applets.h +++ b/include/applets.h | |||
@@ -358,6 +358,9 @@ | |||
358 | #ifdef CONFIG_MESG | 358 | #ifdef CONFIG_MESG |
359 | APPLET(mesg, mesg_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) | 359 | APPLET(mesg, mesg_main, _BB_DIR_USR_BIN, _BB_SUID_NEVER) |
360 | #endif | 360 | #endif |
361 | #ifdef CONFIG_MINIT | ||
362 | APPLET(minit, minit_main, _BB_DIR_SBIN, _BB_SUID_NEVER) | ||
363 | #endif | ||
361 | #ifdef CONFIG_MKDIR | 364 | #ifdef CONFIG_MKDIR |
362 | APPLET(mkdir, mkdir_main, _BB_DIR_BIN, _BB_SUID_NEVER) | 365 | APPLET(mkdir, mkdir_main, _BB_DIR_BIN, _BB_SUID_NEVER) |
363 | #endif | 366 | #endif |
@@ -388,6 +391,9 @@ | |||
388 | #ifdef CONFIG_MSH | 391 | #ifdef CONFIG_MSH |
389 | APPLET_NOUSAGE("msh", msh_main, _BB_DIR_BIN, _BB_SUID_NEVER) | 392 | APPLET_NOUSAGE("msh", msh_main, _BB_DIR_BIN, _BB_SUID_NEVER) |
390 | #endif | 393 | #endif |
394 | #ifdef CONFIG_MSVC | ||
395 | APPLET(msvc, msvc_main, _BB_DIR_BIN, _BB_SUID_NEVER) | ||
396 | #endif | ||
391 | #ifdef CONFIG_MT | 397 | #ifdef CONFIG_MT |
392 | APPLET(mt, mt_main, _BB_DIR_BIN, _BB_SUID_NEVER) | 398 | APPLET(mt, mt_main, _BB_DIR_BIN, _BB_SUID_NEVER) |
393 | #endif | 399 | #endif |
@@ -415,6 +421,9 @@ | |||
415 | #ifdef CONFIG_PASSWD | 421 | #ifdef CONFIG_PASSWD |
416 | APPLET(passwd, passwd_main, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS) | 422 | APPLET(passwd, passwd_main, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS) |
417 | #endif | 423 | #endif |
424 | #ifdef CONFIG_PIDFILEHACK | ||
425 | APPLET(pidfilehack, pidfilehack_main, _BB_DIR_BIN, _BB_SUID_NEVER) | ||
426 | #endif | ||
418 | #ifdef CONFIG_PIDOF | 427 | #ifdef CONFIG_PIDOF |
419 | APPLET(pidof, pidof_main, _BB_DIR_BIN, _BB_SUID_NEVER) | 428 | APPLET(pidof, pidof_main, _BB_DIR_BIN, _BB_SUID_NEVER) |
420 | #endif | 429 | #endif |
diff --git a/include/usage.h b/include/usage.h index e98e8b97c..fde6bbe76 100644 --- a/include/usage.h +++ b/include/usage.h | |||
@@ -1430,6 +1430,11 @@ | |||
1430 | "\ty\tAllow write access to your terminal.\n" \ | 1430 | "\ty\tAllow write access to your terminal.\n" \ |
1431 | "\tn\tDisallow write access to your terminal.\n" | 1431 | "\tn\tDisallow write access to your terminal.\n" |
1432 | 1432 | ||
1433 | #define minit_trivial_usage \ | ||
1434 | "[-spPrRC]" | ||
1435 | #define minit_full_usage \ | ||
1436 | "[-spPrRC]" | ||
1437 | |||
1433 | #define mkdir_trivial_usage \ | 1438 | #define mkdir_trivial_usage \ |
1434 | "[OPTION] DIRECTORY..." | 1439 | "[OPTION] DIRECTORY..." |
1435 | #define mkdir_full_usage \ | 1440 | #define mkdir_full_usage \ |
@@ -1559,6 +1564,25 @@ | |||
1559 | "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \ | 1564 | "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \ |
1560 | "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" | 1565 | "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" |
1561 | 1566 | ||
1567 | #define msvc_trivial_usage \ | ||
1568 | "-[udorspchaitkx] service" | ||
1569 | #define msvc_full_usafe \ | ||
1570 | "[option] service\n" \ | ||
1571 | "Where option is one of\n" \ | ||
1572 | "\t-u\tUp. If the service is not running, start it. If the service stops, restart it.\n" \ | ||
1573 | "\t-d\tDown. If the service is running, stop it, do not restart it.\n" \ | ||
1574 | "\t-o\tOnce. If the service is not running, start it. Do not restart it if it stops.\n" \ | ||
1575 | "\t-r\tTell supervise that the service is normally running; this affects status messages.\n" \ | ||
1576 | "\t-s\tTell supervise that the service is normally stopped; this affects status messages.\n" \ | ||
1577 | "\t-p\tPause. Send the service a STOP signal.\n" \ | ||
1578 | "\t-c\tContinue. Send the service a CONT signal.\n" \ | ||
1579 | "\t-h\tHangup. Send the service a HUP signal.\n" \ | ||
1580 | "\t-a\tAlarm. Send the service an ALRM signal.\n" \ | ||
1581 | "\t-i\tInterrupt. Send the service an INT signal.\n" \ | ||
1582 | "\t-t\tTerminate. Send the service a TERM signal.\n" \ | ||
1583 | "\t-k\tKill. Send the service a KILL signal.\n" \ | ||
1584 | "\t-x\tExit. supervise will quit as soon as the service is down.\n" | ||
1585 | |||
1562 | #define mt_trivial_usage \ | 1586 | #define mt_trivial_usage \ |
1563 | "[-f device] opcode value" | 1587 | "[-f device] opcode value" |
1564 | #define mt_full_usage \ | 1588 | #define mt_full_usage \ |
@@ -1666,6 +1690,11 @@ | |||
1666 | "\t-l\tLocks (disables) the specified user account.\n" \ | 1690 | "\t-l\tLocks (disables) the specified user account.\n" \ |
1667 | "\t-u\tUnlocks (re-enables) the specified user account." | 1691 | "\t-u\tUnlocks (re-enables) the specified user account." |
1668 | 1692 | ||
1693 | #define pidfilehack_trivial_usage \ | ||
1694 | "[daemon.pid] [daemon]" | ||
1695 | #define pidfilehack_full_usage \ | ||
1696 | "service /var/run/daemon.pid /usr/sbin/daemon args...\n" | ||
1697 | |||
1669 | #define pidof_trivial_usage \ | 1698 | #define pidof_trivial_usage \ |
1670 | "process-name [process-name ...]" | 1699 | "process-name [process-name ...]" |
1671 | #define pidof_full_usage \ | 1700 | #define pidof_full_usage \ |
diff --git a/init/Config.in b/init/Config.in index 90173c552..a478e07c8 100644 --- a/init/Config.in +++ b/init/Config.in | |||
@@ -61,6 +61,26 @@ config CONFIG_REBOOT | |||
61 | help | 61 | help |
62 | Please submit a patch to add help text for this item. | 62 | Please submit a patch to add help text for this item. |
63 | 63 | ||
64 | config CONFIG_MINIT | ||
65 | bool "minit" | ||
66 | default n | ||
67 | help | ||
68 | Minimal init, based on minit v0.9.1 | ||
69 | |||
70 | config CONFIG_PIDFILEHACK | ||
71 | bool "pidfilehack" | ||
72 | default y | ||
73 | depends on CONFIG_MINIT | ||
74 | help | ||
75 | pidfilehack is used by minit to run servers. | ||
76 | |||
77 | config CONFIG_MSVC | ||
78 | bool "msvc" | ||
79 | default y | ||
80 | depends on CONFIG_MINIT | ||
81 | help | ||
82 | msvc is used to start and stop processes controlled by minit | ||
83 | |||
64 | # Should start-stop-daemon be moved under debianutils? | 84 | # Should start-stop-daemon be moved under debianutils? |
65 | config CONFIG_START_STOP_DAEMON | 85 | config CONFIG_START_STOP_DAEMON |
66 | bool "start-stop-daemon" | 86 | bool "start-stop-daemon" |
diff --git a/init/Makefile.in b/init/Makefile.in index a43c4a7f4..9e2f4bcf7 100644 --- a/init/Makefile.in +++ b/init/Makefile.in | |||
@@ -26,6 +26,9 @@ INIT-y:= | |||
26 | INIT-$(CONFIG_HALT) += halt.o | 26 | INIT-$(CONFIG_HALT) += halt.o |
27 | INIT-$(CONFIG_INIT) += init.o | 27 | INIT-$(CONFIG_INIT) += init.o |
28 | INIT-$(CONFIG_MESG) += mesg.o | 28 | INIT-$(CONFIG_MESG) += mesg.o |
29 | INIT-$(CONFIG_MINIT) += minit.o | ||
30 | INIT-$(CONFIG_MSVC) += msvc.o | ||
31 | INIT-$(CONFIG_PIDFILEHACK) += pidfilehack.o | ||
29 | INIT-$(CONFIG_POWEROFF) += poweroff.o | 32 | INIT-$(CONFIG_POWEROFF) += poweroff.o |
30 | INIT-$(CONFIG_REBOOT) += reboot.o | 33 | INIT-$(CONFIG_REBOOT) += reboot.o |
31 | INIT-$(CONFIG_START_STOP_DAEMON) += start_stop_daemon.o | 34 | INIT-$(CONFIG_START_STOP_DAEMON) += start_stop_daemon.o |
diff --git a/init/minit.c b/init/minit.c new file mode 100644 index 000000000..6645dc6ce --- /dev/null +++ b/init/minit.c | |||
@@ -0,0 +1,612 @@ | |||
1 | /* | ||
2 | * minit version 0.9.1 by Felix von Leitner | ||
3 | * ported to busybox by Glenn McGrath <bug1@optushome.com.au> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <time.h> | ||
21 | #include <signal.h> | ||
22 | #include <stdio.h> | ||
23 | #include <stdlib.h> | ||
24 | #include <string.h> | ||
25 | #include <unistd.h> | ||
26 | #include <limits.h> | ||
27 | #include <errno.h> | ||
28 | #include <sys/fcntl.h> | ||
29 | #include <sys/ioctl.h> | ||
30 | #include <sys/poll.h> | ||
31 | #include <sys/reboot.h> | ||
32 | #include <sys/socket.h> | ||
33 | #include <sys/types.h> | ||
34 | #include <sys/un.h> | ||
35 | #include <sys/wait.h> | ||
36 | #include <linux/kd.h> | ||
37 | |||
38 | #include "busybox.h" | ||
39 | |||
40 | #define MINITROOT "/etc/minit" | ||
41 | |||
42 | static int i_am_init; | ||
43 | static int infd, outfd; | ||
44 | |||
45 | extern char **environ; | ||
46 | |||
47 | static struct process { | ||
48 | char *name; | ||
49 | pid_t pid; | ||
50 | char respawn; | ||
51 | char circular; | ||
52 | time_t startedat; | ||
53 | int __stdin, __stdout; | ||
54 | int logservice; | ||
55 | } *root; | ||
56 | |||
57 | static int maxprocess = -1; | ||
58 | |||
59 | static int processalloc = 0; | ||
60 | |||
61 | static unsigned int fmt_ulong(char *dest, unsigned long i) | ||
62 | { | ||
63 | register unsigned long len, tmp, len2; | ||
64 | |||
65 | /* first count the number of bytes needed */ | ||
66 | for (len = 1, tmp = i; tmp > 9; ++len) | ||
67 | tmp /= 10; | ||
68 | if (dest) | ||
69 | for (tmp = i, dest += len, len2 = len + 1; --len2; tmp /= 10) | ||
70 | *--dest = (tmp % 10) + '0'; | ||
71 | return len; | ||
72 | } | ||
73 | |||
74 | /* split buf into n strings that are separated by c. return n as *len. | ||
75 | * Allocate plus more slots and leave the first ofs of them alone. */ | ||
76 | static char **split(char *buf, int c, int *len, int plus, int ofs) | ||
77 | { | ||
78 | int n = 1; | ||
79 | char **v = 0; | ||
80 | char **w; | ||
81 | |||
82 | /* step 1: count tokens */ | ||
83 | char *s; | ||
84 | |||
85 | for (s = buf; *s; s++) | ||
86 | if (*s == c) | ||
87 | n++; | ||
88 | /* step 2: allocate space for pointers */ | ||
89 | v = (char **) malloc((n + plus) * sizeof(char *)); | ||
90 | if (!v) | ||
91 | return 0; | ||
92 | w = v + ofs; | ||
93 | *w++ = buf; | ||
94 | for (s = buf;; s++) { | ||
95 | while (*s && *s != c) | ||
96 | s++; | ||
97 | if (*s == 0) | ||
98 | break; | ||
99 | if (*s == c) { | ||
100 | *s = 0; | ||
101 | *w++ = s + 1; | ||
102 | } | ||
103 | } | ||
104 | *len = w - v; | ||
105 | return v; | ||
106 | } | ||
107 | |||
108 | static int openreadclose(char *fn, char **buf, unsigned long *len) | ||
109 | { | ||
110 | int fd = open(fn, O_RDONLY); | ||
111 | |||
112 | if (fd < 0) | ||
113 | return -1; | ||
114 | if (!*buf) { | ||
115 | *len = lseek(fd, 0, SEEK_END); | ||
116 | lseek(fd, 0, SEEK_SET); | ||
117 | *buf = (char *) malloc(*len + 1); | ||
118 | if (!*buf) { | ||
119 | close(fd); | ||
120 | return -1; | ||
121 | } | ||
122 | } | ||
123 | *len = read(fd, *buf, *len); | ||
124 | if (*len != (unsigned long) -1) | ||
125 | (*buf)[*len] = 0; | ||
126 | return close(fd); | ||
127 | } | ||
128 | |||
129 | /* return index of service in process data structure or -1 if not found */ | ||
130 | static int findservice(char *service) | ||
131 | { | ||
132 | int i; | ||
133 | |||
134 | for (i = 0; i <= maxprocess; i++) { | ||
135 | if (!strcmp(root[i].name, service)) | ||
136 | return i; | ||
137 | } | ||
138 | return -1; | ||
139 | } | ||
140 | |||
141 | /* look up process index in data structure by PID */ | ||
142 | static int findbypid(pid_t pid) | ||
143 | { | ||
144 | int i; | ||
145 | |||
146 | for (i = 0; i <= maxprocess; i++) { | ||
147 | if (root[i].pid == pid) | ||
148 | return i; | ||
149 | } | ||
150 | return -1; | ||
151 | } | ||
152 | |||
153 | /* clear circular dependency detection flags */ | ||
154 | static void circsweep(void) | ||
155 | { | ||
156 | int i; | ||
157 | |||
158 | for (i = 0; i <= maxprocess; i++) | ||
159 | root[i].circular = 0; | ||
160 | } | ||
161 | |||
162 | /* add process to data structure, return index or -1 */ | ||
163 | static int addprocess(struct process *p) | ||
164 | { | ||
165 | if (maxprocess + 1 >= processalloc) { | ||
166 | struct process *fump; | ||
167 | |||
168 | processalloc += 8; | ||
169 | if ((fump = | ||
170 | (struct process *) xrealloc(root, | ||
171 | processalloc * | ||
172 | sizeof(struct process))) == 0) | ||
173 | return -1; | ||
174 | root = fump; | ||
175 | } | ||
176 | memmove(&root[++maxprocess], p, sizeof(struct process)); | ||
177 | return maxprocess; | ||
178 | } | ||
179 | |||
180 | /* load a service into the process data structure and return index or -1 | ||
181 | * if failed */ | ||
182 | static int loadservice(char *service) | ||
183 | { | ||
184 | struct process tmp; | ||
185 | int fd; | ||
186 | |||
187 | if (*service == 0) | ||
188 | return -1; | ||
189 | fd = findservice(service); | ||
190 | if (fd >= 0) | ||
191 | return fd; | ||
192 | if (chdir(MINITROOT) || chdir(service)) | ||
193 | return -1; | ||
194 | if (!(tmp.name = strdup(service))) | ||
195 | return -1; | ||
196 | tmp.pid = 0; | ||
197 | fd = open("respawn", O_RDONLY); | ||
198 | if (fd >= 0) { | ||
199 | tmp.respawn = 1; | ||
200 | close(fd); | ||
201 | } else | ||
202 | tmp.respawn = 0; | ||
203 | tmp.startedat = 0; | ||
204 | tmp.circular = 0; | ||
205 | tmp.__stdin = 0; | ||
206 | tmp.__stdout = 1; | ||
207 | { | ||
208 | char *logservice = alloca(strlen(service) + 5); | ||
209 | |||
210 | strcpy(logservice, service); | ||
211 | strcat(logservice, "/log"); | ||
212 | tmp.logservice = loadservice(logservice); | ||
213 | if (tmp.logservice >= 0) { | ||
214 | int pipefd[2]; | ||
215 | |||
216 | if (pipe(pipefd)) | ||
217 | return -1; | ||
218 | root[tmp.logservice].__stdin = pipefd[0]; | ||
219 | tmp.__stdout = pipefd[1]; | ||
220 | } | ||
221 | } | ||
222 | return (addprocess(&tmp)); | ||
223 | } | ||
224 | |||
225 | /* usage: isup(findservice("sshd")). | ||
226 | * returns nonzero if process is up */ | ||
227 | static int isup(int service) | ||
228 | { | ||
229 | if (service < 0) | ||
230 | return 0; | ||
231 | return (root[service].pid != 0); | ||
232 | } | ||
233 | |||
234 | static void opendevconsole(void) | ||
235 | { | ||
236 | int fd; | ||
237 | |||
238 | if ((fd = open("/dev/console", O_RDWR | O_NOCTTY)) >= 0) { | ||
239 | dup2(fd, 0); | ||
240 | dup2(fd, 1); | ||
241 | dup2(fd, 2); | ||
242 | if (fd > 2) | ||
243 | close(fd); | ||
244 | } | ||
245 | } | ||
246 | |||
247 | /* called from inside the service directory, return the PID or 0 on error */ | ||
248 | static pid_t forkandexec(int pause_flag, int service) | ||
249 | { | ||
250 | char **argv = 0; | ||
251 | int count = 0; | ||
252 | pid_t p; | ||
253 | int fd; | ||
254 | unsigned long len; | ||
255 | char *s = 0; | ||
256 | int argc; | ||
257 | char *argv0 = 0; | ||
258 | |||
259 | again: | ||
260 | switch (p = fork()) { | ||
261 | case (pid_t) - 1: | ||
262 | if (count > 3) | ||
263 | return 0; | ||
264 | sleep(++count * 2); | ||
265 | goto again; | ||
266 | case 0: | ||
267 | /* child */ | ||
268 | |||
269 | if (i_am_init) { | ||
270 | ioctl(0, TIOCNOTTY, 0); | ||
271 | setsid(); | ||
272 | opendevconsole(); | ||
273 | tcsetpgrp(0, getpgrp()); | ||
274 | } | ||
275 | close(infd); | ||
276 | close(outfd); | ||
277 | if (pause_flag) { | ||
278 | struct timespec req; | ||
279 | |||
280 | req.tv_sec = 0; | ||
281 | req.tv_nsec = 500000000; | ||
282 | nanosleep(&req, 0); | ||
283 | } | ||
284 | if (!openreadclose("params", &s, &len)) { | ||
285 | argv = split(s, '\n', &argc, 2, 1); | ||
286 | if (argv[argc - 1]) | ||
287 | argv[argc - 1] = 0; | ||
288 | else | ||
289 | argv[argc] = 0; | ||
290 | } else { | ||
291 | argv = (char **) xmalloc(2 * sizeof(char *)); | ||
292 | argv[1] = 0; | ||
293 | } | ||
294 | argv0 = (char *) xmalloc(PATH_MAX + 1); | ||
295 | if (!argv || !argv0) | ||
296 | goto abort; | ||
297 | if (readlink("run", argv0, PATH_MAX) < 0) { | ||
298 | if (errno != EINVAL) | ||
299 | goto abort; /* not a symbolic link */ | ||
300 | argv0 = strdup("./run"); | ||
301 | } | ||
302 | argv[0] = strrchr(argv0, '/'); | ||
303 | if (argv[0]) | ||
304 | argv[0]++; | ||
305 | else | ||
306 | argv[0] = argv0; | ||
307 | if (root[service].__stdin != 0) | ||
308 | dup2(root[service].__stdin, 0); | ||
309 | if (root[service].__stdout != 1) { | ||
310 | dup2(root[service].__stdout, 1); | ||
311 | dup2(root[service].__stdout, 2); | ||
312 | } | ||
313 | { | ||
314 | int i; | ||
315 | |||
316 | for (i = 3; i < 1024; ++i) | ||
317 | close(i); | ||
318 | } | ||
319 | execve(argv0, argv, environ); | ||
320 | _exit(0); | ||
321 | abort: | ||
322 | free(argv0); | ||
323 | free(argv); | ||
324 | _exit(0); | ||
325 | default: | ||
326 | fd = open("sync", O_RDONLY); | ||
327 | if (fd >= 0) { | ||
328 | pid_t p2; | ||
329 | |||
330 | close(fd); | ||
331 | p2 = waitpid(p, 0, 0); | ||
332 | return 1; | ||
333 | } | ||
334 | return p; | ||
335 | } | ||
336 | } | ||
337 | |||
338 | /* start a service, return nonzero on error */ | ||
339 | static int startnodep(int service, int pause_flag) | ||
340 | { | ||
341 | /* step 1: see if the process is already up */ | ||
342 | if (isup(service)) | ||
343 | return 0; | ||
344 | |||
345 | /* step 2: fork and exec service, put PID in data structure */ | ||
346 | if (chdir(MINITROOT) || chdir(root[service].name)) | ||
347 | return -1; | ||
348 | root[service].startedat = time(0); | ||
349 | root[service].pid = forkandexec(pause_flag, service); | ||
350 | return root[service].pid; | ||
351 | } | ||
352 | |||
353 | static int startservice(int service, int pause_flag) | ||
354 | { | ||
355 | int dir = -1; | ||
356 | unsigned long len; | ||
357 | char *s = 0; | ||
358 | pid_t pid; | ||
359 | |||
360 | if (service < 0) | ||
361 | return 0; | ||
362 | if (root[service].circular) | ||
363 | return 0; | ||
364 | root[service].circular = 1; | ||
365 | if (root[service].logservice >= 0) | ||
366 | startservice(root[service].logservice, pause_flag); | ||
367 | if (chdir(MINITROOT) || chdir(root[service].name)) | ||
368 | return -1; | ||
369 | if ((dir = open(".", O_RDONLY)) >= 0) { | ||
370 | if (!openreadclose("depends", &s, &len)) { | ||
371 | char **deps; | ||
372 | int depc, i; | ||
373 | |||
374 | deps = split(s, '\n', &depc, 0, 0); | ||
375 | for (i = 0; i < depc; i++) { | ||
376 | int service_index; | ||
377 | |||
378 | if (deps[i][0] == '#') | ||
379 | continue; | ||
380 | service_index = loadservice(deps[i]); | ||
381 | if (service_index >= 0 && root[service_index].pid != 1) | ||
382 | startservice(service_index, 0); | ||
383 | } | ||
384 | fchdir(dir); | ||
385 | } | ||
386 | pid = startnodep(service, pause_flag); | ||
387 | close(dir); | ||
388 | dir = -1; | ||
389 | return pid; | ||
390 | } | ||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static void sulogin(void) | ||
395 | { | ||
396 | /* exiting on an initialization failure is not a good idea for init */ | ||
397 | char *argv[] = { "sulogin", 0 }; | ||
398 | execve("/sbin/sulogin", argv, environ); | ||
399 | exit(1); | ||
400 | } | ||
401 | |||
402 | static void handlekilled(pid_t killed) | ||
403 | { | ||
404 | int i; | ||
405 | |||
406 | if (killed == (pid_t) - 1) { | ||
407 | write(2, "all services exited.\n", 21); | ||
408 | exit(0); | ||
409 | } | ||
410 | if (killed == 0) | ||
411 | return; | ||
412 | i = findbypid(killed); | ||
413 | if (i >= 0) { | ||
414 | root[i].pid = 0; | ||
415 | if (root[i].respawn) { | ||
416 | circsweep(); | ||
417 | startservice(i, time(0) - root[i].startedat < 1); | ||
418 | } else { | ||
419 | root[i].startedat = time(0); | ||
420 | root[i].pid = 1; | ||
421 | } | ||
422 | } | ||
423 | } | ||
424 | |||
425 | static void childhandler(void) | ||
426 | { | ||
427 | int status; | ||
428 | pid_t killed; | ||
429 | |||
430 | do { | ||
431 | killed = waitpid(-1, &status, WNOHANG); | ||
432 | handlekilled(killed); | ||
433 | } while (killed && killed != (pid_t) - 1); | ||
434 | } | ||
435 | |||
436 | static volatile int dowinch = 0; | ||
437 | static volatile int doint = 0; | ||
438 | |||
439 | static void sigchild(int whatever) | ||
440 | { | ||
441 | } | ||
442 | static void sigwinch(int sig) | ||
443 | { | ||
444 | dowinch = 1; | ||
445 | } | ||
446 | static void sigint(int sig) | ||
447 | { | ||
448 | doint = 1; | ||
449 | } | ||
450 | |||
451 | extern int minit_main(int argc, char *argv[]) | ||
452 | { | ||
453 | /* Schritt 1: argv[1] als Service nehmen und starten */ | ||
454 | struct pollfd pfd; | ||
455 | time_t last = time(0); | ||
456 | int nfds = 1; | ||
457 | int count = 0; | ||
458 | int i; | ||
459 | |||
460 | infd = open("/etc/minit/in", O_RDWR); | ||
461 | outfd = open("/etc/minit/out", O_RDWR | O_NONBLOCK); | ||
462 | if (getpid() == 1) { | ||
463 | int fd; | ||
464 | |||
465 | i_am_init = 1; | ||
466 | reboot(0); | ||
467 | if ((fd = open("/dev/console", O_RDWR | O_NOCTTY))) { | ||
468 | ioctl(fd, KDSIGACCEPT, SIGWINCH); | ||
469 | close(fd); | ||
470 | } else | ||
471 | ioctl(0, KDSIGACCEPT, SIGWINCH); | ||
472 | } | ||
473 | /* signal(SIGPWR,sighandler); don't know what to do about it */ | ||
474 | /* signal(SIGHUP,sighandler); ??? */ | ||
475 | { | ||
476 | struct sigaction sa; | ||
477 | |||
478 | sigemptyset(&sa.sa_mask); | ||
479 | sa.sa_sigaction = 0; | ||
480 | sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; | ||
481 | sa.sa_handler = sigchild; | ||
482 | sigaction(SIGCHLD, &sa, 0); | ||
483 | sa.sa_handler = sigint; | ||
484 | sigaction(SIGINT, &sa, 0); /* ctrl-alt-del */ | ||
485 | sa.sa_handler = sigwinch; | ||
486 | sigaction(SIGWINCH, &sa, 0); /* keyboard request */ | ||
487 | } | ||
488 | if (infd < 0 || outfd < 0) { | ||
489 | puts("minit: could not open /etc/minit/in or /etc/minit/out\n"); | ||
490 | sulogin(); | ||
491 | nfds = 0; | ||
492 | } else | ||
493 | pfd.fd = infd; | ||
494 | pfd.events = POLLIN; | ||
495 | |||
496 | for (i = 1; i < argc; i++) { | ||
497 | circsweep(); | ||
498 | if (startservice(loadservice(argv[i]), 0)) | ||
499 | count++; | ||
500 | } | ||
501 | circsweep(); | ||
502 | if (!count) | ||
503 | startservice(loadservice("default"), 0); | ||
504 | for (;;) { | ||
505 | char buf[1501]; | ||
506 | time_t now; | ||
507 | |||
508 | if (doint) { | ||
509 | doint = 0; | ||
510 | startservice(loadservice("ctrlaltdel"), 0); | ||
511 | } | ||
512 | if (dowinch) { | ||
513 | dowinch = 0; | ||
514 | startservice(loadservice("kbreq"), 0); | ||
515 | } | ||
516 | childhandler(); | ||
517 | now = time(0); | ||
518 | if (now < last || now - last > 30) { | ||
519 | /* The system clock was reset. Compensate. */ | ||
520 | long diff = last - now; | ||
521 | int j; | ||
522 | |||
523 | for (j = 0; j <= maxprocess; ++j) { | ||
524 | root[j].startedat -= diff; | ||
525 | } | ||
526 | } | ||
527 | last = now; | ||
528 | switch (poll(&pfd, nfds, 5000)) { | ||
529 | case -1: | ||
530 | if (errno == EINTR) { | ||
531 | childhandler(); | ||
532 | break; | ||
533 | } | ||
534 | opendevconsole(); | ||
535 | puts("poll failed!\n"); | ||
536 | sulogin(); | ||
537 | /* what should we do if poll fails?! */ | ||
538 | break; | ||
539 | case 1: | ||
540 | i = read(infd, buf, 1500); | ||
541 | if (i > 1) { | ||
542 | pid_t pid; | ||
543 | int idx = 0; | ||
544 | int tmp; | ||
545 | |||
546 | buf[i] = 0; | ||
547 | |||
548 | if (buf[0] != 's' && ((idx = findservice(buf + 1)) < 0)) | ||
549 | error: | ||
550 | write(outfd, "0", 1); | ||
551 | else { | ||
552 | switch (buf[0]) { | ||
553 | case 'p': | ||
554 | write(outfd, buf, fmt_ulong(buf, root[idx].pid)); | ||
555 | break; | ||
556 | case 'r': | ||
557 | root[idx].respawn = 0; | ||
558 | goto ok; | ||
559 | case 'R': | ||
560 | root[idx].respawn = 1; | ||
561 | goto ok; | ||
562 | case 'C': | ||
563 | if (kill(root[idx].pid, 0)) { /* check if still active */ | ||
564 | handlekilled(root[idx].pid); /* no!?! remove form active list */ | ||
565 | goto error; | ||
566 | } | ||
567 | goto ok; | ||
568 | break; | ||
569 | case 'P': | ||
570 | { | ||
571 | unsigned char *x = buf + strlen(buf) + 1; | ||
572 | unsigned char c; | ||
573 | |||
574 | tmp = 0; | ||
575 | while ((c = *x++ - '0') < 10) | ||
576 | tmp = tmp * 10 + c; | ||
577 | } | ||
578 | if (tmp > 0) { | ||
579 | if (kill(tmp, 0)) | ||
580 | goto error; | ||
581 | pid = tmp; | ||
582 | } | ||
583 | root[idx].pid = tmp; | ||
584 | goto ok; | ||
585 | case 's': | ||
586 | idx = loadservice(buf + 1); | ||
587 | if (idx < 0) | ||
588 | goto error; | ||
589 | if (root[idx].pid < 2) { | ||
590 | root[idx].pid = 0; | ||
591 | circsweep(); | ||
592 | idx = startservice(idx, 0); | ||
593 | if (idx == 0) { | ||
594 | write(outfd, "0", 1); | ||
595 | break; | ||
596 | } | ||
597 | } | ||
598 | ok: | ||
599 | write(outfd, "1", 1); | ||
600 | break; | ||
601 | case 'u': | ||
602 | write(outfd, buf, | ||
603 | fmt_ulong(buf, time(0) - root[idx].startedat)); | ||
604 | } | ||
605 | } | ||
606 | } | ||
607 | break; | ||
608 | default: | ||
609 | break; | ||
610 | } | ||
611 | } | ||
612 | } | ||
diff --git a/init/msvc.c b/init/msvc.c new file mode 100644 index 000000000..d72ddce1e --- /dev/null +++ b/init/msvc.c | |||
@@ -0,0 +1,300 @@ | |||
1 | /* | ||
2 | * minit version 0.9.1 by Felix von Leitner | ||
3 | * ported to busybox by Glenn McGrath <bug1@optushome.com.au> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <sys/fcntl.h> | ||
21 | #include <sys/file.h> | ||
22 | #include <signal.h> | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <string.h> | ||
26 | #include <unistd.h> | ||
27 | |||
28 | #include "busybox.h" | ||
29 | |||
30 | static int infd, outfd; | ||
31 | |||
32 | static char buf[1500]; | ||
33 | |||
34 | static unsigned int fmt_ulong(char *dest, unsigned long i) | ||
35 | { | ||
36 | register unsigned long len, tmp, len2; | ||
37 | |||
38 | /* first count the number of bytes needed */ | ||
39 | for (len = 1, tmp = i; tmp > 9; ++len) | ||
40 | tmp /= 10; | ||
41 | if (dest) | ||
42 | for (tmp = i, dest += len, len2 = len + 1; --len2; tmp /= 10) | ||
43 | *--dest = (tmp % 10) + '0'; | ||
44 | return len; | ||
45 | } | ||
46 | |||
47 | static void addservice(char *service) | ||
48 | { | ||
49 | char *service_ptr; | ||
50 | |||
51 | if (strncmp(service, "/etc/minit/", 11) == 0) { | ||
52 | service += 11; | ||
53 | } | ||
54 | |||
55 | while ((service_ptr = last_char_is(service, '/')) != NULL) { | ||
56 | *service_ptr = 0; | ||
57 | } | ||
58 | strncpy(buf + 1, service, 1400); | ||
59 | buf[1400] = 0; | ||
60 | } | ||
61 | |||
62 | static int addreadwrite(char *service) | ||
63 | { | ||
64 | addservice(service); | ||
65 | write(infd, buf, strlen(buf)); | ||
66 | return read(outfd, buf, 1500); | ||
67 | } | ||
68 | |||
69 | /* return PID, 0 if error */ | ||
70 | static pid_t __readpid(char *service) | ||
71 | { | ||
72 | int len; | ||
73 | |||
74 | buf[0] = 'p'; | ||
75 | len = addreadwrite(service); | ||
76 | if (len < 0) | ||
77 | return 0; | ||
78 | buf[len] = 0; | ||
79 | return atoi(buf); | ||
80 | } | ||
81 | |||
82 | /* return nonzero if error */ | ||
83 | static int respawn(char *service, int yesno) | ||
84 | { | ||
85 | int len; | ||
86 | |||
87 | buf[0] = yesno ? 'R' : 'r'; | ||
88 | len = addreadwrite(service); | ||
89 | return (len != 1 || buf[0] == '0'); | ||
90 | } | ||
91 | |||
92 | /* return nonzero if error */ | ||
93 | static int startservice(char *service) | ||
94 | { | ||
95 | int len; | ||
96 | |||
97 | buf[0] = 's'; | ||
98 | len = addreadwrite(service); | ||
99 | return (len != 1 || buf[0] == '0'); | ||
100 | } | ||
101 | |||
102 | extern int msvc_main(int argc, char **argv) | ||
103 | { | ||
104 | if (argc < 2) { | ||
105 | bb_show_usage(); | ||
106 | } | ||
107 | infd = bb_xopen("/etc/minit/in", O_WRONLY); | ||
108 | outfd = bb_xopen("/etc/minit/out", O_RDONLY); | ||
109 | |||
110 | while (lockf(infd, F_LOCK, 1)) { | ||
111 | bb_perror_msg("could not aquire lock!\n"); | ||
112 | sleep(1); | ||
113 | } | ||
114 | |||
115 | if (argc == 2) { | ||
116 | pid_t pid = __readpid(argv[1]); | ||
117 | |||
118 | if (buf[0] != '0') { | ||
119 | int len; | ||
120 | int up_time; | ||
121 | |||
122 | printf("%s: ", argv[1]); | ||
123 | if (pid == 0) | ||
124 | printf("down "); | ||
125 | else if (pid == 1) | ||
126 | printf("finished "); | ||
127 | else { | ||
128 | printf("up (pid %d) ", pid); | ||
129 | } | ||
130 | |||
131 | buf[0] = 'u'; | ||
132 | len = addreadwrite(argv[1]); | ||
133 | if (len < 0) { | ||
134 | up_time = 0; | ||
135 | } else { | ||
136 | buf[len] = 0; | ||
137 | up_time = atoi(buf); | ||
138 | } | ||
139 | printf("%d seconds\n", up_time); | ||
140 | |||
141 | if (pid == 0) | ||
142 | return 2; | ||
143 | else if (pid == 1) | ||
144 | return 3; | ||
145 | else | ||
146 | return 0; | ||
147 | } else { | ||
148 | bb_error_msg_and_die("no such service"); | ||
149 | } | ||
150 | } else { | ||
151 | int i; | ||
152 | int ret = 0; | ||
153 | int sig = 0; | ||
154 | pid_t pid; | ||
155 | |||
156 | if (argv[1][0] == '-') { | ||
157 | switch (argv[1][1]) { | ||
158 | case 'g': | ||
159 | for (i = 2; i < argc; ++i) { | ||
160 | pid = __readpid(argv[i]); | ||
161 | if (pid < 2) { | ||
162 | if (pid == 1) { | ||
163 | bb_error_msg("%s, service termination", argv[i]); | ||
164 | } else { | ||
165 | bb_error_msg("%s, no such service", argv[i]); | ||
166 | } | ||
167 | ret = 1; | ||
168 | } | ||
169 | printf("%d\n", pid); | ||
170 | } | ||
171 | break; | ||
172 | case 'p': | ||
173 | sig = SIGSTOP; | ||
174 | goto dokill; | ||
175 | break; | ||
176 | case 'c': | ||
177 | sig = SIGCONT; | ||
178 | goto dokill; | ||
179 | break; | ||
180 | case 'h': | ||
181 | sig = SIGHUP; | ||
182 | goto dokill; | ||
183 | break; | ||
184 | case 'a': | ||
185 | sig = SIGALRM; | ||
186 | goto dokill; | ||
187 | break; | ||
188 | case 'i': | ||
189 | sig = SIGINT; | ||
190 | goto dokill; | ||
191 | break; | ||
192 | case 't': | ||
193 | sig = SIGTERM; | ||
194 | goto dokill; | ||
195 | break; | ||
196 | case 'k': | ||
197 | sig = SIGKILL; | ||
198 | goto dokill; | ||
199 | break; | ||
200 | case 'o': | ||
201 | for (i = 2; i < argc; ++i) | ||
202 | if (startservice(argv[i]) || respawn(argv[i], 0)) { | ||
203 | bb_error_msg("Couldnt not start %s\n", argv[i]); | ||
204 | ret = 1; | ||
205 | } | ||
206 | break; | ||
207 | case 'd': | ||
208 | for (i = 2; i < argc; ++i) { | ||
209 | pid = __readpid(argv[i]); | ||
210 | if (pid == 0) { | ||
211 | bb_error_msg("%s, no such service\n", argv[i]); | ||
212 | ret = 1; | ||
213 | } else if (pid == 1) | ||
214 | continue; | ||
215 | if (respawn(argv[i], 0) || kill(pid, SIGTERM) | ||
216 | || kill(pid, SIGCONT)); | ||
217 | } | ||
218 | break; | ||
219 | case 'u': | ||
220 | for (i = 2; i < argc; ++i) { | ||
221 | if (startservice(argv[i]) || respawn(argv[i], 1)) { | ||
222 | bb_error_msg("Couldnt not start %s\n", argv[i]); | ||
223 | ret = 1; | ||
224 | } | ||
225 | break; | ||
226 | } | ||
227 | case 'C': | ||
228 | for (i = 2; i < argc; ++i) { | ||
229 | int len; | ||
230 | |||
231 | buf[0] = 'C'; | ||
232 | len = addreadwrite(argv[i]); | ||
233 | if (len != 1 || buf[0] == '0') { | ||
234 | bb_error_msg("%s has terminated or was killed\n", | ||
235 | argv[i]); | ||
236 | ret = 1; | ||
237 | } | ||
238 | } | ||
239 | break; | ||
240 | case 'P': | ||
241 | pid = atoi(argv[1] + 2); | ||
242 | if (pid > 1) { | ||
243 | char *tmp; | ||
244 | int len; | ||
245 | |||
246 | buf[0] = 'P'; | ||
247 | addservice(argv[2]); | ||
248 | tmp = buf + strlen(buf) + 1; | ||
249 | tmp[fmt_ulong(tmp, pid)] = 0; | ||
250 | write(infd, buf, strlen(buf) + strlen(tmp) + 2); | ||
251 | len = read(outfd, buf, 1500); | ||
252 | if (len != 1 || buf[0] == '0') { | ||
253 | bb_error_msg_and_die("Couldnt not set pid of service %s\n", argv[2]); | ||
254 | } | ||
255 | } | ||
256 | break; | ||
257 | default: | ||
258 | bb_show_usage(); | ||
259 | } | ||
260 | } else { | ||
261 | bb_show_usage(); | ||
262 | } | ||
263 | return ret; | ||
264 | dokill: | ||
265 | for (i = 2; i < argc; i++) { | ||
266 | pid = __readpid(argv[i]); | ||
267 | if (!pid) { | ||
268 | bb_error_msg("%s no such service\n", argv[i]); | ||
269 | ret = 1; | ||
270 | } | ||
271 | if (kill(pid, sig)) { | ||
272 | bb_error_msg("%s, could not send signal %d to PID %d\n", | ||
273 | argv[i], sig, pid); | ||
274 | ret = 1; | ||
275 | } | ||
276 | } | ||
277 | return ret; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | -u Up. If the service is not running, start it. If the service stops, | ||
283 | restart it. | ||
284 | -d Down. If the service is running, send it a TERM signal and then a CONT | ||
285 | signal. After it stops, do not restart it. | ||
286 | -o Once. If the service is not running, start it. Do not restart it if it | ||
287 | stops. | ||
288 | -r Tell supervise that the service is normally running; this affects status | ||
289 | messages. | ||
290 | -s Tell supervise that the service is normally stopped; this affects status | ||
291 | messages. | ||
292 | -p Pause. Send the service a STOP signal. | ||
293 | -c Continue. Send the service a CONT signal. | ||
294 | -h Hangup. Send the service a HUP signal. | ||
295 | -a Alarm. Send the service an ALRM signal. | ||
296 | -i Interrupt. Send the service an INT signal. | ||
297 | -t Terminate. Send the service a TERM signal. | ||
298 | -k Kill. Send the service a KILL signal. | ||
299 | -x Exit. supervise will quit as soon as the service is down. | ||
300 | */ | ||
diff --git a/init/pidfilehack.c b/init/pidfilehack.c new file mode 100644 index 000000000..a2d905b55 --- /dev/null +++ b/init/pidfilehack.c | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * minit version 0.9.1 by Felix von Leitner | ||
3 | * ported to busybox by Glenn McGrath <bug1@optushome.com.au> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
18 | */ | ||
19 | |||
20 | #include <unistd.h> | ||
21 | #include <errno.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <sys/fcntl.h> | ||
24 | |||
25 | #include "busybox.h" | ||
26 | /* purpose: argv[1] is the full path to a PID file, | ||
27 | * argv+2 is the daemon to run. | ||
28 | * the daemon is expected to fork in the background and write its PID in | ||
29 | * the pid file. | ||
30 | */ | ||
31 | |||
32 | extern int pidfilehack_main(int argc, char **argv) | ||
33 | { | ||
34 | int count = 0; | ||
35 | |||
36 | if (argc < 3) { | ||
37 | bb_show_usage(); | ||
38 | |||
39 | } | ||
40 | if (unlink(argv[2]) && (errno != ENOENT)) { | ||
41 | bb_perror_msg("could not remove pid file"); | ||
42 | } | ||
43 | switch (fork()) { | ||
44 | case -1: | ||
45 | bb_perror_msg("could not fork"); | ||
46 | return 2; | ||
47 | case 0: /* child */ | ||
48 | execv(argv[3], argv + 3); | ||
49 | bb_perror_msg("execvp failed"); | ||
50 | return 3; | ||
51 | } | ||
52 | do { | ||
53 | int fd = open(argv[2], O_RDONLY); | ||
54 | |||
55 | if (fd >= 0) { | ||
56 | static char buf[100] = "-P"; | ||
57 | int len = read(fd, buf + 2, 100); | ||
58 | |||
59 | close(fd); | ||
60 | if (len > 0) { | ||
61 | char *_argv[] = { "msvc", 0, 0, 0 }; | ||
62 | if (buf[len + 1] == '\n') { | ||
63 | buf[len + 1] = 0; | ||
64 | } else { | ||
65 | buf[len + 2] = 0; | ||
66 | } | ||
67 | _argv[1] = buf; | ||
68 | _argv[2] = argv[1]; | ||
69 | execvp(_argv[0], _argv); | ||
70 | bb_perror_msg("execvp failed"); | ||
71 | return 0; | ||
72 | } | ||
73 | } | ||
74 | sleep(1); | ||
75 | } while (++count < 30); | ||
76 | |||
77 | return(0); | ||
78 | } | ||