• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* timeout.c - Run command line with a timeout
2  *
3  * Copyright 2013 Rob Landley <rob@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 
GLOBALS(char * s_signal;char * k_timeout;int nextsig;pid_t pid;struct timeval ktv;struct itimerval itv;)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 
timeout_main(void)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