Explicitly check for a continued process with waitpid(2). Otherwise,
waitpid() will return 0 when the command is resumed after being suspended, which we were treating the same as -1. Fixes suspend and resume on Linux and probably others.
This commit is contained in:
@@ -1148,13 +1148,14 @@ static bool
|
|||||||
handle_sigchld(int backchannel, struct command_status *cstat)
|
handle_sigchld(int backchannel, struct command_status *cstat)
|
||||||
{
|
{
|
||||||
char signame[SIG2STR_MAX];
|
char signame[SIG2STR_MAX];
|
||||||
|
bool alive = true;
|
||||||
int status;
|
int status;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
debug_decl(handle_sigchld, SUDO_DEBUG_EXEC);
|
debug_decl(handle_sigchld, SUDO_DEBUG_EXEC);
|
||||||
|
|
||||||
/* Read command status. */
|
/* Read command status. */
|
||||||
do {
|
do {
|
||||||
pid = waitpid(cmnd_pid, &status, WUNTRACED|WNOHANG);
|
pid = waitpid(cmnd_pid, &status, WUNTRACED|WCONTINUED|WNOHANG);
|
||||||
} while (pid == -1 && errno == EINTR);
|
} while (pid == -1 && errno == EINTR);
|
||||||
if (pid <= 0) {
|
if (pid <= 0) {
|
||||||
sudo_debug_printf(SUDO_DEBUG_DIAG,
|
sudo_debug_printf(SUDO_DEBUG_DIAG,
|
||||||
@@ -1162,17 +1163,23 @@ handle_sigchld(int backchannel, struct command_status *cstat)
|
|||||||
debug_return_bool(false);
|
debug_return_bool(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WIFSTOPPED(status)) {
|
if (WIFCONTINUED(status)) {
|
||||||
|
sudo_debug_printf(SUDO_DEBUG_INFO, "command (%d) resumed", cmnd_pid);
|
||||||
|
} else if (WIFSTOPPED(status)) {
|
||||||
if (sig2str(WSTOPSIG(status), signame) == -1)
|
if (sig2str(WSTOPSIG(status), signame) == -1)
|
||||||
snprintf(signame, sizeof(signame), "%d", WSTOPSIG(status));
|
snprintf(signame, sizeof(signame), "%d", WSTOPSIG(status));
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO, "command stopped, SIG%s", signame);
|
sudo_debug_printf(SUDO_DEBUG_INFO, "command (%d) stopped, SIG%s",
|
||||||
|
cmnd_pid, signame);
|
||||||
} else if (WIFSIGNALED(status)) {
|
} else if (WIFSIGNALED(status)) {
|
||||||
if (sig2str(WTERMSIG(status), signame) == -1)
|
if (sig2str(WTERMSIG(status), signame) == -1)
|
||||||
snprintf(signame, sizeof(signame), "%d", WTERMSIG(status));
|
snprintf(signame, sizeof(signame), "%d", WTERMSIG(status));
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO, "command killed, SIG%s", signame);
|
sudo_debug_printf(SUDO_DEBUG_INFO, "command (%d) killed, SIG%s",
|
||||||
|
cmnd_pid, signame);
|
||||||
|
alive = false;
|
||||||
} else {
|
} else {
|
||||||
sudo_debug_printf(SUDO_DEBUG_INFO, "command exited: %d",
|
sudo_debug_printf(SUDO_DEBUG_INFO, "command (%d) exited: %d",
|
||||||
WEXITSTATUS(status));
|
cmnd_pid, WEXITSTATUS(status));
|
||||||
|
alive = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Don't overwrite execve() failure with child exit status. */
|
/* Don't overwrite execve() failure with child exit status. */
|
||||||
@@ -1188,13 +1195,11 @@ handle_sigchld(int backchannel, struct command_status *cstat)
|
|||||||
pid = tcgetpgrp(io_fds[SFD_SLAVE]);
|
pid = tcgetpgrp(io_fds[SFD_SLAVE]);
|
||||||
} while (pid == -1 && errno == EINTR);
|
} while (pid == -1 && errno == EINTR);
|
||||||
if (pid != mon_pgrp)
|
if (pid != mon_pgrp)
|
||||||
send_status(backchannel, cstat);
|
send_status(backchannel, cstat);
|
||||||
debug_return_bool(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* It's dead, Jim. */
|
debug_return_bool(alive);
|
||||||
debug_return_bool(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct monitor_closure {
|
struct monitor_closure {
|
||||||
|
Reference in New Issue
Block a user