Home | History | Annotate | Download | only in other
      1 /* timeout.c - Run command line with a timeout
      2  *
      3  * Copyright 2013 Rob Landley <rob (at) landley.net>
      4  *
      5  * No standard
      6 
      7 USE_TIMEOUT(NEWTOY(timeout, "<2^vk:s: ", TOYFLAG_BIN))
      8 
      9 config TIMEOUT
     10   bool "timeout"
     11   default y
     12   depends on TOYBOX_FLOAT
     13   help
     14     usage: timeout [-k LENGTH] [-s SIGNAL] LENGTH COMMAND...
     15 
     16     Run command line as a child process, sending child a signal if the
     17     command doesn't exit soon enough.
     18 
     19     Length can be a decimal fraction. An optional suffix can be "m"
     20     (minutes), "h" (hours), "d" (days), or "s" (seconds, the default).
     21 
     22     -s	Send specified signal (default TERM)
     23     -k	Send KILL signal if child still running this long after first signal.
     24     -v	Verbose
     25 */
     26 
     27 #define FOR_timeout
     28 #include "toys.h"
     29 
     30 GLOBALS(
     31   char *s_signal;
     32   char *k_timeout;
     33 
     34   int nextsig;
     35   pid_t pid;
     36   struct timeval ktv;
     37   struct itimerval itv;
     38 )
     39 
     40 static void handler(int i)
     41 {
     42   fprintf(stderr, "timeout pid %d signal %d\n", TT.pid, TT.nextsig);
     43   kill(TT.pid, TT.nextsig);
     44 
     45   if (TT.k_timeout) {
     46     TT.k_timeout = 0;
     47     TT.nextsig = SIGKILL;
     48     xsignal(SIGALRM, handler);
     49     TT.itv.it_value = TT.ktv;
     50     setitimer(ITIMER_REAL, &TT.itv, (void *)toybuf);
     51   }
     52 }
     53 
     54 void timeout_main(void)
     55 {
     56   // Parse early to get any errors out of the way.
     57   TT.itv.it_value.tv_sec = xparsetime(*toys.optargs, 1000000, &TT.itv.it_value.tv_usec);
     58 
     59   if (TT.k_timeout)
     60     TT.ktv.tv_sec = xparsetime(TT.k_timeout, 1000000, &TT.ktv.tv_usec);
     61   TT.nextsig = SIGTERM;
     62   if (TT.s_signal && -1 == (TT.nextsig = sig_to_num(TT.s_signal)))
     63     error_exit("bad -s: '%s'", TT.s_signal);
     64 
     65   if (!(TT.pid = xfork())) xexec(toys.optargs+1);
     66   else {
     67     int status;
     68 
     69     xsignal(SIGALRM, handler);
     70     setitimer(ITIMER_REAL, &TT.itv, (void *)toybuf);
     71     while (-1 == waitpid(TT.pid, &status, 0) && errno == EINTR);
     72     toys.exitval = WIFEXITED(status)
     73       ? WEXITSTATUS(status) : WTERMSIG(status) + 127;
     74   }
     75 }
     76