2006-03-21 18:33:14 +03:00
/* run a command with a limited timeout
tridge @ samba . org , June 2005
2006-03-30 13:34:02 +04:00
metze @ samba . org , March 2006
2006-03-21 18:33:14 +03:00
attempt to be as portable as possible ( fighting posix all the way )
*/
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <unistd.h>
# include <signal.h>
# include <errno.h>
# include <sys/types.h>
# include <sys/wait.h>
2006-03-22 00:25:29 +03:00
static pid_t child_pid ;
2006-03-21 18:33:14 +03:00
static void usage ( void )
{
printf ( " usage: timelimit <time> <command> \n " ) ;
2006-03-22 00:25:29 +03:00
printf ( " SIGUSR1 - passes SIGTERM to command's process group \n " ) ;
2006-03-30 13:34:02 +04:00
printf ( " SIGALRM - passes SIGTERM to command's process group \n " ) ;
printf ( " after 5s SIGKILL will be passed and exit(1) \n " ) ;
printf ( " SIGTERM - passes SIGTERM to command's process group \n " ) ;
printf ( " after 1s SIGKILL will be passed and exit(1) \n " ) ;
2006-03-21 18:33:14 +03:00
}
2006-03-27 16:32:42 +04:00
static void sig_alrm_kill ( int sig )
2006-03-21 18:33:14 +03:00
{
2006-03-22 00:25:29 +03:00
fprintf ( stderr , " \n Maximum time expired in timelimit - killing \n " ) ;
kill ( - child_pid , SIGKILL ) ;
2006-03-21 18:33:14 +03:00
exit ( 1 ) ;
}
2006-03-27 16:32:42 +04:00
static void sig_alrm_term ( int sig )
{
kill ( - child_pid , SIGTERM ) ;
alarm ( 5 ) ;
signal ( SIGALRM , sig_alrm_kill ) ;
}
2006-03-22 00:25:29 +03:00
static void sig_term ( int sig )
2006-03-21 18:33:14 +03:00
{
2006-03-22 00:25:29 +03:00
kill ( - child_pid , SIGTERM ) ;
2006-03-27 16:32:42 +04:00
alarm ( 1 ) ;
signal ( SIGALRM , sig_alrm_kill ) ;
2006-03-22 00:25:29 +03:00
}
2006-03-21 18:33:14 +03:00
2006-03-22 00:25:29 +03:00
static void sig_usr1 ( int sig )
{
kill ( - child_pid , SIGTERM ) ;
2006-03-21 18:33:14 +03:00
}
2006-03-22 00:25:29 +03:00
static void new_process_group ( void )
2006-03-21 18:33:14 +03:00
{
2006-06-01 10:11:31 +04:00
if ( setpgid ( 0 , 0 ) = = - 1 ) {
perror ( " setpgid " ) ;
2006-03-22 00:25:29 +03:00
exit ( 1 ) ;
}
2006-03-21 18:33:14 +03:00
}
2006-03-22 00:25:29 +03:00
2006-03-21 18:33:14 +03:00
int main ( int argc , char * argv [ ] )
{
int maxtime , ret = 1 ;
if ( argc < 3 ) {
usage ( ) ;
exit ( 1 ) ;
}
2006-03-22 00:25:29 +03:00
maxtime = atoi ( argv [ 1 ] ) ;
child_pid = fork ( ) ;
if ( child_pid = = 0 ) {
new_process_group ( ) ;
execvp ( argv [ 2 ] , argv + 2 ) ;
perror ( argv [ 2 ] ) ;
2006-03-21 18:33:14 +03:00
exit ( 1 ) ;
}
2006-03-22 00:25:29 +03:00
signal ( SIGTERM , sig_term ) ;
2007-09-06 14:51:17 +04:00
signal ( SIGINT , sig_term ) ;
signal ( SIGQUIT , sig_term ) ;
2006-03-22 00:25:29 +03:00
signal ( SIGUSR1 , sig_usr1 ) ;
2006-03-27 16:32:42 +04:00
signal ( SIGALRM , sig_alrm_term ) ;
2006-03-21 18:33:14 +03:00
alarm ( maxtime ) ;
do {
int status ;
pid_t pid = wait ( & status ) ;
if ( pid ! = - 1 ) {
ret = WEXITSTATUS ( status ) ;
} else if ( errno = = ECHILD ) {
break ;
}
} while ( 1 ) ;
2006-03-22 00:25:29 +03:00
kill ( - child_pid , SIGKILL ) ;
2006-03-21 18:33:14 +03:00
exit ( ret ) ;
}