openrc-run: fix rc_parallel race in svc_exec

svc_exec waits until SIGCHLD comes in to close its input, but in
rc_parallel case the SIGCHLD might be unrelated.

Checking the proper pid is found in signal handler and only signaling
signal_pipe the status code directly avoids this problem.
This commit is contained in:
Dominique Martinet 2023-02-02 13:11:59 +09:00 committed by William Hubbs
parent 0b9c3c0803
commit 863e1a5c87

View File

@ -107,7 +107,8 @@ static RC_STRINGLIST *deptypes_mwua; /* need+want+use+after deps for stopping */
static void
handle_signal(int sig)
{
int serrno = errno;
int serrno = errno, status;
pid_t pid;
const char *signame = NULL;
struct winsize ws;
@ -117,12 +118,13 @@ handle_signal(int sig)
break;
case SIGCHLD:
if (signal_pipe[1] > -1) {
if (write(signal_pipe[1], &sig, sizeof(sig)) == -1)
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
if (signal_pipe[1] > -1 && pid == service_pid) {
if (write(signal_pipe[1], &status, sizeof(status)) == -1)
eerror("%s: send: %s",
service, strerror(errno));
} else
rc_waitpid(-1);
}
}
break;
case SIGWINCH:
@ -438,6 +440,7 @@ svc_exec(const char *arg1, const char *arg2)
if (errno != EINTR) {
eerror("%s: poll: %s",
service, strerror(errno));
ret = -1;
break;
}
}
@ -448,10 +451,21 @@ svc_exec(const char *arg1, const char *arg2)
write_prefix(buffer, bytes, &prefixed);
}
/* Only SIGCHLD signals come down this pipe */
if (fd[0].revents & (POLLIN | POLLHUP))
/* signal_pipe receives service_pid's exit status */
if (fd[0].revents & (POLLIN | POLLHUP)) {
if ((s = read(signal_pipe[0], &ret, sizeof(ret))) != sizeof(ret)) {
eerror("%s: receive failed: %s", service,
s < 0 ? strerror(errno) : "short read");
ret = -1;
break;
}
ret = WEXITSTATUS(ret);
if (ret != 0 && errno == ECHILD)
/* killall5 -9 could cause this */
ret = 0;
break;
}
}
}
free(buffer);
@ -473,11 +487,6 @@ svc_exec(const char *arg1, const char *arg2)
master_tty = -1;
}
ret = rc_waitpid(service_pid);
ret = WEXITSTATUS(ret);
if (ret != 0 && errno == ECHILD)
/* killall5 -9 could cause this */
ret = 0;
service_pid = 0;
return ret;