added demo of signal/uid handling feature
[tridge/junkcode.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 }
27
28 static void sig_alrm_kill(int sig)
29 {
30         fprintf(stderr, "\nMaximum time expired in timelimit - killing\n");
31         kill(-child_pid, SIGKILL);
32         exit(1);
33 }
34
35 static void sig_alrm_term(int sig)
36 {
37         kill(-child_pid, SIGTERM);
38         alarm(5);
39         signal(SIGALRM, sig_alrm_kill);
40 }
41
42 static void sig_term(int sig)
43 {
44         kill(-child_pid, SIGTERM);
45         alarm(1);
46         signal(SIGALRM, sig_alrm_kill);
47 }
48
49 static void sig_usr1(int sig)
50 {
51         kill(-child_pid, SIGTERM);
52 }
53
54 static void new_process_group(void)
55 {
56         if (setpgid(0,0) == -1) {
57                 perror("setpgid");
58                 exit(1);
59         }
60 }
61
62
63 int main(int argc, char *argv[])
64 {
65         int maxtime, ret=1;
66
67         if (argc < 3) {
68                 usage();
69                 exit(1);
70         }
71
72         maxtime = atoi(argv[1]);
73
74         child_pid = fork();
75         if (child_pid == 0) {
76                 new_process_group();
77                 execvp(argv[2], argv+2);
78                 perror(argv[2]);
79                 exit(1);
80         }
81
82         signal(SIGTERM, sig_term);
83         signal(SIGUSR1, sig_usr1);
84         signal(SIGALRM, sig_alrm_term);
85         alarm(maxtime);
86
87         do {
88                 int status;
89                 pid_t pid = wait(&status);
90                 if (pid != -1) {
91                         ret = WEXITSTATUS(status);
92                 } else if (errno == ECHILD) {
93                         break;
94                 }
95         } while (1);
96
97         kill(-child_pid, SIGKILL);
98
99         exit(ret);
100 }