git: 2390cbfe55f5 - main - timeout(1): Fix the inheritance of signal dispositions
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 16 Apr 2025 19:46:36 UTC
The branch main has been updated by bapt: URL: https://cgit.FreeBSD.org/src/commit/?id=2390cbfe55f55916eca25e8ba94a3320535e01c9 commit 2390cbfe55f55916eca25e8ba94a3320535e01c9 Author: Aaron LI <aly@aaronly.me> AuthorDate: 2025-04-03 01:07:52 +0000 Commit: Baptiste Daroussin <bapt@FreeBSD.org> CommitDate: 2025-04-16 19:45:38 +0000 timeout(1): Fix the inheritance of signal dispositions POSIX.1-2024 requires that the child process inherit the same signal dispositions as the timeout(1) utility inherited, except for the signal to be sent upon timeout. For example, when timeout(1) is run by nohup(1), the command should be protected from SIGHUP. Obtained-from: DragonFly BSD --- bin/timeout/timeout.1 | 10 +++++++++- bin/timeout/timeout.c | 50 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/bin/timeout/timeout.1 b/bin/timeout/timeout.1 index 14fc19292684..371a167d19f3 100644 --- a/bin/timeout/timeout.1 +++ b/bin/timeout/timeout.1 @@ -24,7 +24,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd April 2, 2025 +.Dd April 3, 2025 .Dt TIMEOUT 1 .Os .Sh NAME @@ -65,6 +65,14 @@ Therefore, a signal is never sent if .Ar duration is 0. .Pp +The signal dispositions inherited by the +.Ar command +are the same as the dispositions that +.Nm +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 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 8a2f0faecd83..1c4cfa6e017d 100644 --- a/bin/timeout/timeout.c +++ b/bin/timeout/timeout.c @@ -224,6 +224,7 @@ main(int argc, char **argv) bool timedout = false; bool do_second_kill = false; bool child_done = false; + sigset_t zeromask, allmask, oldmask; struct sigaction signals; struct procctl_reaper_status info; int signums[] = { @@ -288,6 +289,33 @@ main(int argc, char **argv) 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) + err(EXIT_FAILURE, "sigprocmask()"); + + pid = fork(); + if (pid == -1) { + err(EXIT_FAILURE, "fork()"); + } else if (pid == 0) { + /* + * child process + * + * POSIX.1-2024 requires that the child process inherit the + * same signal dispositions as the timeout(1) utility + * inherited, except for the signal to be sent upon timeout. + */ + signal(killsig, SIG_DFL); + if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) + err(EXIT_FAILURE, "sigprocmask(oldmask)"); + + execvp(argv[0], argv); + warn("exec(%s)", argv[0]); + _exit(errno == ENOENT ? EXIT_CMD_NOENT : EXIT_CMD_ERROR); + } + + /* parent continues here */ + memset(&signals, 0, sizeof(signals)); sigemptyset(&signals.sa_mask); @@ -310,29 +338,11 @@ main(int argc, char **argv) signal(SIGTTIN, SIG_IGN); signal(SIGTTOU, SIG_IGN); - pid = fork(); - if (pid == -1) { - err(EXIT_FAILURE, "fork()"); - } else if (pid == 0) { - /* child process */ - signal(SIGTTIN, SIG_DFL); - signal(SIGTTOU, SIG_DFL); - - execvp(argv[0], argv); - warn("exec(%s)", argv[0]); - _exit(errno == ENOENT ? EXIT_CMD_NOENT : EXIT_CMD_ERROR); - } - - /* parent continues here */ - - if (sigprocmask(SIG_BLOCK, &signals.sa_mask, NULL) == -1) - err(EXIT_FAILURE, "sigprocmask()"); - set_interval(first_kill); - sigemptyset(&signals.sa_mask); + sigemptyset(&zeromask); for (;;) { - sigsuspend(&signals.sa_mask); + sigsuspend(&zeromask); if (sig_chld) { sig_chld = 0;