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   if (toys.optflags & FLAG_v)
     43     fprintf(stderr, "timeout pid %d signal %d\n", TT.pid, TT.nextsig);
     44   kill(TT.pid, TT.nextsig);
     45 
     46   if (TT.k_timeout) {
     47     TT.k_timeout = 0;
     48     TT.nextsig = SIGKILL;
     49     xsignal(SIGALRM, handler);
     50     TT.itv.it_value = TT.ktv;
     51     setitimer(ITIMER_REAL, &TT.itv, (void *)toybuf);
     52   }
     53 }
     54 
     55 void timeout_main(void)
     56 {
     57   // Parse early to get any errors out of the way.
     58   TT.itv.it_value.tv_sec = xparsetime(*toys.optargs, 1000000, &TT.itv.it_value.tv_usec);
     59 
     60   if (TT.k_timeout)
     61     TT.ktv.tv_sec = xparsetime(TT.k_timeout, 1000000, &TT.ktv.tv_usec);
     62   TT.nextsig = SIGTERM;
     63   if (TT.s_signal && -1 == (TT.nextsig = sig_to_num(TT.s_signal)))
     64     error_exit("bad -s: '%s'", TT.s_signal);
     65 
     66   if (!(TT.pid = XVFORK())) xexec(toys.optargs+1);
     67   else {
     68     xsignal(SIGALRM, handler);
     69     setitimer(ITIMER_REAL, &TT.itv, (void *)toybuf);
     70     toys.exitval = xwaitpid(TT.pid);
     71   }
     72 }
     73