Home | History | Annotate | Download | only in pounder21
      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