From: Michael Prokop Date: Fri, 17 Nov 2006 18:58:18 +0000 (+0100) Subject: add binary timeout itself X-Git-Tag: 0.74~1 X-Git-Url: http://git.grml.org/?p=grml-terminalserver.git;a=commitdiff_plain;h=80fced30b0188cc47c32f4bbdece9e80d4263bf7 add binary timeout itself --- diff --git a/timeout b/timeout new file mode 100755 index 0000000..e5c8241 Binary files /dev/null and b/timeout differ diff --git a/timeout.c b/timeout.c new file mode 100644 index 0000000..8cda986 --- /dev/null +++ b/timeout.c @@ -0,0 +1,108 @@ +/*++ +/* NAME +/* timeout 1 +/* SUMMARY +/* run command with bounded time +/* SYNOPSIS +/* \fBtimeout\fR [-\fIsignal\fR] \fItime\fR \fIcommand\fR ... +/* DESCRIPTION +/* \fBtimeout\fR executes a command and imposes an elapsed time limit. +/* The command is run in a separate POSIX process group so that the +/* right thing happens with commands that spawn child processes. +/* +/* Arguments: +/* .IP \fI-signal\fR +/* Specify an optional signal to send to the controlled process. +/* By default, \fBtimeout\fR sends SIGKILL, which cannot be caught +/* or ignored. +/* .IP \fItime\fR +/* The elapsed time limit after which the command is terminated. +/* .IP \fIcommand\fR +/* The command to be executed. +/* DIAGNOSTICS +/* The command exit status is the exit status of the command +/* (status 1 in case of a usage error). +/* AUTHOR(S) +/* Wietse Venema +/* This program is part of SATAN. +/*--*/ + +/* System libraries. */ + +#include +#include +#include +#include +#include + +extern int optind; + +/* Application-specific. */ + +#define perrorexit(s) { perror(s); exit(1); } + +static int kill_signal = SIGKILL; +static char *progname; +static char *commandname; + +static void usage() +{ + fprintf(stderr, "usage: %s [-signal] time command...\n", progname); + exit(1); +} + +static void terminate(sig) +int sig; +{ + signal(kill_signal, SIG_DFL); + fprintf(stderr, "Timeout: aborting command ``%s'' with signal %d\n", + commandname, kill_signal); + kill(0, kill_signal); +} + +int main(argc, argv) +int argc; +char **argv; +{ + int time_to_run; + pid_t pid; + pid_t child_pid; + int status; + + progname = argv[0]; + + /* + * Parse JCL. + */ + while (--argc && *++argv && **argv == '-') + if ((kill_signal = atoi(*argv + 1)) <= 0) + usage(); + + if (argc < 2 || (time_to_run = atoi(argv[0])) <= 0) + usage(); + + commandname = argv[1]; + + /* + * Run the command and its watchdog in a separate process group so that + * both can be killed off with one signal. + */ + setsid(); + switch (child_pid = fork()) { + case -1: /* error */ + perrorexit("timeout: fork"); + case 00: /* run controlled command */ + execvp(argv[1], argv + 1); + perrorexit(argv[1]); + default: /* become watchdog */ + (void) signal(SIGHUP, terminate); + (void) signal(SIGINT, terminate); + (void) signal(SIGQUIT, terminate); + (void) signal(SIGTERM, terminate); + (void) signal(SIGALRM, terminate); + alarm(time_to_run); + while ((pid = wait(&status)) != -1 && pid != child_pid) + /* void */ ; + return (pid == child_pid ? status : -1); + } +}