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.
This commit is contained in:
William Hubbs 2019-02-25 17:32:12 -06:00
parent 028da5c2e3
commit 0d378974bf

View File

@ -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)