| Eric Andersen | c499601 | 1999-10-20 22:08:37 +0000 | [diff] [blame] | 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 |  | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 24 | #include "internal.h" | 
 | 25 | #include <stdio.h> | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 26 | #include <string.h> | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 27 | #include <stdlib.h> | 
 | 28 | #include <stdarg.h> | 
 | 29 | #include <unistd.h> | 
 | 30 | #include <errno.h> | 
 | 31 | #include <signal.h> | 
 | 32 | #include <termios.h> | 
| Eric Andersen | b186d98 | 1999-12-03 09:19:54 +0000 | [diff] [blame] | 33 | #include <paths.h> | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 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> | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 41 | #include <sys/sysmacros.h> | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 42 | #include <linux/serial.h>	/* for serial_struct */ | 
 | 43 | #include <sys/vt.h>		/* for vt_stat */ | 
| Eric Andersen | abc7d59 | 1999-10-19 00:27:50 +0000 | [diff] [blame] | 44 | #include <sys/ioctl.h> | 
| Erik Andersen | 4d1d011 | 1999-12-17 18:44:15 +0000 | [diff] [blame] | 45 | #include <linux/version.h> | 
| Eric Andersen | 4c78147 | 1999-11-26 08:12:56 +0000 | [diff] [blame] | 46 | #ifdef BB_SYSLOGD | 
 | 47 | #include <sys/syslog.h> | 
 | 48 | #endif | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 49 |  | 
| Eric Andersen | 0ecb54a | 1999-12-05 23:24:55 +0000 | [diff] [blame] | 50 | #if ! defined BB_FEATURE_USE_PROCFS | 
 | 51 | #error Sorry, I depend on the /proc filesystem right now. | 
 | 52 | #endif | 
 | 53 |  | 
| Erik Andersen | 4d1d011 | 1999-12-17 18:44:15 +0000 | [diff] [blame] | 54 | #ifndef KERNEL_VERSION | 
 | 55 | #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) | 
 | 56 | #endif | 
 | 57 |  | 
| Eric Andersen | 0ecb54a | 1999-12-05 23:24:55 +0000 | [diff] [blame] | 58 |  | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 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. */ | 
| Erik Andersen | 9c88cac | 1999-12-30 09:25:17 +0000 | [diff] [blame] | 68 |  | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 69 | #define LOG             0x1 | 
 | 70 | #define CONSOLE         0x2 | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 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 |  | 
| Eric Andersen | b186d98 | 1999-12-03 09:19:54 +0000 | [diff] [blame] | 110 | static char *console = _PATH_CONSOLE; | 
| Eric Andersen | be971d6 | 1999-11-03 16:52:50 +0000 | [diff] [blame] | 111 | static char *second_console = VT_SECONDARY; | 
 | 112 | static char *log = VT_LOG; | 
| Eric Andersen | e18c75a | 1999-11-05 04:23:05 +0000 | [diff] [blame] | 113 | static int kernel_version = 0; | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 114 |  | 
 | 115 |  | 
 | 116 | /* try to open up the specified device */ | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 117 | int device_open(char *device, int mode) | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 118 | { | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 119 |     int m, f, fd = -1; | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 120 |  | 
| Eric Andersen | 7f1acfd | 1999-10-29 23:09:13 +0000 | [diff] [blame] | 121 |     m = mode | O_NONBLOCK; | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 122 |  | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 123 |     /* Retry up to 5 times */ | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 124 |     for (f = 0; f < 5; f++) | 
 | 125 | 	if ((fd = open(device, m)) >= 0) | 
 | 126 | 	    break; | 
 | 127 |     if (fd < 0) | 
 | 128 | 	return fd; | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 129 |     /* Reset original flags. */ | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 130 |     if (m != mode) | 
 | 131 | 	fcntl(fd, F_SETFL, mode); | 
 | 132 |     return fd; | 
 | 133 | } | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 134 |  | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 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, ...) | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 138 | { | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 139 |     va_list arguments; | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 140 |     int fd; | 
 | 141 |  | 
| Eric Andersen | 4c78147 | 1999-11-26 08:12:56 +0000 | [diff] [blame] | 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; | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 155 |  | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 156 |     /* Take full control of the log tty, and never close it. | 
 | 157 |      * It's mine, all mine!  Muhahahaha! */ | 
| Eric Andersen | 07e5297 | 1999-11-07 07:38:08 +0000 | [diff] [blame] | 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) { | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 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 |     } | 
| Eric Andersen | 07e5297 | 1999-11-07 07:38:08 +0000 | [diff] [blame] | 172 |     if ( (device & LOG) && (log_fd >= 0) ) { | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 173 | 	va_start(arguments, fmt); | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 174 | 	vdprintf(log_fd, fmt, arguments); | 
| Eric Andersen | a745606 | 1999-10-27 02:31:32 +0000 | [diff] [blame] | 175 | 	va_end(arguments); | 
 | 176 |     } | 
