From 2afabe8b830cc8c33f5f1984767af4b8dc54803b Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Mon, 10 Dec 2007 07:06:04 +0000 Subject: init: remove superfluous forks and messing up with argv[0] cttyhack: add stealing of ctty --- init/init.c | 246 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 122 insertions(+), 124 deletions(-) (limited to 'init/init.c') 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 */ 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 */ -- cgit v1.2.3