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 32static int res = 0; 33static char *progname; 34static pid_t test_pgrp; 35static FILE *out; 36 37static 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 46static 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/* 55static void term_func(int signum) { 56 exit(res); 57} 58*/ 59 60int 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