logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/
commit: 142e21a38b1a52929cbf63650778bf3ed74bd3e3
parent 3452bf237ba357bcc76bfda0db4c90ccd5bd4403
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sun,  9 Nov 2025 19:25:21 +0100

cmd/time: propagate SIGTERM and SIGINT

Diffstat:

MMakefile3++-
Mcmd/time.19+++++++++
Mcmd/time.c33++++++++++++++++++++++++++++++++-
Atest-cmd/echosig.c33+++++++++++++++++++++++++++++++++
Mtest-cmd/time.sh16+++++++++++-----
5 files changed, 87 insertions(+), 7 deletions(-)

diff --git a/Makefile b/Makefile @@ -27,7 +27,7 @@ include common.mk selfcheck: selfcheck-cmds selfcheck-libs .PHONY: selfcheck-cmds -TEST_CMDS = test-cmd/pathchk-getlimits test-cmd/getpriority +TEST_CMDS = test-cmd/pathchk-getlimits test-cmd/getpriority test-cmd/echosig selfcheck-cmds: $(EXE) $(TEST_CMDS) LDSTATIC="$(LDSTATIC)" ./check-cmds.sh @@ -169,6 +169,7 @@ lib/sha256.o: lib/sha256.c lib/sha256.h lib/sha512.o: lib/sha512.c lib/sha512.h lib/bytes2hex.o: lib/bytes2hex.c lib/strconv.h +test-cmd/echosig: test-cmd/echosig.c build/sys_signame.c test-lib/t_sha1: test-lib/t_sha1.c lib/sha1.c lib/bytes2hex.o test-lib/t_sha256: test-lib/t_sha256.c lib/sha256.c lib/bytes2hex.o test-lib/t_sha512: test-lib/t_sha512.c lib/sha512.c lib/bytes2hex.o diff --git a/cmd/time.1 b/cmd/time.1 @@ -41,6 +41,15 @@ was found but couldn't be invoked .Ar command could not be found .El +.Sh SIGNALS +.Nm +propagates +.Dv SIGTERM +and +.Dv SIGINT +to it's child process, allowing constructs like +.Ql timeout 1s time yes +to work as expected. .Sh SEE ALSO .Xr getrusage 3 , .Xr times 3 diff --git a/cmd/time.c b/cmd/time.c @@ -6,6 +6,7 @@ #include "../libutils/getopt_nolong.h" #include <errno.h> +#include <signal.h> #include <spawn.h> #include <stdio.h> // perror, fprintf #include <stdlib.h> // abort @@ -19,6 +20,8 @@ extern char **environ; const char *argv0 = "time"; +static pid_t child = -1; + enum cmd_time_mode { CMD_TIME_POSIX = 0, @@ -26,6 +29,23 @@ enum cmd_time_mode }; static void +kill_child(int sig) +{ + if(child > 0) + { + if(kill(child, sig) != 0) + { + // candicate for sig2str + fprintf(stderr, + "time: warning: Failed propagating signal number %d to child process (%d): %s\n", + sig, + child, + strerror(errno)); + } + } +} + +static void usage(void) { fprintf(stderr, "Usage: time [-p|-v] command [argument ...]\n"); @@ -83,7 +103,6 @@ main(int argc, char *argv[]) return 1; } - pid_t child = -1; if(posix_spawnp(&child, argv[0], NULL, NULL, argv, environ) != 0) { ret = 126 + (errno == ENOENT); @@ -91,8 +110,20 @@ main(int argc, char *argv[]) return ret; } + struct sigaction sa = { + .sa_handler = &kill_child, + .sa_flags = 0, + }; + + if(sigaction(SIGTERM, &sa, NULL) != 0) + fprintf(stderr, "time: warning: Failed adding handler for SIGTERM: %s\n", strerror(errno)); + + if(sigaction(SIGINT, &sa, NULL) != 0) + fprintf(stderr, "time: warning: Failed adding handler for SIGINT: %s\n", strerror(errno)); + int status = 0; waitpid(child, &status, 0); + child = -1; // reaped clock_t t1 = times(&tms); if(t1 == -1) diff --git a/test-cmd/echosig.c b/test-cmd/echosig.c @@ -0,0 +1,33 @@ +// utils-std: Collection of commonly available Unix tools +// SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> +// SPDX-License-Identifier: CC0-1.0 OR WTFPL + +#define _DEFAULT_SOURCE +#include "../lib/sys_signame.h" + +#include <signal.h> +#include <stdio.h> + +int +main(void) +{ + sigset_t sigset; + int sig = -1; + + if(sigfillset(&sigset) != 0) return 1; + + if(sigprocmask(SIG_BLOCK, &sigset, NULL) != 0) return 1; + + if(sigwait(&sigset, &sig) != 0) return 1; + + if(sig > 0 && sig < NSIG && util_sys_signame[sig] != NULL) + { + printf("%s\n", util_sys_signame[sig]); + } + else + { + printf("%d\n", sig); + } + + return 0; +} diff --git a/test-cmd/time.sh b/test-cmd/time.sh @@ -2,7 +2,7 @@ # SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> # SPDX-License-Identifier: MPL-2.0 -plans=6 +plans=7 WD="$(dirname "$0")/../" target="${WD}/cmd/time" . "${WD}/test-cmd/tap.sh" @@ -18,7 +18,7 @@ $usage" time_fmt() { out=$(mktemp time_fmt.XXXXXX) - "$target" "$@" 2> "$out" + "$@" 2> "$out" err=$? cut -f1 -d '.' <"$out" @@ -32,13 +32,19 @@ real 0 user 0 sys 0 " -t_cmd --exit=1 false "$time_zeroes" time_fmt false -t_cmd true "$time_zeroes" time_fmt true +t_cmd --exit=1 false "$time_zeroes" time_fmt "$target" false +t_cmd true "$time_zeroes" time_fmt "$target" true t_cmd sleep_1 'real 1 user 0 sys 0 -' time_fmt "${WD}/cmd/sleep" 1 +' time_fmt "$target" "${WD}/cmd/sleep" 1 + +t_cmd --exit=124 timeout_sig 'TERM +real 0 +user 0 +sys 0 +' time_fmt "${WD}/cmd/timeout" 0.1s "${WD}/cmd/time" "${WD}/test-cmd/echosig" if test "NetBSD" = "$(uname -s)"; then t_skip "# NetBSD somehow doesn't returns ENOENT there, just errno = 0"