init: remove wait() loop on restart, it may be dangerous

This commit is contained in:
Denis Vlasenko 2009-01-31 19:26:12 +00:00
parent 4ae8a05b13
commit 9ec0ecbfdd

View File

@ -418,16 +418,18 @@ static pid_t run(const struct init_action *a)
_exit(-1); _exit(-1);
} }
static struct init_action *mark_terminated(int pid) static struct init_action *mark_terminated(pid_t pid)
{ {
struct init_action *a; struct init_action *a;
if (pid > 0) {
for (a = init_action_list; a; a = a->next) { for (a = init_action_list; a; a = a->next) {
if (a->pid == pid) { if (a->pid == pid) {
a->pid = 0; a->pid = 0;
return a; return a;
} }
} }
}
return NULL; return NULL;
} }
@ -444,7 +446,7 @@ static void waitfor(pid_t pid)
mark_terminated(wpid); mark_terminated(wpid);
/* Unsafe. SIGTSTP handler might have wait'ed it already */ /* Unsafe. SIGTSTP handler might have wait'ed it already */
/*if (wpid == pid) break;*/ /*if (wpid == pid) break;*/
/* More reliable */ /* More reliable: */
if (kill(pid, 0)) if (kill(pid, 0))
break; break;
} }
@ -697,11 +699,11 @@ static void halt_reboot_pwoff(int sig)
*/ */
static void stop_handler(int sig UNUSED_PARAM) static void stop_handler(int sig UNUSED_PARAM)
{ {
int saved_errno;
smallint saved_bb_got_signal; smallint saved_bb_got_signal;
int saved_errno;
saved_errno = errno;
saved_bb_got_signal = bb_got_signal; saved_bb_got_signal = bb_got_signal;
saved_errno = errno;
signal(SIGCONT, record_signo); signal(SIGCONT, record_signo);
while (1) { while (1) {
@ -714,14 +716,13 @@ static void stop_handler(int sig UNUSED_PARAM)
* code which is resilient against this. * code which is resilient against this.
*/ */
wpid = wait_any_nohang(NULL); wpid = wait_any_nohang(NULL);
if (wpid > 0)
mark_terminated(wpid); mark_terminated(wpid);
sleep(1); sleep(1);
} }
signal(SIGCONT, SIG_DFL); signal(SIGCONT, SIG_DFL);
bb_got_signal = saved_bb_got_signal;
errno = saved_errno; errno = saved_errno;
bb_got_signal = saved_bb_got_signal;
} }
/* Handler for QUIT - exec "restart" action, /* Handler for QUIT - exec "restart" action,
@ -747,8 +748,14 @@ static void restart_handler(int sig UNUSED_PARAM)
if (open_stdio_to_tty(a->terminal)) { if (open_stdio_to_tty(a->terminal)) {
dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command); dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command);
while (wait(NULL) > 0) /* Theoretically should be safe.
continue; * But in practice, kernel bugs may leave
* unkillable processes, and wait() may block forever.
* Oh well. Hoping "new" init won't be too surprised
* by having children it didn't create.
*/
//while (wait(NULL) > 0)
// continue;
init_exec(a->command); init_exec(a->command);
} }
/* Open or exec failed */ /* Open or exec failed */
@ -990,14 +997,14 @@ int init_main(int argc UNUSED_PARAM, char **argv)
got_sigs |= check_delayed_sigs(); got_sigs |= check_delayed_sigs();
if (got_sigs)
goto dont_block;
/* Wait for any child process to exit. /* Wait for any child process to exit.
* NB: "delayed" signals will also interrupt this wait(), * NB: "delayed" signals will also interrupt this wait(),
* bb_signals_recursive_norestart() set them up for that. * bb_signals_recursive_norestart() set them up for that.
* This guarantees we won't be stuck here * This guarantees we won't be stuck here
* till next orphan dies. * till next orphan dies.
*/ */
if (got_sigs)
goto dont_block;
wpid = wait(NULL); wpid = wait(NULL);
while (wpid > 0) { while (wpid > 0) {
struct init_action *a = mark_terminated(wpid); struct init_action *a = mark_terminated(wpid);