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
|
/*
timeout.c -- invoke a command and kill it hard (-9) if it is still executing
n seconds (minutes, hrs, days) after starting it.
usage: timeout n{s|m|h|d} command [args]
If n not postfixe with s/m/h/d seconds (s) is assumed.
WARNING: this code is largely untested and provided without any kind of warrenty.
*/
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/wait.h>
pid_t cpid = -1; /* child pid to kill if alarm pops */
void sigh( int i )
{
if( cpid > 1 )
{
kill( cpid, 9 );
fprintf( stderr, "timeout: killed child: %d\n", cpid );
}
exit( 2 );
}
void usage( char *argv0 )
{
fprintf( stderr, "usage: %s time{s|m|h|d} command [args]\n", argv0 );
exit( 1 );
}
int main( int argc, char **argv )
{
int sec = 0;
char *cp;
struct sigaction sig_info;
if( argc < 3 || !isdigit( *(argv[1]) ) )
usage( argv[0] );
sec = atoi( argv[1] ); /* read time value; adjust for post fix m,h,d */
for( cp = argv[1]; *cp && isdigit( *cp ); cp++ );
switch( *cp )
{
case 'm': sec *= 60; break;
case 'h': sec *= 3600; break;
case 'd': sec *= 86400; break;
}
if( sec <= 0 )
{
fprintf( stderr, "time must be a positive integer optionally suffixed with s, d, h, or m (seconds are default)\n" );
usage( argv[0] );
}
memset( &sig_info, 0, sizeof( struct sigaction ) );
sig_info.sa_handler = sigh;
switch( (cpid = fork( )) )
{
case 0:
argv += 2;
execvp( argv[0], argv );
exit( 1 ); /* shouldn't happen; don't take chances */
break; /* good form :) */
case -1:
exit( 1 ); /* error; just exit */
break;
default:
sigaction( SIGALRM, &sig_info, NULL ); /* enable our sig handler*/
alarm( sec ); /* set alarm */
wait( NULL ); /* wait for chld */
break;
}
exit( 0 );
return 0; /* keep compiler happy */
}
| |