timeout: add --verbose to diagnose timeouts

This is useful as handling in shell is complicated
with the varying exit status in the --kill-after case.

* src/timeout.c (main): Handle '-v' and store
COMMAND for the diagnostic.
(cleanup): Diagnose the signal name before sending.
(usage): Document -v, --verbose.
* doc/coreutils.texi (timeout invocation): Likewise.
* tests/misc/timeout.sh: Add a test case.
* NEWS: Mention the new feature
Fixes https://bugs.gnu.org/21760
This commit is contained in:
Pádraig Brady
2017-11-23 14:30:59 -08:00
parent 31dd7a0de2
commit 559c7a57c7
4 changed files with 37 additions and 1 deletions

4
NEWS
View File

@@ -31,6 +31,10 @@ GNU coreutils NEWS -*- outline -*-
timeout would have then waited for the time limit to expire.
[bug introduced in coreutils-8.27]
** New features
timeout now supports the --verbose option to diagnose forced termination.
** Improvements
tail --bytes=NUM will efficiently seek to the end of block devices,

View File

@@ -17388,6 +17388,12 @@ the @var{command}.
Send this @var{signal} to @var{command} on timeout, rather than the
default @samp{TERM} signal. @var{signal} may be a name like @samp{HUP}
or a number. @xref{Signal specifications}.
@item -v
@itemx --verbose
@opindex -v
@opindex --verbose
Diagnose to stderr, any signal sent upon timeout.
@end table
@cindex time units

View File

@@ -83,6 +83,8 @@ static pid_t monitored_pid;
static double kill_after;
static bool foreground; /* whether to use another program group. */
static bool preserve_status; /* whether to use a timeout status or not. */
static bool verbose; /* whether to diagnose timeouts or not. */
static char const* command;
/* for long options with no corresponding short option, use enum */
enum
@@ -95,6 +97,7 @@ static struct option const long_options[] =
{
{"kill-after", required_argument, NULL, 'k'},
{"signal", required_argument, NULL, 's'},
{"verbose", no_argument, NULL, 'v'},
{"foreground", no_argument, NULL, FOREGROUND_OPTION},
{"preserve-status", no_argument, NULL, PRESERVE_STATUS_OPTION},
{GETOPT_HELP_OPTION_DECL},
@@ -196,6 +199,14 @@ cleanup (int sig)
/* Send the signal directly to the monitored child,
in case it has itself become group leader,
or is not running in a separate group. */
if (verbose)
{
char signame[MAX (SIG2STR_MAX, INT_BUFSIZE_BOUND (int))];
if (sig2str (sig, signame) != 0)
snprintf (signame, sizeof signame, "%d", sig);
error (0, 0, _("sending signal %s to command %s"),
signame, quote (command));
}
send_sig (monitored_pid, sig);
/* The normal case is the job has remained in our
@@ -246,6 +257,8 @@ Start COMMAND, and kill it if still running after DURATION.\n\
specify the signal to be sent on timeout;\n\
SIGNAL may be a name like 'HUP' or a number;\n\
see 'kill -l' for a list of signals\n"), stdout);
fputs (_("\
-v, --verbose diagnose to stderr any signal sent upon timeout\n"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -443,6 +456,10 @@ main (int argc, char **argv)
usage (EXIT_CANCELED);
break;
case 'v':
verbose = true;
break;
case FOREGROUND_OPTION:
foreground = true;
break;
@@ -467,6 +484,7 @@ main (int argc, char **argv)
timeout = parse_duration (argv[optind++]);
argv += optind;
command = argv[0];
/* Ensure we're in our own group so all subprocesses can be killed.
Note we don't just put the child in a separate group as
@@ -498,7 +516,7 @@ main (int argc, char **argv)
/* exit like sh, env, nohup, ... */
int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
error (0, errno, _("failed to run command %s"), quote (argv[0]));
error (0, errno, _("failed to run command %s"), quote (command));
return exit_status;
}
else

View File

@@ -57,4 +57,12 @@ out=$(sleep .1 & exec timeout .5 sh -c 'sleep 2; echo foo')
status=$?
test "$out" = "" && test $status = 124 || fail=1
# Verify --verbose output
timeout --verbose -s0 -k .1 .1 sleep 10 2> err
cat > exp <<\EOF
timeout: sending signal EXIT to command 'sleep'
timeout: sending signal KILL to command 'sleep'
EOF
compare exp err || fail=1
Exit $fail