mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-08-05 08:10:15 +02:00
timeout: add --foreground to support interactive commands
Or more accurately, commands not started from the shell prompt, that are interactive, or need to receive Ctrl-C etc. from the terminal. * doc/coreutils.texi (timeout invocation): Document --foreground. * src/timeout.c (main): Set the foreground flag and don't create a separate group. (cleanup): Only send a signal directly to the monitored command when the foreground flag is set. (usage): Describe --foreground. * tests/misc/timeout-group: Add a new test. * tests/Makefile.am: Reference new test. NEWS: Mention the new option. Reported by Shay Shimony Analysis by Alan Curry Fix suggested by Paul Eggert
This commit is contained in:
@@ -33,6 +33,10 @@ GNU coreutils NEWS -*- outline -*-
|
||||
tool exit non-zero for any invalid input line, rather than just warning.
|
||||
This also affects sha1sum, sha224sum, sha384sum and sha512sum.
|
||||
|
||||
timeout accepts a new --foreground option, to support commands not started
|
||||
directly from a shell prompt, where the command is interactive or needs to
|
||||
receive signals initiated from the terminal.
|
||||
|
||||
** Improvements
|
||||
|
||||
shuf outputs small subsets of large permutations much more efficiently.
|
||||
|
||||
@@ -15658,6 +15658,23 @@ The program accepts the following options. Also see @ref{Common options}.
|
||||
Options must precede operands.
|
||||
|
||||
@table @samp
|
||||
@itemx --foreground
|
||||
@opindex --foreground
|
||||
Don't create a separate background program group, so that
|
||||
the managed @var{command} can use the foreground TTY normally.
|
||||
This is needed to support timing out commands not started
|
||||
directly from an interactive shell, in two situations.
|
||||
@enumerate
|
||||
@item
|
||||
@var{command} is interactive and needs to read from the terminal for example
|
||||
@item
|
||||
the user wants to support sending signals directly to @var{command}
|
||||
from the terminal (like Ctrl-C for example)
|
||||
@end enumerate
|
||||
|
||||
Note in this mode of operation, any children of @var{command}
|
||||
will not be timed out.
|
||||
|
||||
@item -k @var{duration}
|
||||
@itemx --kill-after=@var{duration}
|
||||
@opindex -k
|
||||
|
||||
+28
-8
@@ -67,11 +67,19 @@ 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 bool foreground; /* whether to use another program group. */
|
||||
|
||||
/* for long options with no corresponding short option, use enum */
|
||||
enum
|
||||
{
|
||||
FOREGROUND_OPTION = CHAR_MAX + 1
|
||||
};
|
||||
|
||||
static struct option const long_options[] =
|
||||
{
|
||||
{"kill-after", required_argument, NULL, 'k'},
|
||||
{"signal", required_argument, NULL, 's'},
|
||||
{"foreground", no_argument, NULL, FOREGROUND_OPTION},
|
||||
{GETOPT_HELP_OPTION_DECL},
|
||||
{GETOPT_VERSION_OPTION_DECL},
|
||||
{NULL, 0, NULL, 0}
|
||||
@@ -96,6 +104,8 @@ cleanup (int sig)
|
||||
}
|
||||
if (monitored_pid)
|
||||
{
|
||||
int where = foreground ? monitored_pid : 0;
|
||||
|
||||
if (sigs_to_ignore[sig])
|
||||
{
|
||||
sigs_to_ignore[sig] = 0;
|
||||
@@ -108,9 +118,10 @@ cleanup (int sig)
|
||||
alarm (kill_after);
|
||||
kill_after = 0; /* Don't let later signals reset kill alarm. */
|
||||
}
|
||||
send_sig (0, sig);
|
||||
|
||||
send_sig (where, sig);
|
||||
if (sig != SIGKILL && sig != SIGCONT)
|
||||
send_sig (0, SIGCONT);
|
||||
send_sig (where, SIGCONT);
|
||||
}
|
||||
else /* we're the child or the child is not exec'd yet. */
|
||||
_exit (128 + sig);
|
||||
@@ -134,13 +145,17 @@ Start COMMAND, and kill it if still running after DURATION.\n\
|
||||
Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
--foreground\n\
|
||||
When not running timeout directly from a shell prompt,\n\
|
||||
allow COMMAND to read from the TTY and receive TTY signals.\n\
|
||||
In this mode, children of COMMAND will not be timed out.\n\
|
||||
-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\
|
||||
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\
|
||||
See `kill -l` for a list of signals\n"), stdout);
|
||||
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 (HELP_OPTION_DESCRIPTION, stdout);
|
||||
fputs (VERSION_OPTION_DESCRIPTION, stdout);
|
||||
@@ -266,6 +281,10 @@ main (int argc, char **argv)
|
||||
usage (EXIT_CANCELED);
|
||||
break;
|
||||
|
||||
case FOREGROUND_OPTION:
|
||||
foreground = true;
|
||||
break;
|
||||
|
||||
case_GETOPT_HELP_CHAR;
|
||||
|
||||
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
|
||||
@@ -287,7 +306,8 @@ main (int argc, char **argv)
|
||||
Note we don't just put the child in a separate group as
|
||||
then we would need to worry about foreground and background groups
|
||||
and propagating signals between them. */
|
||||
setpgid (0, 0);
|
||||
if (!foreground)
|
||||
setpgid (0, 0);
|
||||
|
||||
/* Setup handlers before fork() so that we
|
||||
handle any signals caused by child, without races. */
|
||||
|
||||
@@ -277,6 +277,7 @@ TESTS = \
|
||||
misc/tee-dash \
|
||||
misc/test-diag \
|
||||
misc/timeout \
|
||||
misc/timeout-group \
|
||||
misc/timeout-parameters \
|
||||
misc/tr \
|
||||
misc/tr-case-class \
|
||||
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
#!/bin/sh
|
||||
# test program group handling
|
||||
|
||||
# Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
. "${srcdir=.}/init.sh"; path_prepend_ ../src
|
||||
print_ver_ timeout
|
||||
|
||||
# construct a program group hierarchy as follows:
|
||||
# timeout-group - foreground group
|
||||
# group.sh - separate group
|
||||
# timeout.cmd - same group as group.sh
|
||||
#
|
||||
# We then send a SIGINT to the "separate group"
|
||||
# to simulate what happens when a Ctrl-C
|
||||
# is sent to the foreground group.
|
||||
|
||||
setsid true || skip_ "setsid required to control groups"
|
||||
|
||||
cat > timeout.cmd <<\EOF
|
||||
#!/bin/sh
|
||||
trap 'touch int.received; exit' INT
|
||||
touch timeout.running
|
||||
sleep 10
|
||||
EOF
|
||||
chmod a+x timeout.cmd
|
||||
|
||||
cat > group.sh <<\EOF
|
||||
#!/bin/sh
|
||||
timeout --foreground 5 ./timeout.cmd&
|
||||
wait
|
||||
EOF
|
||||
chmod a+x group.sh
|
||||
|
||||
# Start above script in its own group.
|
||||
# We could use timeout for this, but that assumes an implementation.
|
||||
setsid ./group.sh &
|
||||
until test -e timeout.running; do sleep .1; done
|
||||
# Simulate a Ctrl-C to the group to test timely exit
|
||||
# Note dash doesn't support signalling groups (a leading -)
|
||||
env kill -INT -- -$!
|
||||
wait
|
||||
test -e int.received || fail=1
|
||||
|
||||
Exit $fail
|
||||
Reference in New Issue
Block a user