]> granicus.if.org Git - sudo/commitdiff
No longer need to check for explicit death of the child (process #2)
authorTodd C. Miller <Todd.Miller@courtesan.com>
Sun, 21 Feb 2010 15:26:30 +0000 (10:26 -0500)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Sun, 21 Feb 2010 15:26:30 +0000 (10:26 -0500)
since if it dies we will get EPIPE from the socketpair.
Fix a sizeof() that was causing a spurious error.
Convert SCRIPT_DEBUG to sudo_debug.

src/script.c

index d61e90789ca2fa4974998663c5f7858c6e4229cb..9e75db905be3773b0648f1b82e5803a1a60cc8f6 100644 (file)
@@ -91,7 +91,6 @@ static int script_fds[3];
 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;
@@ -221,9 +220,7 @@ suspend_parent(int signo, struct script_buf *output)
        /* 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. */
@@ -233,10 +230,8 @@ suspend_parent(int signo, struct script_buf *output)
         * 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) {
@@ -420,7 +415,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
     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;
@@ -459,17 +454,16 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
            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;
@@ -478,19 +472,20 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
                    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 */
            }
        }
@@ -550,7 +545,7 @@ script_execve(struct command_details *details, char *argv[], char *envp[],
        }
     }
 
-    /* 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;
@@ -696,14 +691,12 @@ script_child(const char *path, char *argv[], char *envp[], int backchannel, int
                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 {
@@ -711,9 +704,7 @@ script_child(const char *path, char *argv[], char *envp[], int backchannel, int
                } 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 */
@@ -743,9 +734,7 @@ script_child(const char *path, char *argv[], char *envp[], int backchannel, int
        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 */
@@ -866,6 +855,8 @@ sync_winsize(int src, int dst)
 
 /*
  * 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)
@@ -879,8 +870,6 @@ sigchild(int s)
     if (pid == child) {
        if (WIFSTOPPED(child_status))
            recvsig = WSTOPSIG(child_status);
-       else
-           alive = 0;
     }
 
     errno = serrno;