1 /*
2 * Copyright (c) 2004, Bull S.A.. All rights reserved.
3 * Created by: Sebastien Decugis
4
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
17 * This utility software allows to run any executable file with a timeout limit.
18 * The syntax is:
19 * $ ./t0 n exe arglist
20 * where n is the timeout duration in seconds,
21 * exe is the executable filename to run,
22 * arglist is the arguments to be passed to executable.
23 *
24 * The use of this utility is intended to be "transparent", which means
25 * everything is as if
26 * $ exe arglist
27 * had been called, and a call to "alarm(n)" had been added inside exe's main.
28 *
29 * SPECIAL CASE:
30 * $ ./t0 0
31 * Here another arg is not required. This special case will return immediatly
32 * as if it has been timedout. This is usefull to check a timeout return code value.
33 *
34 */
35
36 /* This utility should compile on any POSIX-conformant implementation. */
37 #define _POSIX_C_SOURCE 200112L
38
39 #include <sys/types.h>
40 #include <sys/wait.h>
41 #include <errno.h>
42 #include <pthread.h>
43 #include <signal.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48
49 pid_t pid_to_monitor;
50
sighandler(int sig)51 void sighandler(int sig)
52 {
53 if (0 < pid_to_monitor) {
54 if (kill(pid_to_monitor, SIGKILL) == -1) {
55 perror("kill(.., SIGKILL) failed");
56 abort(); /* Something's really screwed up if we get here. */
57 }
58 waitpid(pid_to_monitor, NULL, WNOHANG);
59 }
60 exit(SIGALRM + 128);
61 }
62
main(int argc,char * argv[])63 int main(int argc, char *argv[])
64 {
65 int status, timeout;
66
67 /* Special case: t0 0 */
68 if (argc == 2 && (strncmp(argv[1], "0", 1) == 0)) {
69 kill(getpid(), SIGALRM);
70 exit(1);
71 }
72
73 /* General case */
74 if (argc < 3) {
75 printf("\nUsage: \n");
76 printf(" $ %s n exe arglist\n", argv[0]);
77 printf(" $ %s 0\n", argv[0]);
78 printf("\nWhere:\n");
79 printf(" n is the timeout duration in seconds,\n");
80 printf(" exe is the executable filename to run,\n");
81 printf
82 (" arglist is the arguments to be passed to executable.\n\n");
83 printf
84 (" The second use case will emulate an immediate timeout.\n\n");
85 exit(1);
86 }
87
88 timeout = atoi(argv[1]);
89 if (timeout < 1) {
90 fprintf(stderr,
91 "Invalid timeout value \"%s\". Timeout must be a positive integer.\n",
92 argv[1]);
93 exit(1);
94 }
95
96 if (signal(SIGALRM, sighandler) == SIG_ERR) {
97 perror("signal failed");
98 exit(1);
99 }
100
101 alarm(timeout);
102
103 switch (pid_to_monitor = fork()) {
104 case -1:
105 perror("fork failed");
106 exit(1);
107 case 0:
108 setpgid(0, 0);
109 execvp(argv[2], &argv[2]);
110 perror("execvp failed");
111 exit(1);
112 default:
113
114 for (;;) {
115 if (waitpid(pid_to_monitor, &status, 0) ==
116 pid_to_monitor)
117 break;
118 else if (errno == EINTR) {
119 perror("waitpid failed");
120 exit(1);
121 }
122 }
123 /* Relay the child's status back to run-tests.sh */
124 if (WIFEXITED(status))
125 exit(WEXITSTATUS(status));
126 else if (WIFSIGNALED(status))
127 exit(WTERMSIG(status) + 128);
128
129 }
130
131 exit(1);
132 }
133