2 * minit version 0.9.1 by Felix von Leitner
3 * ported to busybox by Glenn McGrath <bug1@optushome.com.au>
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.
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.
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.
28 #include <sys/fcntl.h>
29 #include <sys/ioctl.h>
31 #include <sys/reboot.h>
32 #include <sys/socket.h>
33 #include <sys/types.h>
40 #define MINITROOT "/etc/minit"
43 static int infd, outfd;
45 extern char **environ;
47 static struct process {
53 int __stdin, __stdout;
57 static int maxprocess = -1;
59 static int processalloc = 0;
61 static unsigned int fmt_ulong(char *dest, unsigned long i)
63 register unsigned long len, tmp, len2;
65 /* first count the number of bytes needed */
66 for (len = 1, tmp = i; tmp > 9; ++len)
69 for (tmp = i, dest += len, len2 = len + 1; --len2; tmp /= 10)
70 *--dest = (tmp % 10) + '0';
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)
82 /* step 1: count tokens */
85 for (s = buf; *s; s++)
88 /* step 2: allocate space for pointers */
89 v = (char **) malloc((n + plus) * sizeof(char *));
108 static int openreadclose(char *fn, char **buf, unsigned long *len)
110 int fd = open(fn, O_RDONLY);
115 *len = lseek(fd, 0, SEEK_END);
116 lseek(fd, 0, SEEK_SET);
117 *buf = (char *) malloc(*len + 1);
123 *len = read(fd, *buf, *len);
124 if (*len != (unsigned long) -1)
129 /* return index of service in process data structure or -1 if not found */
130 static int findservice(char *service)
134 for (i = 0; i <= maxprocess; i++) {
135 if (!strcmp(root[i].name, service))
141 /* look up process index in data structure by PID */
142 static int findbypid(pid_t pid)
146 for (i = 0; i <= maxprocess; i++) {
147 if (root[i].pid == pid)
153 /* clear circular dependency detection flags */
154 static void circsweep(void)
158 for (i = 0; i <= maxprocess; i++)
159 root[i].circular = 0;
162 /* add process to data structure, return index or -1 */
163 static int addprocess(struct process *p)
165 if (maxprocess + 1 >= processalloc) {
166 struct process *fump;
170 (struct process *) xrealloc(root,
172 sizeof(struct process))) == 0)
176 memmove(&root[++maxprocess], p, sizeof(struct process));
180 /* load a service into the process data structure and return index or -1
182 static int loadservice(char *service)
189 fd = findservice(service);
192 if (chdir(MINITROOT) || chdir(service))
194 if (!(tmp.name = strdup(service)))
197 fd = open("respawn", O_RDONLY);
208 char *logservice = alloca(strlen(service) + 5);
210 strcpy(logservice, service);
211 strcat(logservice, "/log");
212 tmp.logservice = loadservice(logservice);
213 if (tmp.logservice >= 0) {
218 root[tmp.logservice].__stdin = pipefd[0];
219 tmp.__stdout = pipefd[1];
222 return (addprocess(&tmp));
225 /* usage: isup(findservice("sshd")).
226 * returns nonzero if process is up */
227 static int isup(int service)
231 return (root[service].pid != 0);
234 static void opendevconsole(void)
238 if ((fd = open("/dev/console", O_RDWR | O_NOCTTY)) >= 0) {
247 /* called from inside the service directory, return the PID or 0 on error */
248 static pid_t forkandexec(int pause_flag, int service)
260 switch (p = fork()) {
270 ioctl(0, TIOCNOTTY, 0);
273 tcsetpgrp(0, getpgrp());
281 req.tv_nsec = 500000000;
284 if (!openreadclose("params", &s, &len)) {
285 argv = split(s, '\n', &argc, 2, 1);
291 argv = (char **) xmalloc(2 * sizeof(char *));
294 argv0 = (char *) xmalloc(PATH_MAX + 1);
297 if (readlink("run", argv0, PATH_MAX) < 0) {
299 goto abort; /* not a symbolic link */
300 argv0 = strdup("./run");
302 argv[0] = strrchr(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);
316 for (i = 3; i < 1024; ++i)
319 execve(argv0, argv, environ);
326 fd = open("sync", O_RDONLY);
331 p2 = waitpid(p, 0, 0);
338 /* start a service, return nonzero on error */
339 static int startnodep(int service, int pause_flag)
341 /* step 1: see if the process is already up */
345 /* step 2: fork and exec service, put PID in data structure */
346 if (chdir(MINITROOT) || chdir(root[service].name))
348 root[service].startedat = time(0);
349 root[service].pid = forkandexec(pause_flag, service);
350 return root[service].pid;
353 static int startservice(int service, int pause_flag)
362 if (root[service].circular)
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))
369 if ((dir = open(".", O_RDONLY)) >= 0) {
370 if (!openreadclose("depends", &s, &len)) {
374 deps = split(s, '\n', &depc, 0, 0);
375 for (i = 0; i < depc; i++) {
378 if (deps[i][0] == '#')
380 service_index = loadservice(deps[i]);
381 if (service_index >= 0 && root[service_index].pid != 1)
382 startservice(service_index, 0);
386 pid = startnodep(service, pause_flag);
394 static void sulogin(void)
396 /* exiting on an initialization failure is not a good idea for init */
397 char *argv[] = { "sulogin", 0 };
398 execve("/sbin/sulogin", argv, environ);
402 static void handlekilled(pid_t killed)
406 if (killed == (pid_t) - 1) {
407 write(2, "all services exited.\n", 21);
412 i = findbypid(killed);
415 if (root[i].respawn) {
417 startservice(i, time(0) - root[i].startedat < 1);
419 root[i].startedat = time(0);
425 static void childhandler(void)
431 killed = waitpid(-1, &status, WNOHANG);
432 handlekilled(killed);
433 } while (killed && killed != (pid_t) - 1);
436 static volatile int dowinch = 0;
437 static volatile int doint = 0;
439 static void sigchild(int whatever)
442 static void sigwinch(int sig)
446 static void sigint(int sig)
451 extern int minit_main(int argc, char *argv[])
453 /* Schritt 1: argv[1] als Service nehmen und starten */
455 time_t last = time(0);
460 infd = open("/etc/minit/in", O_RDWR);
461 outfd = open("/etc/minit/out", O_RDWR | O_NONBLOCK);
467 if ((fd = open("/dev/console", O_RDWR | O_NOCTTY))) {
468 ioctl(fd, KDSIGACCEPT, SIGWINCH);
471 ioctl(0, KDSIGACCEPT, SIGWINCH);
473 /* signal(SIGPWR,sighandler); don't know what to do about it */
474 /* signal(SIGHUP,sighandler); ??? */
478 sigemptyset(&sa.sa_mask);
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 */
488 if (infd < 0 || outfd < 0) {
489 puts("minit: could not open /etc/minit/in or /etc/minit/out\n");
496 for (i = 1; i < argc; i++) {
498 if (startservice(loadservice(argv[i]), 0))
503 startservice(loadservice("default"), 0);
510 startservice(loadservice("ctrlaltdel"), 0);
514 startservice(loadservice("kbreq"), 0);
518 if (now < last || now - last > 30) {
519 /* The system clock was reset. Compensate. */
520 long diff = last - now;
523 for (j = 0; j <= maxprocess; ++j) {
524 root[j].startedat -= diff;
528 switch (poll(&pfd, nfds, 5000)) {
530 if (errno == EINTR) {
535 puts("poll failed!\n");
537 /* what should we do if poll fails?! */
540 i = read(infd, buf, 1500);
548 if (buf[0] != 's' && ((idx = findservice(buf + 1)) < 0))
550 write(outfd, "0", 1);
554 write(outfd, buf, fmt_ulong(buf, root[idx].pid));
557 root[idx].respawn = 0;
560 root[idx].respawn = 1;
563 if (kill(root[idx].pid, 0)) { /* check if still active */
564 handlekilled(root[idx].pid); /* no!?! remove form active list */
571 unsigned char *x = buf + strlen(buf) + 1;
575 while ((c = *x++ - '0') < 10)
586 idx = loadservice(buf + 1);
589 if (root[idx].pid < 2) {
592 idx = startservice(idx, 0);
594 write(outfd, "0", 1);
599 write(outfd, "1", 1);
603 fmt_ulong(buf, time(0) - root[idx].startedat));