diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2013-02-16 14:42:43 +0000 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2013-02-16 14:42:43 +0000 |
commit | 7548e75065063dae256d94e6c7f4f9f43bd7f210 (patch) | |
tree | f23b000f8822f6eb70249c1106a3275deaa03bac /src/timeout.c | |
parent | ddefcddae2e97579f82320f4fd70d0ba14a52392 (diff) | |
parent | 974ab3dd887985e3aa347f3c6521f819296396a0 (diff) | |
download | coreutils-7548e75065063dae256d94e6c7f4f9f43bd7f210.tar.gz |
Merge tag 'upstream/8.21'
Upstream version 8.21
Diffstat (limited to 'src/timeout.c')
-rw-r--r-- | src/timeout.c | 95 |
1 files changed, 70 insertions, 25 deletions
diff --git a/src/timeout.c b/src/timeout.c index c0a25274..2ffd2b11 100644 --- a/src/timeout.c +++ b/src/timeout.c @@ -1,5 +1,5 @@ /* timeout -- run a command with bounded time - Copyright (C) 2008-2012 Free Software Foundation, Inc. + Copyright (C) 2008-2013 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 @@ -49,6 +49,9 @@ #include <stdio.h> #include <sys/types.h> #include <signal.h> +#if HAVE_PRCTL +# include <sys/prctl.h> +#endif #include <sys/wait.h> #include "system.h" @@ -78,12 +81,14 @@ static int timed_out; static int term_signal = SIGTERM; /* same default as kill command. */ static int monitored_pid; static double kill_after; -static bool foreground; /* whether to use another program group. */ +static bool foreground; /* whether to use another program group. */ +static bool preserve_status; /* whether to use a timeout status or not. */ /* for long options with no corresponding short option, use enum */ enum { - FOREGROUND_OPTION = CHAR_MAX + 1 + FOREGROUND_OPTION = CHAR_MAX + 1, + PRESERVE_STATUS_OPTION }; static struct option const long_options[] = @@ -91,11 +96,22 @@ static struct option const long_options[] = {"kill-after", required_argument, NULL, 'k'}, {"signal", required_argument, NULL, 's'}, {"foreground", no_argument, NULL, FOREGROUND_OPTION}, + {"preserve-status", no_argument, NULL, PRESERVE_STATUS_OPTION}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0} }; +static void +unblock_signal (int sig) +{ + sigset_t unblock_set; + sigemptyset (&unblock_set); + sigaddset (&unblock_set, sig); + if (sigprocmask (SIG_UNBLOCK, &unblock_set, NULL) != 0) + error (0, errno, _("warning: sigprocmask")); +} + /* Start the timeout after which we'll receive a SIGALRM. Round DURATION up to the next representable value. Treat out-of-range values as if they were maximal, @@ -104,6 +120,11 @@ static struct option const long_options[] = static void settimeout (double duration) { + + /* We configure timers below so that SIGALRM is sent on expiry. + Therefore ensure we don't inherit a mask blocking SIGALRM. */ + unblock_signal (SIGALRM); + /* timer_settime() provides potentially nanosecond resolution. setitimer() is more portable (to Darwin for example), but only provides microsecond resolution and thus is @@ -207,10 +228,14 @@ Usage: %s [OPTION] DURATION COMMAND [ARG]...\n\ fputs (_("\ Start COMMAND, and kill it if still running after DURATION.\n\ -\n\ -Mandatory arguments to long options are mandatory for short options too.\n\ "), stdout); + + emit_mandatory_arg_note (); + fputs (_("\ + --preserve-status\n\ + exit with the same status as COMMAND, even when the\n\ + command times out\n\ --foreground\n\ When not running timeout directly from a shell prompt,\n\ allow COMMAND to read from the TTY and receive TTY signals.\n\ @@ -232,12 +257,12 @@ DURATION is a floating point number with an optional suffix:\n\ 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\ -signal upon timeout. The TERM signal kills any process that does not\n\ -block or catch that signal. For other processes, it may be necessary to\n\ -use the KILL (9) signal, since this signal cannot be caught. If the\n\ -KILL (9) signal is sent, the exit status is 128+9 rather than 124.\n"), stdout); +If the command times out, and --preserve-status is not set, then exit with\n\ +status 124. Otherwise, exit with the status of COMMAND. If no signal\n\ +is specified, send the TERM signal upon timeout. The TERM signal kills\n\ +any process that does not block or catch that signal. It may be necessary\n\ +to use the KILL (9) signal, since this signal cannot be caught, in which\n\ +case the exit status is 128+9 rather than 124.\n"), stdout); emit_ancillary_info (); } exit (status); @@ -316,6 +341,29 @@ install_signal_handlers (int sigterm) sigaction (sigterm, &sa, NULL); /* user specified termination signal. */ } +/* Try to disable core dumps for this process. + Return TRUE if successful, FALSE otherwise. */ +static bool +disable_core_dumps (void) +{ +#if HAVE_PRCTL && defined PR_SET_DUMPABLE + if (prctl (PR_SET_DUMPABLE, 0) == 0) + return true; + +#elif HAVE_SETRLIMIT && defined RLIMIT_CORE + /* Note this doesn't disable processing by a filter in + /proc/sys/kernel/core_pattern on Linux. */ + if (setrlimit (RLIMIT_CORE, &(struct rlimit) {0,0}) == 0) + return true; + +#else + return false; +#endif + + error (0, errno, _("warning: disabling core dumps failed")); + return false; +} + int main (int argc, char **argv) { @@ -350,6 +398,10 @@ main (int argc, char **argv) foreground = true; break; + case PRESERVE_STATUS_OPTION: + preserve_status = true; + break; + case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); @@ -426,21 +478,14 @@ main (int argc, char **argv) else if (WIFSIGNALED (status)) { int sig = WTERMSIG (status); -/* The following is not used as one cannot disable processing - by a filter in /proc/sys/kernel/core_pattern on Linux. */ -#if 0 && HAVE_SETRLIMIT && defined RLIMIT_CORE - if (!timed_out) + if (WCOREDUMP (status)) + error (0, 0, _("the monitored command dumped core")); + if (!timed_out && disable_core_dumps ()) { - /* exit with the signal flag set, but avoid core files. */ - if (setrlimit (RLIMIT_CORE, &(struct rlimit) {0,0}) == 0) - { - signal (sig, SIG_DFL); - raise (sig); - } - else - error (0, errno, _("warning: disabling core dumps failed")); + /* exit with the signal flag set. */ + signal (sig, SIG_DFL); + raise (sig); } -#endif status = sig + 128; /* what sh returns for signaled processes. */ } else @@ -451,7 +496,7 @@ main (int argc, char **argv) } } - if (timed_out) + if (timed_out && !preserve_status) return EXIT_TIMEDOUT; else return status; |