1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 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 <sys/types.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
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);
}
}
|