1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <unistd.h> 4 #include <signal.h> 5 #include <sys/wait.h> 6 #include <sysexits.h> 7 8 #include <assert.h> 9 10 static int caught = 0; 11 12 static void caught_signal(int which) 13 { 14 caught = which; 15 } 16 17 static int wait_for_process(pid_t pid) 18 { 19 int rv = EX_SOFTWARE; 20 int stats = 0; 21 int i = 0; 22 struct sigaction sig_handler; 23 24 sig_handler.sa_handler = caught_signal; 25 sig_handler.sa_flags = 0; 26 27 sigaction(SIGALRM, &sig_handler, NULL); 28 sigaction(SIGHUP, &sig_handler, NULL); 29 sigaction(SIGINT, &sig_handler, NULL); 30 sigaction(SIGTERM, &sig_handler, NULL); 31 sigaction(SIGPIPE, &sig_handler, NULL); 32 33 /* Loop forever waiting for the process to quit */ 34 for (i = 0; ;i++) { 35 pid_t p = waitpid(pid, &stats, 0); 36 if (p == pid) { 37 /* child exited. Let's get out of here */ 38 rv = WIFEXITED(stats) ? 39 WEXITSTATUS(stats) : 40 (0x80 | WTERMSIG(stats)); 41 break; 42 } else { 43 int sig = 0; 44 switch (i) { 45 case 0: 46 /* On the first iteration, pass the signal through */ 47 sig = caught > 0 ? caught : SIGTERM; 48 if (caught == SIGALRM) { 49 fprintf(stderr, "Timeout.. killing the process\n"); 50 } 51 break; 52 case 1: 53 sig = SIGTERM; 54 break; 55 default: 56 sig = SIGKILL; 57 break; 58 } 59 if (kill(pid, sig) < 0) { 60 /* Kill failed. Must have lost the process. :/ */ 61 perror("lost child when trying to kill"); 62 } 63 /* Wait up to 5 seconds for the pid */ 64 alarm(5); 65 } 66 } 67 return rv; 68 } 69 70 static int spawn_and_wait(char **argv) 71 { 72 int rv = EX_SOFTWARE; 73 pid_t pid = fork(); 74 75 switch (pid) { 76 case -1: 77 perror("fork"); 78 rv = EX_OSERR; 79 break; /* NOTREACHED */ 80 case 0: 81 execvp(argv[0], argv); 82 perror("exec"); 83 rv = EX_SOFTWARE; 84 break; /* NOTREACHED */ 85 default: 86 rv = wait_for_process(pid); 87 } 88 return rv; 89 } 90 91 int main(int argc, char **argv) 92 { 93 int naptime = 0; 94 assert(argc > 2); 95 96 naptime = atoi(argv[1]); 97 assert(naptime > 0 && naptime < 1800); 98 99 alarm(naptime); 100 101 return spawn_and_wait(argv+2); 102 } 103