The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=aa8cdb7cae7b7550d5cb81d85ee294c4f182f694

commit aa8cdb7cae7b7550d5cb81d85ee294c4f182f694
Author:     Konstantin Belousov <k...@freebsd.org>
AuthorDate: 2025-06-08 15:47:49 +0000
Commit:     Konstantin Belousov <k...@freebsd.org>
CommitDate: 2025-06-09 23:51:19 +0000

    timeout(1): only start the child command after the parent is fully set up
    
    Since the default disposition for SIGCHLD is ignore, the prematurely
    exited child would cause SIGCHLD dropped.  This makes timeout(1) hang,
    because REAP_STATUS reports a zombie not waited for, but SIGCHLD for it
    was already lost, so the main loop cannot exit, instead calling into
    sigsuspend().
    
    Reported and tested by: pho
    Reviewed by:    markj
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D50752
---
 bin/timeout/timeout.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/bin/timeout/timeout.c b/bin/timeout/timeout.c
index 05904522c5b5..f47976aa27df 100644
--- a/bin/timeout/timeout.c
+++ b/bin/timeout/timeout.c
@@ -26,7 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
+#include <sys/fcntl.h>
 #include <sys/procctl.h>
 #include <sys/resource.h>
 #include <sys/time.h>
@@ -283,6 +283,8 @@ main(int argc, char **argv)
        int ch, status, sig;
        int pstat = 0;
        pid_t pid, cpid;
+       int pp[2], error;
+       char c;
        double first_kill;
        double second_kill = 0;
        bool foreground = false;
@@ -351,6 +353,9 @@ main(int argc, char **argv)
        if (sigprocmask(SIG_BLOCK, &allmask, &oldmask) == -1)
                err(EXIT_FAILURE, "sigprocmask()");
 
+       if (pipe2(pp, O_CLOEXEC) == -1)
+               err(EXIT_FAILURE, "pipe2");
+
        pid = fork();
        if (pid == -1) {
                err(EXIT_FAILURE, "fork()");
@@ -366,6 +371,11 @@ main(int argc, char **argv)
                if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1)
                        err(EXIT_FAILURE, "sigprocmask(oldmask)");
 
+               error = read(pp[0], &c, 1);
+               if (error == -1)
+                       err(EXIT_FAILURE, "read from control pipe");
+               if (error == 0)
+                       errx(EXIT_FAILURE, "eof from control pipe");
                execvp(argv[0], argv);
                warn("exec(%s)", argv[0]);
                _exit(errno == ENOENT ? EXIT_CMD_NOENT : EXIT_CMD_ERROR);
@@ -391,6 +401,11 @@ main(int argc, char **argv)
        signal(SIGTTOU, SIG_IGN);
 
        set_interval(first_kill);
+       error = write(pp[1], "a", 1);
+       if (error == -1)
+               err(EXIT_FAILURE, "write to control pipe");
+       if (error == 0)
+               errx(EXIT_FAILURE, "short write to control pipe");
        sigemptyset(&zeromask);
 
        for (;;) {

Reply via email to