timeout: fix failure if timeout's parent has ignored SIGCHLD
authorPádraig Brady <P@draigBrady.com>
Mon, 7 Dec 2009 19:00:04 +0000 (19:00 +0000)
committerPádraig Brady <P@draigBrady.com>
Tue, 8 Dec 2009 15:17:01 +0000 (15:17 +0000)
* src/timeout.c (main): Reset the SIGCHLD handler to the default
as otherwise wait() could return -1 and set errno to ECHILD.
This condition was ignored until commit 0b1dcf33, on 31-08-2009,
"timeout: defensive handling of all wait() errors"
but subsequently timeout would run the command correctly
but then fail with an error message.
* tests/misc/timeout: In a subshell set the CHLD handler to
SIG_IGN to ensure the timeout command resets it to SIG_DFL.
* NEWS: Mention the fix.

NEWS
src/timeout.c
tests/misc/timeout

diff --git a/NEWS b/NEWS
index 19cca5b..469865a 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -13,6 +13,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   the presence of the empty string argument.
   [bug introduced in coreutils-8.0]
 
+  timeout is now immune to the signal handling of its parent.
+  Specifically timeout now doesn't exit with an error message
+  if its parent ignores CHLD signals. [bug introduced in coreutils-7.6]
 
 * Noteworthy changes in release 8.1 (2009-11-18) [stable]
 
index 3babb8c..c7753d4 100644 (file)
@@ -275,6 +275,7 @@ main (int argc, char **argv)
   install_signal_handlers (term_signal);
   signal (SIGTTIN, SIG_IGN);    /* don't sTop if background child needs tty.  */
   signal (SIGTTOU, SIG_IGN);    /* don't sTop if background child needs tty.  */
+  signal (SIGCHLD, SIG_DFL);    /* Don't inherit CHLD handling from parent.   */
 
   monitored_pid = fork ();
   if (monitored_pid == -1)
index 77a4205..aae45f7 100755 (executable)
@@ -23,7 +23,6 @@ fi
 
 . $srcdir/test-lib.sh
 
-
 # no timeout
 timeout 1 true || fail=1
 
@@ -42,4 +41,14 @@ test $? = 2 || fail=1
 timeout 1 sleep 2
 test $? = 124 || fail=1
 
+# Ensure `timeout` is immune to parent's SIGCHLD handler
+# Use a subshell and an exec to work around a bug in FreeBSD 5.0 /bin/sh.
+(
+  # ash doesn't support "trap '' CHLD"; it knows only signal numbers.
+  sig=`"$abs_top_builddir/src/kill" -l CHLD 2>/dev/null` && trap '' $sig
+
+  # Before 2004-04-21, install would infloop, in the `while (wait...' loop:
+  exec timeout 1 true
+) || fail=1
+
 Exit $fail