Read as many signals on the signal pipe as we can before returning.
This commit is contained in:
88
src/exec.c
88
src/exec.c
@@ -350,53 +350,55 @@ handle_signals(int fd, pid_t child, int log_io, struct command_status *cstat)
|
|||||||
int status;
|
int status;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
/* read signal pipe */
|
for (;;) {
|
||||||
nread = read(signal_pipe[0], &signo, sizeof(signo));
|
/* read signal pipe */
|
||||||
if (nread <= 0) {
|
nread = read(signal_pipe[0], &signo, sizeof(signo));
|
||||||
/* It should not be possible to get EOF but just in case. */
|
if (nread <= 0) {
|
||||||
if (nread == 0)
|
/* It should not be possible to get EOF but just in case. */
|
||||||
errno = ECONNRESET;
|
if (nread == 0)
|
||||||
if (errno != EINTR && errno != EAGAIN) {
|
errno = ECONNRESET;
|
||||||
sudo_debug(9, "error reading signal pipe %s", strerror(errno));
|
if (errno != EINTR && errno != EAGAIN) {
|
||||||
cstat->type = CMD_ERRNO;
|
sudo_debug(9, "error reading signal pipe %s", strerror(errno));
|
||||||
cstat->val = errno;
|
cstat->type = CMD_ERRNO;
|
||||||
}
|
cstat->val = errno;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
sudo_debug(9, "received signal %d", signo);
|
|
||||||
if (signo == SIGCHLD) {
|
|
||||||
/*
|
|
||||||
* If logging I/O, child is the intermediate process,
|
|
||||||
* otherwise it is the command itself.
|
|
||||||
*/
|
|
||||||
do {
|
|
||||||
pid = waitpid(child, &status, WUNTRACED|WNOHANG);
|
|
||||||
} while (pid == -1 && errno == EINTR);
|
|
||||||
if (pid == child) {
|
|
||||||
/* If not logging I/O and child has exited we are done. */
|
|
||||||
if (!log_io) {
|
|
||||||
if (WIFSTOPPED(status)) {
|
|
||||||
/* Child may not have privs to suspend us itself. */
|
|
||||||
kill(getpid(), WSTOPSIG(status));
|
|
||||||
} else {
|
|
||||||
/* Child has exited, we are done. */
|
|
||||||
cstat->type = CMD_WSTATUS;
|
|
||||||
cstat->val = status;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* Else we get ECONNRESET on sv[0] if child dies. */
|
return -1;
|
||||||
}
|
}
|
||||||
} else {
|
sudo_debug(9, "received signal %d", signo);
|
||||||
if (log_io) {
|
if (signo == SIGCHLD) {
|
||||||
/* Schedule signo to be forwared to the child. */
|
/*
|
||||||
schedule_signal(signo);
|
* If logging I/O, child is the intermediate process,
|
||||||
|
* otherwise it is the command itself.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
pid = waitpid(child, &status, WUNTRACED|WNOHANG);
|
||||||
|
} while (pid == -1 && errno == EINTR);
|
||||||
|
if (pid == child) {
|
||||||
|
/* If not logging I/O and child has exited we are done. */
|
||||||
|
if (!log_io) {
|
||||||
|
if (WIFSTOPPED(status)) {
|
||||||
|
/* Child may not have privs to suspend us itself. */
|
||||||
|
kill(getpid(), WSTOPSIG(status));
|
||||||
|
} else {
|
||||||
|
/* Child has exited, we are done. */
|
||||||
|
cstat->type = CMD_WSTATUS;
|
||||||
|
cstat->val = status;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Else we get ECONNRESET on sv[0] if child dies. */
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Nothing listening on sv[0], send directly. */
|
if (log_io) {
|
||||||
if (signo == SIGALRM) {
|
/* Schedule signo to be forwared to the child. */
|
||||||
terminate_child(child, FALSE);
|
schedule_signal(signo);
|
||||||
} else {
|
} else {
|
||||||
kill(child, signo);
|
/* Nothing listening on sv[0], send directly. */
|
||||||
|
if (signo == SIGALRM) {
|
||||||
|
terminate_child(child, FALSE);
|
||||||
|
} else {
|
||||||
|
kill(child, signo);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user