diff options
author | William Hubbs <w.d.hubbs@gmail.com> | 2019-02-25 17:32:12 -0600 |
---|---|---|
committer | William Hubbs <w.d.hubbs@gmail.com> | 2019-02-25 18:55:13 -0600 |
commit | 0d378974bfbd69c5427d44c0a43a9f36389aa235 (patch) | |
tree | 4b9465c29a28ad51d321f503da626e7790e18fbd | |
parent | 028da5c2e37d81d4e242a546eb48a20eafe0cc56 (diff) |
openrc-init: fix waitpid checks
The do_openrc() function was not waiting properly for the child process
which started the runlevel to return. We need to repeatedly call
waitpid() until its return value matches the pid of the child process or
the child process does not exist.
This fixes #216.
This fixes #300.
-rw-r--r-- | src/rc/openrc-init.c | 39 |
1 files changed, 19 insertions, 20 deletions
diff --git a/src/rc/openrc-init.c b/src/rc/openrc-init.c index e1aaeaee..957d5147 100644 --- a/src/rc/openrc-init.c +++ b/src/rc/openrc-init.c @@ -43,40 +43,45 @@ static const char *path_default = "/sbin:/usr/sbin:/bin:/usr/bin"; static const char *rc_default_runlevel = "default"; -static pid_t do_openrc(const char *runlevel) +static void do_openrc(const char *runlevel) { pid_t pid; - sigset_t signals; + sigset_t all_signals; + sigset_t our_signals; + sigfillset(&all_signals); + /* block all signals */ + sigprocmask(SIG_BLOCK, &all_signals, &our_signals); pid = fork(); switch (pid) { case -1: perror("fork"); + exit(1); break; case 0: setsid(); /* unblock all signals */ - sigemptyset(&signals); - sigprocmask(SIG_SETMASK, &signals, NULL); + sigprocmask(SIG_UNBLOCK, &all_signals, NULL); printf("Starting %s runlevel\n", runlevel); execlp("openrc", "openrc", runlevel, NULL); perror("exec"); + exit(1); break; default: + /* restore our signal mask */ + sigprocmask(SIG_SETMASK, &our_signals, NULL); + while (waitpid(pid, NULL, 0) != pid) + if (errno == ECHILD) + break; break; } - return pid; } static void init(const char *default_runlevel) { const char *runlevel = NULL; - pid_t pid; - - pid = do_openrc("sysinit"); - waitpid(pid, NULL, 0); - pid = do_openrc("boot"); - waitpid(pid, NULL, 0); + do_openrc("sysinit"); + do_openrc("boot"); if (default_runlevel) runlevel = default_runlevel; else @@ -87,8 +92,7 @@ static void init(const char *default_runlevel) printf("%s is an invalid runlevel\n", runlevel); runlevel = rc_default_runlevel; } - pid = do_openrc(runlevel); - waitpid(pid, NULL, 0); + do_openrc(runlevel); log_wtmp("reboot", "~~", 0, RUN_LVL, "~~"); } @@ -100,11 +104,9 @@ static void handle_reexec(char *my_name) static void handle_shutdown(const char *runlevel, int cmd) { - pid_t pid; struct timespec ts; - pid = do_openrc(runlevel); - while (waitpid(pid, NULL, 0) != pid); + do_openrc(runlevel); printf("Sending the final term signal\n"); kill(-1, SIGTERM); ts.tv_sec = 3; @@ -118,10 +120,7 @@ static void handle_shutdown(const char *runlevel, int cmd) static void handle_single(void) { - pid_t pid; - - pid = do_openrc("single"); - while (waitpid(pid, NULL, 0) != pid); + do_openrc("single"); } static void reap_zombies(void) |