From 66bea8c4c97e8fce877e4d9e493c0ff54511745e Mon Sep 17 00:00:00 2001 From: "Todd C. Miller" Date: Fri, 10 Sep 2010 11:27:20 -0400 Subject: [PATCH] Read as many signals on the signal pipe as we can before returning. --- src/exec.c | 86 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/src/exec.c b/src/exec.c index 10ffba531..11b078df0 100644 --- a/src/exec.c +++ b/src/exec.c @@ -350,53 +350,55 @@ handle_signals(int fd, pid_t child, int log_io, struct command_status *cstat) int status; pid_t pid; - /* read signal pipe */ - nread = read(signal_pipe[0], &signo, sizeof(signo)); - if (nread <= 0) { - /* It should not be possible to get EOF but just in case. */ - if (nread == 0) - errno = ECONNRESET; - if (errno != EINTR && errno != EAGAIN) { - sudo_debug(9, "error reading signal pipe %s", strerror(errno)); - cstat->type = CMD_ERRNO; - cstat->val = errno; + for (;;) { + /* read signal pipe */ + nread = read(signal_pipe[0], &signo, sizeof(signo)); + if (nread <= 0) { + /* It should not be possible to get EOF but just in case. */ + if (nread == 0) + errno = ECONNRESET; + if (errno != EINTR && errno != EAGAIN) { + sudo_debug(9, "error reading signal pipe %s", strerror(errno)); + cstat->type = CMD_ERRNO; + cstat->val = errno; + } + return -1; } - 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; + 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. */ } - /* Else we get ECONNRESET on sv[0] if child dies. */ - } - } else { - if (log_io) { - /* Schedule signo to be forwared to the child. */ - schedule_signal(signo); } else { - /* Nothing listening on sv[0], send directly. */ - if (signo == SIGALRM) { - terminate_child(child, FALSE); + if (log_io) { + /* Schedule signo to be forwared to the child. */ + schedule_signal(signo); } else { - kill(child, signo); + /* Nothing listening on sv[0], send directly. */ + if (signo == SIGALRM) { + terminate_child(child, FALSE); + } else { + kill(child, signo); + } } } } -- 2.40.0