Syslogd will not go to background if "-n" is given. Better help
[oweals/busybox.git] / init.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * Mini init implementation for busybox
4  *
5  *
6  * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
7  * Adjusted by so many folks, it's impossible to keep track.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22  *
23  */
24
25 /* Turn this on to disable all the dangerous 
26    rebooting stuff when debugging.
27 #define DEBUG_INIT
28 */
29
30 #include "internal.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <paths.h>
35 #include <signal.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <termios.h>
39 #include <unistd.h>
40 #include <asm/types.h>
41 #include <linux/serial.h>               /* for serial_struct */
42 #include <linux/version.h>
43 #include <linux/reboot.h>
44 #include <linux/unistd.h>
45 #include <sys/sysinfo.h>                /* For check_free_memory() */
46 #include <sys/fcntl.h>
47 #include <sys/ioctl.h>
48 #include <sys/mount.h>
49 //#include <sys/sysmacros.h>
50 #include <sys/types.h>
51 #include <sys/vt.h>                             /* for vt_stat */
52 #include <sys/wait.h>
53 #ifdef BB_SYSLOGD
54 # include <sys/syslog.h>
55 #endif
56
57
58 #ifndef RB_HALT_SYSTEM
59 #define RB_HALT_SYSTEM  0xcdef0123
60 #define RB_ENABLE_CAD   0x89abcdef
61 #define RB_DISABLE_CAD  0
62 #define RB_POWER_OFF    0x4321fedc
63 #define RB_AUTOBOOT     0x01234567
64 #if defined(__GLIBC__)
65 #include <sys/reboot.h>
66   #define init_reboot(magic) reboot(magic)
67 #else
68   #define init_reboot(magic) reboot(0xfee1dead, 672274793, magic)
69 #endif
70 #endif
71
72 #ifndef _PATH_STDPATH
73 #define _PATH_STDPATH   "/usr/bin:/bin:/usr/sbin:/sbin"
74 #endif
75
76
77 #if defined BB_FEATURE_INIT_COREDUMPS
78 /*
79  * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called 
80  * before processes are spawned to set core file size as unlimited.
81  * This is for debugging only.  Don't use this is production, unless
82  * you want core dumps lying about....
83  */
84 #define CORE_ENABLE_FLAG_FILE "/.init_enable_core"
85 #include <sys/resource.h>
86 #include <sys/time.h>
87 #endif
88
89 #ifndef KERNEL_VERSION
90 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
91 #endif
92
93 #if defined(__GLIBC__)
94 #include <sys/kdaemon.h>
95 #else
96 _syscall2(int, bdflush, int, func, int, data);
97 #endif                                                  /* __GLIBC__ */
98
99
100 #define VT_PRIMARY   "/dev/tty1"     /* Primary virtual console */
101 #define VT_SECONDARY "/dev/tty2"     /* Virtual console */
102 #define VT_LOG       "/dev/tty3"     /* Virtual console */
103 #define SERIAL_CON0  "/dev/ttyS0"    /* Primary serial console */
104 #define SERIAL_CON1  "/dev/ttyS1"    /* Serial console */
105 #define SHELL        "/bin/sh"       /* Default shell */
106 #define INITTAB      "/etc/inittab"  /* inittab file location */
107 #ifndef INIT_SCRIPT
108 #define INIT_SCRIPT  "/etc/init.d/rcS"   /* Default sysinit script. */
109 #endif
110
111 #define LOG     0x1
112 #define CONSOLE 0x2
113
114 /* Allowed init action types */
115 typedef enum {
116         SYSINIT = 1,
117         RESPAWN,
118         ASKFIRST,
119         WAIT,
120         ONCE,
121         CTRLALTDEL
122 } initActionEnum;
123
124 /* A mapping between "inittab" action name strings and action type codes. */
125 typedef struct initActionType {
126         const char *name;
127         initActionEnum action;
128 } initActionType;
129
130 static const struct initActionType actions[] = {
131         {"sysinit", SYSINIT},
132         {"respawn", RESPAWN},
133         {"askfirst", ASKFIRST},
134         {"wait", WAIT},
135         {"once", ONCE},
136         {"ctrlaltdel", CTRLALTDEL},
137         {0}
138 };
139
140 /* Set up a linked list of initActions, to be read from inittab */
141 typedef struct initActionTag initAction;
142 struct initActionTag {
143         pid_t pid;
144         char process[256];
145         char console[256];
146         initAction *nextPtr;
147         initActionEnum action;
148 };
149 initAction *initActionList = NULL;
150
151
152 static char *secondConsole = VT_SECONDARY;
153 static char *log           = VT_LOG;
154 static int  kernelVersion  = 0;
155 static char termType[32]   = "TERM=linux";
156 static char console[32]    = _PATH_CONSOLE;
157
158 static void delete_initAction(initAction * action);
159
160
161 /* Print a message to the specified device.
162  * Device may be bitwise-or'd from LOG | CONSOLE */
163 static void message(int device, char *fmt, ...)
164                    __attribute__ ((format (printf, 2, 3)));
165 static void message(int device, char *fmt, ...)
166 {
167         va_list arguments;
168         int fd;
169
170 #ifdef BB_SYSLOGD
171
172         /* Log the message to syslogd */
173         if (device & LOG) {
174                 char msg[1024];
175
176                 va_start(arguments, fmt);
177                 vsnprintf(msg, sizeof(msg), fmt, arguments);
178                 va_end(arguments);
179                 openlog("init", 0, LOG_USER);
180                 syslog(LOG_USER|LOG_INFO, msg);
181                 closelog();
182         }
183 #else
184         static int log_fd = -1;
185
186         /* Take full control of the log tty, and never close it.
187          * It's mine, all mine!  Muhahahaha! */
188         if (log_fd < 0) {
189                 if (log == NULL) {
190                         /* don't even try to log, because there is no such console */
191                         log_fd = -2;
192                         /* log to main console instead */
193                         device = CONSOLE;
194                 } else if ((log_fd = device_open(log, O_RDWR|O_NDELAY)) < 0) {
195                         log_fd = -2;
196                         fprintf(stderr, "Bummer, can't write to log on %s!\r\n", log);
197                         fflush(stderr);
198                         log = NULL;
199                         device = CONSOLE;
200                 }
201         }
202         if ((device & LOG) && (log_fd >= 0)) {
203                 va_start(arguments, fmt);
204                 vdprintf(log_fd, fmt, arguments);
205                 va_end(arguments);
206         }
207 #endif
208
209         if (device & CONSOLE) {
210                 /* Always send console messages to /dev/console so people will see them. */
211                 if (
212                         (fd =
213                          device_open(_PATH_CONSOLE,
214                                                  O_WRONLY | O_NOCTTY | O_NDELAY)) >= 0) {
215                         va_start(arguments, fmt);
216                         vdprintf(fd, fmt, arguments);
217                         va_end(arguments);
218                         close(fd);
219                 } else {
220                         fprintf(stderr, "Bummer, can't print: ");
221                         va_start(arguments, fmt);
222                         vfprintf(stderr, fmt, arguments);
223                         fflush(stderr);
224                         va_end(arguments);
225                 }
226         }
227 }
228
229 #define CTRLCHAR(ch)    ((ch)&0x1f)
230
231 /* Set terminal settings to reasonable defaults */
232 void set_term(int fd)
233 {
234         struct termios tty;
235
236         tcgetattr(fd, &tty);
237
238         /* set control chars */
239         tty.c_cc[VINTR]  = CTRLCHAR('C');       /* Ctrl-C */
240         tty.c_cc[VQUIT]  = CTRLCHAR('\\');      /* Ctrl-\ */
241         tty.c_cc[VERASE] = CTRLCHAR('?');       /* Ctrl-? */
242         tty.c_cc[VKILL]  = CTRLCHAR('U');       /* Ctrl-U */
243         tty.c_cc[VEOF]   = CTRLCHAR('D');       /* Ctrl-D */
244         tty.c_cc[VSTOP]  = CTRLCHAR('S');       /* Ctrl-S */
245         tty.c_cc[VSTART] = CTRLCHAR('Q');       /* Ctrl-Q */
246         tty.c_cc[VSUSP]  = CTRLCHAR('Z');       /* Ctrl-Z */
247
248         /* use line dicipline 0 */
249         tty.c_line = 0;
250
251         /* Make it be sane */
252         tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
253         tty.c_cflag |= HUPCL|CLOCAL;
254
255         /* input modes */
256         tty.c_iflag = ICRNL | IXON | IXOFF;
257
258         /* output modes */
259         tty.c_oflag = OPOST | ONLCR;
260
261         /* local modes */
262         tty.c_lflag =
263                 ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
264
265         tcsetattr(fd, TCSANOW, &tty);
266 }
267
268 /* How much memory does this machine have? */
269 static int check_free_memory()
270 {
271         struct sysinfo info;
272
273         sysinfo(&info);
274         if (sysinfo(&info) != 0) {
275                 message(LOG, "Error checking free memory: %s\n", strerror(errno));
276                 return -1;
277         }
278
279         return((info.totalram+info.totalswap)/1024);
280 }
281
282 static void console_init()
283 {
284         int fd;
285         int tried_devcons = 0;
286         int tried_vtprimary = 0;
287         struct vt_stat vt;
288         struct serial_struct sr;
289         char *s;
290
291         if ((s = getenv("TERM")) != NULL) {
292                 snprintf(termType, sizeof(termType) - 1, "TERM=%s", s);
293         }
294
295         if ((s = getenv("CONSOLE")) != NULL) {
296                 snprintf(console, sizeof(console) - 1, "%s", s);
297         }
298 #if #cpu(sparc)
299         /* sparc kernel supports console=tty[ab] parameter which is also 
300          * passed to init, so catch it here */
301         else if ((s = getenv("console")) != NULL) {
302                 /* remap tty[ab] to /dev/ttyS[01] */
303                 if (strcmp(s, "ttya") == 0)
304                         snprintf(console, sizeof(console) - 1, "%s", SERIAL_CON0);
305                 else if (strcmp(s, "ttyb") == 0)
306                         snprintf(console, sizeof(console) - 1, "%s", SERIAL_CON1);
307         }
308 #endif
309         else {
310                 /* 2.2 kernels: identify the real console backend and try to use it */
311                 if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
312                         /* this is a serial console */
313                         snprintf(console, sizeof(console) - 1, "/dev/ttyS%d", sr.line);
314                 } else if (ioctl(0, VT_GETSTATE, &vt) == 0) {
315                         /* this is linux virtual tty */
316                         snprintf(console, sizeof(console) - 1, "/dev/tty%d",
317                                          vt.v_active);
318                 } else {
319                         snprintf(console, sizeof(console) - 1, "%s", _PATH_CONSOLE);
320                         tried_devcons++;
321                 }
322         }
323
324         while ((fd = open(console, O_RDONLY | O_NONBLOCK)) < 0) {
325                 /* Can't open selected console -- try /dev/console */
326                 if (!tried_devcons) {
327                         tried_devcons++;
328                         snprintf(console, sizeof(console) - 1, "%s", _PATH_CONSOLE);
329                         continue;
330                 }
331                 /* Can't open selected console -- try vt1 */
332                 if (!tried_vtprimary) {
333                         tried_vtprimary++;
334                         snprintf(console, sizeof(console) - 1, "%s", VT_PRIMARY);
335                         continue;
336                 }
337                 break;
338         }
339         if (fd < 0) {
340                 /* Perhaps we should panic here? */
341                 snprintf(console, sizeof(console) - 1, "/dev/null");
342         } else {
343                 /* check for serial console and disable logging to tty3 & running a
344                    * shell to tty2 */
345                 if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
346                         log = NULL;
347                         secondConsole = NULL;
348                         /* Force the TERM setting to vt102 for serial console --
349                          * iff TERM is set to linux (the default) */
350                         if (strcmp( termType, "TERM=linux" ) == 0)
351                                 snprintf(termType, sizeof(termType) - 1, "TERM=vt102");
352                         message(LOG | CONSOLE,
353                                         "serial console detected.  Disabling virtual terminals.\r\n");
354                 }
355                 close(fd);
356         }
357         message(LOG, "console=%s\n", console);
358 }
359
360 static pid_t run(char *command, char *terminal, int get_enter)
361 {
362         int i, fd;
363         pid_t pid;
364         char *tmpCmd;
365         char *cmd[255];
366         char buf[255];
367         static const char press_enter[] =
368
369                 "\nPlease press Enter to activate this console. ";
370         char *environment[] = {
371                 "HOME=/",
372                 "PATH=/usr/bin:/bin:/usr/sbin:/sbin",
373                 "SHELL=/bin/sh",
374                 termType,
375                 "USER=root",
376                 0
377         };
378
379
380         if ((pid = fork()) == 0) {
381                 /* Clean up */
382                 close(0);
383                 close(1);
384                 close(2);
385                 setsid();
386
387                 /* Reset signal handlers set for parent process */
388                 signal(SIGUSR1, SIG_DFL);
389                 signal(SIGUSR2, SIG_DFL);
390                 signal(SIGINT, SIG_DFL);
391                 signal(SIGTERM, SIG_DFL);
392                 signal(SIGHUP, SIG_DFL);
393
394                 if ((fd = device_open(terminal, O_RDWR)) < 0) {
395                         message(LOG | CONSOLE, "Bummer, can't open %s\r\n", terminal);
396                         exit(1);
397                 }
398                 dup2(fd, 0);
399                 dup2(fd, 1);
400                 dup2(fd, 2);
401                 tcsetpgrp(0, getpgrp());
402                 set_term(0);
403
404                 if (get_enter == TRUE) {
405                         /*
406                          * Save memory by not exec-ing anything large (like a shell)
407                          * before the user wants it. This is critical if swap is not
408                          * enabled and the system has low memory. Generally this will
409                          * be run on the second virtual console, and the first will
410                          * be allowed to start a shell or whatever an init script 
411                          * specifies.
412                          */
413                         char c;
414 #ifdef DEBUG_INIT
415                         pid_t shell_pgid = getpid();
416                         message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n",
417                                         command, shell_pgid, terminal);
418 #endif
419                         write(fileno(stdout), press_enter, sizeof(press_enter) - 1);
420                         read(fileno(stdin), &c, 1);
421                 }
422
423 #ifdef DEBUG_INIT
424                 /* Log the process name and args */
425                 message(LOG, "Starting pid %d, console %s: '%s'\r\n",
426                                 shell_pgid, terminal, command);
427 #endif
428
429                 /* See if any special /bin/sh requiring characters are present */
430                 if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
431                         cmd[0] = SHELL;
432                         cmd[1] = "-c";
433                         strcpy(buf, "exec ");
434                         strncat(buf, command, sizeof(buf) - strlen(buf) - 1);
435                         cmd[2] = buf;
436                         cmd[3] = NULL;
437                 } else {
438                         /* Convert command (char*) into cmd (char**, one word per string) */
439                         for (tmpCmd = command, i = 0;
440                                  (tmpCmd = strsep(&command, " \t")) != NULL;) {
441                                 if (*tmpCmd != '\0') {
442                                         cmd[i] = tmpCmd;
443                                         tmpCmd++;
444                                         i++;
445                                 }
446                         }
447                         cmd[i] = NULL;
448                 }
449
450 #if defined BB_FEATURE_INIT_COREDUMPS
451                 {
452                         struct stat sb;
453                         if (stat (CORE_ENABLE_FLAG_FILE, &sb) == 0) {
454                                 struct rlimit limit;
455                                 limit.rlim_cur = RLIM_INFINITY;
456                                 limit.rlim_max = RLIM_INFINITY;
457                                 setrlimit(RLIMIT_CORE, &limit);
458                         }
459                 }
460 #endif
461
462                 /* Now run it.  The new program will take over this PID, 
463                  * so nothing further in init.c should be run. */
464                 execve(cmd[0], cmd, environment);
465
466                 /* We're still here?  Some error happened. */
467                 message(LOG | CONSOLE, "Bummer, could not run '%s': %s\n", cmd[0],
468                                 strerror(errno));
469                 exit(-1);
470         }
471         return pid;
472 }
473
474 static int waitfor(char *command, char *terminal, int get_enter)
475 {
476         int status, wpid;
477         int pid = run(command, terminal, get_enter);
478
479         while (1) {
480                 wpid = wait(&status);
481                 if (wpid > 0 && wpid != pid) {
482                         continue;
483                 }
484                 if (wpid == pid)
485                         break;
486         }
487         return wpid;
488 }
489
490 /* Make sure there is enough memory to do something useful. *
491  * Calls "swapon -a" if needed so be sure /etc/fstab is present... */
492 static void check_memory()
493 {
494         struct stat statBuf;
495
496         if (check_free_memory() > 1000)
497                 return;
498
499         if (stat("/etc/fstab", &statBuf) == 0) {
500                 /* swapon -a requires /proc typically */
501                 waitfor("mount proc /proc -t proc", console, FALSE);
502                 /* Try to turn on swap */
503                 waitfor("swapon -a", console, FALSE);
504                 if (check_free_memory() < 1000)
505                         goto goodnight;
506         } else
507                 goto goodnight;
508         return;
509
510   goodnight:
511         message(CONSOLE,
512                         "Sorry, your computer does not have enough memory.\r\n");
513         while (1)
514                 sleep(1);
515 }
516
517 /* Run all commands to be run right before halt/reboot */
518 static void run_lastAction(void)
519 {
520         initAction *a;
521         for (a = initActionList; a; a = a->nextPtr) {
522                 if (a->action == CTRLALTDEL) {
523                         waitfor(a->process, a->console, FALSE);
524                         delete_initAction(a);
525                 }
526         }
527 }
528
529
530 #ifndef DEBUG_INIT
531 static void shutdown_system(void)
532 {
533
534         /* first disable our SIGHUP signal */
535         signal(SIGHUP, SIG_DFL);
536
537         /* Allow Ctrl-Alt-Del to reboot system. */
538         init_reboot(RB_ENABLE_CAD);
539
540         message(CONSOLE|LOG, "\r\nThe system is going down NOW !!\r\n");
541         sync();
542
543         /* Send signals to every process _except_ pid 1 */
544         message(CONSOLE|LOG, "Sending SIGTERM to all processes.\r\n");
545         kill(-1, SIGTERM);
546         sleep(1);
547         sync();
548
549         message(CONSOLE|LOG, "Sending SIGKILL to all processes.\r\n");
550         kill(-1, SIGKILL);
551         sleep(1);
552
553         /* run everything to be run at "ctrlaltdel" */
554         run_lastAction();
555
556         sync();
557         if (kernelVersion > 0 && kernelVersion <= 2 * 65536 + 2 * 256 + 11) {
558                 /* bdflush, kupdate not needed for kernels >2.2.11 */
559                 bdflush(1, 0);
560                 sync();
561         }
562 }
563
564 static void halt_signal(int sig)
565 {
566         shutdown_system();
567         message(CONSOLE|LOG,
568                         "The system is halted. Press %s or turn off power\r\n",
569                         (secondConsole == NULL) /* serial console */
570                         ? "Reset" : "CTRL-ALT-DEL");
571         sync();
572
573         /* allow time for last message to reach serial console */
574         sleep(2);
575
576 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
577         if (sig == SIGUSR2)
578                 init_reboot(RB_POWER_OFF);
579         else
580 #endif
581                 init_reboot(RB_HALT_SYSTEM);
582         exit(0);
583 }
584
585 static void reboot_signal(int sig)
586 {
587         shutdown_system();
588         message(CONSOLE|LOG, "Please stand by while rebooting the system.\r\n");
589         sync();
590
591         /* allow time for last message to reach serial console */
592         sleep(2);
593
594         init_reboot(RB_AUTOBOOT);
595         exit(0);
596 }
597
598 #if defined BB_FEATURE_INIT_CHROOT
599
600 #if ! defined BB_FEATURE_USE_PROCFS
601 #error Sorry, I depend on the /proc filesystem right now.
602 #endif
603
604 static void check_chroot(int sig)
605 {
606         char *argv_init[2] = { "init", NULL, };
607         char *envp_init[3] = { "HOME=/", "TERM=linux", NULL, };
608         char rootpath[256], *tc;
609         int fd;
610
611         if ((fd = open("/proc/sys/kernel/init-chroot", O_RDONLY)) == -1) {
612                 message(CONSOLE,
613                                 "SIGHUP recived, but could not open proc file\r\n");
614                 sleep(2);
615                 return;
616         }
617         if (read(fd, rootpath, sizeof(rootpath)) == -1) {
618                 message(CONSOLE,
619                                 "SIGHUP recived, but could not read proc file\r\n");
620                 sleep(2);
621                 return;
622         }
623         close(fd);
624
625         if (rootpath[0] == '\0') {
626                 message(CONSOLE,
627                                 "SIGHUP recived, but new root is not valid: %s\r\n",
628                                 rootpath);
629                 sleep(2);
630                 return;
631         }
632
633         tc = strrchr(rootpath, '\n');
634         *tc = '\0';
635
636         /* Ok, making it this far means we commit */
637         message(CONSOLE, "Please stand by, changing root to `%s'.\r\n",
638                         rootpath);
639
640         /* kill all other programs first */
641         message(CONSOLE, "Sending SIGTERM to all processes.\r\n");
642         kill(-1, SIGTERM);
643         sleep(2);
644         sync();
645
646         message(CONSOLE, "Sending SIGKILL to all processes.\r\n");
647         kill(-1, SIGKILL);
648         sleep(2);
649         sync();
650
651         /* ok, we don't need /proc anymore. we also assume that the signaling
652          * process left the rest of the filesystems alone for us */
653         umount("/proc");
654
655         /* Ok, now we chroot. Hopefully we only have two things mounted, the
656          * new chroot'd mount point, and the old "/" mount. s,
657          * we go ahead and unmount the old "/". This should trigger the kernel
658          * to set things up the Right Way(tm). */
659
660         if (!chroot(rootpath))
661                 umount("/dev/root");
662
663         /* If the chroot fails, we are already too far to turn back, so we
664          * continue and hope that executing init below will revive the system */
665
666         /* close all of our descriptors and open new ones */
667         close(0);
668         close(1);
669         close(2);
670         open("/dev/console", O_RDWR, 0);
671         dup(0);
672         dup(0);
673
674         message(CONSOLE, "Executing real init...\r\n");
675         /* execute init in the (hopefully) new root */
676         execve("/sbin/init", argv_init, envp_init);
677
678         message(CONSOLE,
679                         "ERROR: Could not exec new init. Press %s to reboot.\r\n",
680                         (secondConsole == NULL) /* serial console */
681                         ? "Reset" : "CTRL-ALT-DEL");
682         return;
683 }
684 #endif                                                  /* BB_FEATURE_INIT_CHROOT */
685
686 #endif                                                  /* ! DEBUG_INIT */
687
688 void new_initAction(initActionEnum action, char *process, char *cons)
689 {
690         initAction *newAction;
691
692         if (*cons == '\0')
693                 cons = console;
694
695         /* If BusyBox detects that a serial console is in use, 
696          * then entries not refering to the console or null devices will _not_ be run.
697          * The exception to this rule is the null device.
698          */
699         if (secondConsole == NULL && strcmp(cons, console)
700                 && strcmp(cons, "/dev/null"))
701                 return;
702
703         newAction = calloc((size_t) (1), sizeof(initAction));
704         if (!newAction) {
705                 message(LOG | CONSOLE, "Memory allocation failure\n");
706                 while (1)
707                         sleep(1);
708         }
709         newAction->nextPtr = initActionList;
710         initActionList = newAction;
711         strncpy(newAction->process, process, 255);
712         newAction->action = action;
713         strncpy(newAction->console, cons, 255);
714         newAction->pid = 0;
715 //    message(LOG|CONSOLE, "process='%s' action='%d' console='%s'\n",
716 //      newAction->process, newAction->action, newAction->console);
717 }
718
719 static void delete_initAction(initAction * action)
720 {
721         initAction *a, *b = NULL;
722
723         for (a = initActionList; a; b = a, a = a->nextPtr) {
724                 if (a == action) {
725                         if (b == NULL) {
726                                 initActionList = a->nextPtr;
727                         } else {
728                                 b->nextPtr = a->nextPtr;
729                         }
730                         free(a);
731                         break;
732                 }
733         }
734 }
735
736 /* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined,
737  * then parse_inittab() simply adds in some default
738  * actions(i.e runs INIT_SCRIPT and then starts a pair 
739  * of "askfirst" shells).  If BB_FEATURE_USE_INITTAB 
740  * _is_ defined, but /etc/inittab is missing, this 
741  * results in the same set of default behaviors.
742  * */
743 void parse_inittab(void)
744 {
745 #ifdef BB_FEATURE_USE_INITTAB
746         FILE *file;
747         char buf[256], lineAsRead[256], tmpConsole[256];
748         char *id, *runlev, *action, *process, *eol;
749         const struct initActionType *a = actions;
750         int foundIt;
751
752
753         file = fopen(INITTAB, "r");
754         if (file == NULL) {
755                 /* No inittab file -- set up some default behavior */
756 #endif
757                 /* Swapoff on halt/reboot */
758                 new_initAction(CTRLALTDEL, "/sbin/swapoff -a > /dev/null 2>&1", console);
759                 /* Umount all filesystems on halt/reboot */
760                 new_initAction(CTRLALTDEL, "/bin/umount -a -r > /dev/null 2>&1", console);
761                 /* Askfirst shell on tty1 */
762                 new_initAction(ASKFIRST, SHELL, console);
763                 /* Askfirst shell on tty2 */
764                 if (secondConsole != NULL)
765                         new_initAction(ASKFIRST, SHELL, secondConsole);
766                 /* sysinit */
767                 new_initAction(SYSINIT, INIT_SCRIPT, console);
768
769                 return;
770 #ifdef BB_FEATURE_USE_INITTAB
771         }
772
773         while (fgets(buf, 255, file) != NULL) {
774                 foundIt = FALSE;
775                 /* Skip leading spaces */
776                 for (id = buf; *id == ' ' || *id == '\t'; id++);
777
778                 /* Skip the line if it's a comment */
779                 if (*id == '#' || *id == '\n')
780                         continue;
781
782                 /* Trim the trailing \n */
783                 eol = strrchr(id, '\n');
784                 if (eol != NULL)
785                         *eol = '\0';
786
787                 /* Keep a copy around for posterity's sake (and error msgs) */
788                 strcpy(lineAsRead, buf);
789
790                 /* Separate the ID field from the runlevels */
791                 runlev = strchr(id, ':');
792                 if (runlev == NULL || *(runlev + 1) == '\0') {
793                         message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
794                         continue;
795                 } else {
796                         *runlev = '\0';
797                         ++runlev;
798                 }
799
800                 /* Separate the runlevels from the action */
801                 action = strchr(runlev, ':');
802                 if (action == NULL || *(action + 1) == '\0') {
803                         message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
804                         continue;
805                 } else {
806                         *action = '\0';
807                         ++action;
808                 }
809
810                 /* Separate the action from the process */
811                 process = strchr(action, ':');
812                 if (process == NULL || *(process + 1) == '\0') {
813                         message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
814                         continue;
815                 } else {
816                         *process = '\0';
817                         ++process;
818                 }
819
820                 /* Ok, now process it */
821                 a = actions;
822                 while (a->name != 0) {
823                         if (strcmp(a->name, action) == 0) {
824                                 if (*id != '\0') {
825                                         struct stat statBuf;
826
827                                         strcpy(tmpConsole, "/dev/");
828                                         strncat(tmpConsole, id, 200);
829                                         if (stat(tmpConsole, &statBuf) != 0) {
830                                                 message(LOG | CONSOLE,
831                                                                 "device '%s' does not exist.  Did you read the directions?\n",
832                                                                 tmpConsole);
833                                                 break;
834                                         }
835                                         id = tmpConsole;
836                                 }
837                                 new_initAction(a->action, process, id);
838                                 foundIt = TRUE;
839                         }
840                         a++;
841                 }
842                 if (foundIt == TRUE)
843                         continue;
844                 else {
845                         /* Choke on an unknown action */
846                         message(LOG | CONSOLE, "Bad inittab entry: %s\n", lineAsRead);
847                 }
848         }
849         return;
850 #endif /* BB_FEATURE_USE_INITTAB */
851 }
852
853
854
855 extern int init_main(int argc, char **argv)
856 {
857         initAction *a;
858         pid_t wpid;
859         int status;
860
861 #ifndef DEBUG_INIT
862         /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */
863         if (getpid() != 1
864 #ifdef BB_FEATURE_LINUXRC
865                         && strstr(argv[0], "linuxrc") == NULL
866 #endif
867                           )
868         {
869                         usage("init\n\nInit is the parent of all processes.\n\n"
870                                   "This version of init is designed to be run only "
871                                   "by the kernel.\n");
872         }
873         /* Set up sig handlers  -- be sure to
874          * clear all of these in run() */
875         signal(SIGUSR1, halt_signal);
876         signal(SIGUSR2, reboot_signal);
877         signal(SIGINT, reboot_signal);
878         signal(SIGTERM, reboot_signal);
879 #if defined BB_FEATURE_INIT_CHROOT
880         signal(SIGHUP, check_chroot);
881 #endif
882
883         /* Turn off rebooting via CTL-ALT-DEL -- we get a 
884          * SIGINT on CAD so we can shut things down gracefully... */
885         init_reboot(RB_DISABLE_CAD);
886 #endif
887
888         /* Figure out what kernel this is running */
889         kernelVersion = get_kernel_revision();
890
891         /* Figure out where the default console should be */
892         console_init();
893
894         /* Close whatever files are open, and reset the console. */
895         close(0);
896         close(1);
897         close(2);
898         set_term(0);
899         chdir("/");
900         setsid();
901
902         /* Make sure PATH is set to something sane */
903         putenv(_PATH_STDPATH);
904
905         /* Hello world */
906 #ifndef DEBUG_INIT
907         message(
908 #if ! defined BB_FEATURE_EXTRA_QUIET
909                         CONSOLE|
910 #endif
911                         LOG,
912                         "init started:  BusyBox v%s (%s) multi-call binary\r\n",
913                         BB_VER, BB_BT);
914 #else
915         message(
916 #if ! defined BB_FEATURE_EXTRA_QUIET
917                         CONSOLE|
918 #endif
919                         LOG,
920                         "init(%d) started:  BusyBox v%s (%s) multi-call binary\r\n",
921                         getpid(), BB_VER, BB_BT);
922 #endif
923
924
925         /* Make sure there is enough memory to do something useful. */
926         check_memory();
927
928         /* Check if we are supposed to be in single user mode */
929         if (argc > 1 && (!strcmp(argv[1], "single") ||
930                                          !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) {
931                 /* Ask first then start a shell on tty2 */
932                 if (secondConsole != NULL)
933                         new_initAction(ASKFIRST, SHELL, secondConsole);
934                 /* Start a shell on tty1 */
935                 new_initAction(RESPAWN, SHELL, console);
936         } else {
937                 /* Not in single user mode -- see what inittab says */
938
939                 /* NOTE that if BB_FEATURE_USE_INITTAB is NOT defined,
940                  * then parse_inittab() simply adds in some default
941                  * actions(i.e runs INIT_SCRIPT and then starts a pair 
942                  * of "askfirst" shells */
943                 parse_inittab();
944         }
945
946         /* Fix up argv[0] to be certain we claim to be init */
947         strncpy(argv[0], "init", strlen(argv[0])+1);
948         if (argc > 1)
949                 strncpy(argv[1], "\0", strlen(argv[1])+1);
950
951         /* Now run everything that needs to be run */
952
953         /* First run the sysinit command */
954         for (a = initActionList; a; a = a->nextPtr) {
955                 if (a->action == SYSINIT) {
956                         waitfor(a->process, a->console, FALSE);
957                         /* Now remove the "sysinit" entry from the list */
958                         delete_initAction(a);
959                 }
960         }
961         /* Next run anything that wants to block */
962         for (a = initActionList; a; a = a->nextPtr) {
963                 if (a->action == WAIT) {
964                         waitfor(a->process, a->console, FALSE);
965                         /* Now remove the "wait" entry from the list */
966                         delete_initAction(a);
967                 }
968         }
969         /* Next run anything to be run only once */
970         for (a = initActionList; a; a = a->nextPtr) {
971                 if (a->action == ONCE) {
972                         run(a->process, a->console, FALSE);
973                         /* Now remove the "once" entry from the list */
974                         delete_initAction(a);
975                 }
976         }
977         /* If there is nothing else to do, stop */
978         if (initActionList == NULL) {
979                 message(LOG | CONSOLE,
980                                 "No more tasks for init -- sleeping forever.\n");
981                 while (1)
982                         sleep(1);
983         }
984
985         /* Now run the looping stuff for the rest of forever */
986         while (1) {
987                 for (a = initActionList; a; a = a->nextPtr) {
988                         /* Only run stuff with pid==0.  If they have
989                          * a pid, that means they are still running */
990                         if (a->pid == 0) {
991                                 switch (a->action) {
992                                 case RESPAWN:
993                                         /* run the respawn stuff */
994                                         a->pid = run(a->process, a->console, FALSE);
995                                         break;
996                                 case ASKFIRST:
997                                         /* run the askfirst stuff */
998                                         a->pid = run(a->process, a->console, TRUE);
999                                         break;
1000                                         /* silence the compiler's incessant whining */
1001                                 default:
1002                                         break;
1003                                 }
1004                         }
1005                 }
1006                 /* Wait for a child process to exit */
1007                 wpid = wait(&status);
1008                 if (wpid > 0) {
1009                         /* Find out who died and clean up their corpse */
1010                         for (a = initActionList; a; a = a->nextPtr) {
1011                                 if (a->pid == wpid) {
1012                                         a->pid = 0;
1013                                         message(LOG,
1014                                                         "Process '%s' (pid %d) exited.  Scheduling it for restart.\n",
1015                                                         a->process, wpid);
1016                                 }
1017                         }
1018                 }
1019                 sleep(1);
1020         }
1021 }
1022
1023 /*
1024 Local Variables:
1025 c-file-style: "linux"
1026 c-basic-offset: 4
1027 tab-width: 4
1028 End:
1029 */