aboutsummaryrefslogtreecommitdiff
path: root/init
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
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')
-rw-r--r--init/Config.in1
-rw-r--r--init/init.c246
2 files changed, 123 insertions, 124 deletions
diff --git a/init/Config.in b/init/Config.in
index 3987d8fee..318f523a0 100644
--- a/init/Config.in
+++ b/init/Config.in
@@ -37,6 +37,7 @@ config FEATURE_INIT_SCTTY
controlling tty (TIOCSCTTY). This is not the traditional init
behavour, but is often what you want in an embedded system where
the console is only accessed during development or for maintenance.
+ NB: using cttyhack applet may work better.
config FEATURE_INIT_SYSLOG
bool "Enable init to write to syslog"
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 */