git: 795153bda6da - stable/14 - timeout(1): Catch all signals and propagate them
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 16 Jun 2025 08:54:07 UTC
The branch stable/14 has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=795153bda6dae27ceac4a7298106c00ca706b0ec
commit 795153bda6dae27ceac4a7298106c00ca706b0ec
Author: Aaron LI <aly@aaronly.me>
AuthorDate: 2025-04-03 01:20:01 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2025-06-16 08:51:53 +0000
timeout(1): Catch all signals and propagate them
(cherry picked from commit 844cef26e810d903e11bf83cc6f6fd2e22a299f1)
---
bin/timeout/timeout.1 | 22 ++++++++++++
bin/timeout/timeout.c | 92 +++++++++++++++++++++++++++++++--------------------
2 files changed, 79 insertions(+), 35 deletions(-)
diff --git a/bin/timeout/timeout.1 b/bin/timeout/timeout.1
index 371a167d19f3..44525daaec59 100644
--- a/bin/timeout/timeout.1
+++ b/bin/timeout/timeout.1
@@ -73,6 +73,28 @@ inherited, except for the signal that will be sent upon timeout,
which is reset to take the default action and should terminate
the process.
.Pp
+If
+.Nm
+receives the
+.Dv SIGALRM
+signal, it will behave as if the time limit has been reached
+and send the specified signal to
+.Ar command .
+For any other signals delivered to
+.Nm ,
+it will propagate them to
+.Ar command ,
+with the exception of
+.Dv SIGKILL
+and
+.Dv SIGSTOP .
+If you want to prevent the
+.Ar command
+from being timed out, send
+.Dv SIGKILL
+to
+.Nm .
+.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl f , Fl -foreground
diff --git a/bin/timeout/timeout.c b/bin/timeout/timeout.c
index 1c4cfa6e017d..6e93e9e2911c 100644
--- a/bin/timeout/timeout.c
+++ b/bin/timeout/timeout.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2014 Baptiste Daroussin <bapt@FreeBSD.org>
* Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
+ * Copyright (c) 2025 Aaron LI <aly@aaronly.me>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,8 +48,10 @@
#define EXIT_CMD_NOENT 127
static volatile sig_atomic_t sig_chld = 0;
-static volatile sig_atomic_t sig_term = 0;
static volatile sig_atomic_t sig_alrm = 0;
+static volatile sig_atomic_t sig_term = 0; /* signal to terminate children */
+static volatile sig_atomic_t sig_other = 0; /* signal to propagate */
+static int killsig = SIGTERM; /* signal to kill children */
static const char *command = NULL;
static bool verbose = false;
@@ -137,19 +140,46 @@ parse_signal(const char *str)
static void
sig_handler(int signo)
{
- switch (signo) {
- case SIGINT:
- case SIGHUP:
- case SIGQUIT:
- case SIGTERM:
+ if (signo == killsig) {
sig_term = signo;
- break;
+ return;
+ }
+
+ switch (signo) {
case SIGCHLD:
sig_chld = 1;
break;
case SIGALRM:
sig_alrm = 1;
break;
+ case SIGHUP:
+ case SIGINT:
+ case SIGQUIT:
+ case SIGILL:
+ case SIGTRAP:
+ case SIGABRT:
+ case SIGEMT:
+ case SIGFPE:
+ case SIGBUS:
+ case SIGSEGV:
+ case SIGSYS:
+ case SIGPIPE:
+ case SIGTERM:
+ case SIGXCPU:
+ case SIGXFSZ:
+ case SIGVTALRM:
+ case SIGPROF:
+ case SIGUSR1:
+ case SIGUSR2:
+ /*
+ * Signals with default action to terminate the process.
+ * See the sigaction(2) man page.
+ */
+ sig_term = signo;
+ break;
+ default:
+ sig_other = signo;
+ break;
}
}
@@ -214,8 +244,6 @@ main(int argc, char **argv)
{
int ch, status, sig;
int pstat = 0;
- int killsig = SIGTERM;
- size_t i;
pid_t pid, cpid;
double first_kill;
double second_kill = 0;
@@ -225,17 +253,8 @@ main(int argc, char **argv)
bool do_second_kill = false;
bool child_done = false;
sigset_t zeromask, allmask, oldmask;
- struct sigaction signals;
+ struct sigaction sa;
struct procctl_reaper_status info;
- int signums[] = {
- -1,
- SIGTERM,
- SIGINT,
- SIGHUP,
- SIGCHLD,
- SIGALRM,
- SIGQUIT,
- };
const char optstr[] = "+fhk:ps:v";
const struct option longopts[] = {
@@ -316,22 +335,17 @@ main(int argc, char **argv)
/* parent continues here */
- memset(&signals, 0, sizeof(signals));
- sigemptyset(&signals.sa_mask);
-
- if (killsig != SIGKILL && killsig != SIGSTOP)
- signums[0] = killsig;
-
- for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i++)
- sigaddset(&signals.sa_mask, signums[i]);
-
- signals.sa_handler = sig_handler;
- signals.sa_flags = SA_RESTART;
-
- for (i = 0; i < sizeof(signums) / sizeof(signums[0]); i++) {
- if (signums[i] > 0 &&
- sigaction(signums[i], &signals, NULL) == -1)
- err(EXIT_FAILURE, "sigaction()");
+ /* Catch all signals in order to propagate them. */
+ memset(&sa, 0, sizeof(sa));
+ sigfillset(&sa.sa_mask);
+ sa.sa_handler = sig_handler;
+ sa.sa_flags = SA_RESTART;
+ for (sig = 1; sig < sys_nsig; sig++) {
+ if (sig == SIGKILL || sig == SIGSTOP || sig == SIGCONT ||
+ sig == SIGTTIN || sig == SIGTTOU)
+ continue;
+ if (sigaction(sig, &sa, NULL) == -1)
+ err(EXIT_FAILURE, "sigaction(%d)", sig);
}
/* Don't stop if background child needs TTY */
@@ -399,6 +413,14 @@ main(int argc, char **argv)
do_second_kill = false;
killsig = SIGKILL;
}
+
+ } else if (sig_other) {
+ /* Propagate any other signals. */
+ sig = sig_other;
+ sig_other = 0;
+ logv("received signal %s(%d)", sys_signame[sig], sig);
+
+ send_sig(pid, sig, foreground);
}
}