From eb1ec4bc2438b6ced53aa11d69b41720547b87d1 Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Wed, 31 Jul 2013 17:30:04 +0200 Subject: [PATCH] orphanripper: Race fix. --- src/orphanripper.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 53 insertions(+), 9 deletions(-) diff --git a/src/orphanripper.c b/src/orphanripper.c index b289477..ffccabf 100644 --- a/src/orphanripper.c +++ b/src/orphanripper.c @@ -47,11 +47,10 @@ static const char *progname; -static volatile int signal_chld_hit = 0; +static volatile pid_t child; static void signal_chld (int signo) { - signal_chld_hit = 1; } static volatile int signal_alrm_hit = 0; @@ -62,7 +61,6 @@ static void signal_alrm (int signo) } static char childptyname[LINE_MAX]; -static pid_t child; static void print_child_error (const char *reason, char **argv) { @@ -103,6 +101,44 @@ static int read_out (int amaster) return 1; } +/* kill (child, 0) ==0 sometimes even when CHILD's state is already Z. */ + +static int child_exited (void) +{ + char buf[200]; + int fd, i, retval; + ssize_t got; + char *state; + + snprintf (buf, sizeof (buf), "/proc/%ld/stat", (long) child); + fd = open (buf, O_RDONLY); + if (fd == -1) + { + perror ("open (/proc/CHILD/stat)"); + exit (EXIT_FAILURE); + } + got = read (fd, buf, sizeof(buf)); + if (got <= 0) + { + perror ("read (/proc/CHILD/stat)"); + exit (EXIT_FAILURE); + } + if (close (fd) != 0) + { + perror ("close (/proc/CHILD/stat)"); + exit (EXIT_FAILURE); + } + i = sscanf (buf, "%*d%*s%ms", &state); + if (i != 1) + { + perror ("sscanf (/proc/CHILD/stat)"); + exit (EXIT_FAILURE); + } + retval = strcmp (state, "Z") == 0; + free (state); + return retval; +} + static int spawn (char **argv, int timeout) { pid_t child_got; @@ -156,6 +192,11 @@ static int spawn (char **argv, int timeout) assert (i == STDIN_FILENO); #endif + i = sigemptyset (&set); + assert (i == 0); + i = sigprocmask (SIG_SETMASK, &set, NULL); + assert (i == 0); + /* Do not setpgrp(2) in the parent process as the process-group is shared for the whole sh(1) pipeline we could be a part of. The process-group is set according to PID of the first @@ -203,8 +244,13 @@ static int spawn (char **argv, int timeout) pollfd.fd = amaster; pollfd.events = POLLIN; i = ppoll (&pollfd, 1, NULL, &set); - if (i == -1 && errno == EINTR && signal_chld_hit) - break; + if (i == -1 && errno == EINTR) + { + if (child_exited ()) + break; + /* Non-CHILD child may have exited. */ + continue; + } assert (i == 1); /* Data available? Process it first. */ if (pollfd.revents & POLLIN) @@ -224,7 +270,7 @@ static int spawn (char **argv, int timeout) exit (EXIT_FAILURE); } /* Child exited? */ - if (signal_chld_hit) + if (child_exited ()) break; } @@ -273,12 +319,10 @@ static int spawn (char **argv, int timeout) exit (EXIT_FAILURE); } - /* In the POLLHUP case we may not have seen SIGCHLD so far. */ + /* Not used in fact. */ i = sigprocmask (SIG_SETMASK, &set, NULL); assert (i == 0); - assert (signal_chld_hit != 0); - /* Do not unset O_NONBLOCK as a stale child (the whole purpose of this program) having open its output pty would block us in read_out. */ #if 0 -- 1.8.3.1