| Eric Andersen | 4c78147 | 1999-11-26 08:12:56 +0000 | [diff] [blame] | 177 | #endif | 
 | 178 |  | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 179 |     if (device & CONSOLE) { | 
| Eric Andersen | ded6259 | 1999-11-18 00:19:26 +0000 | [diff] [blame] | 180 | 	/* Always send console messages to /dev/console so people will see them. */ | 
| Eric Andersen | b186d98 | 1999-12-03 09:19:54 +0000 | [diff] [blame] | 181 | 	if ((fd = device_open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY|O_NDELAY)) >= 0) { | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 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 |     } | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 194 | } | 
 | 195 |  | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 196 |  | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 197 | /* Set terminal settings to reasonable defaults */ | 
| Eric Andersen | c7c41d3 | 1999-10-28 00:24:35 +0000 | [diff] [blame] | 198 | void set_term( int fd) | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 199 | { | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 200 |     struct termios tty; | 
| Eric Andersen | 08b1034 | 1999-11-19 02:38:58 +0000 | [diff] [blame] | 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 | 	}; | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 206 |  | 
| Eric Andersen | c7c41d3 | 1999-10-28 00:24:35 +0000 | [diff] [blame] | 207 |     tcgetattr(fd, &tty); | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 208 |  | 
| Eric Andersen | 08b1034 | 1999-11-19 02:38:58 +0000 | [diff] [blame] | 209 |     /* set control chars */ | 
 | 210 |     memcpy(tty.c_cc, control_characters, sizeof(control_characters)); | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 211 |  | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 212 |     /* use line dicipline 0 */ | 
| Eric Andersen | 7f1acfd | 1999-10-29 23:09:13 +0000 | [diff] [blame] | 213 |     tty.c_line = 0; | 
 | 214 |  | 
| Eric Andersen | 08b1034 | 1999-11-19 02:38:58 +0000 | [diff] [blame] | 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 |  | 
| Eric Andersen | 7f1acfd | 1999-10-29 23:09:13 +0000 | [diff] [blame] | 222 |     /* output modes */ | 
| Eric Andersen | c7c41d3 | 1999-10-28 00:24:35 +0000 | [diff] [blame] | 223 |     tty.c_oflag = OPOST|ONLCR; | 
| Eric Andersen | 7f1acfd | 1999-10-29 23:09:13 +0000 | [diff] [blame] | 224 |  | 
 | 225 |     /* local modes */ | 
