summaryrefslogtreecommitdiff
path: root/src/timeout.c
diff options
context:
space:
mode:
authorIgor Pashev <pashev.igor@gmail.com>2013-02-16 14:42:43 +0000
committerIgor Pashev <pashev.igor@gmail.com>2013-02-16 14:42:43 +0000
commit7548e75065063dae256d94e6c7f4f9f43bd7f210 (patch)
treef23b000f8822f6eb70249c1106a3275deaa03bac /src/timeout.c
parentddefcddae2e97579f82320f4fd70d0ba14a52392 (diff)
parent974ab3dd887985e3aa347f3c6521f819296396a0 (diff)
downloadcoreutils-7548e75065063dae256d94e6c7f4f9f43bd7f210.tar.gz
Merge tag 'upstream/8.21'
Upstream version 8.21
Diffstat (limited to 'src/timeout.c')
-rw-r--r--src/timeout.c95
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;