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 <[email protected]>
AuthorDate: 2026-02-13 20:18:35 +0000
Commit:     Dag-Erling Smørgrav <[email protected]>
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);

Reply via email to