| Eric Andersen | 08b1034 | 1999-11-19 02:38:58 +0000 | [diff] [blame] | 226 |     tty.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE|IEXTEN; | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 227 |  | 
| Eric Andersen | c7c41d3 | 1999-10-28 00:24:35 +0000 | [diff] [blame] | 228 |     tcsetattr(fd, TCSANOW, &tty); | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 229 | } | 
 | 230 |  | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 231 | /* How much memory does this machine have? */ | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 232 | static int mem_total() | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 233 | { | 
| Eric Andersen | abc7d59 | 1999-10-19 00:27:50 +0000 | [diff] [blame] | 234 |     char s[80]; | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 235 |     char *p = "/proc/meminfo"; | 
| Eric Andersen | abc7d59 | 1999-10-19 00:27:50 +0000 | [diff] [blame] | 236 |     FILE *f; | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 237 |     const char pattern[] = "MemTotal:"; | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 238 |  | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 239 |     if ((f = fopen(p, "r")) < 0) { | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 240 | 	message(LOG, "Error opening %s: %s\n", p, strerror( errno)); | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 241 | 	return -1; | 
 | 242 |     } | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 243 |     while (NULL != fgets(s, 79, f)) { | 
 | 244 | 	p = strstr(s, pattern); | 
| Eric Andersen | abc7d59 | 1999-10-19 00:27:50 +0000 | [diff] [blame] | 245 | 	if (NULL != p) { | 
 | 246 | 	    fclose(f); | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 247 | 	    return (atoi(p + strlen(pattern))); | 
| Eric Andersen | abc7d59 | 1999-10-19 00:27:50 +0000 | [diff] [blame] | 248 | 	} | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 249 |     } | 
| Eric Andersen | abc7d59 | 1999-10-19 00:27:50 +0000 | [diff] [blame] | 250 |     return -1; | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 251 | } | 
 | 252 |  | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 253 | static void console_init() | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 254 | { | 
 | 255 |     int fd; | 
 | 256 |     int tried_devcons = 0; | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 257 |     int tried_vtprimary = 0; | 
| Eric Andersen | 07e5297 | 1999-11-07 07:38:08 +0000 | [diff] [blame] | 258 |     struct serial_struct sr; | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 259 |     char *s; | 
 | 260 |  | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 261 |     if ((s = getenv("CONSOLE")) != NULL) { | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 262 | 	console = s; | 
| Eric Andersen | 07e5297 | 1999-11-07 07:38:08 +0000 | [diff] [blame] | 263 |     } | 
| Eric Andersen | fbb39c8 | 1999-11-08 17:00:52 +0000 | [diff] [blame] | 264 | #if #cpu(sparc) | 
| Eric Andersen | 07e5297 | 1999-11-07 07:38:08 +0000 | [diff] [blame] | 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 |     } | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 274 | #endif | 
| Eric Andersen | 07e5297 | 1999-11-07 07:38:08 +0000 | [diff] [blame] | 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 */ | 
| Eric Andersen | 08b1034 | 1999-11-19 02:38:58 +0000 | [diff] [blame] | 281 | 	if (ioctl(0, TIOCGSERIAL, &sr) == 0) { | 
| Eric Andersen | 07e5297 | 1999-11-07 07:38:08 +0000 | [diff] [blame] | 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 { | 
| Eric Andersen | b186d98 | 1999-12-03 09:19:54 +0000 | [diff] [blame] | 289 | 	    console = _PATH_CONSOLE; | 
| Eric Andersen | 07e5297 | 1999-11-07 07:38:08 +0000 | [diff] [blame] | 290 | 	    tried_devcons++; | 
 | 291 | 	} | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 292 |     } | 
| Eric Andersen | a745606 | 1999-10-27 02:31:32 +0000 | [diff] [blame] | 293 |  | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 294 |     while ((fd = open(console, O_RDONLY | O_NONBLOCK)) < 0) { | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 295 | 	/* Can't open selected console -- try /dev/console */ | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 296 | 	if (!tried_devcons) { | 
 | 297 | 	    tried_devcons++; | 
| Eric Andersen | b186d98 | 1999-12-03 09:19:54 +0000 | [diff] [blame] | 298 | 	    console = _PATH_CONSOLE; | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 299 | 	    continue; | 
 | 300 | 	} | 
| Eric Andersen | be971d6 | 1999-11-03 16:52:50 +0000 | [diff] [blame] | 301 | 	/* Can't open selected console -- try vt1 */ | 
 | 302 | 	if (!tried_vtprimary) { | 
 | 303 | 	    tried_vtprimary++; | 
 | 304 | 	    console = VT_PRIMARY; | 
 | 305 | 	    continue; | 
 | 306 | 	} | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 307 | 	break; | 
 | 308 |     } | 
 | 309 |     if (fd < 0) | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 310 | 	/* Perhaps we should panic here? */ | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 311 | 	console = "/dev/null"; | 
