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 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 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