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