allow non-html pages more easily.
[amitay/build-farm.git] / timelimit.c
1 /* run a command with a limited timeout
2    tridge@samba.org, June 2005
3    metze@samba.org, March 2006
4
5    attempt to be as portable as possible (fighting posix all the way)
6 */
7 #include <stdio.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <signal.h>
12 #include <errno.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15
16 static pid_t child_pid;
17
18 static void usage(void)
19 {
20         printf("usage: timelimit <time> <command>\n");
21         printf("   SIGUSR1 - passes SIGTERM to command's process group\n");
22         printf("   SIGALRM - passes SIGTERM to command's process group\n");
23         printf("             after 5s SIGKILL will be passed and exit(1)\n");
24         printf("   SIGTERM - passes SIGTERM to command's process group\n");
25         printf("             after 1s SIGKILL will be passed and exit(1)\n");
26         printf("   SIGINT  - handled like SIGTERM\n");
27         printf("   SIGQUIT - handled like SIGTERM\n");
28 }
29
30 static void sig_alrm_kill(int sig)
31 {
32         fprintf(stderr, "\nMaximum time expired in timelimit - killing\n");
33         kill(-child_pid, SIGKILL);
34         exit(1);
35 }
36
37 static void sig_alrm_term(int sig)
38 {
39         fprintf(stderr, "\nMaximum time expired in timelimit - sending TERM To child\n");
40         kill(-child_pid, SIGTERM);
41         signal(SIGALRM, sig_alrm_kill);
42         alarm(5);
43 }
44
45 static void sig_term(int sig)
46 {
47         fprintf(stderr, "\nReceived TERM/INT/QUIT signal\n");
48         kill(-child_pid, SIGTERM);
49         signal(SIGALRM, sig_alrm_kill);
50         alarm(1);
51 }
52
53 static void sig_usr1(int sig)
54 {
55         kill(-child_pid, SIGTERM);
56 }
57
58 static void new_process_group(void)
59 {
60         if (setpgid(0,0) == -1) {
61                 perror("setpgid");
62                 exit(1);
63         }
64 }
65
66
67 int main(int argc, char *argv[])
68 {
69         int maxtime, ret=1;
70
71         if (argc < 3) {
72                 usage();
73                 exit(1);
74         }
75
76         maxtime = atoi(argv[1]);
77
78         child_pid = fork();
79         if (child_pid == 0) {
80                 new_process_group();
81                 execvp(argv[2], argv+2);
82                 perror(argv[2]);
83                 exit(1);
84         }
85
86         signal(SIGTERM, sig_term);
87         signal(SIGINT,  sig_term);
88         signal(SIGQUIT, sig_term);
89         signal(SIGUSR1, sig_usr1);
90         signal(SIGALRM, sig_alrm_term);
91         alarm(maxtime);
92
93         do {
94                 int status;
95                 pid_t pid = wait(&status);
96                 if (pid != -1) {
97                         if (WIFEXITED(status)) {
98                                 ret = WEXITSTATUS(status);
99                         }
100                 } else if (errno == ECHILD) {
101                         break;
102                 }
103         } while (1);
104
105         kill(-child_pid, SIGKILL);
106
107         exit(ret);
108 }