timeout: handle all terminating signals

* src/timeout.c (term_sig): A new global list of all signals
whose default disposition is to terminate the process.
(install_cleanup): Iterate over the TERM_SIG list, rather than
installing the handler for a specific subset.
(block_cleanup_and_chld): Likewise.
* tests/timeout/timeout.sh: Add a test case for SIGPIPE.
* NEWS: Mention the bug fix.
This commit is contained in:
Pádraig Brady 2025-11-20 16:02:43 +00:00
parent 1d58e4ddab
commit d0a51c614d
3 changed files with 69 additions and 11 deletions

4
NEWS
View File

@ -8,6 +8,10 @@ GNU coreutils NEWS -*- outline -*-
This also applies to the sha*sum and b2sum utilities.
[This bug was present in "the beginning".]
'timeout' will now propagate all terminating signals to the monitored command.
Previously 'timeout' could have exited and left the monitored command running.
[bug introduced with timeout in coreutils-7.0]
wc now documents its --debug option, currently used to
indicate the line count acceleration being used.
[bug introduced in coreutils-9.0]

View File

@ -72,6 +72,14 @@
# define SA_RESTART 0
#endif
#ifndef SIGRTMIN
# define SIGRTMIN 0
# undef SIGRTMAX
#endif
#ifndef SIGRTMAX
# define SIGRTMAX (SIGRTMIN - 1)
#endif
#define PROGRAM_NAME "timeout"
#define AUTHORS proper_name_lite ("Padraig Brady", "P\303\241draig Brady")
@ -191,6 +199,41 @@ chld (MAYBE_UNUSED int sig)
{
}
static int const term_sig[] =
{
SIGALRM, /* our timeout. */
SIGINT, /* Ctrl-C at terminal for example. */
SIGQUIT, /* Ctrl-\ at terminal for example. */
SIGHUP, /* terminal closed for example. */
SIGTERM, /* if terminated, stop monitored proc. */
SIGPIPE, SIGUSR1, SIGUSR2,
SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGSEGV,
#ifdef SIGXCPU
SIGXCPU,
#endif
#ifdef SIGXFSZ
SIGXFSZ,
#endif
#ifdef SIGSYS
SIGSYS,
#endif
#ifdef SIGVTALRM
SIGVTALRM,
#endif
#ifdef SIGPROF
SIGPROF,
#endif
#ifdef SIGPOLL
SIGPOLL,
#endif
#ifdef SIGPWR
SIGPWR,
#endif
#ifdef SIGSTKFLT
SIGSTKFLT,
#endif
};
static void
cleanup (int sig)
@ -410,11 +453,13 @@ install_cleanup (int sigterm)
sa.sa_flags = SA_RESTART; /* Restart syscalls if possible, as that's
more likely to work cleanly. */
sigaction (SIGALRM, &sa, nullptr); /* our timeout. */
sigaction (SIGINT, &sa, nullptr); /* Ctrl-C at terminal for example. */
sigaction (SIGQUIT, &sa, nullptr); /* Ctrl-\ at terminal for example. */
sigaction (SIGHUP, &sa, nullptr); /* terminal closed for example. */
sigaction (SIGTERM, &sa, nullptr); /* if killed, stop monitored proc. */
for (int i = 0; i < countof (term_sig); i++)
sigaction (term_sig[i], &sa, nullptr);
/* Real Time signals also terminate by default. */
for (int s = SIGRTMIN; s <= SIGRTMAX; s++)
sigaction (s, &sa, nullptr);
sigaction (sigterm, &sa, nullptr); /* user specified termination signal. */
}
@ -429,11 +474,12 @@ block_cleanup_and_chld (int sigterm, sigset_t *old_set)
sigset_t block_set;
sigemptyset (&block_set);
sigaddset (&block_set, SIGALRM);
sigaddset (&block_set, SIGINT);
sigaddset (&block_set, SIGQUIT);
sigaddset (&block_set, SIGHUP);
sigaddset (&block_set, SIGTERM);
for (int i = 0; i < countof (term_sig); i++)
sigaddset (&block_set, term_sig[i]);
for (int s = SIGRTMIN; s <= SIGRTMAX; s++)
sigaddset (&block_set, s);
sigaddset (&block_set, sigterm);
sigaddset (&block_set, SIGCHLD);

View File

@ -17,7 +17,7 @@
# along with this program. If not, see <https://www.gnu.org/licenses/>.
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ timeout
print_ver_ timeout kill
require_trap_signame_
# no timeout
@ -71,4 +71,12 @@ for opt in -v --verbose; do
compare exp err || fail=1
done
# Ensure we propagate all terminating signals.
# Specifically here we're testing that SIGPIPE is handled.
# I.e., that we're not killed by the SIGPIPE (and leave the sleep running).
# timeout would exit with 141 usually if SIGPIPE wasn't being handled.
echo 125 > timeout.exp || framework_failure_
{ timeout -v .1 sleep 10 2>&1; echo $? >timeout.status; } | :
compare timeout.exp timeout.status || fail=1
Exit $fail