aboutsummaryrefslogtreecommitdiff
path: root/init/init.c
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-12-10 07:06:04 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-12-10 07:06:04 +0000
commit2afabe8b830cc8c33f5f1984767af4b8dc54803b (patch)
tree2647f259f9584d874dca8a784af4dd87df6db57e /init/init.c
parent191836845e4551fe6191dc0d43b45a0232bff8be (diff)
downloadbusybox-2afabe8b830cc8c33f5f1984767af4b8dc54803b.tar.gz
init: remove superfluous forks and messing up with argv[0]
cttyhack: add stealing of ctty
Diffstat (limited to 'init/init.c')
-rw-r--r--init/init.c246
1 files changed, 122 insertions, 124 deletions
diff --git a/init/init.c b/init/init.c
index fe0ec030a..c0c8b17cb 100644
--- a/init/init.c
+++ b/init/init.c
@@ -47,31 +47,22 @@
#define SHUTDOWN 0x040
#define RESTART 0x080
-/* A mapping between "inittab" action name strings and action type codes. */
-struct init_action_type {
- const char *name;
- int action;
-};
-
-static const struct init_action_type actions[] = {
- {"sysinit", SYSINIT},
- {"respawn", RESPAWN},
- {"askfirst", ASKFIRST},
- {"wait", WAIT},
- {"once", ONCE},
- {"ctrlaltdel", CTRLALTDEL},
- {"shutdown", SHUTDOWN},
- {"restart", RESTART},
- {0, 0}
-};
+#define STR_SYSINIT "\x01"
+#define STR_RESPAWN "\x02"
+#define STR_ASKFIRST "\x04"
+#define STR_WAIT "\x08"
+#define STR_ONCE "\x10"
+#define STR_CTRLALTDEL "\x20"
+#define STR_SHUTDOWN "\x40"
+#define STR_RESTART "\x80"
/* Set up a linked list of init_actions, to be read from inittab */
struct init_action {
struct init_action *next;
- int action;
pid_t pid;
- char command[INIT_BUFFS_SIZE];
+ uint8_t action;
char terminal[CONSOLE_NAME_SIZE];
+ char command[INIT_BUFFS_SIZE];
};
/* Static variables */
@@ -113,7 +104,7 @@ static const char *const environment[] = {
/* Function prototypes */
static void delete_init_action(struct init_action *a);
-static int waitfor(const struct init_action *a, pid_t pid);
+static int waitfor(pid_t pid);
#if !ENABLE_DEBUG_INIT
static void shutdown_signal(int sig);
#endif
@@ -193,43 +184,6 @@ static void message(int device, const char *fmt, ...)
}
}
-/* Set terminal settings to reasonable defaults */
-static void set_sane_term(void)
-{
- struct termios tty;
-
- tcgetattr(STDIN_FILENO, &tty);
-
- /* set control chars */
- tty.c_cc[VINTR] = 3; /* C-c */
- tty.c_cc[VQUIT] = 28; /* C-\ */
- tty.c_cc[VERASE] = 127; /* C-? */
- tty.c_cc[VKILL] = 21; /* C-u */
- tty.c_cc[VEOF] = 4; /* C-d */
- tty.c_cc[VSTART] = 17; /* C-q */
- tty.c_cc[VSTOP] = 19; /* C-s */
- tty.c_cc[VSUSP] = 26; /* C-z */
-
- /* use line dicipline 0 */
- tty.c_line = 0;
-
- /* Make it be sane */
- tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD;
- tty.c_cflag |= CREAD | HUPCL | CLOCAL;
-
- /* input modes */
- tty.c_iflag = ICRNL | IXON | IXOFF;
-
- /* output modes */
- tty.c_oflag = OPOST | ONLCR;
-
- /* local modes */
- tty.c_lflag =
- ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
-
- tcsetattr(STDIN_FILENO, TCSANOW, &tty);
-}
-
/* From <linux/serial.h> */
struct serial_struct {
int type;
@@ -277,7 +231,7 @@ static void console_init(void)
s = getenv("TERM");
if (ioctl(0, TIOCGSERIAL, &sr) == 0) {
- /* Force the TERM setting to vt102 for serial console --
+ /* Force the TERM setting to vt102 for serial console
* if TERM is set to linux (the default) */
if (!s || strcmp(s, "linux") == 0)
putenv((char*)"TERM=vt102");
@@ -288,14 +242,41 @@ static void console_init(void)
putenv((char*)"TERM=linux");
}
-static void fixup_argv(char **argv)
+/* Set terminal settings to reasonable defaults */
+static void set_sane_term(void)
{
- /* Fix up argv[0] to be certain we claim to be init */
- strncpy(argv[0], "init", strlen(argv[0]));
+ struct termios tty;
- /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
- while (*++argv)
- memset(*argv, 0, strlen(*argv));
+ tcgetattr(STDIN_FILENO, &tty);
+
+ /* set control chars */
+ tty.c_cc[VINTR] = 3; /* C-c */
+ tty.c_cc[VQUIT] = 28; /* C-\ */
+ tty.c_cc[VERASE] = 127; /* C-? */
+ tty.c_cc[VKILL] = 21; /* C-u */
+ tty.c_cc[VEOF] = 4; /* C-d */
+ tty.c_cc[VSTART] = 17; /* C-q */
+ tty.c_cc[VSTOP] = 19; /* C-s */
+ tty.c_cc[VSUSP] = 26; /* C-z */
+
+ /* use line dicipline 0 */
+ tty.c_line = 0;
+
+ /* Make it be sane */
+ tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD;
+ tty.c_cflag |= CREAD | HUPCL | CLOCAL;
+
+ /* input modes */
+ tty.c_iflag = ICRNL | IXON | IXOFF;
+
+ /* output modes */
+ tty.c_oflag = OPOST | ONLCR;
+
+ /* local modes */
+ tty.c_lflag =
+ ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN;
+
+ tcsetattr(STDIN_FILENO, TCSANOW, &tty);
}
/* Open the new terminal device */
@@ -324,6 +305,7 @@ static void open_stdio_to_tty(const char* tty_name, int fail)
set_sane_term();
}
+/* Used only by run_actions */
static pid_t run(const struct init_action *a)
{
int i;
@@ -333,16 +315,20 @@ static pid_t run(const struct init_action *a)
char buf[INIT_BUFFS_SIZE + 6]; /* INIT_BUFFS_SIZE+strlen("exec ")+1 */
sigset_t nmask, omask;
- /* Block sigchild while forking. */
+ /* Block sigchild while forking (why?) */
sigemptyset(&nmask);
sigaddset(&nmask, SIGCHLD);
sigprocmask(SIG_BLOCK, &nmask, &omask);
pid = fork();
sigprocmask(SIG_SETMASK, &omask, NULL);
+ if (pid < 0)
+ message(L_LOG | L_CONSOLE, "Can't fork");
if (pid)
return pid;
+ /* Child */
+
/* Reset signal handlers that were set by the parent process */
signal(SIGUSR1, SIG_DFL);
signal(SIGUSR2, SIG_DFL);
@@ -359,8 +345,9 @@ static pid_t run(const struct init_action *a)
setsid();
/* Open the new terminal device */
- open_stdio_to_tty(a->terminal, 1);
+ open_stdio_to_tty(a->terminal, 1 /* - exit if open fails*/);
+#ifdef BUT_RUN_ACTIONS_ALREADY_DOES_WAITING
/* If the init Action requires us to wait, then force the
* supplied terminal to be the controlling tty. */
if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
@@ -373,13 +360,13 @@ static pid_t run(const struct init_action *a)
}
if (pid > 0) {
- /* We are the parent -- wait till the child is done */
+ /* Parent - wait till the child is done */
signal(SIGINT, SIG_IGN);
signal(SIGTSTP, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGCHLD, SIG_DFL);
- waitfor(NULL, pid);
+ waitfor(pid);
/* See if stealing the controlling tty back is necessary */
if (tcgetpgrp(0) != getpid())
_exit(0);
@@ -395,12 +382,13 @@ static pid_t run(const struct init_action *a)
ioctl(0, TIOCSCTTY, 1);
_exit(0);
}
- waitfor(NULL, pid);
+ waitfor(pid);
_exit(0);
}
- /* Now fall though to actually execute things */
+ /* Child - fall though to actually execute things */
}
+#endif
/* See if any special /bin/sh requiring characters are present */
if (strpbrk(a->command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) {
@@ -433,9 +421,9 @@ static pid_t run(const struct init_action *a)
/* skip over the dash */
++cmdpath;
+#ifdef WHY_WE_DO_THIS_SHELL_MUST_HANDLE_THIS_ITSELF
/* find the last component in the command pathname */
s = bb_get_last_path_component_nostrip(cmdpath);
-
/* make a new argv[0] */
cmd[0] = malloc(strlen(s) + 2);
if (cmd[0] == NULL) {
@@ -445,16 +433,16 @@ static pid_t run(const struct init_action *a)
cmd[0][0] = '-';
strcpy(cmd[0] + 1, s);
}
+#endif
+
#if ENABLE_FEATURE_INIT_SCTTY
/* Establish this process as session leader and
- * (attempt) to make the tty (if any) a controlling tty.
+ * _attempt_ to make stdin a controlling tty.
*/
- setsid();
- ioctl(0, TIOCSCTTY, 0 /*don't steal it*/);
+ ioctl(0, TIOCSCTTY, 0 /*only try, don't steal*/);
#endif
}
-#if !defined(__UCLIBC__) || defined(__ARCH_HAS_MMU__)
if (a->action & ASKFIRST) {
static const char press_enter[] ALIGN1 =
#ifdef CUSTOMIZED_BANNER
@@ -474,10 +462,10 @@ static pid_t run(const struct init_action *a)
"(pid %d, tty '%s')\n",
cmdpath, getpid(), a->terminal);
full_write(1, press_enter, sizeof(press_enter) - 1);
- while (read(0, &c, 1) == 1 && c != '\n')
- ;
+ while (safe_read(0, &c, 1) == 1 && c != '\n')
+ continue;
}
-#endif
+
/* Log the process name and args */
message(L_LOG, "starting pid %d, tty '%s': '%s'",
getpid(), a->terminal, cmdpath);
@@ -504,22 +492,15 @@ static pid_t run(const struct init_action *a)
_exit(-1);
}
-static int waitfor(const struct init_action *a, pid_t pid)
+static int waitfor(pid_t runpid)
{
- int runpid;
int status, wpid;
- runpid = (NULL == a)? pid : run(a);
while (1) {
wpid = waitpid(runpid, &status, 0);
- if (wpid == runpid)
- break;
- if (wpid == -1 && errno == ECHILD) {
- /* we missed its termination */
- break;
- }
- /* FIXME other errors should maybe trigger an error, but allow
- * the program to continue */
+ if (wpid == -1 && errno == EINTR)
+ continue;
+ break;
}
return wpid;
}
@@ -534,9 +515,10 @@ static void run_actions(int action)
if (a->action == action) {
/* a->terminal of "" means "init's console" */
if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) {
+ //message(L_LOG | L_CONSOLE, "Device %s cannot be opened in RW mode", a->terminal /*, strerror(errno)*/);
delete_init_action(a);
} else if (a->action & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) {
- waitfor(a, 0);
+ waitfor(run(a));
delete_init_action(a);
} else if (a->action & ONCE) {
run(a);
@@ -607,6 +589,29 @@ static void shutdown_system(void)
sleep(1);
}
+static void shutdown_signal(int sig)
+{
+ const char *m;
+ int rb;
+
+ shutdown_system();
+
+ m = "halt";
+ rb = RB_HALT_SYSTEM;
+ if (sig == SIGTERM) {
+ m = "reboot";
+ rb = RB_AUTOBOOT;
+ } else if (sig == SIGUSR2) {
+ m = "poweroff";
+ rb = RB_POWER_OFF;
+ }
+ message(L_CONSOLE | L_LOG, "Requesting system %s", m);
+ /* allow time for last message to reach serial console */
+ sleep(2);
+ init_reboot(rb);
+ loop_forever();
+}
+
static void exec_signal(int sig ATTRIBUTE_UNUSED)
{
struct init_action *a, *tmp;
@@ -632,7 +637,7 @@ static void exec_signal(int sig ATTRIBUTE_UNUSED)
sigprocmask(SIG_UNBLOCK, &unblock_signals, NULL);
/* Open the new terminal device */
- open_stdio_to_tty(a->terminal, 0);
+ open_stdio_to_tty(a->terminal, 0 /* - shutdown_signal(SIGUSR1) [halt] if open fails */);
messageD(L_CONSOLE | L_LOG, "Trying to re-exec %s", a->command);
BB_EXECLP(a->command, a->command, NULL);
@@ -646,29 +651,6 @@ static void exec_signal(int sig ATTRIBUTE_UNUSED)
}
}
-static void shutdown_signal(int sig)
-{
- const char *m;
- int rb;
-
- shutdown_system();
-
- m = "halt";
- rb = RB_HALT_SYSTEM;
- if (sig == SIGTERM) {
- m = "reboot";
- rb = RB_AUTOBOOT;
- } else if (sig == SIGUSR2) {
- m = "poweroff";
- rb = RB_POWER_OFF;
- }
- message(L_CONSOLE | L_LOG, "Requesting system %s", m);
- /* allow time for last message to reach serial console */
- sleep(2);
- init_reboot(rb);
- loop_forever();
-}
-
static void ctrlaltdel_signal(int sig ATTRIBUTE_UNUSED)
{
run_actions(CTRLALTDEL);
@@ -682,7 +664,7 @@ static void stop_handler(int sig ATTRIBUTE_UNUSED)
got_cont = 0;
while (!got_cont)
pause();
- got_cont = 0;
+
errno = saved_errno;
}
@@ -694,7 +676,7 @@ static void cont_handler(int sig ATTRIBUTE_UNUSED)
#endif /* !ENABLE_DEBUG_INIT */
-static void new_init_action(int action, const char *command, const char *cons)
+static void new_init_action(uint8_t action, const char *command, const char *cons)
{
struct init_action *new_action, *a, *last;
@@ -754,11 +736,21 @@ static void delete_init_action(struct init_action *action)
static void parse_inittab(void)
{
#if ENABLE_FEATURE_USE_INITTAB
+ static const char actions[] =
+ STR_SYSINIT "sysinit\0"
+ STR_RESPAWN "respawn\0"
+ STR_ASKFIRST "askfirst\0"
+ STR_WAIT "wait\0"
+ STR_ONCE "once\0"
+ STR_CTRLALTDEL "ctrlaltdel\0"
+ STR_SHUTDOWN "shutdown\0"
+ STR_RESTART "restart\0"
+ ;
+
FILE *file;
char buf[INIT_BUFFS_SIZE], lineAsRead[INIT_BUFFS_SIZE];
char tmpConsole[CONSOLE_NAME_SIZE];
char *id, *runlev, *action, *command, *eol;
- const struct init_action_type *a = actions;
file = fopen(INITTAB, "r");
if (file == NULL) {
@@ -769,7 +761,8 @@ static void parse_inittab(void)
/* Umount all filesystems on halt/reboot */
new_init_action(SHUTDOWN, "umount -a -r", "");
/* Swapoff on halt/reboot */
- if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a", "");
+ if (ENABLE_SWAPONOFF)
+ new_init_action(SHUTDOWN, "swapoff -a", "");
/* Prepare to restart init when a HUP is received */
new_init_action(RESTART, "init", "");
/* Askfirst shell on tty1-4 */
@@ -785,6 +778,8 @@ static void parse_inittab(void)
}
while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) {
+ const char *a;
+
/* Skip leading spaces */
for (id = buf; *id == ' ' || *id == '\t'; id++);
@@ -832,8 +827,8 @@ static void parse_inittab(void)
}
/* Ok, now process it */
- for (a = actions; a->name != 0; a++) {
- if (strcmp(a->name, action) == 0) {
+ for (a = actions; a[0]; a += strlen(a) + 1) {
+ if (strcmp(a + 1, action) == 0) {
if (*id != '\0') {
if (strncmp(id, "/dev/", 5) == 0)
id += 5;
@@ -842,11 +837,11 @@ static void parse_inittab(void)
sizeof(tmpConsole) - 5);
id = tmpConsole;
}
- new_init_action(a->action, command, id);
+ new_init_action((uint8_t)a[0], command, id);
break;
}
}
- if (a->name == 0) {
+ if (!a[0]) {
/* Choke on an unknown action */
message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead);
}
@@ -981,8 +976,11 @@ int init_main(int argc, char **argv)
}
#endif /* CONFIG_SELINUX */
- /* Make the command line just say "init" -- thats all, nothing else */
- fixup_argv(argv);
+ /* Make the command line just say "init" - thats all, nothing else */
+ strncpy(argv[0], "init", strlen(argv[0]));
+ /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */
+ while (*++argv)
+ memset(*argv, 0, strlen(*argv));
/* Now run everything that needs to be run */