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:
parent
0b9c3c0803
commit
863e1a5c87
@ -107,7 +107,8 @@ static RC_STRINGLIST *deptypes_mwua; /* need+want+use+after deps for stopping */
|
|||||||
static void
|
static void
|
||||||
handle_signal(int sig)
|
handle_signal(int sig)
|
||||||
{
|
{
|
||||||
int serrno = errno;
|
int serrno = errno, status;
|
||||||
|
pid_t pid;
|
||||||
const char *signame = NULL;
|
const char *signame = NULL;
|
||||||
struct winsize ws;
|
struct winsize ws;
|
||||||
|
|
||||||
@ -117,12 +118,13 @@ handle_signal(int sig)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SIGCHLD:
|
case SIGCHLD:
|
||||||
if (signal_pipe[1] > -1) {
|
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
|
||||||
if (write(signal_pipe[1], &sig, sizeof(sig)) == -1)
|
if (signal_pipe[1] > -1 && pid == service_pid) {
|
||||||
eerror("%s: send: %s",
|
if (write(signal_pipe[1], &status, sizeof(status)) == -1)
|
||||||
service, strerror(errno));
|
eerror("%s: send: %s",
|
||||||
} else
|
service, strerror(errno));
|
||||||
rc_waitpid(-1);
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SIGWINCH:
|
case SIGWINCH:
|
||||||
@ -438,6 +440,7 @@ svc_exec(const char *arg1, const char *arg2)
|
|||||||
if (errno != EINTR) {
|
if (errno != EINTR) {
|
||||||
eerror("%s: poll: %s",
|
eerror("%s: poll: %s",
|
||||||
service, strerror(errno));
|
service, strerror(errno));
|
||||||
|
ret = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -448,9 +451,20 @@ svc_exec(const char *arg1, const char *arg2)
|
|||||||
write_prefix(buffer, bytes, &prefixed);
|
write_prefix(buffer, bytes, &prefixed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Only SIGCHLD signals come down this pipe */
|
/* signal_pipe receives service_pid's exit status */
|
||||||
if (fd[0].revents & (POLLIN | POLLHUP))
|
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;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,11 +487,6 @@ svc_exec(const char *arg1, const char *arg2)
|
|||||||
master_tty = -1;
|
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;
|
service_pid = 0;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user