| Eric Andersen | 07e5297 | 1999-11-07 07:38:08 +0000 | [diff] [blame] | 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) { | 
| Eric Andersen | 08b1034 | 1999-11-19 02:38:58 +0000 | [diff] [blame] | 316 | 	    message(LOG|CONSOLE, "serial console detected.  Disabling 2nd virtual terminal.\r\n", console ); | 
| Eric Andersen | 07e5297 | 1999-11-07 07:38:08 +0000 | [diff] [blame] | 317 | 	    log = NULL; | 
 | 318 | 	    second_console = NULL; | 
 | 319 | 	} | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 320 | 	close(fd); | 
| Eric Andersen | 07e5297 | 1999-11-07 07:38:08 +0000 | [diff] [blame] | 321 |     } | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 322 |     message(LOG, "console=%s\n", console ); | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 323 | } | 
 | 324 |  | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 325 | static int waitfor(int pid) | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 326 | { | 
 | 327 |     int status, wpid; | 
 | 328 |  | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 329 |     message(LOG, "Waiting for process %d.\n", pid); | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 330 |     while ((wpid = wait(&status)) != pid) { | 
 | 331 | 	if (wpid > 0) | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 332 | 	    message(LOG, "pid %d exited, status=0x%x.\n", wpid, status); | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 333 |     } | 
 | 334 |     return wpid; | 
 | 335 | } | 
 | 336 |  | 
| Eric Andersen | a745606 | 1999-10-27 02:31:32 +0000 | [diff] [blame] | 337 |  | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 338 | static pid_t run(char* command,  | 
| Eric Andersen | c7c41d3 | 1999-10-28 00:24:35 +0000 | [diff] [blame] | 339 | 	char *terminal, int get_enter) | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 340 | { | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 341 |     int i; | 
| Eric Andersen | c7c41d3 | 1999-10-28 00:24:35 +0000 | [diff] [blame] | 342 |     pid_t pid; | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 343 |     char* tmpCmd; | 
 | 344 |     char* cmd[255]; | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 345 |     static const char press_enter[] = | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 346 | 	"\nPlease press Enter to activate this console. "; | 
 | 347 |  | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 348 |     if ((pid = fork()) == 0) { | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 349 | 	int fd; | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 350 | 	/* Clean up */ | 
 | 351 | 	close(0); | 
 | 352 | 	close(1); | 
 | 353 | 	close(2); | 
 | 354 | 	setsid(); | 
 | 355 |  | 
| Eric Andersen | 2f6c04f | 1999-11-01 23:59:44 +0000 | [diff] [blame] | 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) { | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 363 | 	    message(LOG|CONSOLE, "Bummer, can't open %s\r\n", terminal); | 
| Eric Andersen | 2f6c04f | 1999-11-01 23:59:44 +0000 | [diff] [blame] | 364 | 	    exit(-1); | 
 | 365 | 	} | 
 | 366 | 	dup(fd); | 
 | 367 | 	dup(fd); | 
| Eric Andersen | c7c41d3 | 1999-10-28 00:24:35 +0000 | [diff] [blame] | 368 | 	tcsetpgrp(0, getpgrp()); | 
 | 369 | 	set_term(0); | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 370 |  | 
| Eric Andersen | 2f6c04f | 1999-11-01 23:59:44 +0000 | [diff] [blame] | 371 | 	if (get_enter==TRUE) { | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 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 | 	     */ | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 380 | 	    char c; | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 381 | 	    message(LOG, "Waiting for enter to start '%s' (pid %d, console %s)\r\n",  | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 382 | 		    command, getpid(), terminal ); | 
 | 383 | 	    write(fileno(stdout), press_enter, sizeof(press_enter) - 1); | 
 | 384 | 	    read(fileno(stdin), &c, 1); | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 385 | 	} | 
 | 386 |  | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 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 |  | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 397 | 	/* Log the process name and args */ | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 398 | 	message(LOG, "Starting pid %d, console %s: '%s'\r\n",  | 
 | 399 | 		getpid(), terminal, cmd[0]); | 
 | 400 |  | 
| Eric Andersen | c7c41d3 | 1999-10-28 00:24:35 +0000 | [diff] [blame] | 401 | 	/* Now run it.  The new program will take over this PID,  | 
| Eric Andersen | a745606 | 1999-10-27 02:31:32 +0000 | [diff] [blame] | 402 | 	 * so nothing further in init.c should be run. */ | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 403 | 	execvp(cmd[0], cmd); | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 404 |  | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 405 | 	/* We're still here?  Some error happened. */ | 
 | 406 | 	message(LOG|CONSOLE, "Bummer, could not run '%s': %s\n", cmd[0], | 
 | 407 | 		strerror(errno)); | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 408 | 	exit(-1); | 
 | 409 |     } | 
 | 410 |     return pid; | 
 | 411 | } | 
 | 412 |  | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 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; | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 418 |  | 
 | 419 |     if (mem_total() > 3500) | 
 | 420 | 	return; | 
 | 421 |  | 
 | 422 |     if (stat("/etc/fstab", &statbuf) == 0) { | 
 | 423 | 	/* Try to turn on swap */ | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 424 | 	waitfor(run("/bin/swapon swapon -a", log, FALSE)); | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 425 | 	if (mem_total() < 3500) | 
 | 426 | 	    goto goodnight; | 
 | 427 |     } else | 
 | 428 | 	goto goodnight; | 
 | 429 |     return; | 
 | 430 |  | 
 | 431 | goodnight: | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 432 | 	message(CONSOLE, "Sorry, your computer does not have enough memory.\r\n"); | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 433 | 	while (1) sleep(1); | 
 | 434 | } | 
 | 435 |  | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 436 | #ifndef DEBUG_INIT | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 437 | static void shutdown_system(void) | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 438 | { | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 439 |     /* Allow Ctrl-Alt-Del to reboot system. */ | 
 | 440 |     reboot(RB_ENABLE_CAD); | 
