5 * run command with bounded time
7 * \fBtimeout\fR [-\fIsignal\fR] \fItime\fR \fIcommand\fR ...
9 * \fBtimeout\fR executes a command and imposes an elapsed time limit.
10 * The command is run in a separate POSIX process group so that the
11 * right thing happens with commands that spawn child processes.
15 * Specify an optional signal to send to the controlled process.
16 * By default, \fBtimeout\fR sends SIGKILL, which cannot be caught
19 * The elapsed time limit after which the command is terminated.
21 * The command to be executed.
23 * The command exit status is the exit status of the command
24 * (status 1 in case of a usage error).
27 * This program is part of SATAN.
31 /* System libraries. */
33 #include <sys/types.h>
42 /* Application-specific. */
44 #define perrorexit(s) { perror(s); exit(1); }
45 #define WRITE(x) write(2, x, strlen(x))
47 static int kill_signal = SIGKILL;
48 static char *progname;
49 static char *commandname;
51 // fmt_ulong and fmt_long from libowfat {{{
52 unsigned int fmt_ulong(char *dest,unsigned long i) {
53 register unsigned long len,tmp,len2;
54 /* first count the number of bytes needed */
55 for (len=1, tmp=i; tmp>9; ++len) tmp/=10;
57 for (tmp=i, dest+=len, len2=len+1; --len2; tmp/=10)
58 *--dest = (tmp%10)+'0';
62 unsigned int fmt_long(char *dest,long int i) {
64 if (dest) *dest++='-';
65 return fmt_ulong(dest,-i)+1;
67 return fmt_ulong(dest,i);
73 //fprintf(stderr, "usage: %s [-signal] time command...\n", progname);
76 WRITE(" [-signal] time command...\n");
80 static void terminate(int sig)
82 signal(kill_signal, SIG_DFL);
83 //fprintf(stderr, "Timeout: aborting command ``%s'' with signal %d\n",
84 // commandname, kill_signal);
85 char kill_signal_string[22];
86 fmt_long(kill_signal_string, kill_signal);
87 WRITE("Timeout: aborting command ``");
89 WRITE("'' with signal ");
90 WRITE(kill_signal_string);
95 int main(int argc, char** argv)
107 while (--argc && *++argv && **argv == '-')
108 if ((kill_signal = atoi(*argv + 1)) <= 0)
111 if (argc < 2 || (time_to_run = atoi(argv[0])) <= 0)
114 commandname = argv[1];
117 * Run the command and its watchdog in a separate process group so that
118 * both can be killed off with one signal.
121 switch (child_pid = fork()) {
123 perrorexit("timeout: fork");
124 case 0: /* run controlled command */
125 execvp(argv[1], argv + 1);
127 default: /* become watchdog */
128 (void) signal(SIGHUP, terminate);
129 (void) signal(SIGINT, terminate);
130 (void) signal(SIGQUIT, terminate);
131 (void) signal(SIGTERM, terminate);
132 (void) signal(SIGALRM, terminate);
134 while ((pid = wait(&status)) != -1 && pid != child_pid)
136 return (pid == child_pid ? status : -1);
140 // vim: foldmethod=marker