1 /* Repeatedly run a program for a given length of time. */
2
3 /*
4 * Copyright (C) 2003-2006 IBM
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
19 * 02111-1307, USA.
20 */
21
22 #include <stdio.h>
23 #include <string.h>
24 #include <strings.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <sys/types.h>
28 #include <sys/wait.h>
29
30 #include "debug.h"
31
32 static int res = 0;
33 static char *progname;
34 static pid_t test_pgrp;
35 static FILE *out;
36
int_func(int signum)37 static void int_func(int signum)
38 {
39 pounder_fprintf(out,
40 "%s: Killed by interrupt. Last exit code = %d.\n",
41 progname, res);
42 kill(-test_pgrp, SIGTERM);
43 exit(res);
44 }
45
alarm_func(int signum)46 static void alarm_func(int signum)
47 {
48 pounder_fprintf(out, "%s: Killed by timer. Last exit code = %d.\n",
49 progname, res);
50 kill(-test_pgrp, SIGTERM);
51 exit(res);
52 }
53
54 /*
55 static void term_func(int signum) {
56 exit(res);
57 }
58 */
59
main(int argc,char * argv[])60 int main(int argc, char *argv[])
61 {
62 int secs, stat;
63 pid_t pid;
64 unsigned int revs = 0;
65 struct sigaction zig;
66 int use_max_failures = 0;
67 int max_failures = 0;
68 int fail_counter = 1;
69
70 if (argc < 3) {
71 printf
72 ("Usage: %s [-m max_failures] time_in_sec command [args]\n",
73 argv[0]);
74 exit(1);
75 }
76 //by default, set max_failures to whatever the env variable $MAX_FAILURES is
77 char *max_failures_env = getenv("MAX_FAILURES");
78 max_failures = atoi(max_failures_env);
79
80 //if the -m option is used when calling timed_loop, override max_failures
81 //specified by $MAX_FAILURES with the given argument instead
82 if (argc > 4 && strcmp(argv[1], "-m") == 0) {
83 if ((max_failures = atoi(argv[2])) >= 0) {
84 use_max_failures = 1;
85 } else {
86 printf
87 ("Usage: %s [-m max_failures] time_in_sec command [args]\n",
88 argv[0]);
89 printf
90 ("max_failures should be a nonnegative integer\n");
91 exit(1);
92 }
93 }
94
95 out = stdout;
96
97 if (use_max_failures) {
98 progname = rindex(argv[4], '/');
99 if (progname == NULL) {
100 progname = argv[4];
101 } else {
102 progname++;
103 }
104 } else {
105 progname = rindex(argv[2], '/');
106 if (progname == NULL) {
107 progname = argv[2];
108 } else {
109 progname++;
110 }
111 }
112
113 /* Set up signals */
114 memset(&zig, 0x00, sizeof(zig));
115 zig.sa_handler = alarm_func;
116 sigaction(SIGALRM, &zig, NULL);
117 zig.sa_handler = int_func;
118 sigaction(SIGINT, &zig, NULL);
119 sigaction(SIGTERM, &zig, NULL);
120
121 /* set up process groups so that we can kill the
122 * loop test and descendants easily */
123
124 if (use_max_failures) {
125 secs = atoi(argv[3]);
126 } else {
127 secs = atoi(argv[1]);
128 }
129 alarm(secs);
130
131 while (1) {
132 pounder_fprintf(out, "%s: %s loop #%d.\n", progname,
133 start_msg, revs++);
134 pid = fork();
135 if (pid == 0) {
136 if (setpgrp() < 0) {
137 perror("setpgid");
138 }
139 // run the program
140 if (use_max_failures) {
141 if (argc > 5) {
142 stat = execvp(argv[4], &argv[4]);
143 } else {
144 stat = execvp(argv[4], &argv[4]);
145 }
146
147 perror(argv[4]);
148 } else {
149 if (argc > 3) {
150 stat = execvp(argv[2], &argv[2]);
151 } else {
152 stat = execvp(argv[2], &argv[2]);
153 }
154
155 perror(argv[2]);
156 }
157
158 exit(-1);
159 }
160
161 /* save the pgrp of the spawned process */
162 test_pgrp = pid;
163
164 // wait for it to be done
165 if (waitpid(pid, &stat, 0) != pid) {
166 perror("waitpid");
167 exit(1);
168 }
169 // interrogate it
170 if (WIFSIGNALED(stat)) {
171 pounder_fprintf(out, "%s: %s on signal %d.\n",
172 progname, fail_msg, WTERMSIG(stat));
173 res = 255;
174 } else {
175 res = WEXITSTATUS(stat);
176 if (res == 0) {
177 pounder_fprintf(out, "%s: %s.\n", progname,
178 pass_msg);
179 } else if (res < 0 || res == 255) {
180 pounder_fprintf(out,
181 "CHECK %s: %s with code %d.\n",
182 progname, abort_msg, res);
183 exit(-1);
184 // FIXME: add test to blacklist
185 } else {
186 pounder_fprintf(out,
187 "%s: %s with code %d.\n",
188 progname, fail_msg, res);
189 if (max_failures > 0) {
190 if (++fail_counter > max_failures) {
191 exit(-1);
192 }
193 }
194 }
195 }
196 }
197 }
198