1 /* Repeatedly run a program. */
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
main(int argc,char * argv[])46 int main(int argc, char *argv[])
47 {
48 int stat;
49 pid_t pid;
50 struct sigaction zig;
51 unsigned int revs = 0;
52 int use_max_failures = 0;
53 int max_failures = 0;
54 int fail_counter = 1;
55
56 if (argc < 2) {
57 printf("Usage: %s [-m max_failures] command [args]\n", argv[0]);
58 exit(1);
59 }
60 //by default, set max_failures to whatever the env variable $MAX_FAILURES is
61 char *max_failures_env = getenv("MAX_FAILURES");
62 max_failures = atoi(max_failures_env);
63
64 //if the -m option is used when calling infinite_loop, override max_failures
65 //specified by $MAX_FAILURES with the given argument instead
66 if (argc > 3 && strcmp(argv[1], "-m") == 0) {
67 if ((max_failures = atoi(argv[2])) >= 0) {
68 use_max_failures = 1;
69 } else {
70 printf("Usage: %s [-m max_failures] command [args]\n",
71 argv[0]);
72 printf
73 ("max_failures should be a nonnegative integer\n");
74 exit(1);
75 }
76 }
77
78 out = stdout;
79
80 if (use_max_failures) {
81 progname = rindex(argv[3], '/');
82 if (progname == NULL) {
83 progname = argv[3];
84 } else {
85 progname++;
86 }
87 } else {
88 progname = rindex(argv[1], '/');
89 if (progname == NULL) {
90 progname = argv[1];
91 } else {
92 progname++;
93 }
94 }
95
96 /* Set up signals */
97 memset(&zig, 0x00, sizeof(zig));
98 zig.sa_handler = int_func;
99 sigaction(SIGINT, &zig, NULL);
100 sigaction(SIGTERM, &zig, NULL);
101
102 /* set up process groups so that we can kill the
103 * loop test and descendants easily */
104
105 while (1) {
106 pounder_fprintf(out, "%s: %s loop #%d.\n", progname,
107 start_msg, revs++);
108 pid = fork();
109 if (pid == 0) {
110 if (setpgrp() < 0) {
111 perror("setpgid");
112 }
113 // run the program
114 if (use_max_failures) {
115 if (argc > 5) {
116 stat = execvp(argv[3], &argv[3]);
117 } else {
118 stat = execvp(argv[3], &argv[3]);
119 }
120
121 perror(argv[3]);
122 } else {
123 if (argc > 3) {
124 stat = execvp(argv[1], &argv[1]);
125 } else {
126 stat = execvp(argv[1], &argv[1]);
127 }
128
129 perror(argv[1]);
130 }
131
132 exit(-1);
133 }
134
135 /* save the pgrp of the spawned process */
136 test_pgrp = pid;
137
138 // wait for it to be done
139 if (waitpid(pid, &stat, 0) != pid) {
140 perror("waitpid");
141 exit(1);
142 }
143 // interrogate it
144 if (WIFSIGNALED(stat)) {
145 pounder_fprintf(out, "%s: %s on signal %d.\n",
146 progname, fail_msg, WTERMSIG(stat));
147 res = 255;
148 } else {
149 res = WEXITSTATUS(stat);
150 if (res == 0) {
151 pounder_fprintf(out, "%s: %s.\n", progname,
152 pass_msg);
153 } else if (res < 0 || res == 255) {
154 pounder_fprintf(out,
155 "%s: %s with code %d.\n",
156 progname, abort_msg, res);
157 exit(-1);
158 // FIXME: add test to blacklist
159 } else {
160 pounder_fprintf(out,
161 "%s: %s with code %d.\n",
162 progname, fail_msg, res);
163 if (max_failures > 0) {
164 if (++fail_counter > max_failures) {
165 pounder_fprintf
166 ("Reached max number of failures allowed: %d. Aborting.",
167 max_failures);
168 exit(-1);
169 }
170 }
171 }
172 }
173 }
174 }
175