Subject: bug#6308: Preserve command exit code in timeout(3)

From: "Ángel González" <[email-masked]>
Date: Sun, 30 May 2010 02:15:20 +0200

I wanted to keep the original exit status of the command run by
timeout(3), even after sending a timeout signal.
Thus I added a --exit-status parameter to it. Here it is in case you
find that useful, too.

diff --git a/src/timeout.c b/src/timeout.c
index e2234c3..29f5bec 100644
--- a/src/timeout.c
+++ b/src/timeout.c
@@ -64,6 +64,7 @@
 #define AUTHORS proper_name_utf8 ("Padraig Brady", "P\303\241draig Brady")
 
 static int timed_out;
+static int command_exit_status = 0;
 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.  */
@@ -73,6 +74,7 @@ static struct option const long_options[] =
 {
   {"kill-after", required_argument, NULL, 'k'},
   {"signal", required_argument, NULL, 's'},
+  {"exit-status", no_argument, NULL, 'x'},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -141,7 +143,10 @@ Mandatory arguments to long options are mandatory for short options too.\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);
+                   See `kill -l` for a list of signals\n\
+  -x, --exit-status\n\
+                   exit with the same status as COMMAND even if the \n\
+                   command timed out\n"), stdout);
 
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -152,11 +157,12 @@ DURATION is an integer with an optional suffix:\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.\n"), stdout);
+If the command times out, and --exit-status was 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.  For other processes, \n\
+it may be necessary to use the KILL (9) signal, since this signal cannot \n\
+be caught.\n"), stdout);
       emit_ancillary_info ();
     }
   exit (status);
@@ -253,7 +259,7 @@ main (int argc, char **argv)
   initialize_exit_failure (EXIT_CANCELED);
   atexit (close_stdout);
 
-  while ((c = getopt_long (argc, argv, "+k:s:", long_options, NULL)) != -1)
+  while ((c = getopt_long (argc, argv, "+k:s:x", long_options, NULL)) != -1)
     {
       switch (c)
         {
@@ -266,6 +272,9 @@ main (int argc, char **argv)
           if (term_signal == -1)
             usage (EXIT_CANCELED);
           break;
+		case 'x':
+			command_exit_status = 1;
+			break;
 
         case_GETOPT_HELP_CHAR;
 
@@ -351,7 +360,7 @@ main (int argc, char **argv)
             }
         }
 
-      if (timed_out)
+      if (timed_out && !command_exit_status)
         return EXIT_TIMEDOUT;
       else
         return status;