• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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