| Eric Andersen | 08b1034 | 1999-11-19 02:38:58 +0000 | [diff] [blame] | 441 |     message(CONSOLE, "\r\nThe system is going down NOW !!\r\n"); | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 442 |     sync(); | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 443 |  | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 444 |     /* Send signals to every process _except_ pid 1 */ | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 445 |     message(CONSOLE, "Sending SIGHUP to all processes.\r\n"); | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 446 |     kill(-1, SIGHUP); | 
 | 447 |     sleep(2); | 
 | 448 |     sync(); | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 449 |  | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 450 |     message(CONSOLE, "Sending SIGKILL to all processes.\r\n"); | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 451 |     kill(-1, SIGKILL); | 
 | 452 |     sleep(1); | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 453 |  | 
| Eric Andersen | 08b1034 | 1999-11-19 02:38:58 +0000 | [diff] [blame] | 454 |     message(CONSOLE, "Disabling swap.\r\n"); | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 455 |     waitfor(run( "swapoff -a", console, FALSE)); | 
| Eric Andersen | 08b1034 | 1999-11-19 02:38:58 +0000 | [diff] [blame] | 456 |     message(CONSOLE, "Unmounting filesystems.\r\n"); | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 457 |     waitfor(run( "umount -a", console, FALSE)); | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 458 |     sync(); | 
| Eric Andersen | e18c75a | 1999-11-05 04:23:05 +0000 | [diff] [blame] | 459 |     if (kernel_version > 0 && kernel_version <= 2 * 65536 + 2 * 256 + 11) { | 
| Eric Andersen | cf8c9cf | 1999-11-05 00:31:46 +0000 | [diff] [blame] | 460 | 	/* bdflush, kupdate not needed for kernels >2.2.11 */ | 
| Eric Andersen | e18c75a | 1999-11-05 04:23:05 +0000 | [diff] [blame] | 461 | 	message(CONSOLE, "Flushing buffers.\r\n"); | 
| Eric Andersen | cf8c9cf | 1999-11-05 00:31:46 +0000 | [diff] [blame] | 462 | 	bdflush(1, 0); | 
 | 463 | 	sync(); | 
 | 464 |     } | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 465 | } | 
 | 466 |  | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 467 | static void halt_signal(int sig) | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 468 | { | 
| Eric Andersen | abc7d59 | 1999-10-19 00:27:50 +0000 | [diff] [blame] | 469 |     shutdown_system(); | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 470 |     message(CONSOLE, | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 471 | 	    "The system is halted. Press CTRL-ALT-DEL or turn off power\r\n"); | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 472 |     sync(); | 
| Erik Andersen | 4d1d011 | 1999-12-17 18:44:15 +0000 | [diff] [blame] | 473 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) | 
| Eric Andersen | 2cb5507 | 1999-12-10 08:25:07 +0000 | [diff] [blame] | 474 |     if (sig == SIGUSR2) | 
 | 475 | 	reboot(RB_POWER_OFF); | 
 | 476 |     else | 
