Home | History | Annotate | Download | only in pounder21
      1 /* Repeatedly run a program with a given uid, gid and termination signal. */
      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 int the_signal = SIGTERM;
     38 
     39 static void int_func(int signum)
     40 {
     41 	pounder_fprintf(out,
     42 			"%s: Killed by interrupt.  Last exit code = %d.\n",
     43 			progname, res);
     44 	kill(-test_pgrp, the_signal);
     45 	exit(res);
     46 }
     47 
     48 static void alarm_func(int signum)
     49 {
     50 	pounder_fprintf(out, "%s: Killed by timer.  Last exit code = %d.\n",
     51 			progname, res);
     52 	kill(-test_pgrp, the_signal);
     53 	exit(res);
     54 }
     55 
     56 int main(int argc, char *argv[])
     57 {
     58 	int secs, stat;
     59 	pid_t pid;
     60 	unsigned int revs = 0;
     61 	struct sigaction zig;
     62 	uid_t uid;
     63 	gid_t gid;
     64 	int use_max_failures = 0;
     65 	int max_failures = 0;
     66 	int fail_counter = 1;
     67 
     68 	if (argc < 5) {
     69 		printf
     70 		    ("Usage: %s [-m max_failures] time_in_sec uid gid signal command [args]\n",
     71 		     argv[0]);
     72 		exit(1);
     73 	}
     74 	//by default, set max_failures to whatever the env variable $MAX_FAILURES is
     75 	char *max_failures_env = getenv("MAX_FAILURES");
     76 	max_failures = atoi(max_failures_env);
     77 
     78 	//if the -m option is used when calling fancy_timed_loop, override max_failures
     79 	//specified by $MAX_FAILURES with the given argument instead
     80 	if (argc > 6 && strcmp(argv[1], "-m") == 0) {
     81 		if ((max_failures = atoi(argv[2])) >= 0) {
     82 			use_max_failures = 1;
     83 		} else {
     84 			printf
     85 			    ("Usage: %s [-m max_failures] time_in_sec uid gid signal command [args]\n",
     86 			     argv[0]);
     87 			printf
     88 			    ("max_failures should be a nonnegative integer\n");
     89 			exit(1);
     90 		}
     91 	}
     92 
     93 	out = stdout;
     94 
     95 	if (use_max_failures) {
     96 		progname = rindex(argv[7], '/');
     97 		if (progname == NULL) {
     98 			progname = argv[7];
     99 		} else {
    100 			progname++;
    101 		}
    102 	} else {
    103 		progname = rindex(argv[5], '/');
    104 		if (progname == NULL) {
    105 			progname = argv[5];
    106 		} else {
    107 			progname++;
    108 		}
    109 	}
    110 
    111 	/* Set up signals */
    112 	memset(&zig, 0x00, sizeof(zig));
    113 	zig.sa_handler = alarm_func;
    114 	sigaction(SIGALRM, &zig, NULL);
    115 	zig.sa_handler = int_func;
    116 	sigaction(SIGINT, &zig, NULL);
    117 	sigaction(SIGTERM, &zig, NULL);
    118 
    119 	/* set up process groups so that we can kill the
    120 	 * loop test and descendants easily */
    121 
    122 	if (use_max_failures) {
    123 		secs = atoi(argv[3]);
    124 		alarm(secs);
    125 
    126 		the_signal = atoi(argv[6]);
    127 		uid = atoi(argv[4]);
    128 		gid = atoi(argv[5]);
    129 	} else {
    130 		secs = atoi(argv[1]);
    131 		alarm(secs);
    132 
    133 		the_signal = atoi(argv[4]);
    134 		uid = atoi(argv[2]);
    135 		gid = atoi(argv[3]);
    136 	}
    137 
    138 	pounder_fprintf(out, "%s: uid = %d, gid = %d, sig = %d\n",
    139 			progname, uid, gid, the_signal);
    140 
    141 	while (1) {
    142 		pounder_fprintf(out, "%s: %s loop #%d.\n", progname,
    143 				start_msg, revs++);
    144 		pid = fork();
    145 		if (pid == 0) {
    146 			// set process group
    147 			if (setpgrp() < 0) {
    148 				perror("setpgid");
    149 			}
    150 			// set group and user id
    151 			if (setregid(gid, gid) != 0) {
    152 				perror("setregid");
    153 				exit(-1);
    154 			}
    155 
    156 			if (setreuid(uid, uid) != 0) {
    157 				perror("setreuid");
    158 				exit(-1);
    159 			}
    160 			// run the program
    161 			if (use_max_failures) {
    162 				if (argc > 5) {
    163 					stat = execvp(argv[7], &argv[7]);
    164 				} else {
    165 					stat = execvp(argv[7], &argv[7]);
    166 				}
    167 
    168 				perror(argv[7]);
    169 			} else {
    170 				if (argc > 3) {
    171 					stat = execvp(argv[5], &argv[5]);
    172 				} else {
    173 					stat = execvp(argv[5], &argv[5]);
    174 				}
    175 
    176 				perror(argv[5]);
    177 			}
    178 
    179 			exit(-1);
    180 		}
    181 
    182 		/* save the pgrp of the spawned process */
    183 		test_pgrp = pid;
    184 
    185 		// wait for it to be done
    186 		if (waitpid(pid, &stat, 0) != pid) {
    187 			perror("waitpid");
    188 			exit(1);
    189 		}
    190 		// interrogate it
    191 		if (WIFSIGNALED(stat)) {
    192 			pounder_fprintf(out, "%s: %s on signal %d.\n",
    193 					progname, fail_msg, WTERMSIG(stat));
    194 			res = 255;
    195 		} else {
    196 			res = WEXITSTATUS(stat);
    197 			if (res == 0) {
    198 				pounder_fprintf(out, "%s: %s.\n", progname,
    199 						pass_msg);
    200 			} else if (res < 0 || res == 255) {
    201 				pounder_fprintf(out,
    202 						"%s: %s with code %d.\n",
    203 						progname, abort_msg, res);
    204 				exit(-1);
    205 				// FIXME: add test to blacklist
    206 			} else {
    207 				pounder_fprintf(out,
    208 						"%s: %s with code %d.\n",
    209 						progname, fail_msg, res);
    210 				if (max_failures > 0) {
    211 					if (++fail_counter > max_failures) {
    212 						exit(-1);
    213 					}
    214 				}
    215 			}
    216 		}
    217 	}
    218 }
    219