Read as many signals on the signal pipe as we can before returning.

This commit is contained in:
Todd C. Miller
2010-09-10 11:27:20 -04:00
parent 59399d55c3
commit 66bea8c4c9

View File

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