static int ttyout;
/* XXX - use an array of signals instead of just a single variable */
-static sig_atomic_t alive = 1;
static sig_atomic_t recvsig = 0;
static sig_atomic_t ttymode = TERM_COOKED;
static sig_atomic_t tty_initialized = 0;
/* Suspend self and continue child when we resume. */
sa.sa_handler = SIG_DFL;
sigaction(signo, &sa, &osa);
-#ifdef SCRIPT_DEBUG
- warningx("kill parent %d", signo);
-#endif
+ sudo_debug(8, "kill parent %d", signo);
kill(parent, signo);
/* Check foreground/background status on resume. */
* Only modify term if we are foreground process and either
* the old tty mode was not cooked or child got SIGTT{IN,OU}
*/
-#ifdef SCRIPT_DEBUG
- warningx("parent is in %sground, ttymode %d -> %d",
+ sudo_debug(8, "parent is in %sground, ttymode %d -> %d",
foreground ? "fore" : "back", oldmode, ttymode);
-#endif
if (ttymode != TERM_COOKED) {
if (foreground) {
fdsw = (fd_set *)emalloc2(howmany(maxfd + 1, NFDBITS), sizeof(fd_mask));
zero_bytes(&input, sizeof(input));
zero_bytes(&output, sizeof(output));
- while (alive) {
+ for (;;) {
/* XXX - racey */
if (!relaysig && recvsig != SIGCHLD) {
relaysig = recvsig;
if (n == -1) {
if (errno == EINTR)
continue;
- if (errno != EAGAIN)
- break;
- } else if (n != sizeof(*cstat)) {
- break; /* EOF? */
+ if (errno != EAGAIN) {
+ /* Did the other end of the pipe go away? */
+ cstat->type = CMD_ERRNO;
+ cstat->val = errno;
+ }
}
if (cstat->type == CMD_WSTATUS) {
if (WIFSTOPPED(cstat->val)) {
/* Suspend parent and tell child how to resume on return. */
-#ifdef SCRIPT_DEBUG
- warningx("child stopped, suspending parent");
-#endif
+ sudo_debug(8, "child stopped, suspending parent");
relaysig = suspend_parent(WSTOPSIG(cstat->val), &output);
/* XXX - write relaysig immediately? */
continue;
break;
}
} else if (cstat->type == CMD_ERRNO) {
- /* Child was unable to execute command. */
+ /* Child was unable to execute command or broken pipe. */
break;
}
}
if (FD_ISSET(sv[0], fdsw)) {
/* XXX - we rely on child to be suspended before we suspend us */
+ sudo_debug(9, "sending signal %d to child over backchannel", relaysig);
cstat->type = CMD_SIGNO;
cstat->val = relaysig;
relaysig = 0;
do {
n = send(sv[0], cstat, sizeof(*cstat), 0);
} while (n == -1 && errno == EINTR);
- if (n != sizeof(relaysig)) {
+ if (n != sizeof(cstat)) {
break; /* should not happen */
}
}
}
}
- /* Flush any remaining output to stdout (already updated output file). */
+ /* Flush any remaining output to stdout (already sent to I/O modules). */
n = fcntl(STDOUT_FILENO, F_GETFL, 0);
if (n != -1) {
n &= ~O_NONBLOCK;
pid = waitpid(child, &status, WUNTRACED|WNOHANG);
} while (pid == -1 && errno == EINTR);
if (pid == child) {
-#ifdef SCRIPT_DEBUG
if (WIFSTOPPED(status))
- warningx("command stopped, signal %d", WSTOPSIG(status));
+ sudo_debug(8, "command stopped, signal %d", WSTOPSIG(status));
else if (WIFSIGNALED(status))
- warningx("command killed, signal %d", WTERMSIG(status));
+ sudo_debug(8, "command killed, signal %d", WTERMSIG(status));
else
- warningx("command exited?");
-#endif
+ sudo_debug(8, "command exited: %d", WEXITSTATUS(status));
cstat.type = CMD_WSTATUS;
cstat.val = status;
do {
} while (n == -1 && errno == EINTR);
if (n != sizeof(cstat))
break; /* XXX - error, kill child and exit */
-#ifdef SCRIPT_DEBUG
- warningx("sent wait status to parent");
-#endif
+ sudo_debug(8, "sent wait status to parent");
if (!WIFSTOPPED(status)) {
/* XXX */
_exit(1); /* child dead */
signo = cstat.val;
/* Handle signal from parent. */
-#ifdef SCRIPT_DEBUG
- warningx("signal %d from parent", signo);
-#endif
+ sudo_debug(8, "signal %d from parent", signo);
switch (signo) {
case SIGKILL:
_exit(1); /* XXX */
/*
* Handler for SIGCHLD in parent
+ * Note that this will detect when the child monitoring the command exits,
+ * not the command itself.
*/
static void
sigchild(int s)
if (pid == child) {
if (WIFSTOPPED(child_status))
recvsig = WSTOPSIG(child_status);
- else
- alive = 0;
}
errno = serrno;