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 (;;) {