Cope with files that already exist.
[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         kill(-child_pid, SIGTERM);
40         alarm(5);
41         signal(SIGALRM, sig_alrm_kill);
42 }
43
44 static void sig_term(int sig)
45 {
46         kill(-child_pid, SIGTERM);
47         alarm(1);
48         signal(SIGALRM, sig_alrm_kill);
49 }
50
51 static void sig_usr1(int sig)
52 {
53         kill(-child_pid, SIGTERM);
54 }
55
56 static void new_process_group(void)
57 {
58         if (setpgid(0,0) == -1) {
59                 perror("setpgid");
60                 exit(1);
61         }
62 }
63
64
65 int main(int argc, char *argv[])
66 {
67         int maxtime, ret=1;
68
69         if (argc < 3) {
70                 usage();
71                 exit(1);
72         }
73
74         maxtime = atoi(argv[1]);
75
76         child_pid = fork();
77         if (child_pid == 0) {
78                 new_process_group();
79                 execvp(argv[2], argv+2);
80                 perror(argv[2]);
81                 exit(1);
82         }
83
84         signal(SIGTERM, sig_term);
85         signal(SIGINT,  sig_term);
86         signal(SIGQUIT, sig_term);
87         signal(SIGUSR1, sig_usr1);
88         signal(SIGALRM, sig_alrm_term);
89         alarm(maxtime);
90
91         do {
92                 int status;
93                 pid_t pid = wait(&status);
94                 if (pid != -1) {
95                         if (WIFEXITED(status)) {
96                                 ret = WEXITSTATUS(status);
97                         }
98                 } else if (errno == ECHILD) {
99                         break;
100                 }
101         } while (1);
102
103         kill(-child_pid, SIGKILL);
104
105         exit(ret);
106 }