xref: /6.0.3/moxi/src/timedrun.c (revision d0366df5)
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 <platform/cbassert.h>
9
10static int caught = 0;
11
12static void caught_signal(int which)
13{
14    caught = which;
15}
16
17static 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                break;
49            case 1:
50                sig = SIGTERM;
51                break;
52            default:
53                sig = SIGKILL;
54                break;
55            }
56            if (kill(pid, sig) < 0) {
57                /* Kill failed.  Must have lost the process. :/ */
58                perror("lost child when trying to kill");
59            }
60            /* Wait up to 5 seconds for the pid */
61            alarm(5);
62        }
63    }
64    return rv;
65}
66
67static int spawn_and_wait(int argc, char **argv)
68{
69    int rv = EX_SOFTWARE;
70    pid_t pid = fork();
71
72    cb_assert(argc > 1);
73
74    switch (pid) {
75    case -1:
76        perror("fork");
77        rv = EX_OSERR;
78        break; /* NOTREACHED */
79    case 0:
80        execvp(argv[0], argv);
81        perror("exec");
82        rv = EX_SOFTWARE;
83        break; /* NOTREACHED */
84    default:
85        rv = wait_for_process(pid);
86    }
87    return rv;
88}
89
90int main(int argc, char **argv)
91{
92    int naptime = 0;
93    cb_assert(argc > 2);
94
95    naptime = atoi(argv[1]);
96    cb_assert(naptime > 0 && naptime < 1800);
97
98    alarm(naptime);
99
100    return spawn_and_wait(argc+2, argv+2);
101}
102