Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/init
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- Location:
- branches/2.2.9/mindi-busybox/init
- Files:
-
- 4 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/init/Config.in
r1765 r2725 1 # DO NOT EDIT. This file is generated from Config.src 1 2 # 2 3 # For a description of the syntax of this configuration file, … … 6 7 menu "Init Utilities" 7 8 9 config BOOTCHARTD 10 bool "bootchartd" 11 default y 12 help 13 bootchartd is commonly used to profile the boot process 14 for the purpose of speeding it up. In this case, it is started 15 by the kernel as the init process. This is configured by adding 16 the init=/sbin/bootchartd option to the kernel command line. 17 18 It can also be used to monitor the resource usage of a specific 19 application or the running system in general. In this case, 20 bootchartd is started interactively by running bootchartd start 21 and stopped using bootchartd stop. 22 23 config FEATURE_BOOTCHARTD_BLOATED_HEADER 24 bool "Compatible, bloated header" 25 default y 26 depends on BOOTCHARTD 27 help 28 Create extended header file compatible with "big" bootchartd. 29 "Big" bootchartd is a shell script and it dumps some 30 "convenient" info int the header, such as: 31 title = Boot chart for `hostname` (`date`) 32 system.uname = `uname -srvm` 33 system.release = `cat /etc/DISTRO-release` 34 system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount) 35 system.kernel.options = `cat /proc/cmdline` 36 This data is not mandatory for bootchart graph generation, 37 and is considered bloat. Nevertheless, this option 38 makes bootchartd applet to dump a subset of it. 39 40 config FEATURE_BOOTCHARTD_CONFIG_FILE 41 bool "Support bootchartd.conf" 42 default y 43 depends on BOOTCHARTD 44 help 45 Enable reading and parsing of $PWD/bootchartd.conf 46 and /etc/bootchartd.conf files. 47 config HALT 48 bool "poweroff, halt, and reboot" 49 default y 50 help 51 Stop all processes and either halt, reboot, or power off the system. 52 53 config FEATURE_CALL_TELINIT 54 bool "Call telinit on shutdown and reboot" 55 default y 56 depends on HALT && !INIT 57 help 58 Call an external program (normally telinit) to facilitate 59 a switch to a proper runlevel. 60 61 This option is only available if you selected halt and friends, 62 but did not select init. 63 64 config TELINIT_PATH 65 string "Path to telinit executable" 66 default "/sbin/telinit" 67 depends on FEATURE_CALL_TELINIT 68 help 69 When busybox halt and friends have to call external telinit 70 to facilitate proper shutdown, this path is to be used when 71 locating telinit executable. 8 72 config INIT 9 73 bool "init" 10 default n74 default y 11 75 select FEATURE_SYSLOG 12 76 help 13 77 init is the first program run when the system boots. 14 15 config DEBUG_INIT16 bool "debugging aid"17 default n18 depends on INIT19 help20 Turn this on to disable all the dangerous21 rebooting stuff when debugging.22 78 23 79 config FEATURE_USE_INITTAB … … 28 84 Allow init to read an inittab file when the system boot. 29 85 86 config FEATURE_KILL_REMOVED 87 bool "Support killing processes that have been removed from inittab" 88 default n 89 depends on FEATURE_USE_INITTAB 90 help 91 When respawn entries are removed from inittab and a SIGHUP is 92 sent to init, this option will make init kill the processes 93 that have been removed. 94 95 config FEATURE_KILL_DELAY 96 int "How long to wait between TERM and KILL (0 - send TERM only)" if FEATURE_KILL_REMOVED 97 range 0 1024 98 default 0 99 depends on FEATURE_KILL_REMOVED 100 help 101 With nonzero setting, init sends TERM, forks, child waits N 102 seconds, sends KILL and exits. Setting it too high is unwise 103 (child will hang around for too long and could actually kill 104 the wrong process!) 105 30 106 config FEATURE_INIT_SCTTY 31 bool " Support running commands with a controlling-tty"32 default n107 bool "Run commands with leading dash with controlling tty" 108 default y 33 109 depends on INIT 34 110 help 35 If this option is enabled a command starting with hyphen (-) 36 is run in its own session (setsid(2)) and possibly with a 37 controlling tty (TIOCSCTTY). This is not the traditional init 38 behavour, but is often what you want in an embedded system where 39 the console is only accessed during development or for maintenance. 111 If this option is enabled, init will try to give a controlling 112 tty to any command which has leading hyphen (often it's "-/bin/sh"). 113 More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)". 114 If device attached to STDIN_FILENO can be a ctty but is not yet 115 a ctty for other session, it will become this process' ctty. 116 This is not the traditional init behavour, but is often what you want 117 in an embedded system where the console is only accessed during 118 development or for maintenance. 119 NB: using cttyhack applet may work better. 40 120 41 121 config FEATURE_INIT_SYSLOG 42 122 bool "Enable init to write to syslog" 43 default n123 default y 44 124 depends on INIT 45 125 … … 53 133 config FEATURE_INIT_COREDUMPS 54 134 bool "Support dumping core for child processes (debugging only)" 55 default n135 default y 56 136 depends on INIT 57 137 help 58 138 If this option is enabled and the file /.init_enable_core 59 139 exists, then init will call setrlimit() to allow unlimited 60 core file sizes. 140 core file sizes. If this option is disabled, processes 61 141 will not generate any core files. 62 63 64 142 65 143 config FEATURE_INITRD … … 68 146 depends on INIT 69 147 help 70 Legacy support for running init under the old-style initrd. 148 Legacy support for running init under the old-style initrd. Allows 71 149 the name linuxrc to act as init, and it doesn't assume init is PID 1. 72 150 … … 74 152 requires no special support. 75 153 76 config HALT 77 bool "poweroff, halt, and reboot" 78 default y 154 config INIT_TERMINAL_TYPE 155 string "Initial terminal type" 156 default "linux" 157 depends on INIT 79 158 help 80 Stop all processes and either halt, reboot, or power off the system. 159 This is the initial value set by init for the TERM environment 160 variable. This variable is used by programs which make use of 161 extended terminal capabilities. 81 162 163 Note that on Linux, init attempts to detect serial terminal and 164 sets TERM to "vt102" if one is found. 82 165 config MESG 83 166 bool "mesg" 84 167 default y 85 168 help 86 Mesg controls access to your terminal by others. 169 Mesg controls access to your terminal by others. It is typically 87 170 used to allow or disallow other users to write to your terminal 88 171 -
branches/2.2.9/mindi-busybox/init/Kbuild
r1765 r2725 1 # DO NOT EDIT. This file is generated from Kbuild.src 1 2 # Makefile for busybox 2 3 # 3 4 # Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org> 4 5 # 5 # Licensed under the GPL v2, see the file LICENSE in this tarball.6 # Licensed under GPLv2, see file LICENSE in this source tree. 6 7 7 8 lib-y:= 8 lib-$(CONFIG_HALT) += halt.o 9 lib-$(CONFIG_INIT) += init.o 10 lib-$(CONFIG_MESG) += mesg.o 9 10 lib-$(CONFIG_BOOTCHARTD) += bootchartd.o 11 lib-$(CONFIG_HALT) += halt.o 12 lib-$(CONFIG_INIT) += init.o 13 lib-$(CONFIG_MESG) += mesg.o -
branches/2.2.9/mindi-busybox/init/halt.c
r1765 r2725 5 5 * Copyright 2006 by Rob Landley <rob@landley.net> 6 6 * 7 * Licensed under GPL version 2, see file LICENSE in this tarball for details.7 * Licensed under GPLv2, see file LICENSE in this source tree. 8 8 */ 9 9 10 //applet:IF_HALT(APPLET(halt, _BB_DIR_SBIN, _BB_SUID_DROP)) 11 //applet:IF_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_DROP, poweroff)) 12 //applet:IF_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_DROP, reboot)) 13 14 //kbuild:lib-$(CONFIG_HALT) += halt.o 15 16 //config:config HALT 17 //config: bool "poweroff, halt, and reboot" 18 //config: default y 19 //config: help 20 //config: Stop all processes and either halt, reboot, or power off the system. 21 //config: 22 //config:config FEATURE_CALL_TELINIT 23 //config: bool "Call telinit on shutdown and reboot" 24 //config: default y 25 //config: depends on HALT && !INIT 26 //config: help 27 //config: Call an external program (normally telinit) to facilitate 28 //config: a switch to a proper runlevel. 29 //config: 30 //config: This option is only available if you selected halt and friends, 31 //config: but did not select init. 32 //config: 33 //config:config TELINIT_PATH 34 //config: string "Path to telinit executable" 35 //config: default "/sbin/telinit" 36 //config: depends on FEATURE_CALL_TELINIT 37 //config: help 38 //config: When busybox halt and friends have to call external telinit 39 //config: to facilitate proper shutdown, this path is to be used when 40 //config: locating telinit executable. 41 42 //usage:#define halt_trivial_usage 43 //usage: "[-d DELAY] [-n] [-f]" IF_FEATURE_WTMP(" [-w]") 44 //usage:#define halt_full_usage "\n\n" 45 //usage: "Halt the system\n" 46 //usage: "\nOptions:" 47 //usage: "\n -d SEC Delay interval" 48 //usage: "\n -n Do not sync" 49 //usage: "\n -f Force (don't go through init)" 50 //usage: IF_FEATURE_WTMP( 51 //usage: "\n -w Only write a wtmp record" 52 //usage: ) 53 //usage: 54 //usage:#define poweroff_trivial_usage 55 //usage: "[-d DELAY] [-n] [-f]" 56 //usage:#define poweroff_full_usage "\n\n" 57 //usage: "Halt and shut off power\n" 58 //usage: "\nOptions:" 59 //usage: "\n -d SEC Delay interval" 60 //usage: "\n -n Do not sync" 61 //usage: "\n -f Force (don't go through init)" 62 //usage: 63 //usage:#define reboot_trivial_usage 64 //usage: "[-d DELAY] [-n] [-f]" 65 //usage:#define reboot_full_usage "\n\n" 66 //usage: "Reboot the system\n" 67 //usage: "\nOptions:" 68 //usage: "\n -d SEC Delay interval" 69 //usage: "\n -n Do not sync" 70 //usage: "\n -f Force (don't go through init)" 71 10 72 #include "libbb.h" 11 #include <sys/reboot.h>73 #include "reboot.h" 12 74 13 int halt_main(int argc, char **argv); 14 int halt_main(int argc, char **argv) 75 #if ENABLE_FEATURE_WTMP 76 #include <sys/utsname.h> 77 #include <utmp.h> 78 79 static void write_wtmp(void) 80 { 81 struct utmp utmp; 82 struct utsname uts; 83 /* "man utmp" says wtmp file should *not* be created automagically */ 84 /*if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) { 85 close(creat(bb_path_wtmp_file, 0664)); 86 }*/ 87 memset(&utmp, 0, sizeof(utmp)); 88 utmp.ut_tv.tv_sec = time(NULL); 89 strcpy(utmp.ut_user, "shutdown"); /* it is wide enough */ 90 utmp.ut_type = RUN_LVL; 91 utmp.ut_id[0] = '~'; utmp.ut_id[1] = '~'; /* = strcpy(utmp.ut_id, "~~"); */ 92 utmp.ut_line[0] = '~'; utmp.ut_line[1] = '~'; /* = strcpy(utmp.ut_line, "~~"); */ 93 uname(&uts); 94 safe_strncpy(utmp.ut_host, uts.release, sizeof(utmp.ut_host)); 95 updwtmp(bb_path_wtmp_file, &utmp); 96 } 97 #else 98 #define write_wtmp() ((void)0) 99 #endif 100 101 102 int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 103 int halt_main(int argc UNUSED_PARAM, char **argv) 15 104 { 16 105 static const int magic[] = { 17 #ifdef RB_HALT_SYSTEM 18 RB_HALT_SYSTEM, 19 #elif defined RB_HALT 20 RB_HALT, 21 #endif 22 #ifdef RB_POWER_OFF 23 RB_POWER_OFF, 24 #elif defined RB_POWERDOWN 25 RB_POWERDOWN, 26 #endif 27 RB_AUTOBOOT 106 RB_HALT_SYSTEM, 107 RB_POWER_OFF, 108 RB_AUTOBOOT 28 109 }; 29 static const int signals[] = { SIGUSR1, SIGUSR2, SIGTERM };110 static const smallint signals[] = { SIGUSR1, SIGUSR2, SIGTERM }; 30 111 31 char *delay;32 int which, flags, rc = 1;112 int delay = 0; 113 int which, flags, rc; 33 114 34 115 /* Figure out which applet we're running */ 35 for (which = 0; "hpr"[which] != *applet_name; which++); 116 for (which = 0; "hpr"[which] != applet_name[0]; which++) 117 continue; 36 118 37 119 /* Parse and handle arguments */ 38 flags = getopt32(argv, "d:nf", &delay); 39 if (flags & 1) sleep(xatou(delay)); 40 if (!(flags & 2)) sync(); 120 opt_complementary = "d+"; /* -d N */ 121 /* We support -w even if !ENABLE_FEATURE_WTMP, 122 * in order to not break scripts. 123 * -i (shut down network interfaces) is ignored. 124 */ 125 flags = getopt32(argv, "d:nfwi", &delay); 126 127 sleep(delay); 128 129 write_wtmp(); 130 131 if (flags & 8) /* -w */ 132 return EXIT_SUCCESS; 133 134 if (!(flags & 2)) /* no -n */ 135 sync(); 41 136 42 137 /* Perform action. */ 43 if (ENABLE_INIT && !(flags & 4)) { 138 rc = 1; 139 if (!(flags & 4)) { /* no -f */ 140 //TODO: I tend to think that signalling linuxrc is wrong 141 // pity original author didn't comment on it... 44 142 if (ENABLE_FEATURE_INITRD) { 143 /* talk to linuxrc */ 144 /* bbox init/linuxrc assumed */ 45 145 pid_t *pidlist = find_pid_by_name("linuxrc"); 46 146 if (pidlist[0] > 0) … … 49 149 free(pidlist); 50 150 } 51 if (rc) 52 rc = kill(1, signals[which]); 53 } else 151 if (rc) { 152 /* talk to init */ 153 if (!ENABLE_FEATURE_CALL_TELINIT) { 154 /* bbox init assumed */ 155 rc = kill(1, signals[which]); 156 } else { 157 /* SysV style init assumed */ 158 /* runlevels: 159 * 0 == shutdown 160 * 6 == reboot */ 161 rc = execlp(CONFIG_TELINIT_PATH, 162 CONFIG_TELINIT_PATH, 163 which == 2 ? "6" : "0", 164 (char *)NULL 165 ); 166 } 167 } 168 } else { 54 169 rc = reboot(magic[which]); 170 } 55 171 56 172 if (rc) 57 bb_ error_msg("no");173 bb_perror_nomsg_and_die(); 58 174 return rc; 59 175 } -
branches/2.2.9/mindi-busybox/init/init.c
r1765 r2725 7 7 * Adjusted by so many folks, it's impossible to keep track. 8 8 * 9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.9 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 10 10 */ 11 11 12 //applet:IF_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_DROP)) 13 //applet:IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, _BB_DIR_ROOT, _BB_SUID_DROP, linuxrc)) 14 15 //kbuild:lib-$(CONFIG_INIT) += init.o 16 17 //config:config INIT 18 //config: bool "init" 19 //config: default y 20 //config: select FEATURE_SYSLOG 21 //config: help 22 //config: init is the first program run when the system boots. 23 //config: 24 //config:config FEATURE_USE_INITTAB 25 //config: bool "Support reading an inittab file" 26 //config: default y 27 //config: depends on INIT 28 //config: help 29 //config: Allow init to read an inittab file when the system boot. 30 //config: 31 //config:config FEATURE_KILL_REMOVED 32 //config: bool "Support killing processes that have been removed from inittab" 33 //config: default n 34 //config: depends on FEATURE_USE_INITTAB 35 //config: help 36 //config: When respawn entries are removed from inittab and a SIGHUP is 37 //config: sent to init, this option will make init kill the processes 38 //config: that have been removed. 39 //config: 40 //config:config FEATURE_KILL_DELAY 41 //config: int "How long to wait between TERM and KILL (0 - send TERM only)" if FEATURE_KILL_REMOVED 42 //config: range 0 1024 43 //config: default 0 44 //config: depends on FEATURE_KILL_REMOVED 45 //config: help 46 //config: With nonzero setting, init sends TERM, forks, child waits N 47 //config: seconds, sends KILL and exits. Setting it too high is unwise 48 //config: (child will hang around for too long and could actually kill 49 //config: the wrong process!) 50 //config: 51 //config:config FEATURE_INIT_SCTTY 52 //config: bool "Run commands with leading dash with controlling tty" 53 //config: default y 54 //config: depends on INIT 55 //config: help 56 //config: If this option is enabled, init will try to give a controlling 57 //config: tty to any command which has leading hyphen (often it's "-/bin/sh"). 58 //config: More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)". 59 //config: If device attached to STDIN_FILENO can be a ctty but is not yet 60 //config: a ctty for other session, it will become this process' ctty. 61 //config: This is not the traditional init behavour, but is often what you want 62 //config: in an embedded system where the console is only accessed during 63 //config: development or for maintenance. 64 //config: NB: using cttyhack applet may work better. 65 //config: 66 //config:config FEATURE_INIT_SYSLOG 67 //config: bool "Enable init to write to syslog" 68 //config: default y 69 //config: depends on INIT 70 //config: 71 //config:config FEATURE_EXTRA_QUIET 72 //config: bool "Be _extra_ quiet on boot" 73 //config: default y 74 //config: depends on INIT 75 //config: help 76 //config: Prevent init from logging some messages to the console during boot. 77 //config: 78 //config:config FEATURE_INIT_COREDUMPS 79 //config: bool "Support dumping core for child processes (debugging only)" 80 //config: default y 81 //config: depends on INIT 82 //config: help 83 //config: If this option is enabled and the file /.init_enable_core 84 //config: exists, then init will call setrlimit() to allow unlimited 85 //config: core file sizes. If this option is disabled, processes 86 //config: will not generate any core files. 87 //config: 88 //config:config FEATURE_INITRD 89 //config: bool "Support running init from within an initrd (not initramfs)" 90 //config: default y 91 //config: depends on INIT 92 //config: help 93 //config: Legacy support for running init under the old-style initrd. Allows 94 //config: the name linuxrc to act as init, and it doesn't assume init is PID 1. 95 //config: 96 //config: This does not apply to initramfs, which runs /init as PID 1 and 97 //config: requires no special support. 98 //config: 99 //config:config INIT_TERMINAL_TYPE 100 //config: string "Initial terminal type" 101 //config: default "linux" 102 //config: depends on INIT 103 //config: help 104 //config: This is the initial value set by init for the TERM environment 105 //config: variable. This variable is used by programs which make use of 106 //config: extended terminal capabilities. 107 //config: 108 //config: Note that on Linux, init attempts to detect serial terminal and 109 //config: sets TERM to "vt102" if one is found. 110 12 111 #include "libbb.h" 112 #include <syslog.h> 13 113 #include <paths.h> 14 //#include <signal.h> 15 //#include <sys/ioctl.h> 16 //#include <sys/wait.h> 17 #include <sys/reboot.h> 18 19 #if ENABLE_FEATURE_INIT_SYSLOG 20 # include <sys/syslog.h> 21 #endif 22 23 #define INIT_BUFFS_SIZE 256 114 #include <sys/resource.h> 115 #ifdef __linux__ 116 #include <linux/vt.h> 117 #endif 118 #if ENABLE_FEATURE_UTMP 119 # include <utmp.h> /* DEAD_PROCESS */ 120 #endif 121 #include "reboot.h" /* reboot() constants */ 122 123 /* Used only for sanitizing purposes in set_sane_term() below. On systems where 124 * the baud rate is stored in a separate field, we can safely disable them. */ 125 #ifndef CBAUD 126 # define CBAUD 0 127 # define CBAUDEX 0 128 #endif 129 130 /* Was a CONFIG_xxx option. A lot of people were building 131 * not fully functional init by switching it on! */ 132 #define DEBUG_INIT 0 133 134 #define COMMAND_SIZE 256 24 135 #define CONSOLE_NAME_SIZE 32 25 #define MAXENV 16 /* Number of env. vars */ 26 27 #if ENABLE_FEATURE_INIT_COREDUMPS 136 137 /* Default sysinit script. */ 138 #ifndef INIT_SCRIPT 139 #define INIT_SCRIPT "/etc/init.d/rcS" 140 #endif 141 142 /* Each type of actions can appear many times. They will be 143 * handled in order. RESTART is an exception, only 1st is used. 144 */ 145 /* Start these actions first and wait for completion */ 146 #define SYSINIT 0x01 147 /* Start these after SYSINIT and wait for completion */ 148 #define WAIT 0x02 149 /* Start these after WAIT and *dont* wait for completion */ 150 #define ONCE 0x04 28 151 /* 29 * When a file named CORE_ENABLE_FLAG_FILE exists, setrlimit is called30 * before processes are spawned to set core file size as unlimited.31 * This is for debugging only. Don't use this is production, unless32 * you want core dumps lying about....152 * NB: while SYSINIT/WAIT/ONCE are being processed, 153 * SIGHUP ("reread /etc/inittab") will be processed only after 154 * each group of actions. If new inittab adds, say, a SYSINIT action, 155 * it will not be run, since init is already "past SYSINIT stage". 33 156 */ 34 #define CORE_ENABLE_FLAG_FILE "/.init_enable_core" 35 #include <sys/resource.h> 36 #endif 37 38 #define INITTAB "/etc/inittab" /* inittab file location */ 39 #ifndef INIT_SCRIPT 40 #define INIT_SCRIPT "/etc/init.d/rcS" /* Default sysinit script. */ 41 #endif 42 43 /* Allowed init action types */ 44 #define SYSINIT 0x001 45 #define RESPAWN 0x002 46 #define ASKFIRST 0x004 47 #define WAIT 0x008 48 #define ONCE 0x010 49 #define CTRLALTDEL 0x020 50 #define SHUTDOWN 0x040 51 #define RESTART 0x080 52 53 /* A mapping between "inittab" action name strings and action type codes. */ 54 struct init_action_type { 55 const char *name; 56 int action; 57 }; 58 59 static const struct init_action_type actions[] = { 60 {"sysinit", SYSINIT}, 61 {"respawn", RESPAWN}, 62 {"askfirst", ASKFIRST}, 63 {"wait", WAIT}, 64 {"once", ONCE}, 65 {"ctrlaltdel", CTRLALTDEL}, 66 {"shutdown", SHUTDOWN}, 67 {"restart", RESTART}, 68 {0, 0} 69 }; 70 71 /* Set up a linked list of init_actions, to be read from inittab */ 157 /* Start these after ONCE are started, restart on exit */ 158 #define RESPAWN 0x08 159 /* Like RESPAWN, but wait for <Enter> to be pressed on tty */ 160 #define ASKFIRST 0x10 161 /* 162 * Start these on SIGINT, and wait for completion. 163 * Then go back to respawning RESPAWN and ASKFIRST actions. 164 * NB: kernel sends SIGINT to us if Ctrl-Alt-Del was pressed. 165 */ 166 #define CTRLALTDEL 0x20 167 /* 168 * Start these before killing all processes in preparation for 169 * running RESTART actions or doing low-level halt/reboot/poweroff 170 * (initiated by SIGUSR1/SIGTERM/SIGUSR2). 171 * Wait for completion before proceeding. 172 */ 173 #define SHUTDOWN 0x40 174 /* 175 * exec() on SIGQUIT. SHUTDOWN actions are started and waited for, 176 * then all processes are killed, then init exec's 1st RESTART action, 177 * replacing itself by it. If no RESTART action specified, 178 * SIGQUIT has no effect. 179 */ 180 #define RESTART 0x80 181 182 183 /* A linked list of init_actions, to be read from inittab */ 72 184 struct init_action { 73 185 struct init_action *next; 74 int action;75 186 pid_t pid; 76 char command[INIT_BUFFS_SIZE];187 uint8_t action_type; 77 188 char terminal[CONSOLE_NAME_SIZE]; 189 char command[COMMAND_SIZE]; 78 190 }; 79 191 80 /* Static variables */81 192 static struct init_action *init_action_list = NULL; 82 193 83 #if !ENABLE_FEATURE_INIT_SYSLOG84 194 static const char *log_console = VC_5; 85 #endif86 #if !ENABLE_DEBUG_INIT87 static sig_atomic_t got_cont = 0;88 #endif89 195 90 196 enum { 91 197 L_LOG = 0x1, 92 198 L_CONSOLE = 0x2, 93 94 #if ENABLE_FEATURE_EXTRA_QUIET95 MAYBE_CONSOLE = 0x0,96 #else97 MAYBE_CONSOLE = L_CONSOLE,98 #endif99 100 #ifndef RB_HALT_SYSTEM101 RB_HALT_SYSTEM = 0xcdef0123, /* FIXME: this overflows enum */102 RB_ENABLE_CAD = 0x89abcdef,103 RB_DISABLE_CAD = 0,104 RB_POWER_OFF = 0x4321fedc,105 RB_AUTOBOOT = 0x01234567,106 #endif107 199 }; 108 200 109 static const char *const environment[] = {110 "HOME=/",111 bb_PATH_root_path,112 "SHELL=/bin/sh",113 "USER=root",114 NULL115 };116 117 /* Function prototypes */118 static void delete_init_action(struct init_action *a);119 static int waitfor(const struct init_action *a, pid_t pid);120 #if !ENABLE_DEBUG_INIT121 static void shutdown_signal(int sig);122 #endif123 124 #if !ENABLE_DEBUG_INIT125 static void loop_forever(void)126 {127 while (1)128 sleep(1);129 }130 #endif131 132 201 /* Print a message to the specified device. 133 * Device may be bitwise-or'd from L_LOG | L_CONSOLE */ 134 #if ENABLE_DEBUG_INIT 135 #define messageD message 136 #else 137 #define messageD(...) do {} while (0) 138 #endif 139 static void message(int device, const char *fmt, ...) 202 * "where" may be bitwise-or'd from L_LOG | L_CONSOLE 203 * NB: careful, we can be called after vfork! 204 */ 205 #define dbg_message(...) do { if (DEBUG_INIT) message(__VA_ARGS__); } while (0) 206 static void message(int where, const char *fmt, ...) 140 207 __attribute__ ((format(printf, 2, 3))); 141 static void message(int device, const char *fmt, ...) 142 { 143 #if !ENABLE_FEATURE_INIT_SYSLOG 144 static int log_fd = -1; 145 #endif 146 208 static void message(int where, const char *fmt, ...) 209 { 147 210 va_list arguments; 148 intl;211 unsigned l; 149 212 char msg[128]; 150 213 151 214 msg[0] = '\r'; 152 215 va_start(arguments, fmt); 153 vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments); 216 l = 1 + vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments); 217 if (l > sizeof(msg) - 1) 218 l = sizeof(msg) - 1; 154 219 va_end(arguments); 155 msg[sizeof(msg) - 2] = '\0';156 l = strlen(msg);157 220 158 221 #if ENABLE_FEATURE_INIT_SYSLOG 159 /* Log the message to syslogd */160 if ( device & L_LOG) {161 /* don't out "\r"*/222 msg[l] = '\0'; 223 if (where & L_LOG) { 224 /* Log the message to syslogd */ 162 225 openlog(applet_name, 0, LOG_DAEMON); 163 syslog(LOG_INFO, "init: %s", msg + 1); 226 /* don't print "\r" */ 227 syslog(LOG_INFO, "%s", msg + 1); 164 228 closelog(); 165 229 } … … 167 231 msg[l] = '\0'; 168 232 #else 169 msg[l++] = '\n'; 170 msg[l] = '\0'; 171 /* Take full control of the log tty, and never close it. 172 * It's mine, all mine! Muhahahaha! */ 173 if (log_fd < 0) { 174 if (!log_console) { 175 log_fd = 2; 176 } else { 177 log_fd = device_open(log_console, O_WRONLY | O_NONBLOCK | O_NOCTTY); 178 if (log_fd < 0) { 179 bb_error_msg("can't log to %s", log_console); 180 device = L_CONSOLE; 233 { 234 static int log_fd = -1; 235 236 msg[l++] = '\n'; 237 msg[l] = '\0'; 238 /* Take full control of the log tty, and never close it. 239 * It's mine, all mine! Muhahahaha! */ 240 if (log_fd < 0) { 241 if (!log_console) { 242 log_fd = STDERR_FILENO; 181 243 } else { 182 fcntl(log_fd, F_SETFD, FD_CLOEXEC); 244 log_fd = device_open(log_console, O_WRONLY | O_NONBLOCK | O_NOCTTY); 245 if (log_fd < 0) { 246 bb_error_msg("can't log to %s", log_console); 247 where = L_CONSOLE; 248 } else { 249 close_on_exec_on(log_fd); 250 } 183 251 } 184 252 } 185 }186 if (device & L_LOG) {187 full_write(log_fd, msg, l);188 if (log_fd == 2)189 return; /* don't print dup messages */190 } 191 #endif 192 193 if ( device & L_CONSOLE) {253 if (where & L_LOG) { 254 full_write(log_fd, msg, l); 255 if (log_fd == STDERR_FILENO) 256 return; /* don't print dup messages */ 257 } 258 } 259 #endif 260 261 if (where & L_CONSOLE) { 194 262 /* Send console messages to console so people will see them. */ 195 full_write(2, msg, l); 196 } 197 } 198 199 /* Set terminal settings to reasonable defaults */ 263 full_write(STDERR_FILENO, msg, l); 264 } 265 } 266 267 static void console_init(void) 268 { 269 #ifdef VT_OPENQRY 270 int vtno; 271 #endif 272 char *s; 273 274 s = getenv("CONSOLE"); 275 if (!s) 276 s = getenv("console"); 277 if (s) { 278 int fd = open(s, O_RDWR | O_NONBLOCK | O_NOCTTY); 279 if (fd >= 0) { 280 dup2(fd, STDIN_FILENO); 281 dup2(fd, STDOUT_FILENO); 282 xmove_fd(fd, STDERR_FILENO); 283 } 284 dbg_message(L_LOG, "console='%s'", s); 285 } else { 286 /* Make sure fd 0,1,2 are not closed 287 * (so that they won't be used by future opens) */ 288 bb_sanitize_stdio(); 289 // Users report problems 290 // /* Make sure init can't be blocked by writing to stderr */ 291 // fcntl(STDERR_FILENO, F_SETFL, fcntl(STDERR_FILENO, F_GETFL) | O_NONBLOCK); 292 } 293 294 s = getenv("TERM"); 295 #ifdef VT_OPENQRY 296 if (ioctl(STDIN_FILENO, VT_OPENQRY, &vtno) != 0) { 297 /* Not a linux terminal, probably serial console. 298 * Force the TERM setting to vt102 299 * if TERM is set to linux (the default) */ 300 if (!s || strcmp(s, "linux") == 0) 301 putenv((char*)"TERM=vt102"); 302 if (!ENABLE_FEATURE_INIT_SYSLOG) 303 log_console = NULL; 304 } else 305 #endif 306 if (!s) 307 putenv((char*)"TERM=" CONFIG_INIT_TERMINAL_TYPE); 308 } 309 310 /* Set terminal settings to reasonable defaults. 311 * NB: careful, we can be called after vfork! */ 200 312 static void set_sane_term(void) 201 313 { … … 214 326 tty.c_cc[VSUSP] = 26; /* C-z */ 215 327 216 /* use line dicipline 0 */ 328 #ifdef __linux__ 329 /* use line discipline 0 */ 217 330 tty.c_line = 0; 331 #endif 218 332 219 333 /* Make it be sane */ 220 tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD; 334 #ifndef CRTSCTS 335 # define CRTSCTS 0 336 #endif 337 /* added CRTSCTS to fix Debian bug 528560 */ 338 tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD | CRTSCTS; 221 339 tty.c_cflag |= CREAD | HUPCL | CLOCAL; 222 340 … … 228 346 229 347 /* local modes */ 230 tty.c_lflag = 231 ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; 232 233 tcsetattr(STDIN_FILENO, TCSANOW, &tty); 234 } 235 236 /* From <linux/serial.h> */ 237 struct serial_struct { 238 int type; 239 int line; 240 unsigned int port; 241 int irq; 242 int flags; 243 int xmit_fifo_size; 244 int custom_divisor; 245 int baud_base; 246 unsigned short close_delay; 247 char io_type; 248 char reserved_char[1]; 249 int hub6; 250 unsigned short closing_wait; /* time to wait before closing */ 251 unsigned short closing_wait2; /* no longer used... */ 252 unsigned char *iomem_base; 253 unsigned short iomem_reg_shift; 254 unsigned int port_high; 255 unsigned long iomap_base; /* cookie passed into ioremap */ 256 int reserved[1]; 257 /* Paranoia (imagine 64bit kernel overwriting 32bit userspace stack) */ 258 uint32_t bbox_reserved[16]; 259 }; 260 static void console_init(void) 261 { 262 struct serial_struct sr; 263 char *s; 264 265 s = getenv("CONSOLE"); 266 if (!s) s = getenv("console"); 267 if (s) { 268 int fd = open(s, O_RDWR | O_NONBLOCK | O_NOCTTY); 269 if (fd >= 0) { 270 dup2(fd, 0); 271 dup2(fd, 1); 272 dup2(fd, 2); 273 while (fd > 2) close(fd--); 274 } 275 messageD(L_LOG, "console='%s'", s); 276 } else { 277 /* Make sure fd 0,1,2 are not closed */ 278 bb_sanitize_stdio(); 279 } 280 281 s = getenv("TERM"); 282 if (ioctl(0, TIOCGSERIAL, &sr) == 0) { 283 /* Force the TERM setting to vt102 for serial console -- 284 * if TERM is set to linux (the default) */ 285 if (!s || strcmp(s, "linux") == 0) 286 putenv((char*)"TERM=vt102"); 287 #if !ENABLE_FEATURE_INIT_SYSLOG 288 log_console = NULL; 289 #endif 290 } else if (!s) 291 putenv((char*)"TERM=linux"); 292 } 293 294 static void fixup_argv(char **argv) 295 { 296 /* Fix up argv[0] to be certain we claim to be init */ 297 strncpy(argv[0], "init", strlen(argv[0])); 298 299 /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ 300 while (*++argv) 301 memset(*argv, 0, strlen(*argv)); 302 } 303 304 /* Open the new terminal device */ 305 static void open_stdio_to_tty(const char* tty_name, int fail) 348 tty.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; 349 350 tcsetattr_stdin_TCSANOW(&tty); 351 } 352 353 /* Open the new terminal device. 354 * NB: careful, we can be called after vfork! */ 355 static int open_stdio_to_tty(const char* tty_name) 306 356 { 307 357 /* empty tty_name means "use init's tty", else... */ 308 358 if (tty_name[0]) { 309 int fd = device_open(tty_name, O_RDWR); 310 if (fd < 0) { 311 message(L_LOG | L_CONSOLE, "Can't open %s: %s", 359 int fd; 360 361 close(STDIN_FILENO); 362 /* fd can be only < 0 or 0: */ 363 fd = device_open(tty_name, O_RDWR); 364 if (fd) { 365 message(L_LOG | L_CONSOLE, "can't open %s: %s", 312 366 tty_name, strerror(errno)); 313 if (fail) 314 _exit(1); 315 #if !ENABLE_DEBUG_INIT 316 shutdown_signal(SIGUSR1); 317 #else 318 _exit(2); 319 #endif 320 } else { 321 dup2(fd, 0); 322 dup2(fd, 1); 323 dup2(fd, 2); 324 if (fd > 2) close(fd); 325 } 367 return 0; /* failure */ 368 } 369 dup2(STDIN_FILENO, STDOUT_FILENO); 370 dup2(STDIN_FILENO, STDERR_FILENO); 326 371 } 327 372 set_sane_term(); 328 } 329 330 static pid_t run(const struct init_action *a) 331 { 332 int i; 333 pid_t pid; 334 char *s, *tmpCmd, *cmdpath; 335 char *cmd[INIT_BUFFS_SIZE]; 336 char buf[INIT_BUFFS_SIZE + 6]; /* INIT_BUFFS_SIZE+strlen("exec ")+1 */ 337 sigset_t nmask, omask; 338 339 /* Block sigchild while forking. */ 340 sigemptyset(&nmask); 341 sigaddset(&nmask, SIGCHLD); 342 sigprocmask(SIG_BLOCK, &nmask, &omask); 343 pid = fork(); 344 sigprocmask(SIG_SETMASK, &omask, NULL); 345 346 if (pid) 347 return pid; 348 349 /* Reset signal handlers that were set by the parent process */ 350 signal(SIGUSR1, SIG_DFL); 351 signal(SIGUSR2, SIG_DFL); 352 signal(SIGINT, SIG_DFL); 353 signal(SIGTERM, SIG_DFL); 354 signal(SIGHUP, SIG_DFL); 355 signal(SIGQUIT, SIG_DFL); 356 signal(SIGCONT, SIG_DFL); 357 signal(SIGSTOP, SIG_DFL); 358 signal(SIGTSTP, SIG_DFL); 359 360 /* Create a new session and make ourself the process 361 * group leader */ 362 setsid(); 363 364 /* Open the new terminal device */ 365 open_stdio_to_tty(a->terminal, 1); 366 367 /* If the init Action requires us to wait, then force the 368 * supplied terminal to be the controlling tty. */ 369 if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) { 370 371 /* Now fork off another process to just hang around */ 372 if ((pid = fork()) < 0) { 373 message(L_LOG | L_CONSOLE, "Can't fork"); 374 _exit(1); 375 } 376 377 if (pid > 0) { 378 379 /* We are the parent -- wait till the child is done */ 380 signal(SIGINT, SIG_IGN); 381 signal(SIGTSTP, SIG_IGN); 382 signal(SIGQUIT, SIG_IGN); 383 signal(SIGCHLD, SIG_DFL); 384 385 waitfor(NULL, pid); 386 /* See if stealing the controlling tty back is necessary */ 387 if (tcgetpgrp(0) != getpid()) 388 _exit(0); 389 390 /* Use a temporary process to steal the controlling tty. */ 391 if ((pid = fork()) < 0) { 392 message(L_LOG | L_CONSOLE, "Can't fork"); 393 _exit(1); 394 } 395 if (pid == 0) { 396 setsid(); 397 ioctl(0, TIOCSCTTY, 1); 398 _exit(0); 399 } 400 waitfor(NULL, pid); 401 _exit(0); 402 } 403 404 /* Now fall though to actually execute things */ 405 } 373 return 1; /* success */ 374 } 375 376 static void reset_sighandlers_and_unblock_sigs(void) 377 { 378 bb_signals(0 379 + (1 << SIGUSR1) 380 + (1 << SIGUSR2) 381 + (1 << SIGTERM) 382 + (1 << SIGQUIT) 383 + (1 << SIGINT) 384 + (1 << SIGHUP) 385 + (1 << SIGTSTP) 386 + (1 << SIGSTOP) 387 , SIG_DFL); 388 sigprocmask_allsigs(SIG_UNBLOCK); 389 } 390 391 /* Wrapper around exec: 392 * Takes string (max COMMAND_SIZE chars). 393 * If chars like '>' detected, execs '[-]/bin/sh -c "exec ......."'. 394 * Otherwise splits words on whitespace, deals with leading dash, 395 * and uses plain exec(). 396 * NB: careful, we can be called after vfork! 397 */ 398 static void init_exec(const char *command) 399 { 400 char *cmd[COMMAND_SIZE / 2]; 401 char buf[COMMAND_SIZE + 6]; /* COMMAND_SIZE+strlen("exec ")+1 */ 402 int dash = (command[0] == '-' /* maybe? && command[1] == '/' */); 406 403 407 404 /* See if any special /bin/sh requiring characters are present */ 408 if (strpbrk(a->command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { 409 cmd[0] = (char*)DEFAULT_SHELL; 405 if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { 406 strcpy(buf, "exec "); 407 strcpy(buf + 5, command + dash); /* excluding "-" */ 408 /* NB: LIBBB_DEFAULT_LOGIN_SHELL define has leading dash */ 409 cmd[0] = (char*)(LIBBB_DEFAULT_LOGIN_SHELL + !dash); 410 410 cmd[1] = (char*)"-c"; 411 cmd[2] = strcat(strcpy(buf, "exec "), a->command);411 cmd[2] = buf; 412 412 cmd[3] = NULL; 413 413 } else { 414 414 /* Convert command (char*) into cmd (char**, one word per string) */ 415 strcpy(buf, a->command); 416 s = buf; 417 for (tmpCmd = buf, i = 0; (tmpCmd = strsep(&s, " \t")) != NULL;) { 418 if (*tmpCmd != '\0') { 419 cmd[i] = tmpCmd; 415 char *word, *next; 416 int i = 0; 417 next = strcpy(buf, command); /* including "-" */ 418 while ((word = strsep(&next, " \t")) != NULL) { 419 if (*word != '\0') { /* not two spaces/tabs together? */ 420 cmd[i] = word; 420 421 i++; 421 422 } … … 423 424 cmd[i] = NULL; 424 425 } 425 426 cmdpath = cmd[0]; 427 428 /* 429 * Interactive shells want to see a dash in argv[0]. This 430 * typically is handled by login, argv will be setup this 431 * way if a dash appears at the front of the command path 432 * (like "-/bin/sh"). 433 */ 434 if (*cmdpath == '-') { 435 /* skip over the dash */ 436 ++cmdpath; 437 438 /* find the last component in the command pathname */ 439 s = bb_get_last_path_component(cmdpath); 440 441 /* make a new argv[0] */ 442 if ((cmd[0] = malloc(strlen(s) + 2)) == NULL) { 443 message(L_LOG | L_CONSOLE, bb_msg_memory_exhausted); 444 cmd[0] = cmdpath; 445 } else { 446 cmd[0][0] = '-'; 447 strcpy(cmd[0] + 1, s); 448 } 449 #if ENABLE_FEATURE_INIT_SCTTY 450 /* Establish this process as session leader and 451 * (attempt) to make the tty (if any) a controlling tty. 452 */ 453 setsid(); 454 ioctl(0, TIOCSCTTY, 0 /*don't steal it*/); 455 #endif 456 } 457 458 #if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__) 459 if (a->action & ASKFIRST) { 426 /* If we saw leading "-", it is interactive shell. 427 * Try harder to give it a controlling tty. 428 * And skip "-" in actual exec call. */ 429 if (dash) { 430 /* _Attempt_ to make stdin a controlling tty. */ 431 if (ENABLE_FEATURE_INIT_SCTTY) 432 ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/); 433 } 434 BB_EXECVP(cmd[0] + dash, cmd); 435 message(L_LOG | L_CONSOLE, "can't run '%s': %s", cmd[0], strerror(errno)); 436 /* returns if execvp fails */ 437 } 438 439 /* Used only by run_actions */ 440 static pid_t run(const struct init_action *a) 441 { 442 pid_t pid; 443 444 /* Careful: don't be affected by a signal in vforked child */ 445 sigprocmask_allsigs(SIG_BLOCK); 446 if (BB_MMU && (a->action_type & ASKFIRST)) 447 pid = fork(); 448 else 449 pid = vfork(); 450 if (pid < 0) 451 message(L_LOG | L_CONSOLE, "can't fork"); 452 if (pid) { 453 sigprocmask_allsigs(SIG_UNBLOCK); 454 return pid; /* Parent or error */ 455 } 456 457 /* Child */ 458 459 /* Reset signal handlers that were set by the parent process */ 460 reset_sighandlers_and_unblock_sigs(); 461 462 /* Create a new session and make ourself the process group leader */ 463 setsid(); 464 465 /* Open the new terminal device */ 466 if (!open_stdio_to_tty(a->terminal)) 467 _exit(EXIT_FAILURE); 468 469 /* NB: on NOMMU we can't wait for input in child, so 470 * "askfirst" will work the same as "respawn". */ 471 if (BB_MMU && (a->action_type & ASKFIRST)) { 460 472 static const char press_enter[] ALIGN1 = 461 473 #ifdef CUSTOMIZED_BANNER … … 472 484 * specifies. 473 485 */ 474 messageD(L_LOG, "waiting for enter to start '%s'"486 dbg_message(L_LOG, "waiting for enter to start '%s'" 475 487 "(pid %d, tty '%s')\n", 476 cmdpath, getpid(), a->terminal);477 full_write( 1, press_enter, sizeof(press_enter) - 1);478 while ( read(0, &c, 1) == 1 && c != '\n')479 ;480 } 481 #endif 482 /* Log the process name and args */483 message(L_LOG, "starting pid %d, tty '%s': '%s'",484 getpid(), a->terminal, cmdpath);485 486 #if ENABLE_FEATURE_INIT_COREDUMPS 487 {488 struct stat sb;489 if ( stat(CORE_ENABLE_FLAG_FILE, &sb) == 0) {488 a->command, getpid(), a->terminal); 489 full_write(STDOUT_FILENO, press_enter, sizeof(press_enter) - 1); 490 while (safe_read(STDIN_FILENO, &c, 1) == 1 && c != '\n') 491 continue; 492 } 493 494 /* 495 * When a file named /.init_enable_core exists, setrlimit is called 496 * before processes are spawned to set core file size as unlimited. 497 * This is for debugging only. Don't use this is production, unless 498 * you want core dumps lying about.... 499 */ 500 if (ENABLE_FEATURE_INIT_COREDUMPS) { 501 if (access("/.init_enable_core", F_OK) == 0) { 490 502 struct rlimit limit; 491 492 503 limit.rlim_cur = RLIM_INFINITY; 493 504 limit.rlim_max = RLIM_INFINITY; … … 495 506 } 496 507 } 497 #endif 508 509 /* Log the process name and args */ 510 message(L_LOG, "starting pid %d, tty '%s': '%s'", 511 getpid(), a->terminal, a->command); 512 498 513 /* Now run it. The new program will take over this PID, 499 514 * so nothing further in init.c should be run. */ 500 BB_EXECVP(cmdpath, cmd); 501 515 init_exec(a->command); 502 516 /* We're still here? Some error happened. */ 503 message(L_LOG | L_CONSOLE, "Cannot run '%s': %s",504 cmdpath, strerror(errno));505 517 _exit(-1); 506 518 } 507 519 508 static int waitfor(const struct init_action *a, pid_t pid) 509 { 510 int runpid; 511 int status, wpid; 512 513 runpid = (NULL == a)? pid : run(a); 520 static struct init_action *mark_terminated(pid_t pid) 521 { 522 struct init_action *a; 523 524 if (pid > 0) { 525 for (a = init_action_list; a; a = a->next) { 526 if (a->pid == pid) { 527 a->pid = 0; 528 return a; 529 } 530 } 531 update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, 532 /*username:*/ NULL, 533 /*hostname:*/ NULL); 534 } 535 return NULL; 536 } 537 538 static void waitfor(pid_t pid) 539 { 540 /* waitfor(run(x)): protect against failed fork inside run() */ 541 if (pid <= 0) 542 return; 543 544 /* Wait for any child (prevent zombies from exiting orphaned processes) 545 * but exit the loop only when specified one has exited. */ 514 546 while (1) { 515 wpid = waitpid(runpid, &status, 0); 516 if (wpid == runpid) 547 pid_t wpid = wait(NULL); 548 mark_terminated(wpid); 549 /* Unsafe. SIGTSTP handler might have wait'ed it already */ 550 /*if (wpid == pid) break;*/ 551 /* More reliable: */ 552 if (kill(pid, 0)) 517 553 break; 518 if (wpid == -1 && errno == ECHILD) { 519 /* we missed its termination */ 554 } 555 } 556 557 /* Run all commands of a particular type */ 558 static void run_actions(int action_type) 559 { 560 struct init_action *a; 561 562 for (a = init_action_list; a; a = a->next) { 563 if (!(a->action_type & action_type)) 564 continue; 565 566 if (a->action_type & (SYSINIT | WAIT | ONCE | CTRLALTDEL | SHUTDOWN)) { 567 pid_t pid = run(a); 568 if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN)) 569 waitfor(pid); 570 } 571 if (a->action_type & (RESPAWN | ASKFIRST)) { 572 /* Only run stuff with pid == 0. If pid != 0, 573 * it is already running 574 */ 575 if (a->pid == 0) 576 a->pid = run(a); 577 } 578 } 579 } 580 581 static void new_init_action(uint8_t action_type, const char *command, const char *cons) 582 { 583 struct init_action *a, **nextp; 584 585 /* Scenario: 586 * old inittab: 587 * ::shutdown:umount -a -r 588 * ::shutdown:swapoff -a 589 * new inittab: 590 * ::shutdown:swapoff -a 591 * ::shutdown:umount -a -r 592 * On reload, we must ensure entries end up in correct order. 593 * To achieve that, if we find a matching entry, we move it 594 * to the end. 595 */ 596 nextp = &init_action_list; 597 while ((a = *nextp) != NULL) { 598 /* Don't enter action if it's already in the list, 599 * This prevents losing running RESPAWNs. 600 */ 601 if (strcmp(a->command, command) == 0 602 && strcmp(a->terminal, cons) == 0 603 ) { 604 /* Remove from list */ 605 *nextp = a->next; 606 /* Find the end of the list */ 607 while (*nextp != NULL) 608 nextp = &(*nextp)->next; 609 a->next = NULL; 520 610 break; 521 611 } 522 /* FIXME other errors should maybe trigger an error, but allow 523 * the program to continue */ 524 } 525 return wpid; 526 } 527 528 /* Run all commands of a particular type */ 529 static void run_actions(int action) 530 { 531 struct init_action *a, *tmp; 532 533 for (a = init_action_list; a; a = tmp) { 534 tmp = a->next; 535 if (a->action == action) { 536 /* a->terminal of "" means "init's console" */ 537 if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) { 538 delete_init_action(a); 539 } else if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) { 540 waitfor(a, 0); 541 delete_init_action(a); 542 } else if (a->action & ONCE) { 543 run(a); 544 delete_init_action(a); 545 } else if (a->action & (RESPAWN | ASKFIRST)) { 546 /* Only run stuff with pid==0. If they have 547 * a pid, that means it is still running */ 548 if (a->pid == 0) { 549 a->pid = run(a); 550 } 551 } 552 } 553 } 554 } 555 556 #if !ENABLE_DEBUG_INIT 557 static void init_reboot(unsigned long magic) 612 nextp = &a->next; 613 } 614 615 if (!a) 616 a = xzalloc(sizeof(*a)); 617 /* Append to the end of the list */ 618 *nextp = a; 619 a->action_type = action_type; 620 safe_strncpy(a->command, command, sizeof(a->command)); 621 safe_strncpy(a->terminal, cons, sizeof(a->terminal)); 622 dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n", 623 a->command, a->action_type, a->terminal); 624 } 625 626 /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined, 627 * then parse_inittab() simply adds in some default 628 * actions(i.e., runs INIT_SCRIPT and then starts a pair 629 * of "askfirst" shells). If CONFIG_FEATURE_USE_INITTAB 630 * _is_ defined, but /etc/inittab is missing, this 631 * results in the same set of default behaviors. 632 */ 633 static void parse_inittab(void) 634 { 635 #if ENABLE_FEATURE_USE_INITTAB 636 char *token[4]; 637 parser_t *parser = config_open2("/etc/inittab", fopen_for_read); 638 639 if (parser == NULL) 640 #endif 641 { 642 /* No inittab file - set up some default behavior */ 643 /* Reboot on Ctrl-Alt-Del */ 644 new_init_action(CTRLALTDEL, "reboot", ""); 645 /* Umount all filesystems on halt/reboot */ 646 new_init_action(SHUTDOWN, "umount -a -r", ""); 647 /* Swapoff on halt/reboot */ 648 if (ENABLE_SWAPONOFF) 649 new_init_action(SHUTDOWN, "swapoff -a", ""); 650 /* Prepare to restart init when a QUIT is received */ 651 new_init_action(RESTART, "init", ""); 652 /* Askfirst shell on tty1-4 */ 653 new_init_action(ASKFIRST, bb_default_login_shell, ""); 654 //TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users 655 new_init_action(ASKFIRST, bb_default_login_shell, VC_2); 656 new_init_action(ASKFIRST, bb_default_login_shell, VC_3); 657 new_init_action(ASKFIRST, bb_default_login_shell, VC_4); 658 /* sysinit */ 659 new_init_action(SYSINIT, INIT_SCRIPT, ""); 660 return; 661 } 662 663 #if ENABLE_FEATURE_USE_INITTAB 664 /* optional_tty:ignored_runlevel:action:command 665 * Delims are not to be collapsed and need exactly 4 tokens 666 */ 667 while (config_read(parser, token, 4, 0, "#:", 668 PARSE_NORMAL & ~(PARSE_TRIM | PARSE_COLLAPSE))) { 669 /* order must correspond to SYSINIT..RESTART constants */ 670 static const char actions[] ALIGN1 = 671 "sysinit\0""wait\0""once\0""respawn\0""askfirst\0" 672 "ctrlaltdel\0""shutdown\0""restart\0"; 673 int action; 674 char *tty = token[0]; 675 676 if (!token[3]) /* less than 4 tokens */ 677 goto bad_entry; 678 action = index_in_strings(actions, token[2]); 679 if (action < 0 || !token[3][0]) /* token[3]: command */ 680 goto bad_entry; 681 /* turn .*TTY -> /dev/TTY */ 682 if (tty[0]) { 683 tty = concat_path_file("/dev/", skip_dev_pfx(tty)); 684 } 685 new_init_action(1 << action, token[3], tty); 686 if (tty[0]) 687 free(tty); 688 continue; 689 bad_entry: 690 message(L_LOG | L_CONSOLE, "Bad inittab entry at line %d", 691 parser->lineno); 692 } 693 config_close(parser); 694 #endif 695 } 696 697 static void pause_and_low_level_reboot(unsigned magic) NORETURN; 698 static void pause_and_low_level_reboot(unsigned magic) 558 699 { 559 700 pid_t pid; 560 /* We have to fork here, since the kernel calls do_exit(0) in 561 * linux/kernel/sys.c, which can cause the machine to panic when 562 * the init process is killed.... */ 701 702 /* Allow time for last message to reach serial console, etc */ 703 sleep(1); 704 705 /* We have to fork here, since the kernel calls do_exit(EXIT_SUCCESS) 706 * in linux/kernel/sys.c, which can cause the machine to panic when 707 * the init process exits... */ 563 708 pid = vfork(); 564 709 if (pid == 0) { /* child */ 565 710 reboot(magic); 566 _exit(0); 567 } 568 waitpid(pid, NULL, 0); 569 } 570 571 static void shutdown_system(void) 572 { 573 sigset_t block_signals; 574 575 /* run everything to be run at "shutdown". This is done _prior_ 711 _exit(EXIT_SUCCESS); 712 } 713 while (1) 714 sleep(1); 715 } 716 717 static void run_shutdown_and_kill_processes(void) 718 { 719 /* Run everything to be run at "shutdown". This is done _prior_ 576 720 * to killing everything, in case people wish to use scripts to 577 721 * shut things down gracefully... */ 578 722 run_actions(SHUTDOWN); 579 723 580 /* first disable all our signals */581 sigemptyset(&block_signals);582 sigaddset(&block_signals, SIGHUP);583 sigaddset(&block_signals, SIGQUIT);584 sigaddset(&block_signals, SIGCHLD);585 sigaddset(&block_signals, SIGUSR1);586 sigaddset(&block_signals, SIGUSR2);587 sigaddset(&block_signals, SIGINT);588 sigaddset(&block_signals, SIGTERM);589 sigaddset(&block_signals, SIGCONT);590 sigaddset(&block_signals, SIGSTOP);591 sigaddset(&block_signals, SIGTSTP);592 sigprocmask(SIG_BLOCK, &block_signals, NULL);593 594 724 message(L_CONSOLE | L_LOG, "The system is going down NOW!"); 595 725 596 /* Allow Ctrl-Alt-Del to reboot system. */597 init_reboot(RB_ENABLE_CAD);598 599 726 /* Send signals to every process _except_ pid 1 */ 600 message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "TERM");601 727 kill(-1, SIGTERM); 728 message(L_CONSOLE | L_LOG, "Sent SIG%s to all processes", "TERM"); 602 729 sync(); 603 730 sleep(1); 604 731 605 message(L_CONSOLE | L_LOG, "Sending SIG%s to all processes", "KILL");606 732 kill(-1, SIGKILL); 733 message(L_CONSOLE, "Sent SIG%s to all processes", "KILL"); 607 734 sync(); 608 sleep(1); 609 } 610 611 static void exec_signal(int sig ATTRIBUTE_UNUSED) 612 { 613 struct init_action *a, *tmp; 614 sigset_t unblock_signals; 615 616 for (a = init_action_list; a; a = tmp) { 617 tmp = a->next; 618 if (a->action & RESTART) { 619 shutdown_system(); 620 621 /* unblock all signals, blocked in shutdown_system() */ 622 sigemptyset(&unblock_signals); 623 sigaddset(&unblock_signals, SIGHUP); 624 sigaddset(&unblock_signals, SIGQUIT); 625 sigaddset(&unblock_signals, SIGCHLD); 626 sigaddset(&unblock_signals, SIGUSR1); 627 sigaddset(&unblock_signals, SIGUSR2); 628 sigaddset(&unblock_signals, SIGINT); 629 sigaddset(&unblock_signals, SIGTERM); 630 sigaddset(&unblock_signals, SIGCONT); 631 sigaddset(&unblock_signals, SIGSTOP); 632 sigaddset(&unblock_signals, SIGTSTP); 633 sigprocmask(SIG_UNBLOCK, &unblock_signals, NULL); 634 635 /* Open the new terminal device */ 636 open_stdio_to_tty(a->terminal, 0); 637 638 messageD(L_CONSOLE | L_LOG, "Trying to re-exec %s", a->command); 639 BB_EXECLP(a->command, a->command, NULL); 640 641 message(L_CONSOLE | L_LOG, "Cannot run '%s': %s", 642 a->command, strerror(errno)); 643 sleep(2); 644 init_reboot(RB_HALT_SYSTEM); 645 loop_forever(); 646 } 647 } 648 } 649 650 static void shutdown_signal(int sig) 735 /*sleep(1); - callers take care about making a pause */ 736 } 737 738 /* Signal handling by init: 739 * 740 * For process with PID==1, on entry kernel sets all signals to SIG_DFL 741 * and unmasks all signals. However, for process with PID==1, 742 * default action (SIG_DFL) on any signal is to ignore it, 743 * even for special signals SIGKILL and SIGCONT. 744 * Also, any signal can be caught or blocked. 745 * (but SIGSTOP is still handled specially, at least in 2.6.20) 746 * 747 * We install two kinds of handlers, "immediate" and "delayed". 748 * 749 * Immediate handlers execute at any time, even while, say, sysinit 750 * is running. 751 * 752 * Delayed handlers just set a flag variable. The variable is checked 753 * in the main loop and acted upon. 754 * 755 * halt/poweroff/reboot and restart have immediate handlers. 756 * They only traverse linked list of struct action's, never modify it, 757 * this should be safe to do even in signal handler. Also they 758 * never return. 759 * 760 * SIGSTOP and SIGTSTP have immediate handlers. They just wait 761 * for SIGCONT to happen. 762 * 763 * SIGHUP has a delayed handler, because modifying linked list 764 * of struct action's from a signal handler while it is manipulated 765 * by the program may be disastrous. 766 * 767 * Ctrl-Alt-Del has a delayed handler. Not a must, but allowing 768 * it to happen even somewhere inside "sysinit" would be a bit awkward. 769 * 770 * There is a tiny probability that SIGHUP and Ctrl-Alt-Del will collide 771 * and only one will be remembered and acted upon. 772 */ 773 774 /* The SIGUSR[12]/SIGTERM handler */ 775 static void halt_reboot_pwoff(int sig) NORETURN; 776 static void halt_reboot_pwoff(int sig) 651 777 { 652 778 const char *m; 653 int rb; 654 655 shutdown_system(); 779 unsigned rb; 780 781 /* We may call run() and it unmasks signals, 782 * including the one masked inside this signal handler. 783 * Testcase which would start multiple reboot scripts: 784 * while true; do reboot; done 785 * Preventing it: 786 */ 787 reset_sighandlers_and_unblock_sigs(); 788 789 run_shutdown_and_kill_processes(); 656 790 657 791 m = "halt"; … … 664 798 rb = RB_POWER_OFF; 665 799 } 666 message(L_CONSOLE | L_LOG, "Requesting system %s", m); 667 /* allow time for last message to reach serial console */ 668 sleep(2); 669 init_reboot(rb); 670 loop_forever(); 671 } 672 673 static void ctrlaltdel_signal(int sig ATTRIBUTE_UNUSED) 674 { 675 run_actions(CTRLALTDEL); 676 } 677 678 /* The SIGSTOP & SIGTSTP handler */ 679 static void stop_handler(int sig ATTRIBUTE_UNUSED) 680 { 681 int saved_errno = errno; 682 683 got_cont = 0; 684 while (!got_cont) 685 pause(); 686 got_cont = 0; 800 message(L_CONSOLE, "Requesting system %s", m); 801 pause_and_low_level_reboot(rb); 802 /* not reached */ 803 } 804 805 /* Handler for QUIT - exec "restart" action, 806 * else (no such action defined) do nothing */ 807 static void restart_handler(int sig UNUSED_PARAM) 808 { 809 struct init_action *a; 810 811 for (a = init_action_list; a; a = a->next) { 812 if (!(a->action_type & RESTART)) 813 continue; 814 815 /* Starting from here, we won't return. 816 * Thus don't need to worry about preserving errno 817 * and such. 818 */ 819 820 reset_sighandlers_and_unblock_sigs(); 821 822 run_shutdown_and_kill_processes(); 823 824 #ifdef RB_ENABLE_CAD 825 /* Allow Ctrl-Alt-Del to reboot the system. 826 * This is how kernel sets it up for init, we follow suit. 827 */ 828 reboot(RB_ENABLE_CAD); /* misnomer */ 829 #endif 830 831 if (open_stdio_to_tty(a->terminal)) { 832 dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command); 833 /* Theoretically should be safe. 834 * But in practice, kernel bugs may leave 835 * unkillable processes, and wait() may block forever. 836 * Oh well. Hoping "new" init won't be too surprised 837 * by having children it didn't create. 838 */ 839 //while (wait(NULL) > 0) 840 // continue; 841 init_exec(a->command); 842 } 843 /* Open or exec failed */ 844 pause_and_low_level_reboot(RB_HALT_SYSTEM); 845 /* not reached */ 846 } 847 } 848 849 /* The SIGSTOP/SIGTSTP handler 850 * NB: inside it, all signals except SIGCONT are masked 851 * via appropriate setup in sigaction(). 852 */ 853 static void stop_handler(int sig UNUSED_PARAM) 854 { 855 smallint saved_bb_got_signal; 856 int saved_errno; 857 858 saved_bb_got_signal = bb_got_signal; 859 saved_errno = errno; 860 signal(SIGCONT, record_signo); 861 862 while (1) { 863 pid_t wpid; 864 865 if (bb_got_signal == SIGCONT) 866 break; 867 /* NB: this can accidentally wait() for a process 868 * which we waitfor() elsewhere! waitfor() must have 869 * code which is resilient against this. 870 */ 871 wpid = wait_any_nohang(NULL); 872 mark_terminated(wpid); 873 sleep(1); 874 } 875 876 signal(SIGCONT, SIG_DFL); 687 877 errno = saved_errno; 688 } 689 690 /* The SIGCONT handler */ 691 static void cont_handler(int sig ATTRIBUTE_UNUSED) 692 { 693 got_cont = 1; 694 } 695 696 #endif /* !ENABLE_DEBUG_INIT */ 697 698 static void new_init_action(int action, const char *command, const char *cons) 699 { 700 struct init_action *new_action, *a, *last; 701 702 if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST)) 703 return; 704 705 /* Append to the end of the list */ 706 for (a = last = init_action_list; a; a = a->next) { 707 /* don't enter action if it's already in the list, 708 * but do overwrite existing actions */ 709 if ((strcmp(a->command, command) == 0) 710 && (strcmp(a->terminal, cons) == 0) 878 bb_got_signal = saved_bb_got_signal; 879 } 880 881 #if ENABLE_FEATURE_USE_INITTAB 882 static void reload_inittab(void) 883 { 884 struct init_action *a, **nextp; 885 886 message(L_LOG, "reloading /etc/inittab"); 887 888 /* Disable old entries */ 889 for (a = init_action_list; a; a = a->next) 890 a->action_type = 0; 891 892 /* Append new entries, or modify existing entries 893 * (incl. setting a->action_type) if cmd and device name 894 * match new ones. End result: only entries with 895 * a->action_type == 0 are stale. 896 */ 897 parse_inittab(); 898 899 #if ENABLE_FEATURE_KILL_REMOVED 900 /* Kill stale entries */ 901 /* Be nice and send SIGTERM first */ 902 for (a = init_action_list; a; a = a->next) 903 if (a->action_type == 0 && a->pid != 0) 904 kill(a->pid, SIGTERM); 905 if (CONFIG_FEATURE_KILL_DELAY) { 906 /* NB: parent will wait in NOMMU case */ 907 if ((BB_MMU ? fork() : vfork()) == 0) { /* child */ 908 sleep(CONFIG_FEATURE_KILL_DELAY); 909 for (a = init_action_list; a; a = a->next) 910 if (a->action_type == 0 && a->pid != 0) 911 kill(a->pid, SIGKILL); 912 _exit(EXIT_SUCCESS); 913 } 914 } 915 #endif 916 917 /* Remove stale entries and SYSINIT entries. 918 * We never rerun SYSINIT entries anyway, 919 * removing them too saves a few bytes */ 920 nextp = &init_action_list; 921 while ((a = *nextp) != NULL) { 922 if ((a->action_type & ~SYSINIT) == 0) { 923 *nextp = a->next; 924 free(a); 925 } else { 926 nextp = &a->next; 927 } 928 } 929 930 /* Not needed: */ 931 /* run_actions(RESPAWN | ASKFIRST); */ 932 /* - we return to main loop, which does this automagically */ 933 } 934 #endif 935 936 static int check_delayed_sigs(void) 937 { 938 int sigs_seen = 0; 939 940 while (1) { 941 smallint sig = bb_got_signal; 942 943 if (!sig) 944 return sigs_seen; 945 bb_got_signal = 0; 946 sigs_seen = 1; 947 #if ENABLE_FEATURE_USE_INITTAB 948 if (sig == SIGHUP) 949 reload_inittab(); 950 #endif 951 if (sig == SIGINT) 952 run_actions(CTRLALTDEL); 953 } 954 } 955 956 int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 957 int init_main(int argc UNUSED_PARAM, char **argv) 958 { 959 if (argv[1] && strcmp(argv[1], "-q") == 0) { 960 return kill(1, SIGHUP); 961 } 962 963 if (!DEBUG_INIT) { 964 /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ 965 if (getpid() != 1 966 && (!ENABLE_FEATURE_INITRD || applet_name[0] != 'l') /* not linuxrc? */ 711 967 ) { 712 a->action = action; 713 return; 714 } 715 last = a; 716 } 717 718 new_action = xzalloc(sizeof(struct init_action)); 719 if (last) { 720 last->next = new_action; 721 } else { 722 init_action_list = new_action; 723 } 724 strcpy(new_action->command, command); 725 new_action->action = action; 726 strcpy(new_action->terminal, cons); 727 messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n", 728 new_action->command, new_action->action, new_action->terminal); 729 } 730 731 static void delete_init_action(struct init_action *action) 732 { 733 struct init_action *a, *b = NULL; 734 735 for (a = init_action_list; a; b = a, a = a->next) { 736 if (a == action) { 737 if (b == NULL) { 738 init_action_list = a->next; 739 } else { 740 b->next = a->next; 741 } 742 free(a); 743 break; 744 } 745 } 746 } 747 748 /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined, 749 * then parse_inittab() simply adds in some default 750 * actions(i.e., runs INIT_SCRIPT and then starts a pair 751 * of "askfirst" shells). If CONFIG_FEATURE_USE_INITTAB 752 * _is_ defined, but /etc/inittab is missing, this 753 * results in the same set of default behaviors. 754 */ 755 static void parse_inittab(void) 756 { 757 #if ENABLE_FEATURE_USE_INITTAB 758 FILE *file; 759 char buf[INIT_BUFFS_SIZE], lineAsRead[INIT_BUFFS_SIZE]; 760 char tmpConsole[CONSOLE_NAME_SIZE]; 761 char *id, *runlev, *action, *command, *eol; 762 const struct init_action_type *a = actions; 763 764 file = fopen(INITTAB, "r"); 765 if (file == NULL) { 766 /* No inittab file -- set up some default behavior */ 767 #endif 768 /* Reboot on Ctrl-Alt-Del */ 769 new_init_action(CTRLALTDEL, "reboot", ""); 770 /* Umount all filesystems on halt/reboot */ 771 new_init_action(SHUTDOWN, "umount -a -r", ""); 772 /* Swapoff on halt/reboot */ 773 if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a", ""); 774 /* Prepare to restart init when a HUP is received */ 775 new_init_action(RESTART, "init", ""); 776 /* Askfirst shell on tty1-4 */ 777 new_init_action(ASKFIRST, bb_default_login_shell, ""); 778 new_init_action(ASKFIRST, bb_default_login_shell, VC_2); 779 new_init_action(ASKFIRST, bb_default_login_shell, VC_3); 780 new_init_action(ASKFIRST, bb_default_login_shell, VC_4); 781 /* sysinit */ 782 new_init_action(SYSINIT, INIT_SCRIPT, ""); 783 784 return; 785 #if ENABLE_FEATURE_USE_INITTAB 786 } 787 788 while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) { 789 /* Skip leading spaces */ 790 for (id = buf; *id == ' ' || *id == '\t'; id++); 791 792 /* Skip the line if it's a comment */ 793 if (*id == '#' || *id == '\n') 794 continue; 795 796 /* Trim the trailing \n */ 797 //XXX: chomp() ? 798 eol = strrchr(id, '\n'); 799 if (eol != NULL) 800 *eol = '\0'; 801 802 /* Keep a copy around for posterity's sake (and error msgs) */ 803 strcpy(lineAsRead, buf); 804 805 /* Separate the ID field from the runlevels */ 806 runlev = strchr(id, ':'); 807 if (runlev == NULL || *(runlev + 1) == '\0') { 808 message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead); 809 continue; 810 } else { 811 *runlev = '\0'; 812 ++runlev; 813 } 814 815 /* Separate the runlevels from the action */ 816 action = strchr(runlev, ':'); 817 if (action == NULL || *(action + 1) == '\0') { 818 message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead); 819 continue; 820 } else { 821 *action = '\0'; 822 ++action; 823 } 824 825 /* Separate the action from the command */ 826 command = strchr(action, ':'); 827 if (command == NULL || *(command + 1) == '\0') { 828 message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead); 829 continue; 830 } else { 831 *command = '\0'; 832 ++command; 833 } 834 835 /* Ok, now process it */ 836 for (a = actions; a->name != 0; a++) { 837 if (strcmp(a->name, action) == 0) { 838 if (*id != '\0') { 839 if (strncmp(id, "/dev/", 5) == 0) 840 id += 5; 841 strcpy(tmpConsole, "/dev/"); 842 safe_strncpy(tmpConsole + 5, id, 843 sizeof(tmpConsole) - 5); 844 id = tmpConsole; 845 } 846 new_init_action(a->action, command, id); 847 break; 848 } 849 } 850 if (a->name == 0) { 851 /* Choke on an unknown action */ 852 message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead); 853 } 854 } 855 fclose(file); 856 #endif /* FEATURE_USE_INITTAB */ 857 } 858 859 #if ENABLE_FEATURE_USE_INITTAB 860 static void reload_signal(int sig ATTRIBUTE_UNUSED) 861 { 862 struct init_action *a, *tmp; 863 864 message(L_LOG, "reloading /etc/inittab"); 865 866 /* disable old entrys */ 867 for (a = init_action_list; a; a = a->next ) { 868 a->action = ONCE; 869 } 870 871 parse_inittab(); 872 873 /* remove unused entrys */ 874 for (a = init_action_list; a; a = tmp) { 875 tmp = a->next; 876 if ((a->action & (ONCE | SYSINIT | WAIT)) && a->pid == 0) { 877 delete_init_action(a); 878 } 879 } 880 run_actions(RESPAWN); 881 } 882 #endif /* FEATURE_USE_INITTAB */ 883 884 int init_main(int argc, char **argv); 885 int init_main(int argc, char **argv) 886 { 887 struct init_action *a; 888 pid_t wpid; 889 890 die_sleep = 30 * 24*60*60; /* if xmalloc will ever die... */ 891 892 if (argc > 1 && !strcmp(argv[1], "-q")) { 893 return kill(1, SIGHUP); 894 } 895 #if !ENABLE_DEBUG_INIT 896 /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ 897 if (getpid() != 1 898 && (!ENABLE_FEATURE_INITRD || !strstr(applet_name, "linuxrc")) 899 ) { 900 bb_show_usage(); 901 } 902 /* Set up sig handlers -- be sure to 903 * clear all of these in run() */ 904 signal(SIGHUP, exec_signal); 905 signal(SIGQUIT, exec_signal); 906 signal(SIGUSR1, shutdown_signal); 907 signal(SIGUSR2, shutdown_signal); 908 signal(SIGINT, ctrlaltdel_signal); 909 signal(SIGTERM, shutdown_signal); 910 signal(SIGCONT, cont_handler); 911 signal(SIGSTOP, stop_handler); 912 signal(SIGTSTP, stop_handler); 913 914 /* Turn off rebooting via CTL-ALT-DEL -- we get a 915 * SIGINT on CAD so we can shut things down gracefully... */ 916 init_reboot(RB_DISABLE_CAD); 917 #endif 918 968 bb_error_msg_and_die("must be run as PID 1"); 969 } 970 #ifdef RB_DISABLE_CAD 971 /* Turn off rebooting via CTL-ALT-DEL - we get a 972 * SIGINT on CAD so we can shut things down gracefully... */ 973 reboot(RB_DISABLE_CAD); /* misnomer */ 974 #endif 975 } 976 977 /* If, say, xmalloc would ever die, we don't want to oops kernel 978 * by exiting. 979 * NB: we set die_sleep *after* PID 1 check and bb_show_usage. 980 * Otherwise, for example, "init u" ("please rexec yourself" 981 * command for sysvinit) will show help text (which isn't too bad), 982 * *and sleep forever* (which is bad!) 983 */ 984 die_sleep = 30 * 24*60*60; 919 985 920 986 /* Figure out where the default console should be */ 921 987 console_init(); 922 988 set_sane_term(); 923 chdir("/");989 xchdir("/"); 924 990 setsid(); 925 { 926 const char *const *e; 927 /* Make sure environs is set to something sane */ 928 for (e = environment; *e; e++) 929 putenv((char *) *e); 930 } 931 932 if (argc > 1) setenv("RUNLEVEL", argv[1], 1); 933 991 992 /* Make sure environs is set to something sane */ 993 putenv((char *) "HOME=/"); 994 putenv((char *) bb_PATH_root_path); 995 putenv((char *) "SHELL=/bin/sh"); 996 putenv((char *) "USER=root"); /* needed? why? */ 997 998 if (argv[1]) 999 xsetenv("RUNLEVEL", argv[1]); 1000 1001 #if !ENABLE_FEATURE_EXTRA_QUIET 934 1002 /* Hello world */ 935 message(MAYBE_CONSOLE | L_LOG, "init started: %s", bb_banner); 936 1003 message(L_CONSOLE | L_LOG, "init started: %s", bb_banner); 1004 #endif 1005 1006 /* struct sysinfo is linux-specific */ 1007 #ifdef __linux__ 937 1008 /* Make sure there is enough memory to do something useful. */ 938 1009 if (ENABLE_SWAPONOFF) { 939 1010 struct sysinfo info; 940 1011 941 if ( !sysinfo(&info) &&942 (info.mem_unit ? : 1) * (long long)info.totalram < 1024*1024)943 {1012 if (sysinfo(&info) == 0 1013 && (info.mem_unit ? info.mem_unit : 1) * (long long)info.totalram < 1024*1024 1014 ) { 944 1015 message(L_CONSOLE, "Low memory, forcing swapon"); 945 1016 /* swapon -a requires /proc typically */ … … 950 1021 } 951 1022 } 1023 #endif 952 1024 953 1025 /* Check if we are supposed to be in single user mode */ 954 if (arg c > 1955 && ( !strcmp(argv[1], "single") || !strcmp(argv[1], "-s")|| LONE_CHAR(argv[1], '1'))1026 if (argv[1] 1027 && (strcmp(argv[1], "single") == 0 || strcmp(argv[1], "-s") == 0 || LONE_CHAR(argv[1], '1')) 956 1028 ) { 1029 /* ??? shouldn't we set RUNLEVEL="b" here? */ 957 1030 /* Start a shell on console */ 958 1031 new_init_action(RESPAWN, bb_default_login_shell, ""); 959 1032 } else { 960 /* Not in single user mode - -see what inittab says */1033 /* Not in single user mode - see what inittab says */ 961 1034 962 1035 /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined, 963 1036 * then parse_inittab() simply adds in some default 964 * actions(i.e., runs INIT_SCRIPT and then startsa pair1037 * actions(i.e., INIT_SCRIPT and a pair 965 1038 * of "askfirst" shells */ 966 1039 parse_inittab(); … … 976 1049 } else if (enforce > 0) { 977 1050 /* SELinux in enforcing mode but load_policy failed */ 978 /* At this point, we probably can't open /dev/console, so log() won't work */ 979 message(L_CONSOLE, "Cannot load SELinux Policy. " 1051 message(L_CONSOLE, "can't load SELinux Policy. " 980 1052 "Machine is in enforcing mode. Halting now."); 981 exit(1); 982 } 983 } 984 #endif /* CONFIG_SELINUX */ 985 986 /* Make the command line just say "init" -- thats all, nothing else */ 987 fixup_argv(argv); 1053 return EXIT_FAILURE; 1054 } 1055 } 1056 #endif 1057 1058 /* Make the command line just say "init" - thats all, nothing else */ 1059 strncpy(argv[0], "init", strlen(argv[0])); 1060 /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ 1061 while (*++argv) 1062 memset(*argv, 0, strlen(*argv)); 1063 1064 /* Set up signal handlers */ 1065 if (!DEBUG_INIT) { 1066 struct sigaction sa; 1067 1068 bb_signals(0 1069 + (1 << SIGUSR1) /* halt */ 1070 + (1 << SIGTERM) /* reboot */ 1071 + (1 << SIGUSR2) /* poweroff */ 1072 , halt_reboot_pwoff); 1073 signal(SIGQUIT, restart_handler); /* re-exec another init */ 1074 1075 /* Stop handler must allow only SIGCONT inside itself */ 1076 memset(&sa, 0, sizeof(sa)); 1077 sigfillset(&sa.sa_mask); 1078 sigdelset(&sa.sa_mask, SIGCONT); 1079 sa.sa_handler = stop_handler; 1080 /* NB: sa_flags doesn't have SA_RESTART. 1081 * It must be able to interrupt wait(). 1082 */ 1083 sigaction_set(SIGTSTP, &sa); /* pause */ 1084 /* Does not work as intended, at least in 2.6.20. 1085 * SIGSTOP is simply ignored by init: 1086 */ 1087 sigaction_set(SIGSTOP, &sa); /* pause */ 1088 1089 /* SIGINT (Ctrl-Alt-Del) must interrupt wait(), 1090 * setting handler without SA_RESTART flag. 1091 */ 1092 bb_signals_recursive_norestart((1 << SIGINT), record_signo); 1093 } 1094 1095 /* Set up "reread /etc/inittab" handler. 1096 * Handler is set up without SA_RESTART, it will interrupt syscalls. 1097 */ 1098 if (!DEBUG_INIT && ENABLE_FEATURE_USE_INITTAB) 1099 bb_signals_recursive_norestart((1 << SIGHUP), record_signo); 988 1100 989 1101 /* Now run everything that needs to be run */ 990 991 1102 /* First run the sysinit command */ 992 1103 run_actions(SYSINIT); 993 1104 check_delayed_sigs(); 994 1105 /* Next run anything that wants to block */ 995 1106 run_actions(WAIT); 996 1107 check_delayed_sigs(); 997 1108 /* Next run anything to be run only once */ 998 1109 run_actions(ONCE); 999 1110 1000 #if ENABLE_FEATURE_USE_INITTAB 1001 /* Redefine SIGHUP to reread /etc/inittab */ 1002 signal(SIGHUP, reload_signal); 1003 #else 1004 signal(SIGHUP, SIG_IGN); 1005 #endif /* FEATURE_USE_INITTAB */ 1006 1007 /* Now run the looping stuff for the rest of forever */ 1111 /* Now run the looping stuff for the rest of forever. 1112 */ 1008 1113 while (1) { 1009 /* run the respawn stuff */ 1010 run_actions(RESPAWN); 1011 1012 /* run the askfirst stuff */ 1013 run_actions(ASKFIRST); 1014 1015 /* Don't consume all CPU time -- sleep a bit */ 1114 int maybe_WNOHANG; 1115 1116 maybe_WNOHANG = check_delayed_sigs(); 1117 1118 /* (Re)run the respawn/askfirst stuff */ 1119 run_actions(RESPAWN | ASKFIRST); 1120 maybe_WNOHANG |= check_delayed_sigs(); 1121 1122 /* Don't consume all CPU time - sleep a bit */ 1016 1123 sleep(1); 1017 1018 /* Wait for a child process to exit */ 1019 wpid = wait(NULL); 1020 while (wpid > 0) { 1021 /* Find out who died and clean up their corpse */ 1022 for (a = init_action_list; a; a = a->next) { 1023 if (a->pid == wpid) { 1024 /* Set the pid to 0 so that the process gets 1025 * restarted by run_actions() */ 1026 a->pid = 0; 1027 message(L_LOG, "process '%s' (pid %d) exited. " 1028 "Scheduling it for restart.", 1029 a->command, wpid); 1030 } 1124 maybe_WNOHANG |= check_delayed_sigs(); 1125 1126 /* Wait for any child process(es) to exit. 1127 * 1128 * If check_delayed_sigs above reported that a signal 1129 * was caught, wait will be nonblocking. This ensures 1130 * that if SIGHUP has reloaded inittab, respawn and askfirst 1131 * actions will not be delayed until next child death. 1132 */ 1133 if (maybe_WNOHANG) 1134 maybe_WNOHANG = WNOHANG; 1135 while (1) { 1136 pid_t wpid; 1137 struct init_action *a; 1138 1139 /* If signals happen _in_ the wait, they interrupt it, 1140 * bb_signals_recursive_norestart set them up that way 1141 */ 1142 wpid = waitpid(-1, NULL, maybe_WNOHANG); 1143 if (wpid <= 0) 1144 break; 1145 1146 a = mark_terminated(wpid); 1147 if (a) { 1148 message(L_LOG, "process '%s' (pid %d) exited. " 1149 "Scheduling for restart.", 1150 a->command, wpid); 1031 1151 } 1032 /* see if anyone else is waiting to be reaped */ 1033 wpid = waitpid(-1, NULL, WNOHANG); 1034 } 1035 } 1036 } 1152 /* See if anyone else is waiting to be reaped */ 1153 maybe_WNOHANG = WNOHANG; 1154 } 1155 } /* while (1) */ 1156 } 1157 1158 //usage:#define linuxrc_trivial_usage NOUSAGE_STR 1159 //usage:#define linuxrc_full_usage "" 1160 1161 //usage:#define init_trivial_usage 1162 //usage: "" 1163 //usage:#define init_full_usage "\n\n" 1164 //usage: "Init is the parent of all processes" 1165 //usage: 1166 //usage:#define init_notes_usage 1167 //usage: "This version of init is designed to be run only by the kernel.\n" 1168 //usage: "\n" 1169 //usage: "BusyBox init doesn't support multiple runlevels. The runlevels field of\n" 1170 //usage: "the /etc/inittab file is completely ignored by BusyBox init. If you want\n" 1171 //usage: "runlevels, use sysvinit.\n" 1172 //usage: "\n" 1173 //usage: "BusyBox init works just fine without an inittab. If no inittab is found,\n" 1174 //usage: "it has the following default behavior:\n" 1175 //usage: "\n" 1176 //usage: " ::sysinit:/etc/init.d/rcS\n" 1177 //usage: " ::askfirst:/bin/sh\n" 1178 //usage: " ::ctrlaltdel:/sbin/reboot\n" 1179 //usage: " ::shutdown:/sbin/swapoff -a\n" 1180 //usage: " ::shutdown:/bin/umount -a -r\n" 1181 //usage: " ::restart:/sbin/init\n" 1182 //usage: "\n" 1183 //usage: "if it detects that /dev/console is _not_ a serial console, it will also run:\n" 1184 //usage: "\n" 1185 //usage: " tty2::askfirst:/bin/sh\n" 1186 //usage: " tty3::askfirst:/bin/sh\n" 1187 //usage: " tty4::askfirst:/bin/sh\n" 1188 //usage: "\n" 1189 //usage: "If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" 1190 //usage: "\n" 1191 //usage: " <id>:<runlevels>:<action>:<process>\n" 1192 //usage: "\n" 1193 //usage: " <id>:\n" 1194 //usage: "\n" 1195 //usage: " WARNING: This field has a non-traditional meaning for BusyBox init!\n" 1196 //usage: " The id field is used by BusyBox init to specify the controlling tty for\n" 1197 //usage: " the specified process to run on. The contents of this field are\n" 1198 //usage: " appended to \"/dev/\" and used as-is. There is no need for this field to\n" 1199 //usage: " be unique, although if it isn't you may have strange results. If this\n" 1200 //usage: " field is left blank, the controlling tty is set to the console. Also\n" 1201 //usage: " note that if BusyBox detects that a serial console is in use, then only\n" 1202 //usage: " entries whose controlling tty is either the serial console or /dev/null\n" 1203 //usage: " will be run. BusyBox init does nothing with utmp. We don't need no\n" 1204 //usage: " stinkin' utmp.\n" 1205 //usage: "\n" 1206 //usage: " <runlevels>:\n" 1207 //usage: "\n" 1208 //usage: " The runlevels field is completely ignored.\n" 1209 //usage: "\n" 1210 //usage: " <action>:\n" 1211 //usage: "\n" 1212 //usage: " Valid actions include: sysinit, respawn, askfirst, wait,\n" 1213 //usage: " once, restart, ctrlaltdel, and shutdown.\n" 1214 //usage: "\n" 1215 //usage: " The available actions can be classified into two groups: actions\n" 1216 //usage: " that are run only once, and actions that are re-run when the specified\n" 1217 //usage: " process exits.\n" 1218 //usage: "\n" 1219 //usage: " Run only-once actions:\n" 1220 //usage: "\n" 1221 //usage: " 'sysinit' is the first item run on boot. init waits until all\n" 1222 //usage: " sysinit actions are completed before continuing. Following the\n" 1223 //usage: " completion of all sysinit actions, all 'wait' actions are run.\n" 1224 //usage: " 'wait' actions, like 'sysinit' actions, cause init to wait until\n" 1225 //usage: " the specified task completes. 'once' actions are asynchronous,\n" 1226 //usage: " therefore, init does not wait for them to complete. 'restart' is\n" 1227 //usage: " the action taken to restart the init process. By default this should\n" 1228 //usage: " simply run /sbin/init, but can be a script which runs pivot_root or it\n" 1229 //usage: " can do all sorts of other interesting things. The 'ctrlaltdel' init\n" 1230 //usage: " actions are run when the system detects that someone on the system\n" 1231 //usage: " console has pressed the CTRL-ALT-DEL key combination. Typically one\n" 1232 //usage: " wants to run 'reboot' at this point to cause the system to reboot.\n" 1233 //usage: " Finally the 'shutdown' action specifies the actions to taken when\n" 1234 //usage: " init is told to reboot. Unmounting filesystems and disabling swap\n" 1235 //usage: " is a very good here.\n" 1236 //usage: "\n" 1237 //usage: " Run repeatedly actions:\n" 1238 //usage: "\n" 1239 //usage: " 'respawn' actions are run after the 'once' actions. When a process\n" 1240 //usage: " started with a 'respawn' action exits, init automatically restarts\n" 1241 //usage: " it. Unlike sysvinit, BusyBox init does not stop processes from\n" 1242 //usage: " respawning out of control. The 'askfirst' actions acts just like\n" 1243 //usage: " respawn, except that before running the specified process it\n" 1244 //usage: " displays the line \"Please press Enter to activate this console.\"\n" 1245 //usage: " and then waits for the user to press enter before starting the\n" 1246 //usage: " specified process.\n" 1247 //usage: "\n" 1248 //usage: " Unrecognized actions (like initdefault) will cause init to emit an\n" 1249 //usage: " error message, and then go along with its business. All actions are\n" 1250 //usage: " run in the order they appear in /etc/inittab.\n" 1251 //usage: "\n" 1252 //usage: " <process>:\n" 1253 //usage: "\n" 1254 //usage: " Specifies the process to be executed and its command line.\n" 1255 //usage: "\n" 1256 //usage: "Example /etc/inittab file:\n" 1257 //usage: "\n" 1258 //usage: " # This is run first except when booting in single-user mode\n" 1259 //usage: " #\n" 1260 //usage: " ::sysinit:/etc/init.d/rcS\n" 1261 //usage: " \n" 1262 //usage: " # /bin/sh invocations on selected ttys\n" 1263 //usage: " #\n" 1264 //usage: " # Start an \"askfirst\" shell on the console (whatever that may be)\n" 1265 //usage: " ::askfirst:-/bin/sh\n" 1266 //usage: " # Start an \"askfirst\" shell on /dev/tty2-4\n" 1267 //usage: " tty2::askfirst:-/bin/sh\n" 1268 //usage: " tty3::askfirst:-/bin/sh\n" 1269 //usage: " tty4::askfirst:-/bin/sh\n" 1270 //usage: " \n" 1271 //usage: " # /sbin/getty invocations for selected ttys\n" 1272 //usage: " #\n" 1273 //usage: " tty4::respawn:/sbin/getty 38400 tty4\n" 1274 //usage: " tty5::respawn:/sbin/getty 38400 tty5\n" 1275 //usage: " \n" 1276 //usage: " \n" 1277 //usage: " # Example of how to put a getty on a serial line (for a terminal)\n" 1278 //usage: " #\n" 1279 //usage: " #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" 1280 //usage: " #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" 1281 //usage: " #\n" 1282 //usage: " # Example how to put a getty on a modem line\n" 1283 //usage: " #::respawn:/sbin/getty 57600 ttyS2\n" 1284 //usage: " \n" 1285 //usage: " # Stuff to do when restarting the init process\n" 1286 //usage: " ::restart:/sbin/init\n" 1287 //usage: " \n" 1288 //usage: " # Stuff to do before rebooting\n" 1289 //usage: " ::ctrlaltdel:/sbin/reboot\n" 1290 //usage: " ::shutdown:/bin/umount -a -r\n" 1291 //usage: " ::shutdown:/sbin/swapoff -a\n" -
branches/2.2.9/mindi-busybox/init/mesg.c
r1765 r2725 5 5 * Copyright (c) 2002 Manuel Novoa III <mjn3@codepoet.org> 6 6 * 7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 8 8 */ 9 10 //applet:IF_MESG(APPLET(mesg, _BB_DIR_USR_BIN, _BB_SUID_DROP)) 11 12 //kbuild:lib-$(CONFIG_MESG) += mesg.o 13 14 //config:config MESG 15 //config: bool "mesg" 16 //config: default y 17 //config: help 18 //config: Mesg controls access to your terminal by others. It is typically 19 //config: used to allow or disallow other users to write to your terminal 20 21 //usage:#define mesg_trivial_usage 22 //usage: "[y|n]" 23 //usage:#define mesg_full_usage "\n\n" 24 //usage: "Control write access to your terminal\n" 25 //usage: " y Allow write access to your terminal\n" 26 //usage: " n Disallow write access to your terminal" 9 27 10 28 #include "libbb.h" 11 29 12 30 #ifdef USE_TTY_GROUP 13 #define S_IWGRP_OR_S_IWOTH 31 #define S_IWGRP_OR_S_IWOTH S_IWGRP 14 32 #else 15 #define S_IWGRP_OR_S_IWOTH 33 #define S_IWGRP_OR_S_IWOTH (S_IWGRP | S_IWOTH) 16 34 #endif 17 35 18 int mesg_main(int argc, char **argv) ;19 int mesg_main(int argc , char **argv)36 int mesg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 37 int mesg_main(int argc UNUSED_PARAM, char **argv) 20 38 { 21 39 struct stat sb; … … 23 41 char c = 0; 24 42 25 if (--argc == 0 26 || (argc == 1 && ((c = **++argv) == 'y' || c == 'n')) 43 argv++; 44 45 if (!argv[0] 46 || (!argv[1] && ((c = argv[0][0]) == 'y' || c == 'n')) 27 47 ) { 28 tty = ttyname(STDERR_FILENO);48 tty = xmalloc_ttyname(STDERR_FILENO); 29 49 if (tty == NULL) { 30 50 tty = "ttyname"; 31 51 } else if (stat(tty, &sb) == 0) { 32 52 mode_t m; 33 if ( argc == 0) {53 if (c == 0) { 34 54 puts((sb.st_mode & (S_IWGRP|S_IWOTH)) ? "is y" : "is n"); 35 55 return EXIT_SUCCESS; … … 41 61 } 42 62 } 43 bb_ perror_msg_and_die("%s",tty);63 bb_simple_perror_msg_and_die(tty); 44 64 } 45 65 bb_show_usage();
Note:
See TracChangeset
for help on using the changeset viewer.