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