| Erik Andersen | 4d1d011 | 1999-12-17 18:44:15 +0000 | [diff] [blame] | 477 | #endif | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 478 |     reboot(RB_HALT_SYSTEM); | 
| Eric Andersen | abc7d59 | 1999-10-19 00:27:50 +0000 | [diff] [blame] | 479 |     exit(0); | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 480 | } | 
 | 481 |  | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 482 | static void reboot_signal(int sig) | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 483 | { | 
| Eric Andersen | abc7d59 | 1999-10-19 00:27:50 +0000 | [diff] [blame] | 484 |     shutdown_system(); | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 485 |     message(CONSOLE, "Please stand by while rebooting the system.\r\n"); | 
 | 486 |     sync(); | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 487 |     reboot(RB_AUTOBOOT); | 
| Eric Andersen | abc7d59 | 1999-10-19 00:27:50 +0000 | [diff] [blame] | 488 |     exit(0); | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 489 | } | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 490 |  | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 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 |  | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 612 | extern int init_main(int argc, char **argv) | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 613 | { | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 614 |     initAction *a; | 
 | 615 |     pid_t wpid; | 
 | 616 |     int status; | 
| Eric Andersen | d00c262 | 1999-12-07 08:37:31 +0000 | [diff] [blame] | 617 |     int single = FALSE; | 
| Eric Andersen | b6a44b8 | 1999-11-13 04:47:09 +0000 | [diff] [blame] | 618 |  | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 619 |  | 
| Eric Andersen | d73dc5b | 1999-11-10 23:13:02 +0000 | [diff] [blame] | 620 | #ifndef DEBUG_INIT | 
| Eric Andersen | 0727458 | 1999-11-21 21:50:07 +0000 | [diff] [blame] | 621 |     /* Expect to be PID 1 iff we are run as init (not linuxrc) */ | 
 | 622 |     if (getpid() != 1 && strstr(argv[0], "init")!=NULL ) { | 
| Eric Andersen | d73dc5b | 1999-11-10 23:13:02 +0000 | [diff] [blame] | 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 |     } | 
| Eric Andersen | d73dc5b | 1999-11-10 23:13:02 +0000 | [diff] [blame] | 626 |  | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 627 |     /* Set up sig handlers  -- be sure to clear all of these in run() */ | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 628 |     signal(SIGUSR1, halt_signal); | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 629 |     signal(SIGUSR2, reboot_signal); | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 630 |     signal(SIGINT, ctrl_alt_del_signal); | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 631 |     signal(SIGTERM, reboot_signal); | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 632 |  | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 633 |     /* Turn off rebooting via CTL-ALT-DEL -- we get a  | 
 | 634 |      * SIGINT on CAD so we can shut things down gracefully... */ | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 635 |     reboot(RB_DISABLE_CAD); | 
| Eric Andersen | 7f1acfd | 1999-10-29 23:09:13 +0000 | [diff] [blame] | 636 | #endif  | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 637 |      | 
| Eric Andersen | c7c41d3 | 1999-10-28 00:24:35 +0000 | [diff] [blame] | 638 |     /* Figure out where the default console should be */ | 
 | 639 |     console_init(); | 
| Eric Andersen | 0460ff2 | 1999-10-25 23:32:44 +0000 | [diff] [blame] | 640 |  | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 641 |     /* Close whatever files are open, and reset the console. */ | 
 | 642 |     close(0); | 
 | 643 |     close(1); | 
 | 644 |     close(2); | 
| Eric Andersen | 7f1acfd | 1999-10-29 23:09:13 +0000 | [diff] [blame] | 645 |     set_term(0); | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 646 |     setsid(); | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 647 |  | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 648 |     /* Make sure PATH is set to something sane */ | 
| Eric Andersen | b186d98 | 1999-12-03 09:19:54 +0000 | [diff] [blame] | 649 |     putenv(_PATH_STDPATH); | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 650 |  | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 651 |     | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 652 |     /* Hello world */ | 
| Eric Andersen | 7f1acfd | 1999-10-29 23:09:13 +0000 | [diff] [blame] | 653 | #ifndef DEBUG_INIT | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 654 |     message(CONSOLE|LOG,  | 
 | 655 | 	    "init started:  BusyBox v%s (%s) multi-call binary\r\n",  | 
 | 656 | 	    BB_VER, BB_BT); | 
