diff options
author | Pádraig Brady <P@draigBrady.com> | 2010-03-15 23:03:30 +0000 |
---|---|---|
committer | Pádraig Brady <P@draigBrady.com> | 2010-03-16 23:10:15 +0000 |
commit | c403c31e8806b732e1164ef4a206b0eab71bca95 (patch) | |
tree | c593bccff037db3c5f332810aec7dfbc33a30683 /src | |
parent | 4edb86215deec3ad7478eb4eca54d563bd3b95c0 (diff) | |
download | coreutils-c403c31e8806b732e1164ef4a206b0eab71bca95.tar.xz |
timeout: add the --kill-after option
Based on a report from Kim Hansen who wanted to
send a KILL signal to the monitored command
when `timeout` itself received a termination signal.
Rather than changing such a signal into a KILL,
we provide the more general mechanism of sending
the KILL after the specified grace period.
* src/timeout.c (cleanup): If a non zero kill delay
is specified, (re)set the alarm to that delay, after
which a KILL signal will be sent to the process group.
(usage): Mention the new option. Separate the description
of DURATION since it's now specified in 2 places.
Clarify that the duration is an integer.
(parse_duration): A new function refactored from main(),
since this logic is now called for two parameters.
(main): Parse the -k option.
* doc/coreutils.texi (timeout invocation): Describe the
new --kill-after option and use @display rather than
@table to show the duration suffixes. Clarify that
a duration of 0 disables the associated timeout.
* tests/misc/timeout-parameters: Check invalid --kill-after.
* tests/misc/timeout: Check a valid --kill-after works.
* NEWS: Mention the new feature.
Diffstat (limited to 'src')
-rw-r--r-- | src/timeout.c | 69 |
1 files changed, 47 insertions, 22 deletions
diff --git a/src/timeout.c b/src/timeout.c index 10dcbe855..49fc4d879 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -77,9 +77,11 @@ static int timed_out; static int term_signal = SIGTERM; /* same default as kill command. */ static int monitored_pid; static int sigs_to_ignore[NSIG]; /* so monitor can ignore sigs it resends. */ +static unsigned long kill_after; static struct option const long_options[] = { + {"kill-after", required_argument, NULL, 'k'}, {"signal", required_argument, NULL, 's'}, {NULL, 0, NULL, 0} }; @@ -108,6 +110,13 @@ cleanup (int sig) sigs_to_ignore[sig] = 0; return; } + if (kill_after) + { + /* Start a new timeout after which we'll send SIGKILL. */ + term_signal = SIGKILL; + alarm (kill_after); + kill_after = 0; /* Don't let later signals reset kill alarm. */ + } send_sig (0, sig); if (sig != SIGKILL && sig != SIGCONT) send_sig (0, SIGCONT); @@ -125,20 +134,18 @@ usage (int status) else { printf (_("\ -Usage: %s [OPTION] NUMBER[SUFFIX] COMMAND [ARG]...\n\ +Usage: %s [OPTION] DURATION COMMAND [ARG]...\n\ or: %s [OPTION]\n"), program_name, program_name); fputs (_("\ -Start COMMAND, and kill it if still running after NUMBER seconds.\n\ -SUFFIX may be `s' for seconds (the default), `m' for minutes,\n\ -`h' for hours or `d' for days.\n\ +Start COMMAND, and kill it if still running after DURATION.\n\ \n\ -"), stdout); - - fputs (_("\ Mandatory arguments to long options are mandatory for short options too.\n\ "), stdout); fputs (_("\ + -k, --kill-after=DURATION\n\ + also send a KILL signal if COMMAND is still running\n\ + this long after the initial signal was sent.\n\ -s, --signal=SIGNAL\n\ specify the signal to be sent on timeout.\n\ SIGNAL may be a name like `HUP' or a number.\n\ @@ -146,6 +153,12 @@ Mandatory arguments to long options are mandatory for short options too.\n\ fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); + + fputs (_("\n\ +DURATION is an integer with an optional suffix:\n\ +`s' for seconds(the default), `m' for minutes, `h' for hours or `d' for days.\n\ +"), stdout); + fputs (_("\n\ If the command times out, then exit with status 124. Otherwise, exit\n\ with the status of COMMAND. If no signal is specified, send the TERM\n\ @@ -195,11 +208,32 @@ apply_time_suffix (unsigned long *x, char suffix_char) return true; } +static unsigned long +parse_duration (const char* str) +{ + unsigned long duration; + char *ep; + + if (xstrtoul (str, &ep, 10, &duration, NULL) + /* Invalid interval. Note 0 disables timeout */ + || (duration > UINT_MAX) + /* Extra chars after the number and an optional s,m,h,d char. */ + || (*ep && *(ep + 1)) + /* Check any suffix char and update timeout based on the suffix. */ + || !apply_time_suffix (&duration, *ep)) + { + error (0, 0, _("invalid time interval %s"), quote (str)); + usage (EXIT_CANCELED); + } + + return duration; +} + static void install_signal_handlers (int sigterm) { struct sigaction sa; - sigemptyset(&sa.sa_mask); /* Allow concurrent calls to handler */ + sigemptyset (&sa.sa_mask); /* Allow concurrent calls to handler */ sa.sa_handler = cleanup; sa.sa_flags = SA_RESTART; /* restart syscalls (like wait() below) */ @@ -217,7 +251,6 @@ main (int argc, char **argv) unsigned long timeout; char signame[SIG2STR_MAX]; int c; - char *ep; initialize_main (&argc, &argv); set_program_name (argv[0]); @@ -231,10 +264,13 @@ main (int argc, char **argv) parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version, usage, AUTHORS, (char const *) NULL); - while ((c = getopt_long (argc, argv, "+s:", long_options, NULL)) != -1) + while ((c = getopt_long (argc, argv, "+k:s:", long_options, NULL)) != -1) { switch (c) { + case 'k': + kill_after = parse_duration (optarg); + break; case 's': term_signal = operand2sig (optarg, signame); if (term_signal == -1) @@ -249,18 +285,7 @@ main (int argc, char **argv) if (argc - optind < 2) usage (EXIT_CANCELED); - if (xstrtoul (argv[optind], &ep, 10, &timeout, NULL) - /* Invalid interval. Note 0 disables timeout */ - || (timeout > UINT_MAX) - /* Extra chars after the number and an optional s,m,h,d char. */ - || (*ep && *(ep + 1)) - /* Check any suffix char and update timeout based on the suffix. */ - || !apply_time_suffix (&timeout, *ep)) - { - error (0, 0, _("invalid time interval %s"), quote (argv[optind])); - usage (EXIT_CANCELED); - } - optind++; + timeout = parse_duration (argv[optind++]); argv += optind; |