diff options
-rw-r--r-- | init/Config.in | 20 | ||||
-rw-r--r-- | init/init.c | 117 |
2 files changed, 74 insertions, 63 deletions
diff --git a/init/Config.in b/init/Config.in index 318f523a0..1084de905 100644 --- a/init/Config.in +++ b/init/Config.in @@ -27,6 +27,26 @@ config FEATURE_USE_INITTAB help Allow init to read an inittab file when the system boot. +config FEATURE_KILL_REMOVED + bool "Support killing processes that have been removed from inittab" + default y + depends on FEATURE_USE_INITTAB + help + When respawn entries are removed from inittab and a SIGHUP is + sent to init, this feature will kill the processes that have + been removed. + +config FEATURE_KILL_DELAY + int "How long to wait between TERM and KILL (0 - send TERM only)" + range 0 1024 + default 0 + depends on FEATURE_KILL_REMOVED + help + With nonzero setting, init sends TERM, forks, child waits N + seconds, sends KILL and exits. Setting it too high is unwise + (child will hang around for too long and can actually kill + wrong process!) + config FEATURE_INIT_SCTTY bool "Support running commands with a controlling-tty" default n diff --git a/init/init.c b/init/init.c index baa5a5000..e6581880c 100644 --- a/init/init.c +++ b/init/init.c @@ -738,21 +738,8 @@ 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; + char buf[INIT_BUFFS_SIZE]; file = fopen(INITTAB, "r"); if (file == NULL) { @@ -780,57 +767,43 @@ static void parse_inittab(void) } while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) { + 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" + ; + char tmpConsole[CONSOLE_NAME_SIZE]; + char *id, *runlev, *action, *command; const char *a; /* Skip leading spaces */ - for (id = buf; *id == ' ' || *id == '\t'; id++); - + id = skip_whitespace(buf); /* Skip the line if it's a comment */ if (*id == '#' || *id == '\n') continue; + /* Trim the trailing '\n' */ + *strchrnul(id, '\n') = '\0'; - /* Trim the trailing \n */ - //XXX: chomp() ? - eol = strrchr(id, '\n'); - if (eol != NULL) - *eol = '\0'; - - /* Keep a copy around for posterity's sake (and error msgs) */ - strcpy(lineAsRead, buf); - - /* Separate the ID field from the runlevels */ + /* Line is: "id:runlevel_ignored:action:command" */ runlev = strchr(id, ':'); - if (runlev == NULL || *(runlev + 1) == '\0') { - message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead); - continue; - } else { - *runlev = '\0'; - ++runlev; - } - - /* Separate the runlevels from the action */ - action = strchr(runlev, ':'); - if (action == NULL || *(action + 1) == '\0') { - message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead); - continue; - } else { - *action = '\0'; - ++action; - } - - /* Separate the action from the command */ - command = strchr(action, ':'); - if (command == NULL || *(command + 1) == '\0') { - message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead); - continue; - } else { - *command = '\0'; - ++command; - } - - /* Ok, now process it */ + if (runlev == NULL /*|| runlev[1] == '\0' - not needed */) + goto bad_entry; + action = strchr(runlev + 1, ':'); + if (action == NULL /*|| action[1] == '\0' - not needed */) + goto bad_entry; + command = strchr(action + 1, ':'); + if (command == NULL || command[1] == '\0') + goto bad_entry; + + *command = '\0'; /* action => ":action\0" now */ for (a = actions; a[0]; a += strlen(a) + 1) { - if (strcmp(a + 1, action) == 0) { + if (strcmp(a + 1, action + 1) == 0) { + *runlev = '\0'; if (*id != '\0') { if (strncmp(id, "/dev/", 5) == 0) id += 5; @@ -839,14 +812,15 @@ static void parse_inittab(void) sizeof(tmpConsole) - 5); id = tmpConsole; } - new_init_action((uint8_t)a[0], command, id); - break; + new_init_action((uint8_t)a[0], command + 1, id); + goto next_line; } } - if (!a[0]) { - /* Choke on an unknown action */ - message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", lineAsRead); - } + *command = ':'; + /* Choke on an unknown action */ + bad_entry: + message(L_LOG | L_CONSOLE, "Bad inittab entry: %s", id); + next_line: ; } fclose(file); #endif /* FEATURE_USE_INITTAB */ @@ -860,12 +834,29 @@ static void reload_signal(int sig ATTRIBUTE_UNUSED) message(L_LOG, "reloading /etc/inittab"); /* disable old entrys */ - for (a = init_action_list; a; a = a->next ) { + for (a = init_action_list; a; a = a->next) { a->action = ONCE; } parse_inittab(); +#if ENABLE_FEATURE_KILL_REMOVED + for (a = init_action_list; a; a = a->next) { + pid_t pid = a->pid; + if ((a->action & ONCE) && pid != 0) { + /* Be nice and send SIGTERM first */ + kill(pid, SIGTERM); +#if CONFIG_FEATURE_KILL_DELAY + if (fork() == 0) { /* child */ + sleep(CONFIG_FEATURE_KILL_DELAY); + kill(pid, SIGKILL); + _exit(0); + } +#endif + } + } +#endif /* FEATURE_KILL_REMOVED */ + /* remove unused entrys */ for (a = init_action_list; a; a = tmp) { tmp = a->next; |