diff --git a/src/timeout.c b/src/timeout.c index a686225..3d5e8db 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -26,9 +26,6 @@ EXIT_ENOENT 127 couldn't find job to exec Caveats: - If user specifies the KILL (9) signal is to be sent on timeout, - the monitor is killed and so exits with 128+9 rather than 124. - If you start a command in the background, which reads from the tty and so is immediately sent SIGTTIN to stop, then the timeout process will ignore this so it can timeout the command as expected. @@ -108,9 +105,9 @@ cleanup (int sig) alarm (kill_after); kill_after = 0; /* Don't let later signals reset kill alarm. */ } - send_sig (0, sig); + send_sig (-monitored_pid, sig); if (sig != SIGKILL && sig != SIGCONT) - send_sig (0, SIGCONT); + send_sig (-monitored_pid, SIGCONT); } else /* we're the child or the child is not exec'd yet. */ _exit (128 + sig); @@ -283,12 +280,6 @@ main (int argc, char **argv) argv += optind; - /* Ensure we're in our own group so all subprocesses can be killed. - Note we don't just put the child in a separate group as - then we would need to worry about foreground and background groups - and propagating signals between them. */ - setpgid (0, 0); - /* Setup handlers before fork() so that we handle any signals caused by child, without races. */ install_signal_handlers (term_signal); @@ -310,6 +301,9 @@ main (int argc, char **argv) signal (SIGTTIN, SIG_DFL); signal (SIGTTOU, SIG_DFL); + /* Ensure we're in our own group so all subprocesses can be killed. */ + setpgid (0, 0); + execvp (argv[0], argv); /* FIXME: should we use "sh -c" ... here? */ /* exit like sh, env, nohup, ... */ @@ -341,7 +335,16 @@ main (int argc, char **argv) if (WIFEXITED (status)) status = WEXITSTATUS (status); else if (WIFSIGNALED (status)) - status = WTERMSIG (status) + 128; /* what sh does at least. */ + { + int sig = WTERMSIG (status); + if (!timed_out) + { + /* FIXME: use sigaction to ensure exit without cores etc. */ + signal (sig, SIG_DFL); + raise (sig); /* Exit with signal flag set. */ + } + status = sig + 128; /* Exit with this if didn't exit above. */ + } else { /* shouldn't happen. */ diff --git a/tests/misc/timeout b/tests/misc/timeout index 7506e7c..c7867c6 100755 --- a/tests/misc/timeout +++ b/tests/misc/timeout @@ -39,8 +39,13 @@ test $? = 124 || fail=1 # kill delay. Note once the initial timeout triggers, # the exit status will be 124 even if the command # exits on its own accord. -timeout -s0 -k1 1 sleep 10 -test $? = 124 && fail=1 +cat <<\EOF > sleep_msg +sleep $1 +echo completed +EOF +chmod a+x sleep_msg +timeout -s0 -k1 1 ./sleep_msg 10 > out +test -s out && 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.