be04ec34f2e7d3a062b579ba9d6e67664b5556f3
[oweals/busybox.git] / init.c
1 /*
2  * Mini init implementation for busybox
3  *
4  *
5  * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
6  * Adjusted by so many folks, it's impossible to keep track.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  *
22  */
23
24 #include "internal.h"
25 #include <stdio.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdarg.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <signal.h>
32 #include <termios.h>
33 #include <paths.h>
34 #include <sys/types.h>
35 #include <sys/fcntl.h>
36 #include <sys/wait.h>
37 #include <string.h>
38 #include <sys/mount.h>
39 #include <sys/reboot.h>
40 #include <sys/kdaemon.h>
41 #include <sys/sysmacros.h>
42 #include <linux/serial.h>       /* for serial_struct */
43 #include <sys/vt.h>             /* for vt_stat */
44 #include <sys/ioctl.h>
45 #include <linux/version.h>
46 #ifdef BB_SYSLOGD
47 #include <sys/syslog.h>
48 #endif
49
50 #if ! defined BB_FEATURE_USE_PROCFS
51 #error Sorry, I depend on the /proc filesystem right now.
52 #endif
53
54 #ifndef KERNEL_VERSION
55 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
56 #endif
57
58
59 #define VT_PRIMARY      "/dev/tty1"       /* Primary virtual console */
60 #define VT_SECONDARY    "/dev/tty2"       /* Virtual console */
61 #define VT_LOG          "/dev/tty3"       /* Virtual console */
62 #define SERIAL_CON0     "/dev/ttyS0"      /* Primary serial console */
63 #define SERIAL_CON1     "/dev/ttyS1"      /* Serial console */
64 #define SHELL           "/bin/sh"         /* Default shell */
65 #define REBOOT          "/sbin/reboot"    /* Default ctrl-alt-del command */
66 #define INITTAB         "/etc/inittab"    /* inittab file location */
67 #define INIT_SCRIPT     "/etc/init.d/rcS" /* Default sysinit script. */
68
69 #define LOG             0x1
70 #define CONSOLE         0x2
71
72 /* Allowed init action types */
73 typedef enum {
74     SYSINIT=1,
75     CTRLALTDEL,
76     RESPAWN,
77     ASKFIRST,
78     WAIT,
79     ONCE
80 } initActionEnum;
81
82 /* And now a list of the actions we support in the version of init */
83 typedef struct initActionType{
84     const char* name;
85     initActionEnum action;
86 } initActionType;
87
88 static const struct initActionType actions[] = {
89     {"sysinit",     SYSINIT},
90     {"ctrlaltdel",  CTRLALTDEL},
91     {"respawn",     RESPAWN},
92     {"askfirst",    ASKFIRST},
93     {"wait",        WAIT},
94     {"once",        ONCE},
95     {0}
96 };
97
98 /* Set up a linked list of initactions, to be read from inittab */
99 typedef struct initActionTag initAction;
100 struct initActionTag {
101     pid_t pid;
102     char process[256];
103     char *console;
104     initAction *nextPtr;
105     initActionEnum action;
106 };
107 initAction* initActionList = NULL;
108
109
110 static char *console = _PATH_CONSOLE;
111 static char *second_console = VT_SECONDARY;
112 static char *log = VT_LOG;
113 static int kernel_version = 0;
114
115
116 /* try to open up the specified device */
117 int device_open(char *device, int mode)
118 {
119     int m, f, fd = -1;
120
121     m = mode | O_NONBLOCK;
122
123     /* Retry up to 5 times */
124     for (f = 0; f < 5; f++)
125         if ((fd = open(device, m)) >= 0)
126             break;
127     if (fd < 0)
128         return fd;
129     /* Reset original flags. */
130     if (m != mode)
131         fcntl(fd, F_SETFL, mode);
132     return fd;
133 }
134
135 /* print a message to the specified device:
136  * device may be bitwise-or'd from LOG | CONSOLE */
137 void message(int device, char *fmt, ...)
138 {
139     va_list arguments;
140     int fd;
141
142 #ifdef BB_SYSLOGD
143
144     /* Log the message to syslogd */
145     if (device & LOG ) {
146         char msg[1024];
147         va_start(arguments, fmt);
148         vsnprintf(msg, sizeof(msg), fmt, arguments);
149         va_end(arguments);
150         syslog(LOG_DAEMON|LOG_NOTICE, msg);
151     }
152
153 #else
154     static int log_fd=-1;
155
156     /* Take full control of the log tty, and never close it.
157      * It's mine, all mine!  Muhahahaha! */
158     if (log_fd < 0) {
159         if (log == NULL) {
160         /* don't even try to log, because there is no such console */
161         log_fd = -2;
162         /* log to main console instead */
163         device = CONSOLE;
164     }
165     else if ((log_fd = device_open(log, O_RDWR|O_NDELAY)) < 0) {
166             log_fd=-1;
167             fprintf(stderr, "Bummer, can't write to log on %s!\r\n", log);
168             fflush(stderr);
169             return;
170         }
171     }
172     if ( (device & LOG) && (log_fd >= 0) ) {
173         va_start(arguments, fmt);
174         vdprintf(log_fd, fmt, arguments);
175         va_end(arguments);
176     }
177 #endif
178
179     if (device & CONSOLE) {
180         /* Always send console messages to /dev/console so people will see them. */
181         if ((fd = device_open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) {
182             va_start(arguments, fmt);
183             vdprintf(fd, fmt, arguments);
184             va_end(arguments);
185             close(fd);
186         } else {
187             fprintf(stderr, "Bummer, can't print: ");
188             va_start(arguments, fmt);
189             vfprintf(stderr, fmt, arguments);
190             fflush(stderr);
191             va_end(arguments);
192         }
193     }
194 }
195
196
197 /* Set terminal settings to reasonable defaults */
198 void set_term( int fd)
199 {
200     struct termios tty;
201     static const char control_characters[] = {
202         '\003', '\034', '\177', '\025', '\004', '\0',
203         '\1', '\0', '\021', '\023', '\032', '\0', '\022',
204         '\017', '\027', '\026', '\0'
205         };
206
207     tcgetattr(fd, &tty);
208
209     /* set control chars */
210     memcpy(tty.c_cc, control_characters, sizeof(control_characters));
211
212     /* use line dicipline 0 */
213     tty.c_line = 0;
214
215     /* Make it be sane */
216     //tty.c_cflag &= CBAUD|CBAUDEX|CSIZE|CSTOPB|PARENB|PARODD;
217     //tty.c_cflag |= HUPCL|CLOCAL;
218
219     /* input modes */
220     tty.c_iflag = ICRNL|IXON|IXOFF;
221
222     /* output modes */
223     tty.c_oflag = OPOST|ONLCR;
224
225     /* local modes */
226     tty.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN;
227
228     tcsetattr(fd, TCSANOW, &tty);
229 }
230
231 /* How much memory does this machine have? */
232 static int mem_total()
233 {
234     char s[80];
235     char *p = "/proc/meminfo";
236     FILE *f;
237     const char pattern[] = "MemTotal:";
238
239     if ((f = fopen(p, "r")) < 0) {
240         message(LOG, "Error opening %s: %s\n", p, strerror( errno));
241         return -1;
242     }
243     while (NULL != fgets(s, 79, f)) {
244         p = strstr(s, pattern);
245         if (NULL != p) {
246             fclose(f);
247             return (atoi(p + strlen(pattern)));
248         }
249     }
250     return -1;
251 }
252
253 static void console_init()
254 {
255     int fd;
256     int tried_devcons = 0;
257     int tried_vtprimary = 0;
258     struct serial_struct sr;
259     char *s;
260
261     if ((s = getenv("CONSOLE")) != NULL) {
262         console = s;
263     }
264 #if #cpu(sparc)
265     /* sparc kernel supports console=tty[ab] parameter which is also 
266      * passed to init, so catch it here */
267     else if ((s = getenv("console")) != NULL) {
268         /* remap tty[ab] to /dev/ttyS[01] */
269         if (strcmp( s, "ttya" )==0)
270             console = SERIAL_CON0;
271         else if (strcmp( s, "ttyb" )==0)
272             console = SERIAL_CON1;
273     }
274 #endif
275     else {
276         struct vt_stat vt;
277         static char the_console[13];
278
279         console = the_console;
280         /* 2.2 kernels: identify the real console backend and try to use it */
281         if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
282             /* this is a serial console */
283             snprintf( the_console, sizeof the_console, "/dev/ttyS%d", sr.line );
284         }
285         else if (ioctl(0, VT_GETSTATE, &vt) == 0) {
286             /* this is linux virtual tty */
287             snprintf( the_console, sizeof the_console, "/dev/tty%d", vt.v_active );
288         } else {
289             console = _PATH_CONSOLE;
290             tried_devcons++;
291         }
292     }
293
294     while ((fd = open(console, O_RDONLY | O_NONBLOCK)) < 0) {
295         /* Can't open selected console -- try /dev/console */
296         if (!tried_devcons) {
297             tried_devcons++;
298             console = _PATH_CONSOLE;
299             continue;
300         }
301         /* Can't open selected console -- try vt1 */
302         if (!tried_vtprimary) {
303             tried_vtprimary++;
304             console = VT_PRIMARY;
305             continue;
306         }
307         break;
308     }
309     if (fd < 0)
310         /* Perhaps we should panic here? */
311         console = "/dev/null";
312     else {
313         /* check for serial console and disable logging to tty3 & running a
314         * shell to tty2 */
315         if (ioctl(0,TIOCGSERIAL,&sr) == 0) {
316             message(LOG|CONSOLE, "serial console detected.  Disabling 2nd virtual terminal.\r\n", console );
317             log = NULL;
318             second_console = NULL;
319         }
320         close(fd);
321     }
322     message(LOG, "console=%s\n", console );
323 }
324
325 static int waitfor(int pid)
326 {
327     int status, wpid;
328
329     message(LOG, "Waiting for process %d.\n", pid);
330     while ((wpid = wait(&status)) != pid) {
331         if (wpid > 0)
332             message(LOG, "pid %d exited, status=0x%x.\n", wpid, status);
333     }
334     return wpid;
335 }
336
337
338 static pid_t run(char* command, 
339         char *terminal, int get_enter)
340 {
341     int i;
342     pid_t pid;
343     char* tmpCmd;
344     char* cmd[255];
345     static const char press_enter[] =
346         "\nPlease press Enter to activate this console. ";
347
348     if ((pid = fork()) == 0) {
349         int fd;
350         /* Clean up */
351         close(0);
352         close(1);
353         close(2);
354         setsid();
355
356         /* Reset signal handlers set for parent process */
357         signal(SIGUSR1, SIG_DFL);
358         signal(SIGUSR2, SIG_DFL);
359         signal(SIGINT, SIG_DFL);
360         signal(SIGTERM, SIG_DFL);
361
362         if ((fd = device_open(terminal, O_RDWR)) < 0) {
363             message(LOG|CONSOLE, "Bummer, can't open %s\r\n", terminal);
364             exit(-1);
365         }
366         dup(fd);
367         dup(fd);
368         tcsetpgrp(0, getpgrp());
369         set_term(0);
370
371         if (get_enter==TRUE) {
372             /*
373              * Save memory by not exec-ing anything large (like a shell)
374              * before the user wants it. This is critical if swap is not
375              * enabled and the system has low memory. Generally this will
376              * be run on the second virtual console, and the first will
377              * be allowed to start a shell or whatever an init script 
378              * specifies.
379              */
380             char c;
381             message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n", 
382                     command, getpid(), terminal );
383             write(fileno(stdout), press_enter, sizeof(press_enter) - 1);
384             read(fileno(stdin), &c, 1);
385         }
386
387         /* Convert command (char*) into cmd (char**, one word per string) */
388         for (tmpCmd=command, i=0; (tmpCmd=strsep(&command, " \t")) != NULL;) {
389             if (*tmpCmd != '\0') {
390                 cmd[i] = tmpCmd;
391                 tmpCmd++;
392                 i++;
393             }
394         }
395         cmd[i] = NULL;
396
397         /* Log the process name and args */
398         message(LOG, "Starting pid %d, console %s: '%s'\r\n", 
399                 getpid(), terminal, cmd[0]);
400
401         /* Now run it.  The new program will take over this PID, 
402          * so nothing further in init.c should be run. */
403         execvp(cmd[0], cmd);
404
405         /* We're still here?  Some error happened. */
406         message(LOG|CONSOLE, "Bummer, could not run '%s': %s\n", cmd[0],
407                 strerror(errno));
408         exit(-1);
409     }
410     return pid;
411 }
412
413 /* Make sure there is enough memory to do something useful. *
414  * Calls swapon if needed so be sure /proc is mounted. */
415 static void check_memory()
416 {
417     struct stat statbuf;
418
419     if (mem_total() > 3500)
420         return;
421
422     if (stat("/etc/fstab", &statbuf) == 0) {
423         /* Try to turn on swap */
424         waitfor(run("/bin/swapon swapon -a", log, FALSE));
425         if (mem_total() < 3500)
426             goto goodnight;
427     } else
428         goto goodnight;
429     return;
430
431 goodnight:
432         message(CONSOLE, "Sorry, your computer does not have enough memory.\r\n");
433         while (1) sleep(1);
434 }
435
436 #ifndef DEBUG_INIT
437 static void shutdown_system(void)
438 {
439     /* Allow Ctrl-Alt-Del to reboot system. */
440     reboot(RB_ENABLE_CAD);
441     message(CONSOLE, "\r\nThe system is going down NOW !!\r\n");
442     sync();
443
444     /* Send signals to every process _except_ pid 1 */
445     message(CONSOLE, "Sending SIGHUP to all processes.\r\n");
446     kill(-1, SIGHUP);
447     sleep(2);
448     sync();
449
450     message(CONSOLE, "Sending SIGKILL to all processes.\r\n");
451     kill(-1, SIGKILL);
452     sleep(1);
453
454     message(CONSOLE, "Disabling swap.\r\n");
455     waitfor(run( "swapoff -a", console, FALSE));
456     message(CONSOLE, "Unmounting filesystems.\r\n");
457     waitfor(run( "umount -a", console, FALSE));
458     sync();
459     if (kernel_version > 0 && kernel_version <= 2 * 65536 + 2 * 256 + 11) {
460         /* bdflush, kupdate not needed for kernels >2.2.11 */
461         message(CONSOLE, "Flushing buffers.\r\n");
462         bdflush(1, 0);
463         sync();
464     }
465 }
466
467 static void halt_signal(int sig)
468 {
469     shutdown_system();
470     message(CONSOLE,
471             "The system is halted. Press CTRL-ALT-DEL or turn off power\r\n");
472     sync();
473 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
474     if (sig == SIGUSR2)
475         reboot(RB_POWER_OFF);
476     else
477 #endif
478     reboot(RB_HALT_SYSTEM);
479     exit(0);
480 }
481
482 static void reboot_signal(int sig)
483 {
484     shutdown_system();
485     message(CONSOLE, "Please stand by while rebooting the system.\r\n");
486     sync();
487     reboot(RB_AUTOBOOT);
488     exit(0);
489 }
490
491 static void ctrl_alt_del_signal(int sig)
492 {
493     initAction* a;
494     /* Run whatever we are supposed to run */
495     for( a=initActionList ; a; a=a->nextPtr) {
496         if (a->action == CTRLALTDEL) {
497             waitfor(run(a->process, console, FALSE));
498         }
499     }
500 }
501 #endif
502
503 void new_initAction (const struct initActionType *a, 
504         char* process, char* console)
505 {
506     initAction* newAction;
507     newAction = calloc ((size_t)(1), sizeof(initAction));
508     if (!newAction) {
509         fprintf(stderr, "Memory allocation failure\n");
510         while (1) sleep(1);
511     }
512     newAction->nextPtr = initActionList;
513     initActionList = newAction;
514     strncpy( newAction->process, process, 255);
515     newAction->action = a->action;
516     newAction->console = console;
517     newAction->pid = 0;
518 }
519
520 void delete_initAction (initAction *action)
521 {
522     initAction *a, *b=NULL;
523     for( a=initActionList ; a; b=a, a=a->nextPtr) {
524         if (a == action && b != NULL) {
525             b->nextPtr=a->nextPtr;
526             free( a);
527             break;
528         }
529     }
530 }
531
532 void parse_inittab(void) 
533 {
534     FILE* file;
535     char buf[256];
536     char *p, *q, *r;
537     const struct initActionType *a = actions;
538     int foundIt;
539
540
541     file = fopen(INITTAB, "r");
542     if (file == NULL) {
543         /* No inittab file -- set up some default behavior */
544
545         /* Askfirst shell on tty1 */
546         new_initAction( &(actions[3]), SHELL, console );
547         /* Askfirst shell on tty2 */
548         if (second_console != NULL) 
549             new_initAction( &(actions[3]), SHELL, second_console );
550         /* Control-alt-del */
551         new_initAction( &(actions[1]), REBOOT, console );
552         /* sysinit */
553         new_initAction( &(actions[0]), INIT_SCRIPT, console );
554
555         return;
556     }
557
558     while ( fgets(buf, 255, file) != NULL) {
559         foundIt=FALSE;
560         for(p = buf; *p == ' ' || *p == '\t'; p++);
561         if (*p == '#' || *p == '\n') continue;
562
563         /* Trim the trailing \n */
564         q = strrchr( p, '\n');
565         if (q != NULL)
566             *q='\0';
567
568         /* Skip past the ID field and the runlevel 
569          * field (both are ignored) */
570         p = strchr( p, ':');
571
572         /* Now peal off the process field from the end
573          * of the string */
574         q = strrchr( p, ':');
575         if ( q == NULL || *(q+1) == '\0' ) {
576             fprintf(stderr, "Bad inittab entry: %s\n", buf);
577             continue;
578         } else {
579             *q='\0';
580             ++q;
581         }
582
583         /* Now peal off the action field */
584         r = strrchr( p, ':');
585         if ( r == NULL || *(r+1) == '\0') {
586             fprintf(stderr, "Bad inittab entry: %s\n", buf);
587             continue;
588         } else {
589             ++r;
590         }
591
592         /* Ok, now process it */
593         a = actions;
594         while (a->name != 0) {
595             if (strcmp(a->name, r) == 0) {
596                 new_initAction( a, q, NULL);
597                 foundIt=TRUE;
598             }
599             a++;
600         }
601         if (foundIt==TRUE)
602             continue;
603         else {
604             /* Choke on an unknown action */
605             fprintf(stderr, "Bad inittab entry: %s\n", buf);
606         }
607     }
608     return;
609 }
610
611
612 extern int init_main(int argc, char **argv)
613 {
614     initAction *a;
615     pid_t wpid;
616     int status;
617     int single = FALSE;
618
619
620 #ifndef DEBUG_INIT
621     /* Expect to be PID 1 iff we are run as init (not linuxrc) */
622     if (getpid() != 1 && strstr(argv[0], "init")!=NULL ) {
623         usage( "init\n\nInit is the parent of all processes.\n\n"
624                 "This version of init is designed to be run only by the kernel\n");
625     }
626
627     /* Set up sig handlers  -- be sure to clear all of these in run() */
628     signal(SIGUSR1, halt_signal);
629     signal(SIGUSR2, reboot_signal);
630     signal(SIGINT, ctrl_alt_del_signal);
631     signal(SIGTERM, reboot_signal);
632
633     /* Turn off rebooting via CTL-ALT-DEL -- we get a 
634      * SIGINT on CAD so we can shut things down gracefully... */
635     reboot(RB_DISABLE_CAD);
636 #endif 
637     
638     /* Figure out where the default console should be */
639     console_init();
640
641     /* Close whatever files are open, and reset the console. */
642     close(0);
643     close(1);
644     close(2);
645     set_term(0);
646     setsid();
647
648     /* Make sure PATH is set to something sane */
649     putenv(_PATH_STDPATH);
650
651    
652     /* Hello world */
653 #ifndef DEBUG_INIT
654     message(CONSOLE|LOG, 
655             "init started:  BusyBox v%s (%s) multi-call binary\r\n", 
656             BB_VER, BB_BT);
657 #else
658     message(CONSOLE|LOG, 
659             "init(%d) started:  BusyBox v%s (%s) multi-call binary\r\n", 
660             getpid(), BB_VER, BB_BT);
661 #endif
662
663     
664     /* Mount /proc */
665     if (mount ("proc", "/proc", "proc", 0, 0) == 0) {
666         message(CONSOLE|LOG, "Mounting /proc: done.\n");
667         kernel_version = get_kernel_revision();
668     } else
669         message(CONSOLE|LOG, "Mounting /proc: failed!\n");
670
671     /* Make sure there is enough memory to do something useful. */
672     check_memory();
673
674     /* Check if we are supposed to be in single user mode */
675     if ( argc > 1 && (!strcmp(argv[1], "single") || 
676                 !strcmp(argv[1], "-s") || !strcmp(argv[1], "1"))) {
677         single = TRUE;
678         /* Ask first then start a shell on tty2 */
679         if (second_console != NULL) 
680             new_initAction( &(actions[3]), SHELL, second_console);
681         /* Ask first then start a shell on tty1 */
682         new_initAction( &(actions[3]), SHELL, console);
683     } else {
684         /* Not in single user mode -- see what inittab says */
685         parse_inittab();
686     }
687
688     /* Now run everything that needs to be run */
689
690     /* First run sysinit */
691     for( a=initActionList ; a; a=a->nextPtr) {
692         if (a->action == SYSINIT) {
693             waitfor(run(a->process, console, FALSE));
694             /* Now remove the "sysinit" entry from the list */
695             delete_initAction( a);
696         }
697     }
698     /* Next run anything that wants to block */
699     for( a=initActionList ; a; a=a->nextPtr) {
700         if (a->action == WAIT) {
701             waitfor(run(a->process, console, FALSE));
702             /* Now remove the "wait" entry from the list */
703             delete_initAction( a);
704         }
705     }
706     /* Next run anything to be run only once */
707     for( a=initActionList ; a; a=a->nextPtr) {
708         if (a->action == ONCE) {
709             run(a->process, console, FALSE);
710             /* Now remove the "once" entry from the list */
711             delete_initAction( a);
712         }
713     }
714
715     /* Now run the looping stuff */
716     for (;;) {
717         for( a=initActionList ; a; a=a->nextPtr) {
718             /* Only run stuff with pid==0.  If they have
719              * a pid, that means they are still running */
720             if (a->pid == 0) {
721                 switch(a->action) {
722                     case RESPAWN:
723                         /* run the respawn stuff */
724                         a->pid = run(a->process, console, FALSE);
725                         break;
726                     case ASKFIRST:
727                         /* run the askfirst stuff */
728                         a->pid = waitfor(run(a->process, console, TRUE));
729                         break;
730                     /* silence the compiler's whining */
731                     default:
732                         break;
733                 }
734             }
735         }
736
737         wpid = wait(&status);
738         /* Find out who died and clean up their corpse */
739         if (wpid > 0 ) {
740             message(LOG, "pid %d exited, status=%x.\n", wpid, status);
741             for( a=initActionList ; a; a=a->nextPtr) {
742                 if (a->pid==wpid) {
743                     a->pid=0;
744                 }
745             }
746         }
747
748         sleep(1);
749     }
750 }
751