| Eric Andersen | 7f1acfd | 1999-10-29 23:09:13 +0000 | [diff] [blame] | 657 | #else | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 658 |     message(CONSOLE|LOG,  | 
 | 659 | 	    "init(%d) started:  BusyBox v%s (%s) multi-call binary\r\n",  | 
 | 660 | 	    getpid(), BB_VER, BB_BT); | 
| Eric Andersen | 7f1acfd | 1999-10-29 23:09:13 +0000 | [diff] [blame] | 661 | #endif | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 662 |  | 
| Eric Andersen | c7c41d3 | 1999-10-28 00:24:35 +0000 | [diff] [blame] | 663 |      | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 664 |     /* Mount /proc */ | 
| Eric Andersen | e18c75a | 1999-11-05 04:23:05 +0000 | [diff] [blame] | 665 |     if (mount ("proc", "/proc", "proc", 0, 0) == 0) { | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 666 | 	message(CONSOLE|LOG, "Mounting /proc: done.\n"); | 
| Eric Andersen | e18c75a | 1999-11-05 04:23:05 +0000 | [diff] [blame] | 667 | 	kernel_version = get_kernel_revision(); | 
 | 668 |     } else | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 669 | 	message(CONSOLE|LOG, "Mounting /proc: failed!\n"); | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 670 |  | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 671 |     /* Make sure there is enough memory to do something useful. */ | 
 | 672 |     check_memory(); | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 673 |  | 
| Eric Andersen | d00c262 | 1999-12-07 08:37:31 +0000 | [diff] [blame] | 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; | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 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(); | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 686 |     } | 
 | 687 |  | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 688 |     /* Now run everything that needs to be run */ | 
| Eric Andersen | 84b0092 | 1999-12-11 04:16:51 +0000 | [diff] [blame] | 689 |  | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 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); | 
| Eric Andersen | d00c262 | 1999-12-07 08:37:31 +0000 | [diff] [blame] | 696 | 	} | 
 | 697 |     } | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 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 |     } | 
| Eric Andersen | 219d6f5 | 1999-11-02 19:43:01 +0000 | [diff] [blame] | 714 |  | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 715 |     /* Now run the looping stuff */ | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 716 |     for (;;) { | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 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 | 	} | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 736 |  | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 737 | 	wpid = wait(&status); | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 738 | 	/* Find out who died and clean up their corpse */ | 
| Eric Andersen | a745606 | 1999-10-27 02:31:32 +0000 | [diff] [blame] | 739 | 	if (wpid > 0 ) { | 
| Eric Andersen | 3ae0c78 | 1999-11-04 01:13:21 +0000 | [diff] [blame] | 740 | 	    message(LOG, "pid %d exited, status=%x.\n", wpid, status); | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 741 | 	    for( a=initActionList ; a; a=a->nextPtr) { | 
 | 742 | 		if (a->pid==wpid) { | 
 | 743 | 		    a->pid=0; | 
 | 744 | 		} | 
| Eric Andersen | b6a44b8 | 1999-11-13 04:47:09 +0000 | [diff] [blame] | 745 | 	    } | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 746 | 	} | 
| Erik Andersen | 7dc1607 | 2000-01-04 01:10:25 +0000 | [diff] [blame^] | 747 |  | 
| Eric Andersen | 8a8fbb8 | 1999-10-26 00:18:56 +0000 | [diff] [blame] | 748 | 	sleep(1); | 
 | 749 |     } | 
| Eric Andersen | cc8ed39 | 1999-10-05 16:24:54 +0000 | [diff] [blame] | 750 | } | 
| Erik Andersen | 9c88cac | 1999-12-30 09:25:17 +0000 | [diff] [blame] | 751 |  |