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