| @@ -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 */ |
| |