blob: 457de0f75efba3255ef282a0f485f5092411ce6b [file] [log] [blame]
nstrazf307d5f2000-09-14 21:54:44 +00001/*
2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of version 2 of the GNU General Public License as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it would be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 *
12 * Further, this software is distributed without any warranty that it is
13 * free of the rightful claim of any third person regarding infringement
14 * or the like. Any license provided herein, whether implied or
15 * otherwise, applies only to this software file. Patent licenses, if
16 * any, provided herein do not apply to combinations of this program with
17 * other software, or any other product whatsoever.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write the Free Software Foundation, Inc., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
22 *
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
25 *
26 * http://www.sgi.com
27 *
28 * For further information regarding this notice, see:
29 *
30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31 *
robbiewc1706732002-02-19 18:06:31 +000032 * Changelog:
33 *
34 * Added timer options: William Jay Huie, IBM
iyermanoj66314512003-01-27 22:56:23 +000035 * 01/27/03 - Added: Manoj Iyer, manjo@mail.utexas.edu
36 * - option '-p' (pretty printing)i to enabled formatted printing
37 * of results.
robbiewc1706732002-02-19 18:06:31 +000038 *
iyermanoj32518582003-01-28 19:44:34 +000039 * 01/27/03 - Added: Manoj Iyer, manjo@mail.utexas.edu
40 * - added code to print system information
41 *
iyermanoj8c484e92003-01-29 02:09:13 +000042 * 01/28/03 - Added: Manoj Iyer, manjo@mail.utexas.edu
43 * - added code to print test exit value.
iyermanoj492e88e2003-01-30 06:22:31 +000044 *
45 * 01/29/03 - Added: Manoj Iyer, manjo@mail.utexas.edu
46 * - added code supresses test start and test end tags.
subrata_modakbc833d32007-07-25 10:12:02 +000047 *
48 * 07/22/07 - Added: Ricardo Salveti de Araujo, rsalveti@linux.vnet.ibm.com
49 * - added option to create a command file with all failed tests.
50 *
nstrazf307d5f2000-09-14 21:54:44 +000051 */
subrata_modak1cad5c02008-05-19 13:37:14 +000052/* $Id: pan.c,v 1.26 2008/05/19 13:37:14 subrata_modak Exp $ */
nstrazf307d5f2000-09-14 21:54:44 +000053
54#include <errno.h>
55#include <string.h>
plars404bea32002-09-04 13:15:55 +000056#include <sys/param.h>
nstrazf307d5f2000-09-14 21:54:44 +000057#include <sys/types.h>
nstrazcd87d682000-09-21 20:42:31 +000058#include <sys/times.h>
nstrazf307d5f2000-09-14 21:54:44 +000059#include <sys/wait.h>
60#include <sys/stat.h>
nstrazf307d5f2000-09-14 21:54:44 +000061#include <time.h>
nstrazcd87d682000-09-21 20:42:31 +000062#include <stdlib.h>
63#include <limits.h>
iyermanoj32518582003-01-28 19:44:34 +000064#include <sys/utsname.h>
nstrazf307d5f2000-09-14 21:54:44 +000065
nstrazcd87d682000-09-21 20:42:31 +000066#include "splitstr.h"
nstrazf307d5f2000-09-14 21:54:44 +000067#include "zoolib.h"
68
nstrazcde46c82001-03-08 19:13:21 +000069/* One entry in the command line collection. */
nstrazf307d5f2000-09-14 21:54:44 +000070struct coll_entry
71{
nstrazcde46c82001-03-08 19:13:21 +000072 char *name; /* tag name */
73 char *cmdline; /* command line */
74 char *pcnt_f; /* location of %f in the command line args, flag */
nstrazf307d5f2000-09-14 21:54:44 +000075 struct coll_entry *next;
76};
77
78struct collection
79{
80 int cnt;
81 struct coll_entry **ary;
82};
83
nstrazcd87d682000-09-21 20:42:31 +000084struct tag_pgrp
nstrazf307d5f2000-09-14 21:54:44 +000085{
86 int pgrp;
87 int stopping;
vapier9e78ade2006-12-13 22:55:21 +000088 time_t mystime;
nstrazf307d5f2000-09-14 21:54:44 +000089 struct coll_entry *cmd;
nstrazcd87d682000-09-21 20:42:31 +000090 char output[PATH_MAX];
nstrazf307d5f2000-09-14 21:54:44 +000091};
92
93struct orphan_pgrp
94{
95 int pgrp;
96 struct orphan_pgrp *next;
97};
98
iyermanoj492e88e2003-01-30 06:22:31 +000099static pid_t run_child(struct coll_entry *colle, struct tag_pgrp *active,
100 int quiet_mode);
nstrazcd87d682000-09-21 20:42:31 +0000101static char *slurp(char *file);
102static struct collection *get_collection(char *file, int optind, int argc,
103 char **argv);
104static void pids_running(struct tag_pgrp *running, int keep_active);
105static int check_pids(struct tag_pgrp *running, int *num_active,
subrata_modakbc833d32007-07-25 10:12:02 +0000106 int keep_active, FILE * logfile, FILE * failcmdfile,
107 struct orphan_pgrp *orphans, int fmt_print,
108 int *failcnt, int quiet_mode);
nstrazcd87d682000-09-21 20:42:31 +0000109static void propagate_signal(struct tag_pgrp *running, int keep_active,
110 struct orphan_pgrp *orphans);
111static void dump_coll(struct collection *coll);
nstrazcde46c82001-03-08 19:13:21 +0000112static char *subst_pcnt_f(struct coll_entry *colle);
nstrazcd87d682000-09-21 20:42:31 +0000113static void mark_orphan(struct orphan_pgrp *orphans, pid_t cpid);
114static void orphans_running(struct orphan_pgrp *orphans);
115static void check_orphans(struct orphan_pgrp *orphans, int sig);
nstrazf307d5f2000-09-14 21:54:44 +0000116
nstrazcd87d682000-09-21 20:42:31 +0000117static void copy_buffered_output(struct tag_pgrp *running);
118static void write_test_start(struct tag_pgrp *running, const char *init_status);
119static void write_test_end(struct tag_pgrp *running,
120 time_t exit_time, char *term_type, int stat_loc,
121 int term_id, struct tms *tms1, struct tms *tms2);
nstrazf307d5f2000-09-14 21:54:44 +0000122
robbiewc1706732002-02-19 18:06:31 +0000123//wjh
124static char PAN_STOP_FILE[] = "PAN_STOP_FILE";
125
nstrazf307d5f2000-09-14 21:54:44 +0000126static char *panname = NULL;
nstrazfef21be2001-03-15 21:23:27 +0000127static char *test_out_dir = NULL; /* dir to buffer output to */
128zoo_t zoofile;
nstrazcd87d682000-09-21 20:42:31 +0000129static char *reporttype = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000130
vapier53ef45c2006-02-16 05:56:51 +0000131/* zoolib */
132int rec_signal; /* received signal */
133int send_signal; /* signal to send */
134
nstrazf307d5f2000-09-14 21:54:44 +0000135/* Debug Bits */
136int Debug = 0;
nstrazcd87d682000-09-21 20:42:31 +0000137#define Dbuffile 0x000400 /* buffer file use */
nstrazf307d5f2000-09-14 21:54:44 +0000138#define Dsetup 0x000200 /* one-time set-up */
139#define Dshutdown 0x000100 /* killed by signal */
140#define Dexit 0x000020 /* exit status */
141#define Drunning 0x000010 /* current pids running */
142#define Dstartup 0x000004 /* started command */
143#define Dstart 0x000002 /* started command */
144#define Dwait 0x000001 /* wait interrupted */
145
nstrazcd87d682000-09-21 20:42:31 +0000146int
147main(int argc, char **argv)
nstrazf307d5f2000-09-14 21:54:44 +0000148{
149 extern char *optarg;
150 extern int optind;
nstrazfef21be2001-03-15 21:23:27 +0000151 char *zooname = NULL; /* name of the zoo file to use */
152 char *filename = "/dev/null"; /* filename to read test tags from */
nstrazf307d5f2000-09-14 21:54:44 +0000153 char *logfilename = NULL;
subrata_modakbc833d32007-07-25 10:12:02 +0000154 char *failcmdfilename = NULL;
nstrazcd87d682000-09-21 20:42:31 +0000155 char *outputfilename = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000156 struct collection *coll = NULL;
nstrazcd87d682000-09-21 20:42:31 +0000157 struct tag_pgrp *running;
nstrazf307d5f2000-09-14 21:54:44 +0000158 struct orphan_pgrp *orphans, *orph;
iyermanoj32518582003-01-28 19:44:34 +0000159 struct utsname unamebuf;
160 FILE *logfile = NULL;
subrata_modakbc833d32007-07-25 10:12:02 +0000161 FILE *failcmdfile = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000162 int keep_active = 1;
163 int num_active = 0;
iyermanoj32518582003-01-28 19:44:34 +0000164 int failcnt = 0; /* count of total testcases that failed. */
nstrazf307d5f2000-09-14 21:54:44 +0000165 int err, i;
166 int starts = -1;
robbiewc1706732002-02-19 18:06:31 +0000167 int run_time = -1; char modifier = 'm'; int ret = 0;
nstrazf307d5f2000-09-14 21:54:44 +0000168 int stop;
169 int go_idle;
nstrazfef21be2001-03-15 21:23:27 +0000170 int has_brakes = 0; /* stop everything if a test case fails */
171 int sequential = 0; /* run tests sequentially */
nstrazf307d5f2000-09-14 21:54:44 +0000172 int fork_in_road = 0;
nstrazf307d5f2000-09-14 21:54:44 +0000173 int exit_stat;
nstrazfef21be2001-03-15 21:23:27 +0000174 int track_exit_stats = 0; /* exit non-zero if any test exits non-zero */
iyermanoj66314512003-01-27 22:56:23 +0000175 int fmt_print = 0; /* enables formatted printing of logfiles. */
iyermanoj492e88e2003-01-30 06:22:31 +0000176 int quiet_mode = 0; /* supresses test start and test end tags. */
iyermanoj32518582003-01-28 19:44:34 +0000177 int c;
178 pid_t cpid;
nstrazb755b282003-03-03 23:35:55 +0000179 struct sigaction sa;
nstrazf307d5f2000-09-14 21:54:44 +0000180
subrata_modakbc833d32007-07-25 10:12:02 +0000181 while ((c = getopt(argc, argv, "AO:Sa:C:d:ef:hl:n:o:pqr:s:t:x:y")) != -1) {
nstrazf307d5f2000-09-14 21:54:44 +0000182 switch (c) {
nstrazfef21be2001-03-15 21:23:27 +0000183 case 'A': /* all-stop flag */
nstrazf307d5f2000-09-14 21:54:44 +0000184 has_brakes = 1;
185 track_exit_stats = 1;
186 break;
nstrazfef21be2001-03-15 21:23:27 +0000187 case 'O': /* output buffering directory */
nstrazcd87d682000-09-21 20:42:31 +0000188 test_out_dir = strdup(optarg);
nstrazf307d5f2000-09-14 21:54:44 +0000189 break;
nstrazfef21be2001-03-15 21:23:27 +0000190 case 'S': /* run tests sequentially */
nstrazf307d5f2000-09-14 21:54:44 +0000191 sequential = 1;
192 break;
nstrazfef21be2001-03-15 21:23:27 +0000193 case 'a': /* name of the zoo file to use */
nstrazcd87d682000-09-21 20:42:31 +0000194 zooname = strdup(optarg);
nstrazf307d5f2000-09-14 21:54:44 +0000195 break;
subrata_modakbc833d32007-07-25 10:12:02 +0000196 case 'C': /* name of the file where all failed commands will be */
197 failcmdfilename = strdup(optarg);
198 break;
nstrazfef21be2001-03-15 21:23:27 +0000199 case 'd': /* debug options */
nstrazcd87d682000-09-21 20:42:31 +0000200 sscanf(optarg, "%i", &Debug);
nstrazf307d5f2000-09-14 21:54:44 +0000201 break;
nstrazfef21be2001-03-15 21:23:27 +0000202 case 'e': /* exit non-zero if any test exists non-zero */
nstrazf307d5f2000-09-14 21:54:44 +0000203 track_exit_stats = 1;
204 break;
nstrazfef21be2001-03-15 21:23:27 +0000205 case 'f': /* filename to read test tags from */
nstrazcd87d682000-09-21 20:42:31 +0000206 filename = strdup(optarg);
207 break;
nstrazfef21be2001-03-15 21:23:27 +0000208 case 'h': /* help */
iyermanoj66314512003-01-27 22:56:23 +0000209 fprintf(stdout, "Usage: pan -n name [ -SyAehp ] [ -s starts ]"
210 " [-t time[s|m|h|d] [ -x nactive ] [ -l logfile ]\n\t"
211 "[ -a active-file ] [ -f command-file ] "
subrata_modakbc833d32007-07-25 10:12:02 +0000212 "[ -C fail-command-file ] "
iyermanoj66314512003-01-27 22:56:23 +0000213 "[ -d debug-level ]\n\t[-o output-file] "
214 "[-O output-buffer-directory] [cmd]\n");
nstrazcd87d682000-09-21 20:42:31 +0000215 exit(0);
nstrazfef21be2001-03-15 21:23:27 +0000216 case 'l': /* log file */
nstrazcd87d682000-09-21 20:42:31 +0000217 logfilename = strdup(optarg);
218 break;
nstrazfef21be2001-03-15 21:23:27 +0000219 case 'n': /* tag given to pan */
nstrazcd87d682000-09-21 20:42:31 +0000220 panname = strdup(optarg);
221 break;
nstrazfef21be2001-03-15 21:23:27 +0000222 case 'o': /* send test output here */
nstrazcd87d682000-09-21 20:42:31 +0000223 outputfilename = strdup(optarg);
224 break;
iyermanoj66314512003-01-27 22:56:23 +0000225 case 'p': /* formatted printing. */
226 fmt_print = 1;
227 break;
iyermanoj492e88e2003-01-30 06:22:31 +0000228 case 'q': /* supress test start and test end messages */
229 quiet_mode = 1;
230 break;
nstrazfef21be2001-03-15 21:23:27 +0000231 case 'r': /* reporting type: none, rts */
nstrazcd87d682000-09-21 20:42:31 +0000232 reporttype = strdup(optarg);
233 break;
nstrazfef21be2001-03-15 21:23:27 +0000234 case 's': /* number of tags to run */
nstrazcd87d682000-09-21 20:42:31 +0000235 starts = atoi(optarg);
236 break;
robbiewc1706732002-02-19 18:06:31 +0000237 case 't': /* run_time to run */
238 ret = sscanf(optarg, "%d%c", &run_time, &modifier);
239 if (ret == 0) { printf("Need proper time input: ####x where"
240 "x is one of s,m,h,d\n"); break; }
241 else if (ret == 1) { printf("Only got a time value of %d "
242 "modifiers need to come immediately after #"
243 " assuming %c\n", run_time, modifier); }
244 else
245 {
246 switch (modifier)
247 {
248 case 's': run_time = run_time; break;
249 case 'm': run_time = run_time * 60; break;
250 case 'h': run_time = run_time * 60 * 60; break;
251 case 'd': run_time = run_time * 60 * 60 * 24; break;
252 default:
253 printf("Invalid time modifier, try: s|h|m|d\n"); exit(-1);
254 }
255 printf("PAN will run for %d seconds\n", run_time);
256 }
257 starts = 0; //-t implies run as many starts as possible
258 break;
nstrazfef21be2001-03-15 21:23:27 +0000259 case 'x': /* number of tags to keep running */
nstrazcd87d682000-09-21 20:42:31 +0000260 keep_active = atoi(optarg);
261 break;
nstrazfef21be2001-03-15 21:23:27 +0000262 case 'y': /* restart on failure or signal */
nstrazcd87d682000-09-21 20:42:31 +0000263 fork_in_road = 1;
264 break;
nstrazf307d5f2000-09-14 21:54:44 +0000265 }
266 }
267
268 if (panname == NULL) {
nstrazcd87d682000-09-21 20:42:31 +0000269 fprintf(stderr, "pan: Must supply -n\n");
270 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000271 }
nstrazcd87d682000-09-21 20:42:31 +0000272 if (zooname == NULL) {
nstrazcde46c82001-03-08 19:13:21 +0000273 zooname = zoo_getname();
nstrazcd87d682000-09-21 20:42:31 +0000274 if (zooname == NULL) {
275 fprintf(stderr,
276 "pan(%s): Must supply -a or set ZOO env variable\n",
277 panname);
278 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000279 }
280 }
nstrazcd87d682000-09-21 20:42:31 +0000281 if (reporttype) {
282 /* make sure we understand the report type */
283 if (strcasecmp(reporttype, "rts")
284 && strcasecmp(reporttype, "none")
285 /* && strcasecmp(reporttype, "xml")*/)
286 reporttype = "rts";
287 } else {
288 /* set the default */
289 reporttype = "rts";
290 }
nstrazf307d5f2000-09-14 21:54:44 +0000291
292 if (logfilename != NULL) {
293 time_t startup;
294 char *s;
295
nstrazcd87d682000-09-21 20:42:31 +0000296 if (!strcmp(logfilename, "-")) {
nstrazf307d5f2000-09-14 21:54:44 +0000297 logfile = stdout;
298 } else {
nstrazcd87d682000-09-21 20:42:31 +0000299 if ((logfile = fopen(logfilename, "a+")) == NULL) {
300 fprintf(stderr,
301 "pan(%s): Error %s (%d) opening log file '%s'\n",
302 panname, strerror(errno), errno, logfilename);
303 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000304 }
305 }
306
nstrazcd87d682000-09-21 20:42:31 +0000307 time(&startup);
308 s = ctime(&startup);
309 *(s + strlen(s) - 1) = '\0';
iyermanoj66314512003-01-27 22:56:23 +0000310 if (!fmt_print)
311 fprintf(logfile, "startup='%s'\n", s);
312 else
313 {
iyermanoj32518582003-01-28 19:44:34 +0000314 fprintf(logfile, "Test Start Time: %s\n", s);
315 fprintf(logfile, "-----------------------------------------\n");
iyermanoj8c484e92003-01-29 02:09:13 +0000316 fprintf(logfile, "%-30.20s %-10.10s %-10.10s\n",
317 "Testcase", "Result", "Exit Value");
318 fprintf(logfile, "%-30.20s %-10.10s %-10.10s\n",
319 "--------", "------", "------------");
iyermanoj66314512003-01-27 22:56:23 +0000320 }
nstrazf307d5f2000-09-14 21:54:44 +0000321 }
322
nstrazcd87d682000-09-21 20:42:31 +0000323 coll = get_collection(filename, optind, argc, argv);
subrata_modak1cad5c02008-05-19 13:37:14 +0000324 if(!coll)
325 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000326 if (coll->cnt == 0) {
nstrazcd87d682000-09-21 20:42:31 +0000327 fprintf(stderr,
328 "pan(%s): Must supply a file collection or a command\n",
329 panname);
330 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000331 }
332
333 if (Debug & Dsetup)
nstrazcd87d682000-09-21 20:42:31 +0000334 dump_coll(coll);
nstrazf307d5f2000-09-14 21:54:44 +0000335
336 /* a place to store the pgrps we're watching */
nstrazcd87d682000-09-21 20:42:31 +0000337 running = (struct tag_pgrp *)malloc((keep_active + 1) * sizeof(struct tag_pgrp));
338 memset(running, 0, keep_active * sizeof(struct tag_pgrp));
nstrazf307d5f2000-09-14 21:54:44 +0000339 running[keep_active].pgrp = -1; /* end sentinel */
340
341 /* a head to the orphaned pgrp list */
nstrazcd87d682000-09-21 20:42:31 +0000342 orphans = (struct orphan_pgrp *) malloc(sizeof(struct orphan_pgrp));
343 memset(orphans, 0, sizeof(struct orphan_pgrp));
nstrazf307d5f2000-09-14 21:54:44 +0000344
nstrazcd87d682000-09-21 20:42:31 +0000345 srand48(time(NULL) ^ (getpid() + (getpid() << 15)));
nstrazf307d5f2000-09-14 21:54:44 +0000346
347 /* Supply a default for starts. If we are in sequential mode, use
348 * the number of commands available; otherwise 1.
349 */
nstrazcd87d682000-09-21 20:42:31 +0000350 if (starts == -1) {
351 if (sequential) {
nstrazf307d5f2000-09-14 21:54:44 +0000352 starts = coll->cnt;
nstrazcd87d682000-09-21 20:42:31 +0000353 } else {
nstrazf307d5f2000-09-14 21:54:44 +0000354 starts = 1;
nstrazcd87d682000-09-21 20:42:31 +0000355 }
356 } else if (starts == 0) { /* if the user specified infinite, set it */
357 starts = -1;
358 } else { /* else, make sure we are starting at least keep_active processes */
359 if (starts < keep_active)
360 starts = keep_active;
nstrazf307d5f2000-09-14 21:54:44 +0000361 }
nstrazcd87d682000-09-21 20:42:31 +0000362
363 /* if we're buffering output, but we're only running on process at a time,
364 * then essentially "turn off buffering"
365 */
366 if (test_out_dir && (keep_active == 1)) {
367 free(test_out_dir);
368 test_out_dir = NULL;
369 }
370
371 if (test_out_dir) {
372 struct stat sbuf;
373
374 if (stat(test_out_dir, &sbuf) < 0) {
375 fprintf(stderr,
376 "pan(%s): stat of -O arg '%s' failed. errno: %d %s\n",
377 panname, test_out_dir, errno, strerror(errno));
378 exit(1);
379 }
380 if (!S_ISDIR(sbuf.st_mode)) {
381 fprintf(stderr, "pan(%s): -O arg '%s' must be a directory.\n",
382 panname, test_out_dir);
383 exit(1);
384 }
385 if (access(test_out_dir, W_OK | R_OK | X_OK) < 0) {
386 fprintf(stderr,
387 "pan(%s): permission denied on -O arg '%s'. errno: %d %s\n",
388 panname, test_out_dir, errno, strerror(errno));
389 exit(1);
390 }
391 }
392
393 if (outputfilename) {
394 if (!freopen(outputfilename, "a+", stdout)) {
395 fprintf(stderr,
396 "pan(%s): Error %s (%d) openning output file '%s'\n",
397 panname, strerror(errno), errno, outputfilename);
398 exit(1);
399 }
400 }
401
subrata_modakbc833d32007-07-25 10:12:02 +0000402 if (failcmdfilename) {
403 if (!(failcmdfile = fopen(failcmdfilename, "a+"))) {
404 fprintf(stderr,
405 "pan(%s): Error %s (%d) opening fail cmd file '%s'\n",
406 panname, strerror(errno), errno, failcmdfilename);
407 exit(1);
408 }
409 }
410
nstrazcde46c82001-03-08 19:13:21 +0000411 if ((zoofile = zoo_open(zooname)) == NULL) {
412 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000413 exit(1);
414 }
nstrazcde46c82001-03-08 19:13:21 +0000415 if (zoo_mark_args(zoofile, getpid(), panname, argc, argv)) {
416 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000417 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000418 }
419
420 /* Allocate N spaces for max-arg commands.
421 * this is an "active file cleanliness" thing
422 */
423 {
424 char *av[2], bigarg[82];
nstrazf307d5f2000-09-14 21:54:44 +0000425
nstrazcd87d682000-09-21 20:42:31 +0000426 memset(bigarg, '.', 81);
nstrazf307d5f2000-09-14 21:54:44 +0000427 bigarg[81] = '\0';
428 av[0] = bigarg;
429 av[1] = NULL;
430
431 for (c = 0; c < keep_active; c++) {
nstrazcde46c82001-03-08 19:13:21 +0000432 if (zoo_mark_cmdline(zoofile, c, panname, "")) {
433 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000434 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000435 }
436 }
437 for (c = 0; c < keep_active; c++) {
nstrazcde46c82001-03-08 19:13:21 +0000438 if (zoo_clear(zoofile, c)) {
439 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000440 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000441 }
442 }
443 }
444
445 rec_signal = send_signal = 0;
robbiewcba89702002-09-05 20:48:35 +0000446 if (run_time != -1) { alarm(run_time); }
nstrazb755b282003-03-03 23:35:55 +0000447 sa.sa_handler = wait_handler;
448 sigaction(SIGALRM, &sa, NULL);
449 sigaction(SIGINT, &sa, NULL);
450 sigaction(SIGTERM, &sa, NULL);
451 sigaction(SIGHUP, &sa, NULL);
452 sigaction(SIGUSR1, &sa, NULL); /* ignore fork_in_road */
453 sigaction(SIGUSR2, &sa, NULL); /* stop the scheduler */
nstrazf307d5f2000-09-14 21:54:44 +0000454
455 c = 0; /* in this loop, c is the command index */
456 stop = 0;
457 exit_stat = 0;
458 go_idle = 0;
459 while (1) {
460
461 while ((num_active < keep_active) && (starts != 0)) {
462 if (stop || rec_signal || go_idle)
463 break;
464
465 if (!sequential)
nstrazcd87d682000-09-21 20:42:31 +0000466 c = lrand48() % coll->cnt;
nstrazf307d5f2000-09-14 21:54:44 +0000467
468 /* find a slot for the child */
469 for (i = 0; i < keep_active; ++i) {
470 if (running[i].pgrp == 0)
471 break;
472 }
473 if (i == keep_active) {
nstrazcd87d682000-09-21 20:42:31 +0000474 fprintf(stderr, "pan(%s): Aborting: i == keep_active = %d\n",
475 panname, i);
476 wait_handler(SIGINT);
nstrazf307d5f2000-09-14 21:54:44 +0000477 exit_stat++;
478 break;
479 }
480
iyermanoj492e88e2003-01-30 06:22:31 +0000481 cpid = run_child(coll->ary[c], running + i, quiet_mode);
mreed103bed8b02006-07-10 15:46:10 +0000482 if (cpid != -1)
nstrazf307d5f2000-09-14 21:54:44 +0000483 ++num_active;
mreed103bed8b02006-07-10 15:46:10 +0000484 if ((cpid != -1 || sequential) && starts > 0)
485 --starts;
nstrazf307d5f2000-09-14 21:54:44 +0000486
487 if (sequential)
488 if (++c >= coll->cnt)
489 c = 0;
490
robbiewc1706732002-02-19 18:06:31 +0000491 } /* while( (num_active < keep_active) && (starts != 0) ) */
nstrazf307d5f2000-09-14 21:54:44 +0000492
493 if (starts == 0)
iyermanoj8a3f9292003-01-30 06:28:39 +0000494 {
495 if (!quiet_mode)
496 printf("incrementing stop\n");
497 ++stop;
498 }
499 else if (starts == -1) //wjh
500 {
501 FILE *f = (FILE*)-1;
502 if ((f = fopen(PAN_STOP_FILE, "r")) != 0)
503 { printf("Got %s Stopping!\n", PAN_STOP_FILE);
504 fclose(f); unlink(PAN_STOP_FILE); stop++;
505 }
506 }
nstrazf307d5f2000-09-14 21:54:44 +0000507
508 if (rec_signal) {
509 /* propagate everything except sigusr2 */
510
511 if (rec_signal == SIGUSR2) {
512 if (fork_in_road)
513 ++go_idle;
514 else
515 ++stop;
nstrazf307d5f2000-09-14 21:54:44 +0000516 rec_signal = send_signal = 0;
517 } else {
518 if (rec_signal == SIGUSR1)
519 fork_in_road = 0;
nstrazcd87d682000-09-21 20:42:31 +0000520 propagate_signal(running, keep_active, orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000521 if (fork_in_road)
522 ++go_idle;
523 else
524 ++stop;
525 }
526 }
527
subrata_modakbc833d32007-07-25 10:12:02 +0000528 err = check_pids(running, &num_active, keep_active, logfile,
529 failcmdfile, orphans, fmt_print, &failcnt, quiet_mode);
nstrazf307d5f2000-09-14 21:54:44 +0000530 if (Debug & Drunning) {
nstrazcd87d682000-09-21 20:42:31 +0000531 pids_running(running, keep_active);
532 orphans_running(orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000533 }
534 if (err) {
535 if (fork_in_road)
536 ++go_idle;
537 if (track_exit_stats)
538 exit_stat++;
539 if (has_brakes) {
nstrazcd87d682000-09-21 20:42:31 +0000540 fprintf(stderr, "pan(%s): All stop!%s\n", panname,
nstrazf307d5f2000-09-14 21:54:44 +0000541 go_idle ? " (idling)" : "");
nstrazcd87d682000-09-21 20:42:31 +0000542 wait_handler(SIGINT);
nstrazf307d5f2000-09-14 21:54:44 +0000543 }
544 }
545
546 if (stop && (num_active == 0))
547 break;
548
549 if (go_idle && (num_active == 0)) {
550 go_idle = 0; /* It is idle, now resume scheduling. */
nstrazcd87d682000-09-21 20:42:31 +0000551 wait_handler(0); /* Reset the signal ratchet. */
nstrazf307d5f2000-09-14 21:54:44 +0000552 }
553 }
554
555 /* Wait for orphaned pgrps */
556 while (1) {
557 for (orph = orphans; orph != NULL; orph = orph->next) {
558 if (orph->pgrp == 0)
559 continue;
560 /* Yes, we have orphaned pgrps */
nstrazcd87d682000-09-21 20:42:31 +0000561 sleep(5);
nstrazf307d5f2000-09-14 21:54:44 +0000562 if (!rec_signal) {
563 /* force an artificial signal, move us
564 * through the signal ratchet.
565 */
nstrazcd87d682000-09-21 20:42:31 +0000566 wait_handler(SIGINT);
nstrazf307d5f2000-09-14 21:54:44 +0000567 }
nstrazcd87d682000-09-21 20:42:31 +0000568 propagate_signal(running, keep_active, orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000569 if (Debug & Drunning)
nstrazcd87d682000-09-21 20:42:31 +0000570 orphans_running(orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000571 break;
572 }
573 if (orph == NULL)
574 break;
575 }
576
nstrazcde46c82001-03-08 19:13:21 +0000577 if (zoo_clear(zoofile, getpid())) {
578 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazf307d5f2000-09-14 21:54:44 +0000579 ++exit_stat;
580 }
nstrazcd87d682000-09-21 20:42:31 +0000581 fclose(zoofile);
subrata_modak1cad5c02008-05-19 13:37:14 +0000582 if (logfile && fmt_print)
iyermanoj45e9d982003-01-28 22:33:34 +0000583 {
584 if (uname(&unamebuf) == -1)
585 fprintf(stderr, "ERROR: uname(): %s\n", strerror(errno));
iyermanoj492e88e2003-01-30 06:22:31 +0000586 fprintf(logfile, "\n-----------------------------------------------\n");
iyermanoj45e9d982003-01-28 22:33:34 +0000587 fprintf(logfile, "Total Tests: %d\n", coll->cnt);
588 fprintf(logfile, "Total Failures: %d\n", failcnt);
589 fprintf(logfile, "Kernel Version: %s\n", unamebuf.release);
590 fprintf(logfile, "Machine Architecture: %s\n", unamebuf.machine);
591 fprintf(logfile, "Hostname: %s\n\n", unamebuf.nodename);
592 }
nstrazcd87d682000-09-21 20:42:31 +0000593 if (logfile && (logfile != stdout))
594 fclose(logfile);
595
596 exit(exit_stat);
nstrazf307d5f2000-09-14 21:54:44 +0000597}
598
599
nstrazf307d5f2000-09-14 21:54:44 +0000600
601static void
nstrazcd87d682000-09-21 20:42:31 +0000602propagate_signal(struct tag_pgrp *running, int keep_active,
603 struct orphan_pgrp *orphans)
nstrazf307d5f2000-09-14 21:54:44 +0000604{
605 int i;
606
607 if (Debug & Dshutdown)
nstrazcd87d682000-09-21 20:42:31 +0000608 fprintf(stderr, "pan was signaled with sig %d...\n", rec_signal);
nstrazf307d5f2000-09-14 21:54:44 +0000609
robbiewc1706732002-02-19 18:06:31 +0000610 if (rec_signal == SIGALRM)
611 {
612 printf("PAN stop Alarm was received\n");
613 rec_signal = SIGTERM;
614 }
615
nstrazf307d5f2000-09-14 21:54:44 +0000616 for (i = 0; i < keep_active; ++i) {
617 if (running[i].pgrp == 0)
618 continue;
619
620 if (Debug & Dshutdown)
nstrazcd87d682000-09-21 20:42:31 +0000621 fprintf(stderr, " propagating sig %d to %d\n",
nstrazf307d5f2000-09-14 21:54:44 +0000622 send_signal, -running[i].pgrp);
nstrazcd87d682000-09-21 20:42:31 +0000623 if (kill(-running[i].pgrp, send_signal) != 0) {
624 fprintf(stderr,
625 "pan(%s): kill(%d,%d) failed on tag (%s). errno:%d %s\n",
626 panname, -running[i].pgrp, send_signal,
627 running[i].cmd->name, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000628 }
629 running[i].stopping = 1;
630 }
631
nstrazcd87d682000-09-21 20:42:31 +0000632 check_orphans(orphans, send_signal);
nstrazf307d5f2000-09-14 21:54:44 +0000633
nstrazf307d5f2000-09-14 21:54:44 +0000634 rec_signal = send_signal = 0;
635}
636
637
638static int
nstrazcd87d682000-09-21 20:42:31 +0000639check_pids(struct tag_pgrp *running, int *num_active, int keep_active,
subrata_modakbc833d32007-07-25 10:12:02 +0000640 FILE * logfile, FILE * failcmdfile, struct orphan_pgrp *orphans,
641 int fmt_print, int *failcnt, int quiet_mode)
nstrazf307d5f2000-09-14 21:54:44 +0000642{
643 int w;
644 pid_t cpid;
645 int stat_loc;
646 int ret = 0;
647 int i;
648 time_t t;
649 char *status;
650 int signaled = 0;
651 struct tms tms1, tms2;
652 clock_t tck;
653
nstrazcd87d682000-09-21 20:42:31 +0000654 check_orphans(orphans, 0);
nstrazf307d5f2000-09-14 21:54:44 +0000655
nstrazcd87d682000-09-21 20:42:31 +0000656 tck = times(&tms1);
nstrazf307d5f2000-09-14 21:54:44 +0000657 if (tck == -1) {
nstrazcd87d682000-09-21 20:42:31 +0000658 fprintf(stderr, "pan(%s): times(&tms1) failed. errno:%d %s\n",
659 panname, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000660 }
nstrazcd87d682000-09-21 20:42:31 +0000661 cpid = wait(&stat_loc);
662 tck = times(&tms2);
nstrazf307d5f2000-09-14 21:54:44 +0000663 if (tck == -1) {
nstrazcd87d682000-09-21 20:42:31 +0000664 fprintf(stderr, "pan(%s): times(&tms2) failed. errno:%d %s\n",
665 panname, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000666 }
667
668 if (cpid < 0) {
669 if (errno == EINTR) {
670 if (Debug)
nstrazcd87d682000-09-21 20:42:31 +0000671 fprintf(stderr, "pan(%s): wait() interrupted\n", panname);
nstrazf307d5f2000-09-14 21:54:44 +0000672 } else if (errno != ECHILD) {
nstrazcd87d682000-09-21 20:42:31 +0000673 fprintf(stderr, "pan(%s): wait() failed. errno:%d %s\n",
674 panname, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000675 }
676 } else if (cpid > 0) {
677
nstrazcd87d682000-09-21 20:42:31 +0000678 if (WIFSIGNALED(stat_loc)) {
679 w = WTERMSIG(stat_loc);
nstrazf307d5f2000-09-14 21:54:44 +0000680 status = "signaled";
681 if (Debug & Dexit)
nstrazcd87d682000-09-21 20:42:31 +0000682 fprintf(stderr, "child %d terminated with signal %d\n", cpid,
683 w);
nstrazf307d5f2000-09-14 21:54:44 +0000684 --*num_active;
685 signaled = 1;
nstrazcd87d682000-09-21 20:42:31 +0000686 } else if (WIFEXITED(stat_loc)) {
687 w = WEXITSTATUS(stat_loc);
nstrazf307d5f2000-09-14 21:54:44 +0000688 status = "exited";
689 if (Debug & Dexit)
nstrazcd87d682000-09-21 20:42:31 +0000690 fprintf(stderr, "child %d exited with status %d\n", cpid, w);
nstrazf307d5f2000-09-14 21:54:44 +0000691 --*num_active;
692 if (w != 0)
693 ret++;
nstrazcd87d682000-09-21 20:42:31 +0000694 } else if (WIFSTOPPED(stat_loc)) { /* should never happen */
695 w = WSTOPSIG(stat_loc);
nstrazf307d5f2000-09-14 21:54:44 +0000696 status = "stopped";
697 ret++;
698 } else { /* should never happen */
699 w = 0;
700 status = "unknown";
701 ret++;
702 }
703
704 for (i = 0; i < keep_active; ++i) {
705 if (running[i].pgrp == cpid) {
706 if ((w == 130) && running[i].stopping &&
nstrazcd87d682000-09-21 20:42:31 +0000707 (strcmp(status, "exited") == 0)) {
nstrazf307d5f2000-09-14 21:54:44 +0000708 /* The child received sigint, but
709 * did not trap for it? Compensate
710 * for it here.
711 */
712 w = 0;
713 ret--; /* undo */
714 if (Debug & Drunning)
nstrazcd87d682000-09-21 20:42:31 +0000715 fprintf(stderr,
716 "pan(%s): tag=%s exited 130, known to be signaled; will give it an exit 0.\n",
717 panname, running[i].cmd->name);
nstrazf307d5f2000-09-14 21:54:44 +0000718 }
plarsdebdbd12001-11-30 19:30:29 +0000719 time(&t);
nstrazf307d5f2000-09-14 21:54:44 +0000720 if (logfile != NULL) {
iyermanoj66314512003-01-27 22:56:23 +0000721 if (!fmt_print)
722 fprintf(logfile,
723 "tag=%s stime=%d dur=%d exit=%s stat=%d core=%s cu=%d cs=%d\n",
vapier9e78ade2006-12-13 22:55:21 +0000724 running[i].cmd->name, (int) (running[i].mystime),
725 (int) (t - running[i].mystime), status, w,
iyermanoj66314512003-01-27 22:56:23 +0000726 (stat_loc & 0200) ? "yes" : "no",
727 (int) (tms2.tms_cutime - tms1.tms_cutime),
728 (int) (tms2.tms_cstime - tms1.tms_cstime));
729 else
730 {
iyermanoj32518582003-01-28 19:44:34 +0000731 if (w != 0)
732 ++*failcnt;
robbiewe126a0d2004-07-15 19:13:51 +0000733 fprintf(logfile, "%-30.30s %-10.10s %-5d\n",
iyermanoj8c484e92003-01-29 02:09:13 +0000734 running[i].cmd->name, ((w != 0) ? "FAIL" : "PASS"),
735 w);
iyermanoj66314512003-01-27 22:56:23 +0000736 }
737
738 fflush(logfile);
nstrazf307d5f2000-09-14 21:54:44 +0000739 }
nstrazcd87d682000-09-21 20:42:31 +0000740
subrata_modakbc833d32007-07-25 10:12:02 +0000741 if ((failcmdfile != NULL) && (w !=0)) {
742 fprintf(failcmdfile, "%s %s\n", running[i].cmd->name, running[i].cmd->cmdline);
743 }
nstrazcd87d682000-09-21 20:42:31 +0000744
745 if (running[i].stopping)
746 status = "driver_interrupt";
747
748 if (test_out_dir) {
iyermanoj492e88e2003-01-30 06:22:31 +0000749 if (!quiet_mode)
750 write_test_start(running+i, "ok");
751 copy_buffered_output(running + i);
752 unlink(running[i].output);
nstrazcd87d682000-09-21 20:42:31 +0000753 }
iyermanoj492e88e2003-01-30 06:22:31 +0000754 if (!quiet_mode)
755 write_test_end(running+i, t, status,
756 stat_loc, w, &tms1, &tms2);
nstrazcd87d682000-09-21 20:42:31 +0000757
nstrazf307d5f2000-09-14 21:54:44 +0000758 /* If signaled and we weren't expecting
759 * this to be stopped then the proc
760 * had a problem.
761 */
762 if (signaled && !running[i].stopping)
763 ret++;
764
765 running[i].pgrp = 0;
nstrazcde46c82001-03-08 19:13:21 +0000766 if (zoo_clear(zoofile, cpid)) {
767 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000768 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000769 }
770
771 /* Check for orphaned pgrps */
nstrazcd87d682000-09-21 20:42:31 +0000772 if ((kill(-cpid, 0) == 0) || (errno == EPERM)) {
nstrazcde46c82001-03-08 19:13:21 +0000773 if (zoo_mark_cmdline(zoofile, cpid, "panorphan",
774 running[i].cmd->cmdline)) {
775 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000776 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000777 }
nstrazcd87d682000-09-21 20:42:31 +0000778 mark_orphan(orphans, cpid);
nstrazf307d5f2000-09-14 21:54:44 +0000779 /* status of kill doesn't matter */
nstrazcd87d682000-09-21 20:42:31 +0000780 kill(-cpid, SIGTERM);
nstrazf307d5f2000-09-14 21:54:44 +0000781 }
782
783 break;
784 }
785 }
786 }
787 return ret;
788}
789
790
791static pid_t
iyermanoj492e88e2003-01-30 06:22:31 +0000792run_child(struct coll_entry *colle, struct tag_pgrp *active, int quiet_mode)
nstrazf307d5f2000-09-14 21:54:44 +0000793{
794 int cpid;
robbiewf3a83d52002-05-28 16:26:16 +0000795 int c_stdout = -1; /* child's stdout, stderr */
nstrazcd87d682000-09-21 20:42:31 +0000796 int capturing = 0; /* output is going to a file instead of stdout */
nstrazcde46c82001-03-08 19:13:21 +0000797 char *c_cmdline;
nstrazcd87d682000-09-21 20:42:31 +0000798 static long cmdno = 0;
nstrazcd87d682000-09-21 20:42:31 +0000799 int errpipe[2]; /* way to communicate to parent that the tag */
800 char errbuf[1024]; /* didn't actually start */
801 int errlen;
nstrazf307d5f2000-09-14 21:54:44 +0000802
nstrazcd87d682000-09-21 20:42:31 +0000803 /* Try to open the file that will be stdout for the test */
804 if (test_out_dir) {
805 capturing = 1;
806 do {
807 sprintf(active->output, "%s/%s.%ld",
808 test_out_dir, colle->name, cmdno++);
nstraz566e8c82000-09-22 19:52:17 +0000809 c_stdout = open(active->output, O_CREAT | O_RDWR | O_EXCL | O_SYNC, 0666);
nstrazcd87d682000-09-21 20:42:31 +0000810 } while (c_stdout < 0 && errno == EEXIST);
811 if (c_stdout < 0) {
812 fprintf(stderr,
813 "pan(%s): open of stdout file failed (tag %s). errno: %d %s\n file: %s\n",
814 panname, colle->name, errno, strerror(errno),
815 active->output);
816 return -1;
817 }
818 }
819
820 /* get the tag's command line arguments ready. subst_pcnt_f() uses a
821 * static counter, that's why we do it here instead of after we fork.
822 */
823 if (colle->pcnt_f) {
nstrazcde46c82001-03-08 19:13:21 +0000824 c_cmdline = subst_pcnt_f(colle);
nstrazcd87d682000-09-21 20:42:31 +0000825 } else {
nstrazcde46c82001-03-08 19:13:21 +0000826 c_cmdline = colle->cmdline;
nstrazcd87d682000-09-21 20:42:31 +0000827 }
828
829 if (pipe(errpipe) < 0) {
830 fprintf(stderr, "pan(%s): pipe() failed. errno:%d %s\n",
831 panname, errno, strerror(errno));
nstraz6c3f66b2001-09-28 21:56:46 +0000832 if (capturing) {
nstrazcd87d682000-09-21 20:42:31 +0000833 close(c_stdout);
nstraz6c3f66b2001-09-28 21:56:46 +0000834 unlink(active->output);
835 }
nstrazcd87d682000-09-21 20:42:31 +0000836 return -1;
837 }
838
839 if ((cpid = fork()) < 0) {
840 fprintf(stderr, "pan(%s): fork failed (tag %s). errno:%d %s\n",
841 panname, colle->name, errno, strerror(errno));
nstraz6c3f66b2001-09-28 21:56:46 +0000842 if (capturing) {
843 unlink(active->output);
nstrazcd87d682000-09-21 20:42:31 +0000844 close(c_stdout);
nstraz6c3f66b2001-09-28 21:56:46 +0000845 }
nstrazcd87d682000-09-21 20:42:31 +0000846 close(errpipe[0]);
847 close(errpipe[1]);
nstrazf307d5f2000-09-14 21:54:44 +0000848 return -1;
849 } else if (cpid == 0) {
850 /* child */
nstrazf307d5f2000-09-14 21:54:44 +0000851
nstrazcd87d682000-09-21 20:42:31 +0000852 fclose(zoofile);
853 close(errpipe[0]);
854 fcntl(errpipe[1], F_SETFD, 1); /* close the pipe if we succeed */
855 setpgrp();
nstrazf307d5f2000-09-14 21:54:44 +0000856
nstrazcd87d682000-09-21 20:42:31 +0000857 umask(0);
858
859 /* if we're putting output into a buffer file, we need to do the
860 * redirection now. If we fail
861 */
862 if (capturing) {
863 if (dup2(c_stdout, fileno(stdout)) == -1) {
864 errlen = sprintf(errbuf, "pan(%s): couldn't redirect stdout for tag %s. errno:%d %s",
865 panname, colle->name, errno, strerror(errno));
866 write(errpipe[1], &errlen, sizeof(errlen));
867 write(errpipe[1], errbuf, errlen);
868 exit(2);
869 }
870 if (dup2(c_stdout, fileno(stderr)) == -1) {
871 errlen = sprintf(errbuf, "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s",
872 panname, colle->name, errno, strerror(errno));
873 write(errpipe[1], &errlen, sizeof(errlen));
874 write(errpipe[1], errbuf, errlen);
875 exit(2);
876 }
877 } else { /* stderr still needs to be redirected */
878 if (dup2(fileno(stdout), fileno(stderr)) == -1) {
879 errlen = sprintf(errbuf, "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s",
880 panname, colle->name, errno, strerror(errno));
881 write(errpipe[1], &errlen, sizeof(errlen));
882 write(errpipe[1], errbuf, errlen);
883 exit(2);
884 }
nstrazf307d5f2000-09-14 21:54:44 +0000885 }
nstrazcde46c82001-03-08 19:13:21 +0000886 /* If there are any shell-type characters in the cmdline
887 * such as '>', '<', '$', '|', etc, then we exec a shell and
888 * run the cmd under a shell.
889 *
890 * Otherwise, break the cmdline at white space and exec the
891 * cmd directly.
892 */
893 if (strpbrk(c_cmdline, "\"';|<>$\\")) {
894 execlp("sh", "sh", "-c", c_cmdline, 0);
895 errlen = sprintf(errbuf,
896 "pan(%s): execlp of '%s' (tag %s) failed. errno:%d %s",
897 panname, c_cmdline, colle->name, errno, strerror(errno));
898 } else {
899 char **arg_v;
900
901 arg_v = (char **)splitstr(c_cmdline, NULL, NULL);
902
903 execvp(arg_v[0], arg_v);
904 errlen = sprintf(errbuf,
905 "pan(%s): execvp of '%s' (tag %s) failed. errno:%d %s",
906 panname, arg_v[0], colle->name, errno, strerror(errno));
907 }
nstrazcd87d682000-09-21 20:42:31 +0000908 write(errpipe[1], &errlen, sizeof(errlen));
909 write(errpipe[1], errbuf, errlen);
910 exit(errno);
nstrazf307d5f2000-09-14 21:54:44 +0000911 }
912
913 /* parent */
nstrazcd87d682000-09-21 20:42:31 +0000914
nstrazcde46c82001-03-08 19:13:21 +0000915 /* subst_pcnt_f() allocates the command line dynamically
916 * free the malloc to prevent a memory leak
nstrazcd87d682000-09-21 20:42:31 +0000917 */
nstrazcde46c82001-03-08 19:13:21 +0000918 if (colle->pcnt_f) free(c_cmdline);
919
nstrazcd87d682000-09-21 20:42:31 +0000920 close(errpipe[1]);
vapier9e78ade2006-12-13 22:55:21 +0000921 time(&active->mystime);
nstrazf307d5f2000-09-14 21:54:44 +0000922 active->cmd = colle;
923
nstrazcd87d682000-09-21 20:42:31 +0000924 /* if the child couldn't go through with the exec,
925 * clean up the mess, note it, and move on
926 */
927 if(read(errpipe[0], &errlen, sizeof(errlen))) {
928 int status;
929 time_t end_time;
930 int termid;
931 char *termtype;
932 struct tms notime = {0, 0, 0, 0};
933
934 read(errpipe[0], errbuf, errlen);
935 close(errpipe[0]);
936 errbuf[errlen] = '\0';
937 /* fprintf(stderr, "%s", errbuf); */
938 waitpid(cpid, &status, 0);
939 if (WIFSIGNALED(status)) {
940 termid = WTERMSIG(status);
941 termtype = "signaled";
942 } else if (WIFEXITED(status)) {
943 termid = WEXITSTATUS(status);
944 termtype = "exited";
945 } else if (WIFSTOPPED(status)) {
946 termid = WSTOPSIG(status);
947 termtype = "stopped";
948 } else {
949 termid = 0;
950 termtype = "unknown";
951 }
952 time(&end_time);
iyermanoj492e88e2003-01-30 06:22:31 +0000953 if (!quiet_mode)
954 {
955 write_test_start(active, errbuf);
956 write_test_end(active, end_time, termtype, status,
nstrazcd87d682000-09-21 20:42:31 +0000957 termid, &notime, &notime);
iyermanoj492e88e2003-01-30 06:22:31 +0000958 }
nstraz6c3f66b2001-09-28 21:56:46 +0000959 if (capturing) {
960 close(c_stdout);
961 unlink(active->output);
962 }
nstrazcd87d682000-09-21 20:42:31 +0000963 return -1;
964 }
965
966 close(errpipe[0]);
nstraz6c3f66b2001-09-28 21:56:46 +0000967 if (capturing) close(c_stdout);
nstrazcd87d682000-09-21 20:42:31 +0000968
969 if (!test_out_dir)
iyermanoj492e88e2003-01-30 06:22:31 +0000970 if (!quiet_mode)
971 write_test_start(active, "ok");
nstrazcd87d682000-09-21 20:42:31 +0000972
973 active->pgrp = cpid;
974 active->stopping = 0;
975
nstrazcde46c82001-03-08 19:13:21 +0000976 if (zoo_mark_cmdline(zoofile, cpid, colle->name, colle->cmdline)) {
977 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000978 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000979 }
980
981 if (Debug & Dstartup)
nstrazcd87d682000-09-21 20:42:31 +0000982 fprintf(stderr, "started %s cpid=%d at %s",
vapier9e78ade2006-12-13 22:55:21 +0000983 colle->name, cpid, ctime(&active->mystime));
nstrazf307d5f2000-09-14 21:54:44 +0000984
985 if (Debug & Dstart) {
nstrazcde46c82001-03-08 19:13:21 +0000986 fprintf(stderr, "Executing test = %s as %s", colle->name, colle->cmdline);
nstrazcd87d682000-09-21 20:42:31 +0000987 if (capturing)
988 fprintf(stderr, "with output file = %s\n", active->output);
989 else
990 fprintf(stderr, "\n");
nstrazf307d5f2000-09-14 21:54:44 +0000991 }
992
993 return cpid;
994}
995
996
nstrazcde46c82001-03-08 19:13:21 +0000997static char *
nstrazcd87d682000-09-21 20:42:31 +0000998subst_pcnt_f(struct coll_entry *colle)
nstrazf307d5f2000-09-14 21:54:44 +0000999{
nstrazcde46c82001-03-08 19:13:21 +00001000 static int counter = 1;
1001 char pid_and_counter[20];
1002 char new_cmdline[1024];
nstrazf307d5f2000-09-14 21:54:44 +00001003
nstrazcde46c82001-03-08 19:13:21 +00001004 /* if we get called falsely, do the right thing anyway */
1005 if (!colle->pcnt_f)
1006 return colle->cmdline;
nstrazf307d5f2000-09-14 21:54:44 +00001007
nstrazcde46c82001-03-08 19:13:21 +00001008 snprintf(pid_and_counter, 20, "%d_%d", getpid(), counter++);
1009 snprintf(new_cmdline, 1024, colle->cmdline, pid_and_counter);
1010 return strdup(new_cmdline);
nstrazf307d5f2000-09-14 21:54:44 +00001011}
1012
1013static struct collection *
nstrazcd87d682000-09-21 20:42:31 +00001014get_collection(char *file, int optind, int argc, char **argv)
nstrazf307d5f2000-09-14 21:54:44 +00001015{
1016 char *buf, *a, *b;
1017 struct coll_entry *head, *p, *n;
1018 struct collection *coll;
1019 int i;
1020
nstrazcd87d682000-09-21 20:42:31 +00001021 buf = slurp(file);
subrata_modak1cad5c02008-05-19 13:37:14 +00001022 if(!buf)
1023 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +00001024
nstrazcd87d682000-09-21 20:42:31 +00001025 coll = (struct collection *) malloc(sizeof(struct collection));
nstrazf307d5f2000-09-14 21:54:44 +00001026 coll->cnt = 0;
1027
1028 head = p = n = NULL;
1029 a = b = buf;
1030 while (*b != '\0') {
nstrazcde46c82001-03-08 19:13:21 +00001031 /* set b to the start of the next line and add a NULL character
1032 * to separate the two lines */
nstrazcd87d682000-09-21 20:42:31 +00001033 if ((b = strchr(a, '\n')) != NULL)
nstrazf307d5f2000-09-14 21:54:44 +00001034 *b = '\0';
1035
nstrazcde46c82001-03-08 19:13:21 +00001036 /* If this is line isn't a comment */
nstrazf307d5f2000-09-14 21:54:44 +00001037 if ((*a != '#') && (*a != '\0') && (*a != ' ')) {
nstrazcde46c82001-03-08 19:13:21 +00001038 n = (struct coll_entry *) malloc(sizeof(struct coll_entry));
1039 if ((n->pcnt_f = strstr(a, "%f"))) {
1040 n->pcnt_f[1] = 's';
nstrazf307d5f2000-09-14 21:54:44 +00001041 }
nstrazcde46c82001-03-08 19:13:21 +00001042 n->name = strdup(strsep(&a, " \t"));
1043 n->cmdline = strdup(a);
1044 n->next = NULL;
1045
1046 if (p) {
1047 p->next = n;
1048 }
1049 if (head == NULL) {
1050 head = n;
1051 }
1052 p = n;
nstrazf307d5f2000-09-14 21:54:44 +00001053 coll->cnt++;
1054 }
nstrazcd87d682000-09-21 20:42:31 +00001055 a += strlen(a) + 1;
nstrazf307d5f2000-09-14 21:54:44 +00001056 b = a;
1057 }
nstrazcd87d682000-09-21 20:42:31 +00001058 free(buf);
nstrazf307d5f2000-09-14 21:54:44 +00001059
1060 /* is there something on the commandline to be counted? */
1061 if (optind < argc) {
nstrazcde46c82001-03-08 19:13:21 +00001062 char workstr[1024] = "";
1063 int workstr_left = 1023;
1064
nstrazf307d5f2000-09-14 21:54:44 +00001065 /* fill arg list */
1066 for (i = 0; optind < argc; ++optind, ++i) {
nstrazcde46c82001-03-08 19:13:21 +00001067 strncat(workstr, argv[optind], workstr_left);
1068 workstr_left = workstr_left - strlen(argv[optind]);
1069 strncat(workstr, " ", workstr_left);
1070 workstr_left--;
nstrazf307d5f2000-09-14 21:54:44 +00001071 }
nstrazf307d5f2000-09-14 21:54:44 +00001072
nstrazcde46c82001-03-08 19:13:21 +00001073 n = (struct coll_entry *) malloc(sizeof(struct coll_entry));
1074 if ((n->pcnt_f = strstr(workstr, "%f"))) {
1075 n->pcnt_f[1] = 's';
1076 }
1077 n->cmdline = strdup(workstr);
1078 n->name = "cmdln";
1079 n->next = NULL;
1080 if (p) {
nstrazf307d5f2000-09-14 21:54:44 +00001081 p->next = n;
nstrazcde46c82001-03-08 19:13:21 +00001082 }
1083 if (head == NULL) {
1084 head = n;
nstrazf307d5f2000-09-14 21:54:44 +00001085 }
1086 coll->cnt++;
1087 }
1088
1089 /* get an array */
nstrazcd87d682000-09-21 20:42:31 +00001090 coll->ary = (struct coll_entry **) malloc(coll->cnt *
1091 sizeof(struct coll_entry *));
nstrazf307d5f2000-09-14 21:54:44 +00001092
1093 /* fill the array */
1094 i = 0;
1095 n = head;
1096 while (n != NULL) {
1097 coll->ary[i] = n;
1098 n = n->next;
1099 ++i;
1100 }
1101 if (i != coll->cnt)
nstrazcd87d682000-09-21 20:42:31 +00001102 fprintf(stderr, "pan(%s): i doesn't match cnt\n", panname);
nstrazf307d5f2000-09-14 21:54:44 +00001103
1104 return coll;
1105}
1106
1107
1108static char *
nstrazcd87d682000-09-21 20:42:31 +00001109slurp(char *file)
nstrazf307d5f2000-09-14 21:54:44 +00001110{
1111 char *buf;
1112 int fd;
1113 struct stat sbuf;
1114
nstrazcd87d682000-09-21 20:42:31 +00001115 if ((fd = open(file, O_RDONLY)) < 0) {
1116 fprintf(stderr, "pan(%s): open(%s,O_RDONLY) failed. errno:%d %s\n",
1117 panname, file, errno, strerror(errno));
1118 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +00001119 }
1120
nstrazcd87d682000-09-21 20:42:31 +00001121 if (fstat(fd, &sbuf) < 0) {
1122 fprintf(stderr, "pan(%s): fstat(%s) failed. errno:%d %s\n",
1123 panname, file, errno, strerror(errno));
1124 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +00001125 }
1126
nstrazcd87d682000-09-21 20:42:31 +00001127 buf = (char *) malloc(sbuf.st_size + 1);
1128 if (read(fd, buf, sbuf.st_size) != sbuf.st_size) {
1129 fprintf(stderr, "pan(%s): slurp failed. errno:%d %s\n",
1130 panname, errno, strerror(errno));
1131 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +00001132 }
1133 buf[sbuf.st_size] = '\0';
1134
nstrazcd87d682000-09-21 20:42:31 +00001135 close(fd);
nstrazf307d5f2000-09-14 21:54:44 +00001136 return buf;
1137}
1138
1139static void
nstrazcd87d682000-09-21 20:42:31 +00001140check_orphans(struct orphan_pgrp *orphans, int sig)
nstrazf307d5f2000-09-14 21:54:44 +00001141{
1142 struct orphan_pgrp *orph;
1143
1144 for (orph = orphans; orph != NULL; orph = orph->next) {
1145 if (orph->pgrp == 0)
1146 continue;
1147
1148 if (Debug & Dshutdown)
nstrazcd87d682000-09-21 20:42:31 +00001149 fprintf(stderr, " propagating sig %d to orphaned pgrp %d\n",
nstrazf307d5f2000-09-14 21:54:44 +00001150 sig, -(orph->pgrp));
nstrazcd87d682000-09-21 20:42:31 +00001151 if (kill(-(orph->pgrp), sig) != 0) {
nstrazf307d5f2000-09-14 21:54:44 +00001152 if (errno == ESRCH) {
1153 /* This pgrp is now empty */
nstrazcde46c82001-03-08 19:13:21 +00001154 if (zoo_clear(zoofile, orph->pgrp)) {
1155 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazf307d5f2000-09-14 21:54:44 +00001156 }
1157 orph->pgrp = 0;
1158 } else {
nstrazcd87d682000-09-21 20:42:31 +00001159 fprintf(stderr,
1160 "pan(%s): kill(%d,%d) on orphaned pgrp failed. errno:%d %s\n",
1161 panname, -(orph->pgrp), sig, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +00001162 }
1163 }
1164 }
1165}
1166
1167
1168static void
nstrazcd87d682000-09-21 20:42:31 +00001169mark_orphan(struct orphan_pgrp *orphans, pid_t cpid)
nstrazf307d5f2000-09-14 21:54:44 +00001170{
1171 struct orphan_pgrp *orph;
1172
1173 for (orph = orphans; orph != NULL; orph = orph->next) {
1174 if (orph->pgrp == 0)
1175 break;
1176 }
1177 if (orph == NULL) {
1178 /* make a new struct */
nstrazcd87d682000-09-21 20:42:31 +00001179 orph = (struct orphan_pgrp *) malloc(sizeof(struct orphan_pgrp));
nstrazf307d5f2000-09-14 21:54:44 +00001180
1181 /* plug in the new struct just after the head */
1182 orph->next = orphans->next;
1183 orphans->next = orph;
1184 }
1185 orph->pgrp = cpid;
1186}
1187
1188
nstrazf307d5f2000-09-14 21:54:44 +00001189
nstrazcd87d682000-09-21 20:42:31 +00001190static void
1191copy_buffered_output(struct tag_pgrp *running)
1192{
1193 char *tag_output;
1194
1195 tag_output = slurp(running->output);
1196 if (tag_output) {
1197 printf("%s", tag_output);
1198 /* make sure the output ends with a newline */
1199 if (tag_output[strlen(tag_output) - 1] != '\n')
1200 printf("\n");
1201 fflush(stdout);
1202 free(tag_output);
nstrazf307d5f2000-09-14 21:54:44 +00001203 }
nstrazcd87d682000-09-21 20:42:31 +00001204}
1205
1206
1207static void
1208write_test_start(struct tag_pgrp *running, const char *init_status)
1209{
1210 if (!strcmp(reporttype, "rts")) {
nstrazcd87d682000-09-21 20:42:31 +00001211
1212 printf("%s\ntag=%s stime=%ld\ncmdline=\"%s\"\ncontacts=\"%s\"\nanalysis=%s\ninitiation_status=\"%s\"\n%s\n",
1213 "<<<test_start>>>",
vapier9e78ade2006-12-13 22:55:21 +00001214 running->cmd->name, running->mystime, running->cmd->cmdline, "",
nstrazcd87d682000-09-21 20:42:31 +00001215 "exit", init_status,
1216 "<<<test_output>>>");
nstrazcd87d682000-09-21 20:42:31 +00001217 }
1218 fflush(stdout);
1219}
1220
1221
1222static void
1223write_test_end(struct tag_pgrp *running, time_t exit_time,
1224 char *term_type, int stat_loc, int term_id,
1225 struct tms *tms1, struct tms *tms2)
1226{
1227 if (!strcmp(reporttype, "rts")) {
1228 printf("%s\nduration=%ld termination_type=%s termination_id=%d corefile=%s\ncutime=%d cstime=%d\n%s\n",
1229 "<<<execution_status>>>",
vapier9e78ade2006-12-13 22:55:21 +00001230 (long) (exit_time - running->mystime),
nstrazcd87d682000-09-21 20:42:31 +00001231 term_type, term_id, (stat_loc & 0200) ? "yes" : "no",
1232 (int) (tms2->tms_cutime - tms1->tms_cutime),
1233 (int) (tms2->tms_cstime - tms1->tms_cstime),
1234 "<<<test_end>>>");
1235 }
1236 fflush(stdout);
1237}
1238
1239/* The functions below are all debugging related */
1240
1241static void
1242pids_running(struct tag_pgrp *running, int keep_active)
1243{
1244 int i;
1245
1246 fprintf(stderr, "pids still running: ");
1247 for (i = 0; i < keep_active; ++i) {
1248 if (running[i].pgrp != 0)
1249 fprintf(stderr, "%d ", running[i].pgrp);
1250 }
1251 fprintf(stderr, "\n");
nstrazf307d5f2000-09-14 21:54:44 +00001252}
1253
1254static void
nstrazcd87d682000-09-21 20:42:31 +00001255orphans_running(struct orphan_pgrp *orphans)
1256{
1257 struct orphan_pgrp *orph;
1258
1259 fprintf(stderr, "orphans still running: ");
1260 for (orph = orphans; orph != NULL; orph = orph->next) {
1261 if (orph->pgrp != 0)
1262 fprintf(stderr, "%d ", -(orph->pgrp));
1263 }
1264 fprintf(stderr, "\n");
1265}
1266
1267static void
1268dump_coll(struct collection *coll)
nstrazf307d5f2000-09-14 21:54:44 +00001269{
nstrazcde46c82001-03-08 19:13:21 +00001270 int i;
nstrazf307d5f2000-09-14 21:54:44 +00001271
1272 for (i = 0; i < coll->cnt; ++i) {
nstrazcd87d682000-09-21 20:42:31 +00001273 fprintf(stderr, "coll %d\n", i);
nstrazcde46c82001-03-08 19:13:21 +00001274 fprintf(stderr, " name=%s cmdline=%s\n", coll->ary[i]->name,
1275 coll->ary[i]->cmdline);
1276 }
1277}
1278
1279void
1280wait_handler( int sig )
1281{
1282 static int lastsent = 0;
1283
1284 if( sig == 0 ){
1285 lastsent = 0;
1286 } else {
1287 rec_signal = sig;
1288 if( sig == SIGUSR2 )
1289 return;
1290 if( lastsent == 0 )
1291 send_signal = sig;
1292 else if( lastsent == SIGUSR1 )
1293 send_signal = SIGINT;
1294 else if( lastsent == sig )
1295 send_signal = SIGTERM;
1296 else if( lastsent == SIGTERM )
1297 send_signal = SIGHUP;
1298 else if( lastsent == SIGHUP )
1299 send_signal = SIGKILL;
1300 lastsent = send_signal;
nstrazf307d5f2000-09-14 21:54:44 +00001301 }
1302}