git: 3bfe51c7252a - stable/15 - timeout: Clean up
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 18 Feb 2026 00:25:57 UTC
The branch stable/15 has been updated by des:
URL: https://cgit.FreeBSD.org/src/commit/?id=3bfe51c7252ac3e61ab00208e63c0baad8d7229e
commit 3bfe51c7252ac3e61ab00208e63c0baad8d7229e
Author: Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2026-02-13 20:18:35 +0000
Commit: Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2026-02-18 00:15:34 +0000
timeout: Clean up
* Annotate logv() and fix format string bug.
* Don't reinvent str2sig(3).
* Reorganize kill_self() so we unblock signals as late as possible, and
use raise(2) instead of kill(2).
* Explicitly close unused pipe descriptors.
* Use correct type to collect result of read(2) and write(2).
* Compare return values to 0, not -1.
* Sort local variables according to style(9).
* Reduce unnecessary nesting.
* Reindent.
* Fix typo in manual page.
MFC after: 1 week
Sponsored by: Klara, Inc.
Reviewed by: kevans
Differential Revision: https://reviews.freebsd.org/D55277
(cherry picked from commit 08208cd694815cc855835960f55231342eb35934)
---
bin/timeout/timeout.1 | 2 +-
bin/timeout/timeout.c | 156 +++++++++++++++++++++++---------------------------
2 files changed, 73 insertions(+), 85 deletions(-)
diff --git a/bin/timeout/timeout.1 b/bin/timeout/timeout.1
index 6486ccf99a36..0a9754a2cc4e 100644
--- a/bin/timeout/timeout.1
+++ b/bin/timeout/timeout.1
@@ -188,7 +188,7 @@ will terminate itself with the same signal if the
is terminated by a signal.
.Pp
If an error occurred, the following exit values are returned:
-.Bl -tag -offset indent with indent -compact
+.Bl -tag -offset indent -width indent -compact
.It 125
An error other than the two described below occurred.
For example, an invalid duration or signal was specified.
diff --git a/bin/timeout/timeout.c b/bin/timeout/timeout.c
index 58a5797f3eaf..5f045653f35b 100644
--- a/bin/timeout/timeout.c
+++ b/bin/timeout/timeout.c
@@ -26,13 +26,13 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/fcntl.h>
#include <sys/procctl.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <err.h>
+#include <fcntl.h>
#include <errno.h>
#include <getopt.h>
#include <signal.h>
@@ -60,14 +60,14 @@ static void __dead2
usage(void)
{
fprintf(stderr,
- "Usage: %s [-f | --foreground] [-k time | --kill-after time]"
- " [-p | --preserve-status] [-s signal | --signal signal] "
- " [-v | --verbose] <duration> <command> [arg ...]\n",
- getprogname());
+ "Usage: %s [-f | --foreground] [-k time | --kill-after time]"
+ " [-p | --preserve-status] [-s signal | --signal signal] "
+ " [-v | --verbose] <duration> <command> [arg ...]\n",
+ getprogname());
exit(EXIT_FAILURE);
}
-static void
+static void __printflike(1, 2)
logv(const char *fmt, ...)
{
va_list ap;
@@ -118,26 +118,6 @@ parse_duration(const char *duration)
return (ret);
}
-static int
-parse_signal(const char *str)
-{
- int sig, i;
- const char *errstr;
-
- sig = strtonum(str, 1, sys_nsig - 1, &errstr);
- if (errstr == NULL)
- return (sig);
-
- if (strncasecmp(str, "SIG", 3) == 0)
- str += 3;
- for (i = 1; i < sys_nsig; i++) {
- if (strcasecmp(str, sys_signame[i]) == 0)
- return (i);
- }
-
- errx(EXIT_INVALID, "invalid signal");
-}
-
static void
sig_handler(int signo)
{
@@ -188,28 +168,22 @@ static void
send_sig(pid_t pid, int signo, bool foreground)
{
struct procctl_reaper_kill rk;
- int error;
logv("sending signal %s(%d) to command '%s'",
- sys_signame[signo], signo, command);
+ sys_signame[signo], signo, command);
if (foreground) {
- if (kill(pid, signo) == -1) {
- if (errno != ESRCH)
- warn("kill(%d, %s)", (int)pid,
- sys_signame[signo]);
- }
+ if (kill(pid, signo) < 0 && errno != ESRCH)
+ warn("kill(%d, %s)", (int)pid, sys_signame[signo]);
} else {
memset(&rk, 0, sizeof(rk));
rk.rk_sig = signo;
- error = procctl(P_PID, getpid(), PROC_REAP_KILL, &rk);
- if (error == 0 || (error == -1 && errno == ESRCH))
- ;
- else if (error == -1) {
+ if (procctl(P_PID, getpid(), PROC_REAP_KILL, &rk) < 0 &&
+ errno != ESRCH) {
warn("procctl(PROC_REAP_KILL)");
- if (rk.rk_fpid > 0)
- warnx(
- "failed to signal some processes: first pid=%d",
- (int)rk.rk_fpid);
+ if (rk.rk_fpid > 0) {
+ warnx("failed to signal some processes:"
+ " first pid=%d", (int)rk.rk_fpid);
+ }
}
logv("signaled %u processes", rk.rk_killed);
}
@@ -222,7 +196,7 @@ send_sig(pid_t pid, int signo, bool foreground)
*/
if (signo != SIGKILL && signo != SIGSTOP && signo != SIGCONT) {
logv("sending signal %s(%d) to command '%s'",
- sys_signame[SIGCONT], SIGCONT, command);
+ sys_signame[SIGCONT], SIGCONT, command);
if (foreground) {
kill(pid, SIGCONT);
} else {
@@ -245,7 +219,7 @@ set_interval(double iv)
tim.it_value.tv_usec = (suseconds_t)(iv * 1000000UL);
}
- if (setitimer(ITIMER_REAL, &tim, NULL) == -1)
+ if (setitimer(ITIMER_REAL, &tim, NULL) < 0)
err(EXIT_FAILURE, "setitimer()");
}
@@ -261,20 +235,20 @@ kill_self(int signo)
sigset_t mask;
struct rlimit rl;
+ logv("killing self with signal %s(%d)", sys_signame[signo], signo);
+
+ /* Disable core generation. */
+ memset(&rl, 0, sizeof(rl));
+ setrlimit(RLIMIT_CORE, &rl);
+
/* Reset the signal disposition and make sure it's unblocked. */
signal(signo, SIG_DFL);
sigfillset(&mask);
sigdelset(&mask, signo);
sigprocmask(SIG_SETMASK, &mask, NULL);
- /* Disable core generation. */
- memset(&rl, 0, sizeof(rl));
- setrlimit(RLIMIT_CORE, &rl);
-
- logv("killing self with signal %s(%d)", sys_signame[signo], signo);
- kill(getpid(), signo);
- err(128 + signo, "signal %s(%d) failed to kill self",
- sys_signame[signo], signo);
+ raise(signo);
+ err(128 + signo, "raise(%d)", signo);
}
static void
@@ -285,7 +259,7 @@ log_termination(const char *name, const siginfo_t *si)
} else if (si->si_code == CLD_DUMPED || si->si_code == CLD_KILLED) {
logv("%s: pid=%d, sig=%d", name, si->si_pid, si->si_status);
} else {
- logv("%s: pid=%d, reason=%d, status=%d", si->si_pid,
+ logv("%s: pid=%d, reason=%d, status=%d", name, si->si_pid,
si->si_code, si->si_status);
}
}
@@ -293,22 +267,23 @@ log_termination(const char *name, const siginfo_t *si)
int
main(int argc, char **argv)
{
+ struct procctl_reaper_status info;
+ siginfo_t si, child_si;
+ struct sigaction sa;
+ sigset_t zeromask, allmask, oldmask;
+ double first_kill;
+ double second_kill = 0;
+ ssize_t error;
+ pid_t pid;
+ int pp[2];
int ch, sig;
int pstat = 0;
- pid_t pid;
- int pp[2], error;
char c;
- double first_kill;
- double second_kill = 0;
bool foreground = false;
bool preserve = false;
bool timedout = false;
bool do_second_kill = false;
bool child_done = false;
- sigset_t zeromask, allmask, oldmask;
- struct sigaction sa;
- struct procctl_reaper_status info;
- siginfo_t si, child_si;
const char optstr[] = "+fhk:ps:v";
const struct option longopts[] = {
@@ -334,7 +309,8 @@ main(int argc, char **argv)
preserve = true;
break;
case 's':
- killsig = parse_signal(optarg);
+ if (str2sig(optarg, &killsig) != 0)
+ errx(EXIT_INVALID, "invalid signal");
break;
case 'v':
verbose = true;
@@ -358,22 +334,22 @@ main(int argc, char **argv)
if (!foreground) {
/* Acquire a reaper */
- if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) == -1)
+ if (procctl(P_PID, getpid(), PROC_REAP_ACQUIRE, NULL) < 0)
err(EXIT_FAILURE, "procctl(PROC_REAP_ACQUIRE)");
}
/* Block all signals to avoid racing against the child. */
sigfillset(&allmask);
- if (sigprocmask(SIG_BLOCK, &allmask, &oldmask) == -1)
+ if (sigprocmask(SIG_BLOCK, &allmask, &oldmask) < 0)
err(EXIT_FAILURE, "sigprocmask()");
- if (pipe2(pp, O_CLOEXEC) == -1)
+ if (pipe2(pp, O_CLOEXEC) < 0)
err(EXIT_FAILURE, "pipe2");
pid = fork();
- if (pid == -1) {
+ if (pid < 0)
err(EXIT_FAILURE, "fork()");
- } else if (pid == 0) {
+ if (pid == 0) {
/*
* child process
*
@@ -382,11 +358,12 @@ main(int argc, char **argv)
* inherited, except for the signal to be sent upon timeout.
*/
signal(killsig, SIG_DFL);
- if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1)
+ if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0)
err(EXIT_FAILURE, "sigprocmask(oldmask)");
+ (void)close(pp[1]);
error = read(pp[0], &c, 1);
- if (error == -1)
+ if (error < 0)
err(EXIT_FAILURE, "read from control pipe");
if (error == 0)
errx(EXIT_FAILURE, "eof from control pipe");
@@ -396,6 +373,7 @@ main(int argc, char **argv)
}
/* parent continues here */
+ (void)close(pp[0]);
/* Catch all signals in order to propagate them. */
memset(&sa, 0, sizeof(sa));
@@ -403,25 +381,36 @@ main(int argc, char **argv)
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);
+ switch (sig) {
+ case SIGTTIN:
+ case SIGTTOU:
+ /* Don't stop if background child needs TTY */
+ if (signal(sig, SIG_IGN) == SIG_ERR)
+ err(EXIT_FAILURE, "signal(%d)", sig);
+ break;
+ case SIGKILL:
+ case SIGSTOP:
+ case SIGCONT:
+ /* These can't be caught or ignored */
+ break;
+ default:
+ if (sigaction(sig, &sa, NULL) < 0)
+ err(EXIT_FAILURE, "sigaction(%d)", sig);
+ }
}
- /* Don't stop if background child needs TTY */
- signal(SIGTTIN, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
-
+ /* Start the timer */
set_interval(first_kill);
+
+ /* Let the child know we're ready */
error = write(pp[1], "a", 1);
- if (error == -1)
+ if (error < 0)
err(EXIT_FAILURE, "write to control pipe");
if (error == 0)
errx(EXIT_FAILURE, "short write to control pipe");
- sigemptyset(&zeromask);
+ (void)close(pp[1]);
+ sigemptyset(&zeromask);
for (;;) {
sigsuspend(&zeromask);
@@ -430,9 +419,8 @@ main(int argc, char **argv)
for (;;) {
memset(&si, 0, sizeof(si));
- error = waitid(P_ALL, -1, &si, WEXITED |
- WNOHANG);
- if (error == -1) {
+ if (waitid(P_ALL, -1, &si,
+ WEXITED | WNOHANG) < 0) {
if (errno != EINTR)
break;
} else if (si.si_pid == pid) {
@@ -456,7 +444,7 @@ main(int argc, char **argv)
break;
} else {
procctl(P_PID, getpid(),
- PROC_REAP_STATUS, &info);
+ PROC_REAP_STATUS, &info);
if (info.rs_children == 0)
break;
}
@@ -471,7 +459,7 @@ main(int argc, char **argv)
sig = sig_term;
sig_term = 0;
logv("received terminating signal %s(%d)",
- sys_signame[sig], sig);
+ sys_signame[sig], sig);
}
send_sig(pid, sig, foreground);