git: 613310263ae1 - main - timeout(1): Kill self with the same signal that terminated the child
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 16 Apr 2025 19:46:38 UTC
The branch main has been updated by bapt: URL: https://cgit.FreeBSD.org/src/commit/?id=613310263ae1f0f65df498dc8e98f460b781946d commit 613310263ae1f0f65df498dc8e98f460b781946d Author: Aaron LI <aly@aaronly.me> AuthorDate: 2025-04-03 02:51:06 +0000 Commit: Baptiste Daroussin <bapt@FreeBSD.org> CommitDate: 2025-04-16 19:45:38 +0000 timeout(1): Kill self with the same signal that terminated the child A shell may not set '$?' to '128 + signal_number' when the process was terminated by a signal. For example, KornShell 93 sets '$?' to '256 + signal_number' in such cases. In order to avoid any possible ambiguity, the POSIX.1-2024 standard requires that timeout mimic the wait status of the child process by terminating itself with the same signal, while disabling core generation. Update the man page accordingly. Obtained-from: DragonFly BSD Reference: https://pubs.opengroup.org/onlinepubs/9799919799/utilities/timeout.html --- bin/timeout/timeout.1 | 51 ++++++++++++++++++++++++--------------------------- bin/timeout/timeout.c | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/bin/timeout/timeout.1 b/bin/timeout/timeout.1 index 44525daaec59..43a484dac76f 100644 --- a/bin/timeout/timeout.1 +++ b/bin/timeout/timeout.1 @@ -146,37 +146,33 @@ hours days .El .Sh EXIT STATUS -If the timeout was not reached, the exit status of -.Ar command -is returned. -.Pp -If the timeout was reached and -.Fl -preserve-status -is set, the exit status of -.Ar command -is returned. -If +If the time limit was reached and the .Fl -preserve-status -is not set, an exit status of 124 is returned. -.Pp -If an invalid parameter is passed to -.Fl s -or -.Fl k , -the exit status returned is 125. -.Pp -If +option is not specified, the exit status is 124. +Otherwise, +.Nm +exits with the same exit status as the +.Ar command . +For example, +.Nm +will terminate itself with the same signal if the .Ar command -is an otherwise invalid program, the exit status returned is 126. +is terminated by a signal. .Pp -If +If an error occurred, the following exit values are returned: +.Bl -tag -offset indent with indent -compact +.It 125 +An error other than the two described below occurred. +For example, an invalid duration or signal was specified. +.It 126 +The .Ar command -refers to a non-existing program, the exit status returned is 127. -.Pp -If +was found but could not be executed. +.It 127 +The .Ar command -exits after receiving a signal, the exit status returned is the signal number -plus 128. +could not be found. +.El .Sh EXAMPLES Run .Xr sleep 1 @@ -202,7 +198,8 @@ $ echo $? .Pp Same as above but preserving status. The exit status is 128 + signal number (15 for -.Dv SIGTERM ) : +.Dv SIGTERM ) +for most shells: .Bd -literal -offset indent $ timeout --preserve-status 2 sleep 4 $ echo $? diff --git a/bin/timeout/timeout.c b/bin/timeout/timeout.c index 6e93e9e2911c..e9c4e22fc7d3 100644 --- a/bin/timeout/timeout.c +++ b/bin/timeout/timeout.c @@ -28,6 +28,7 @@ #include <sys/cdefs.h> #include <sys/procctl.h> +#include <sys/resource.h> #include <sys/time.h> #include <sys/wait.h> @@ -239,6 +240,34 @@ set_interval(double iv) err(EXIT_FAILURE, "setitimer()"); } +/* + * In order to avoid any possible ambiguity that a shell may not set '$?' to + * '128+signal_number', POSIX.1-2024 requires that timeout mimic the wait + * status of the child process by terminating itself with the same signal, + * while disabling core generation. + */ +static void __dead2 +kill_self(int signo) +{ + sigset_t mask; + struct rlimit 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); +} + int main(int argc, char **argv) { @@ -430,10 +459,12 @@ main(int argc, char **argv) if (timedout && !preserve) { pstat = EXIT_TIMEOUT; } else { + if (WIFSIGNALED(pstat)) + kill_self(WTERMSIG(pstat)); + /* NOTREACHED */ + if (WIFEXITED(pstat)) pstat = WEXITSTATUS(pstat); - else if (WIFSIGNALED(pstat)) - pstat = 128 + WTERMSIG(pstat); } return (pstat);