init: fix bug 1111: restart actions were not splitting words:
No binary (build failed)
—
(log yok)
| @@ -47,15 +47,18 @@ config FEATURE_KILL_DELAY | |
| wrong process!) | |
| config FEATURE_INIT_SCTTY | |
| - | bool "Support running commands with a controlling-tty" |
| + | bool "Run commands with leading dash with controlling tty" |
| default n | |
| depends on INIT | |
| help | |
| - | If this option is enabled a command starting with hyphen (-) |
| - | is run in its own session (setsid(2)) and possibly with a |
| - | 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. |
| + | If this option is enabled, init will try to give a controlling |
| + | tty to any command which has leading hyphen (often it's "-/bin/sh"). |
| + | More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)". |
| + | If device attached to STDIN_FILENO can be a ctty but is not yet |
| + | a ctty for other session, it will become this process' ctty. |
| + | 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 | |
| @@ -14,7 +14,7 @@ | |
| #include <paths.h> | |
| #include <sys/reboot.h> | |
| - | #define INIT_BUFFS_SIZE 256 |
| + | #define COMMAND_SIZE 256 |
| #define CONSOLE_NAME_SIZE 32 | |
| #define MAXENV 16 /* Number of env. vars */ | |
| @@ -55,9 +55,9 @@ | |
| struct init_action { | |
| struct init_action *next; | |
| pid_t pid; | |
| - | uint8_t action; |
| + | uint8_t action_type; |
| char terminal[CONSOLE_NAME_SIZE]; | |
| - | char command[INIT_BUFFS_SIZE]; |
| + | char command[COMMAND_SIZE]; |
| }; | |
| /* Static variables */ | |
| @@ -294,14 +294,57 @@ static void open_stdio_to_tty(const char* tty_name, int exit_on_failure) | |
| set_sane_term(); | |
| } | |
| + | /* wrapper around exec: |
| + | * takes string (max COMMAND_SIZE chars) |
| + | * runs [-]/bin/sh -c "exec ......." if '>' etc detected. |
| + | * otherwise splits words on whitespace and deals with leading dash. |
| + | */ |
| + | static void init_exec(const char *command) |
| + | { |
| + | char *cmd[COMMAND_SIZE / 2]; |
| + | char buf[COMMAND_SIZE + 6]; /* COMMAND_SIZE+strlen("exec ")+1 */ |
| + | int dash = (command[0] == '-'); |
| + | |
| + | /* See if any special /bin/sh requiring characters are present */ |
| + | if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { |
| + | strcpy(buf, "exec "); |
| + | strcpy(buf + 5, command + dash); /* excluding "-" */ |
| + | /* LIBBB_DEFAULT_LOGIN_SHELL has leading dash */ |
| + | cmd[0] = (char*)(LIBBB_DEFAULT_LOGIN_SHELL + !dash); |
| + | cmd[1] = (char*)"-c"; |
| + | cmd[2] = buf; |
| + | cmd[3] = NULL; |
| + | } else { |
| + | /* Convert command (char*) into cmd (char**, one word per string) */ |
| + | char *word, *next; |
| + | int i = 0; |
| + | next = strcpy(buf, command); /* including "-" */ |
| + | while ((word = strsep(&next, " \t")) != NULL) { |
| + | if (*word != '\0') { /* not two spaces/tabs together? */ |
| + | cmd[i] = word; |
| + | i++; |
| + | } |
| + | } |
| + | cmd[i] = NULL; |
| + | } |
| + | /* If we saw leading "-", it is interactive shell. |
| + | * Try harder to give it a controlling tty. |
| + | * And skip "-" in actual exec call. */ |
| + | if (dash) { |
| + | /* _Attempt_ to make stdin a controlling tty. */ |
| + | if (ENABLE_FEATURE_INIT_SCTTY) |
| + | ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/); |
| + | } |
| + | BB_EXECVP(cmd[0] + dash, cmd); |
| + | message(L_LOG | L_CONSOLE, "Cannot run '%s': %s", |
| + | cmd[0], strerror(errno)); |
| + | /* returns if execvp fails */ |
| + | } |
| + | |
| /* Used only by run_actions */ | |
| static pid_t run(const struct init_action *a) | |
| { | |
| - | int i; |
| pid_t pid; | |
| - | char *s, *tmpCmd, *cmdpath; |
| - | char *cmd[INIT_BUFFS_SIZE]; |
| - | char buf[INIT_BUFFS_SIZE + 6]; /* INIT_BUFFS_SIZE+strlen("exec ")+1 */ |
| sigset_t nmask, omask; | |
| /* Block sigchild while forking (why?) */ | |
| @@ -341,7 +384,7 @@ static pid_t run(const struct init_action *a) | |
| #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)) { |
| + | if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) { |
| /* Now fork off another process to just hang around */ | |
| pid = fork(); | |
| if (pid < 0) { | |
| @@ -381,58 +424,7 @@ static pid_t run(const struct init_action *a) | |
| /* Child - fall though to actually execute things */ | |
| } | |
| #endif | |
| - | |
| - | /* See if any special /bin/sh requiring characters are present */ |
| - | if (strpbrk(a->command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { |
| - | cmd[0] = (char*)DEFAULT_SHELL; |
| - | cmd[1] = (char*)"-c"; |
| - | cmd[2] = strcat(strcpy(buf, "exec "), a->command); |
| - | cmd[3] = NULL; |
| - | } else { |
| - | /* Convert command (char*) into cmd (char**, one word per string) */ |
| - | strcpy(buf, a->command); |
| - | s = buf; |
| - | for (tmpCmd = buf, i = 0; (tmpCmd = strsep(&s, " \t")) != NULL;) { |
| - | if (*tmpCmd != '\0') { |
| - | cmd[i] = tmpCmd; |
| - | i++; |
| - | } |
| - | } |
| - | cmd[i] = NULL; |
| - | } |
| - | |
| - | cmdpath = cmd[0]; |
| - | |
| - | /* |
| - | * Interactive shells want to see a dash in argv[0]. This |
| - | * typically is handled by login, argv will be setup this |
| - | * way if a dash appears at the front of the command path |
| - | * (like "-/bin/sh"). |
| - | */ |
| - | if (*cmdpath == '-') { |
| - | /* 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) { |
| - | message(L_LOG | L_CONSOLE, bb_msg_memory_exhausted); |
| - | cmd[0] = cmdpath; |
| - | } else { |
| - | cmd[0][0] = '-'; |
| - | strcpy(cmd[0] + 1, s); |
| - | } |
| - | #endif |
| - | |
| - | /* _Attempt_ to make stdin a controlling tty. */ |
| - | if (ENABLE_FEATURE_INIT_SCTTY) |
| - | ioctl(0, TIOCSCTTY, 0 /*only try, don't steal*/); |
| - | } |
| - | |
| - | if (a->action & ASKFIRST) { |
| + | if (a->action_type & ASKFIRST) { |
| static const char press_enter[] ALIGN1 = | |
| #ifdef CUSTOMIZED_BANNER | |
| #include CUSTOMIZED_BANNER | |
| @@ -449,58 +441,54 @@ static pid_t run(const struct init_action *a) | |
| */ | |
| messageD(L_LOG, "waiting for enter to start '%s'" | |
| "(pid %d, tty '%s')\n", | |
| - | cmdpath, getpid(), a->terminal); |
| + | a->command, getpid(), a->terminal); |
| full_write(1, press_enter, sizeof(press_enter) - 1); | |
| while (safe_read(0, &c, 1) == 1 && c != '\n') | |
| continue; | |
| } | |
| - | /* Log the process name and args */ |
| - | message(L_LOG, "starting pid %d, tty '%s': '%s'", |
| - | getpid(), a->terminal, cmdpath); |
| - | |
| if (ENABLE_FEATURE_INIT_COREDUMPS) { | |
| struct stat sb; | |
| if (stat(CORE_ENABLE_FLAG_FILE, &sb) == 0) { | |
| struct rlimit limit; | |
| - | |
| limit.rlim_cur = RLIM_INFINITY; | |
| limit.rlim_max = RLIM_INFINITY; | |
| setrlimit(RLIMIT_CORE, &limit); | |
| } | |
| } | |
| + | /* Log the process name and args */ |
| + | message(L_LOG, "starting pid %d, tty '%s': '%s'", |
| + | getpid(), a->terminal, a->command); |
| + | |
| /* Now run it. The new program will take over this PID, | |
| * so nothing further in init.c should be run. */ | |
| - | BB_EXECVP(cmdpath, cmd); |
| - | |
| + | init_exec(a->command); |
| /* We're still here? Some error happened. */ | |
| - | message(L_LOG | L_CONSOLE, "Cannot run '%s': %s", |
| - | cmdpath, strerror(errno)); |
| _exit(-1); | |
| } | |
| /* Run all commands of a particular type */ | |
| - | static void run_actions(int action) |
| + | static void run_actions(int action_type) |
| { | |
| struct init_action *a, *tmp; | |
| for (a = init_action_list; a; a = tmp) { | |
| tmp = a->next; | |
| - | if (a->action == action) { |
| + | if (a->action_type == action_type) { |
| // Pointless: run() will error out if open of device fails. | |
| ///* 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)) { |
| + | if (a->action_type & (SYSINIT | WAIT | CTRLALTDEL | SHUTDOWN | RESTART)) { |
| waitfor(run(a)); | |
| delete_init_action(a); | |
| - | } else if (a->action & ONCE) { |
| + | } else if (a->action_type & ONCE) { |
| run(a); | |
| delete_init_action(a); | |
| - | } else if (a->action & (RESPAWN | ASKFIRST)) { |
| + | } else if (a->action_type & (RESPAWN | ASKFIRST)) { |
| /* Only run stuff with pid==0. If they have | |
| * a pid, that means it is still running */ | |
| if (a->pid == 0) { | |
| @@ -593,12 +581,11 @@ static void halt_reboot_pwoff(int sig) | |
| * else (no such action defined) do nothing */ | |
| static void exec_restart_action(int sig ATTRIBUTE_UNUSED) | |
| { | |
| - | struct init_action *a, *tmp; |
| + | struct init_action *a; |
| sigset_t unblock_signals; | |
| - | for (a = init_action_list; a; a = tmp) { |
| - | tmp = a->next; |
| - | if (a->action & RESTART) { |
| + | for (a = init_action_list; a; a = a->next) { |
| + | if (a->action_type & RESTART) { |
| kill_all_processes(); | |
| /* unblock all signals (blocked in kill_all_processes()) */ | |
| @@ -620,10 +607,7 @@ static void exec_restart_action(int sig ATTRIBUTE_UNUSED) | |
| open_stdio_to_tty(a->terminal, 0 /* - halt if open fails */); | |
| messageD(L_CONSOLE | L_LOG, "Trying to re-exec %s", a->command); | |
| - | BB_EXECLP(a->command, a->command, NULL); |
| - | |
| - | message(L_CONSOLE | L_LOG, "Cannot run '%s': %s", |
| - | a->command, strerror(errno)); |
| + | init_exec(a->command); |
| sleep(2); | |
| init_reboot(RB_HALT_SYSTEM); | |
| loop_forever(); | |
| @@ -654,12 +638,13 @@ static void cont_handler(int sig ATTRIBUTE_UNUSED) | |
| got_cont = 1; | |
| } | |
| - | static void new_init_action(uint8_t action, const char *command, const char *cons) |
| + | static void new_init_action(uint8_t action_type, const char *command, const char *cons) |
| { | |
| - | struct init_action *new_action, *a, *last; |
| + | struct init_action *a, *last; |
| - | if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST)) |
| - | return; |
| + | // Why? |
| + | // if (strcmp(cons, bb_dev_null) == 0 && (action & ASKFIRST)) |
| + | // return; |
| /* Append to the end of the list */ | |
| for (a = last = init_action_list; a; a = a->next) { | |
| @@ -668,23 +653,23 @@ static void new_init_action(uint8_t action, const char *command, const char *con | |
| if ((strcmp(a->command, command) == 0) | |
| && (strcmp(a->terminal, cons) == 0) | |
| ) { | |
| - | a->action = action; |
| + | a->action_type = action_type; |
| return; | |
| } | |
| last = a; | |
| } | |
| - | new_action = xzalloc(sizeof(struct init_action)); |
| + | a = xzalloc(sizeof(*a)); |
| if (last) { | |
| - | last->next = new_action; |
| + | last->next = a; |
| } else { | |
| - | init_action_list = new_action; |
| + | init_action_list = a; |
| } | |
| - | strcpy(new_action->command, command); |
| - | new_action->action = action; |
| - | strcpy(new_action->terminal, cons); |
| + | a->action_type = action_type; |
| + | safe_strncpy(a->command, command, sizeof(a->command)); |
| + | safe_strncpy(a->terminal, cons, sizeof(a->terminal)); |
| messageD(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n", | |
| - | new_action->command, new_action->action, new_action->terminal); |
| + | a->command, a->action_type, a->terminal); |
| } | |
| static void delete_init_action(struct init_action *action) | |
| @@ -714,7 +699,7 @@ static void delete_init_action(struct init_action *action) | |
| static void parse_inittab(void) | |
| { | |
| FILE *file; | |
| - | char buf[INIT_BUFFS_SIZE]; |
| + | char buf[COMMAND_SIZE]; |
| if (ENABLE_FEATURE_USE_INITTAB) | |
| file = fopen(INITTAB, "r"); | |
| @@ -743,7 +728,7 @@ static void parse_inittab(void) | |
| return; | |
| } | |
| - | while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) { |
| + | while (fgets(buf, COMMAND_SIZE, file) != NULL) { |
| static const char actions[] = | |
| STR_SYSINIT "sysinit\0" | |
| STR_RESPAWN "respawn\0" | |
| @@ -810,7 +795,7 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED) | |
| /* disable old entrys */ | |
| for (a = init_action_list; a; a = a->next) { | |
| - | a->action = ONCE; |
| + | a->action_type = ONCE; |
| } | |
| parse_inittab(); | |
| @@ -819,7 +804,7 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED) | |
| /* Be nice and send SIGTERM first */ | |
| for (a = init_action_list; a; a = a->next) { | |
| pid_t pid = a->pid; | |
| - | if ((a->action & ONCE) && pid != 0) { |
| + | if ((a->action_type & ONCE) && pid != 0) { |
| kill(pid, SIGTERM); | |
| } | |
| } | |
| @@ -828,7 +813,7 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED) | |
| sleep(CONFIG_FEATURE_KILL_DELAY); | |
| for (a = init_action_list; a; a = a->next) { | |
| pid_t pid = a->pid; | |
| - | if ((a->action & ONCE) && pid != 0) { |
| + | if ((a->action_type & ONCE) && pid != 0) { |
| kill(pid, SIGKILL); | |
| } | |
| } | |
| @@ -840,7 +825,7 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED) | |
| /* remove unused entrys */ | |
| for (a = init_action_list; a; a = tmp) { | |
| tmp = a->next; | |
| - | if ((a->action & (ONCE | SYSINIT | WAIT)) && a->pid == 0) { |
| + | if ((a->action_type & (ONCE | SYSINIT | WAIT)) && a->pid == 0) { |
| delete_init_action(a); | |
| } | |
| } | |
| @@ -998,7 +983,7 @@ int init_main(int argc, char **argv) | |
| * restarted by run_actions() */ | |
| a->pid = 0; | |
| message(L_LOG, "process '%s' (pid %d) exited. " | |
| - | "Scheduling it for restart.", |
| + | "Scheduling for restart.", |
| a->command, wpid); | |
| } | |
| } | |