blob: 82e75e19490492e3974e6f4d3c8536e35b7e7668 [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
35 *
nstrazf307d5f2000-09-14 21:54:44 +000036 */
robbiewcba89702002-09-05 20:48:35 +000037/* $Id: pan.c,v 1.13 2002/09/05 20:48:35 robbiew Exp $ */
nstrazf307d5f2000-09-14 21:54:44 +000038
39#include <errno.h>
40#include <string.h>
plars404bea32002-09-04 13:15:55 +000041#include <sys/param.h>
nstrazf307d5f2000-09-14 21:54:44 +000042#include <sys/types.h>
nstrazcd87d682000-09-21 20:42:31 +000043#include <sys/times.h>
nstrazf307d5f2000-09-14 21:54:44 +000044#include <sys/wait.h>
45#include <sys/stat.h>
nstrazf307d5f2000-09-14 21:54:44 +000046#include <time.h>
nstrazcd87d682000-09-21 20:42:31 +000047#include <stdlib.h>
48#include <limits.h>
nstrazf307d5f2000-09-14 21:54:44 +000049
nstrazcd87d682000-09-21 20:42:31 +000050#include "splitstr.h"
nstrazf307d5f2000-09-14 21:54:44 +000051#include "zoolib.h"
52
nstrazcde46c82001-03-08 19:13:21 +000053/* One entry in the command line collection. */
nstrazf307d5f2000-09-14 21:54:44 +000054struct coll_entry
55{
nstrazcde46c82001-03-08 19:13:21 +000056 char *name; /* tag name */
57 char *cmdline; /* command line */
58 char *pcnt_f; /* location of %f in the command line args, flag */
nstrazf307d5f2000-09-14 21:54:44 +000059 struct coll_entry *next;
60};
61
62struct collection
63{
64 int cnt;
65 struct coll_entry **ary;
66};
67
nstrazcd87d682000-09-21 20:42:31 +000068struct tag_pgrp
nstrazf307d5f2000-09-14 21:54:44 +000069{
70 int pgrp;
71 int stopping;
72 time_t stime;
73 struct coll_entry *cmd;
nstrazcd87d682000-09-21 20:42:31 +000074 char output[PATH_MAX];
nstrazf307d5f2000-09-14 21:54:44 +000075};
76
77struct orphan_pgrp
78{
79 int pgrp;
80 struct orphan_pgrp *next;
81};
82
nstrazcd87d682000-09-21 20:42:31 +000083static pid_t run_child(struct coll_entry *colle, struct tag_pgrp *active);
84static char *slurp(char *file);
85static struct collection *get_collection(char *file, int optind, int argc,
86 char **argv);
87static void pids_running(struct tag_pgrp *running, int keep_active);
88static int check_pids(struct tag_pgrp *running, int *num_active,
89 int keep_active, FILE * logfile, struct orphan_pgrp *orphans);
90static void propagate_signal(struct tag_pgrp *running, int keep_active,
91 struct orphan_pgrp *orphans);
92static void dump_coll(struct collection *coll);
nstrazcde46c82001-03-08 19:13:21 +000093static char *subst_pcnt_f(struct coll_entry *colle);
nstrazcd87d682000-09-21 20:42:31 +000094static void mark_orphan(struct orphan_pgrp *orphans, pid_t cpid);
95static void orphans_running(struct orphan_pgrp *orphans);
96static void check_orphans(struct orphan_pgrp *orphans, int sig);
nstrazf307d5f2000-09-14 21:54:44 +000097
nstrazcd87d682000-09-21 20:42:31 +000098static void copy_buffered_output(struct tag_pgrp *running);
99static void write_test_start(struct tag_pgrp *running, const char *init_status);
100static void write_test_end(struct tag_pgrp *running,
101 time_t exit_time, char *term_type, int stat_loc,
102 int term_id, struct tms *tms1, struct tms *tms2);
nstrazf307d5f2000-09-14 21:54:44 +0000103
robbiewc1706732002-02-19 18:06:31 +0000104//wjh
105static char PAN_STOP_FILE[] = "PAN_STOP_FILE";
106
nstrazf307d5f2000-09-14 21:54:44 +0000107static char *panname = NULL;
nstrazfef21be2001-03-15 21:23:27 +0000108static char *test_out_dir = NULL; /* dir to buffer output to */
109zoo_t zoofile;
nstrazcd87d682000-09-21 20:42:31 +0000110static char *reporttype = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000111
112/* Debug Bits */
113int Debug = 0;
nstrazcd87d682000-09-21 20:42:31 +0000114#define Dbuffile 0x000400 /* buffer file use */
nstrazf307d5f2000-09-14 21:54:44 +0000115#define Dsetup 0x000200 /* one-time set-up */
116#define Dshutdown 0x000100 /* killed by signal */
117#define Dexit 0x000020 /* exit status */
118#define Drunning 0x000010 /* current pids running */
119#define Dstartup 0x000004 /* started command */
120#define Dstart 0x000002 /* started command */
121#define Dwait 0x000001 /* wait interrupted */
122
nstrazcd87d682000-09-21 20:42:31 +0000123int
124main(int argc, char **argv)
nstrazf307d5f2000-09-14 21:54:44 +0000125{
126 extern char *optarg;
127 extern int optind;
128 int c;
nstrazfef21be2001-03-15 21:23:27 +0000129 char *zooname = NULL; /* name of the zoo file to use */
130 char *filename = "/dev/null"; /* filename to read test tags from */
nstrazf307d5f2000-09-14 21:54:44 +0000131 char *logfilename = NULL;
132 FILE *logfile = NULL;
nstrazcd87d682000-09-21 20:42:31 +0000133 char *outputfilename = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000134 struct collection *coll = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000135 pid_t cpid;
nstrazcd87d682000-09-21 20:42:31 +0000136 struct tag_pgrp *running;
nstrazf307d5f2000-09-14 21:54:44 +0000137 struct orphan_pgrp *orphans, *orph;
138 int keep_active = 1;
139 int num_active = 0;
140 int err, i;
141 int starts = -1;
robbiewc1706732002-02-19 18:06:31 +0000142 int run_time = -1; char modifier = 'm'; int ret = 0;
nstrazf307d5f2000-09-14 21:54:44 +0000143 int stop;
144 int go_idle;
nstrazfef21be2001-03-15 21:23:27 +0000145 int has_brakes = 0; /* stop everything if a test case fails */
146 int sequential = 0; /* run tests sequentially */
nstrazf307d5f2000-09-14 21:54:44 +0000147 int fork_in_road = 0;
nstrazf307d5f2000-09-14 21:54:44 +0000148 int exit_stat;
nstrazfef21be2001-03-15 21:23:27 +0000149 int track_exit_stats = 0; /* exit non-zero if any test exits non-zero */
nstrazf307d5f2000-09-14 21:54:44 +0000150
robbiewc1706732002-02-19 18:06:31 +0000151 while ((c = getopt(argc, argv, "AO:Sa:d:ef:hl:n:o:r:s:t:x:y")) != -1) {
nstrazf307d5f2000-09-14 21:54:44 +0000152 switch (c) {
nstrazfef21be2001-03-15 21:23:27 +0000153 case 'A': /* all-stop flag */
nstrazf307d5f2000-09-14 21:54:44 +0000154 has_brakes = 1;
155 track_exit_stats = 1;
156 break;
nstrazfef21be2001-03-15 21:23:27 +0000157 case 'O': /* output buffering directory */
nstrazcd87d682000-09-21 20:42:31 +0000158 test_out_dir = strdup(optarg);
nstrazf307d5f2000-09-14 21:54:44 +0000159 break;
nstrazfef21be2001-03-15 21:23:27 +0000160 case 'S': /* run tests sequentially */
nstrazf307d5f2000-09-14 21:54:44 +0000161 sequential = 1;
162 break;
nstrazfef21be2001-03-15 21:23:27 +0000163 case 'a': /* name of the zoo file to use */
nstrazcd87d682000-09-21 20:42:31 +0000164 zooname = strdup(optarg);
nstrazf307d5f2000-09-14 21:54:44 +0000165 break;
nstrazfef21be2001-03-15 21:23:27 +0000166 case 'd': /* debug options */
nstrazcd87d682000-09-21 20:42:31 +0000167 sscanf(optarg, "%i", &Debug);
nstrazf307d5f2000-09-14 21:54:44 +0000168 break;
nstrazfef21be2001-03-15 21:23:27 +0000169 case 'e': /* exit non-zero if any test exists non-zero */
nstrazf307d5f2000-09-14 21:54:44 +0000170 track_exit_stats = 1;
171 break;
nstrazfef21be2001-03-15 21:23:27 +0000172 case 'f': /* filename to read test tags from */
nstrazcd87d682000-09-21 20:42:31 +0000173 filename = strdup(optarg);
174 break;
nstrazfef21be2001-03-15 21:23:27 +0000175 case 'h': /* help */
nstrazf307d5f2000-09-14 21:54:44 +0000176 printf
robbiewc1706732002-02-19 18:06:31 +0000177 ("Usage: pan -n name [ -SyAeh ] [ -s starts ] [-t time[s|m|h|d] [ -x nactive ] [ -l logfile ]\n\t[ -a active-file ] [ -f command-file ] [ -d debug-level ]\n\t[-o output-file] [-O output-buffer-directory] [cmd]\n");
nstrazcd87d682000-09-21 20:42:31 +0000178 exit(0);
nstrazfef21be2001-03-15 21:23:27 +0000179 case 'l': /* log file */
nstrazcd87d682000-09-21 20:42:31 +0000180 logfilename = strdup(optarg);
181 break;
nstrazfef21be2001-03-15 21:23:27 +0000182 case 'n': /* tag given to pan */
nstrazcd87d682000-09-21 20:42:31 +0000183 panname = strdup(optarg);
184 break;
nstrazfef21be2001-03-15 21:23:27 +0000185 case 'o': /* send test output here */
nstrazcd87d682000-09-21 20:42:31 +0000186 outputfilename = strdup(optarg);
187 break;
nstrazfef21be2001-03-15 21:23:27 +0000188 case 'r': /* reporting type: none, rts */
nstrazcd87d682000-09-21 20:42:31 +0000189 reporttype = strdup(optarg);
190 break;
nstrazfef21be2001-03-15 21:23:27 +0000191 case 's': /* number of tags to run */
nstrazcd87d682000-09-21 20:42:31 +0000192 starts = atoi(optarg);
193 break;
robbiewc1706732002-02-19 18:06:31 +0000194 case 't': /* run_time to run */
195 ret = sscanf(optarg, "%d%c", &run_time, &modifier);
196 if (ret == 0) { printf("Need proper time input: ####x where"
197 "x is one of s,m,h,d\n"); break; }
198 else if (ret == 1) { printf("Only got a time value of %d "
199 "modifiers need to come immediately after #"
200 " assuming %c\n", run_time, modifier); }
201 else
202 {
203 switch (modifier)
204 {
205 case 's': run_time = run_time; break;
206 case 'm': run_time = run_time * 60; break;
207 case 'h': run_time = run_time * 60 * 60; break;
208 case 'd': run_time = run_time * 60 * 60 * 24; break;
209 default:
210 printf("Invalid time modifier, try: s|h|m|d\n"); exit(-1);
211 }
212 printf("PAN will run for %d seconds\n", run_time);
213 }
214 starts = 0; //-t implies run as many starts as possible
215 break;
nstrazfef21be2001-03-15 21:23:27 +0000216 case 'x': /* number of tags to keep running */
nstrazcd87d682000-09-21 20:42:31 +0000217 keep_active = atoi(optarg);
218 break;
nstrazfef21be2001-03-15 21:23:27 +0000219 case 'y': /* restart on failure or signal */
nstrazcd87d682000-09-21 20:42:31 +0000220 fork_in_road = 1;
221 break;
nstrazf307d5f2000-09-14 21:54:44 +0000222 }
223 }
224
225 if (panname == NULL) {
nstrazcd87d682000-09-21 20:42:31 +0000226 fprintf(stderr, "pan: Must supply -n\n");
227 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000228 }
nstrazcd87d682000-09-21 20:42:31 +0000229 if (zooname == NULL) {
nstrazcde46c82001-03-08 19:13:21 +0000230 zooname = zoo_getname();
nstrazcd87d682000-09-21 20:42:31 +0000231 if (zooname == NULL) {
232 fprintf(stderr,
233 "pan(%s): Must supply -a or set ZOO env variable\n",
234 panname);
235 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000236 }
237 }
nstrazcd87d682000-09-21 20:42:31 +0000238 if (reporttype) {
239 /* make sure we understand the report type */
240 if (strcasecmp(reporttype, "rts")
241 && strcasecmp(reporttype, "none")
242 /* && strcasecmp(reporttype, "xml")*/)
243 reporttype = "rts";
244 } else {
245 /* set the default */
246 reporttype = "rts";
247 }
nstrazf307d5f2000-09-14 21:54:44 +0000248
249 if (logfilename != NULL) {
250 time_t startup;
251 char *s;
252
nstrazcd87d682000-09-21 20:42:31 +0000253 if (!strcmp(logfilename, "-")) {
nstrazf307d5f2000-09-14 21:54:44 +0000254 logfile = stdout;
255 } else {
nstrazcd87d682000-09-21 20:42:31 +0000256 if ((logfile = fopen(logfilename, "a+")) == NULL) {
257 fprintf(stderr,
258 "pan(%s): Error %s (%d) opening log file '%s'\n",
259 panname, strerror(errno), errno, logfilename);
260 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000261 }
262 }
263
nstrazcd87d682000-09-21 20:42:31 +0000264 time(&startup);
265 s = ctime(&startup);
266 *(s + strlen(s) - 1) = '\0';
267 fprintf(logfile, "startup='%s'\n", s);
nstrazf307d5f2000-09-14 21:54:44 +0000268 }
269
nstrazcd87d682000-09-21 20:42:31 +0000270 coll = get_collection(filename, optind, argc, argv);
nstrazf307d5f2000-09-14 21:54:44 +0000271 if (coll->cnt == 0) {
nstrazcd87d682000-09-21 20:42:31 +0000272 fprintf(stderr,
273 "pan(%s): Must supply a file collection or a command\n",
274 panname);
275 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000276 }
277
278 if (Debug & Dsetup)
nstrazcd87d682000-09-21 20:42:31 +0000279 dump_coll(coll);
nstrazf307d5f2000-09-14 21:54:44 +0000280
281 /* a place to store the pgrps we're watching */
nstrazcd87d682000-09-21 20:42:31 +0000282 running = (struct tag_pgrp *)malloc((keep_active + 1) * sizeof(struct tag_pgrp));
283 memset(running, 0, keep_active * sizeof(struct tag_pgrp));
nstrazf307d5f2000-09-14 21:54:44 +0000284 running[keep_active].pgrp = -1; /* end sentinel */
285
286 /* a head to the orphaned pgrp list */
nstrazcd87d682000-09-21 20:42:31 +0000287 orphans = (struct orphan_pgrp *) malloc(sizeof(struct orphan_pgrp));
288 memset(orphans, 0, sizeof(struct orphan_pgrp));
nstrazf307d5f2000-09-14 21:54:44 +0000289
nstrazcd87d682000-09-21 20:42:31 +0000290 srand48(time(NULL) ^ (getpid() + (getpid() << 15)));
nstrazf307d5f2000-09-14 21:54:44 +0000291
292 /* Supply a default for starts. If we are in sequential mode, use
293 * the number of commands available; otherwise 1.
294 */
nstrazcd87d682000-09-21 20:42:31 +0000295 if (starts == -1) {
296 if (sequential) {
nstrazf307d5f2000-09-14 21:54:44 +0000297 starts = coll->cnt;
nstrazcd87d682000-09-21 20:42:31 +0000298 } else {
nstrazf307d5f2000-09-14 21:54:44 +0000299 starts = 1;
nstrazcd87d682000-09-21 20:42:31 +0000300 }
301 } else if (starts == 0) { /* if the user specified infinite, set it */
302 starts = -1;
303 } else { /* else, make sure we are starting at least keep_active processes */
304 if (starts < keep_active)
305 starts = keep_active;
nstrazf307d5f2000-09-14 21:54:44 +0000306 }
nstrazcd87d682000-09-21 20:42:31 +0000307
308 /* if we're buffering output, but we're only running on process at a time,
309 * then essentially "turn off buffering"
310 */
311 if (test_out_dir && (keep_active == 1)) {
312 free(test_out_dir);
313 test_out_dir = NULL;
314 }
315
316 if (test_out_dir) {
317 struct stat sbuf;
318
319 if (stat(test_out_dir, &sbuf) < 0) {
320 fprintf(stderr,
321 "pan(%s): stat of -O arg '%s' failed. errno: %d %s\n",
322 panname, test_out_dir, errno, strerror(errno));
323 exit(1);
324 }
325 if (!S_ISDIR(sbuf.st_mode)) {
326 fprintf(stderr, "pan(%s): -O arg '%s' must be a directory.\n",
327 panname, test_out_dir);
328 exit(1);
329 }
330 if (access(test_out_dir, W_OK | R_OK | X_OK) < 0) {
331 fprintf(stderr,
332 "pan(%s): permission denied on -O arg '%s'. errno: %d %s\n",
333 panname, test_out_dir, errno, strerror(errno));
334 exit(1);
335 }
336 }
337
338 if (outputfilename) {
339 if (!freopen(outputfilename, "a+", stdout)) {
340 fprintf(stderr,
341 "pan(%s): Error %s (%d) openning output file '%s'\n",
342 panname, strerror(errno), errno, outputfilename);
343 exit(1);
344 }
345 }
346
nstrazcde46c82001-03-08 19:13:21 +0000347 if ((zoofile = zoo_open(zooname)) == NULL) {
348 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000349 exit(1);
350 }
nstrazcde46c82001-03-08 19:13:21 +0000351 if (zoo_mark_args(zoofile, getpid(), panname, argc, argv)) {
352 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000353 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000354 }
355
356 /* Allocate N spaces for max-arg commands.
357 * this is an "active file cleanliness" thing
358 */
359 {
360 char *av[2], bigarg[82];
nstrazf307d5f2000-09-14 21:54:44 +0000361
nstrazcd87d682000-09-21 20:42:31 +0000362 memset(bigarg, '.', 81);
nstrazf307d5f2000-09-14 21:54:44 +0000363 bigarg[81] = '\0';
364 av[0] = bigarg;
365 av[1] = NULL;
366
367 for (c = 0; c < keep_active; c++) {
nstrazcde46c82001-03-08 19:13:21 +0000368 if (zoo_mark_cmdline(zoofile, c, panname, "")) {
369 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000370 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000371 }
372 }
373 for (c = 0; c < keep_active; c++) {
nstrazcde46c82001-03-08 19:13:21 +0000374 if (zoo_clear(zoofile, c)) {
375 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000376 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000377 }
378 }
379 }
380
381 rec_signal = send_signal = 0;
robbiewcba89702002-09-05 20:48:35 +0000382 if (run_time != -1) { alarm(run_time); }
robbiewc1706732002-02-19 18:06:31 +0000383 signal(SIGALRM, wait_handler);
nstrazcd87d682000-09-21 20:42:31 +0000384 signal(SIGINT, wait_handler);
385 signal(SIGTERM, wait_handler);
386 signal(SIGHUP, wait_handler);
387 signal(SIGUSR1, wait_handler); /* ignore fork_in_road */
388 signal(SIGUSR2, wait_handler); /* stop the scheduler */
nstrazf307d5f2000-09-14 21:54:44 +0000389
390 c = 0; /* in this loop, c is the command index */
391 stop = 0;
392 exit_stat = 0;
393 go_idle = 0;
394 while (1) {
395
396 while ((num_active < keep_active) && (starts != 0)) {
397 if (stop || rec_signal || go_idle)
398 break;
399
400 if (!sequential)
nstrazcd87d682000-09-21 20:42:31 +0000401 c = lrand48() % coll->cnt;
nstrazf307d5f2000-09-14 21:54:44 +0000402
403 /* find a slot for the child */
404 for (i = 0; i < keep_active; ++i) {
405 if (running[i].pgrp == 0)
406 break;
407 }
408 if (i == keep_active) {
nstrazcd87d682000-09-21 20:42:31 +0000409 fprintf(stderr, "pan(%s): Aborting: i == keep_active = %d\n",
410 panname, i);
411 wait_handler(SIGINT);
nstrazf307d5f2000-09-14 21:54:44 +0000412 exit_stat++;
413 break;
414 }
415
nstrazcd87d682000-09-21 20:42:31 +0000416 cpid = run_child(coll->ary[c], running + i);
nstrazf307d5f2000-09-14 21:54:44 +0000417 if (cpid != -1) {
418 ++num_active;
419 if (starts > 0)
420 --starts;
421 }
422
423 if (sequential)
424 if (++c >= coll->cnt)
425 c = 0;
426
robbiewc1706732002-02-19 18:06:31 +0000427 } /* while( (num_active < keep_active) && (starts != 0) ) */
nstrazf307d5f2000-09-14 21:54:44 +0000428
429 if (starts == 0)
robbiewc1706732002-02-19 18:06:31 +0000430 { printf("incrementing stop\n"); ++stop; }
431 else if (starts == -1) //wjh
432 {
433 FILE *f = (FILE*)-1;
434 if ((f = fopen(PAN_STOP_FILE, "r")) != 0)
435 { printf("Got %s Stopping!\n", PAN_STOP_FILE);
robbiew15226cd2002-04-10 16:10:40 +0000436 fclose(f); unlink(PAN_STOP_FILE); stop++;
robbiewc1706732002-02-19 18:06:31 +0000437 }
438 }
nstrazf307d5f2000-09-14 21:54:44 +0000439
440 if (rec_signal) {
441 /* propagate everything except sigusr2 */
442
443 if (rec_signal == SIGUSR2) {
444 if (fork_in_road)
445 ++go_idle;
446 else
447 ++stop;
nstrazcd87d682000-09-21 20:42:31 +0000448 signal(rec_signal, wait_handler);
nstrazf307d5f2000-09-14 21:54:44 +0000449 rec_signal = send_signal = 0;
450 } else {
451 if (rec_signal == SIGUSR1)
452 fork_in_road = 0;
nstrazcd87d682000-09-21 20:42:31 +0000453 propagate_signal(running, keep_active, orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000454 if (fork_in_road)
455 ++go_idle;
456 else
457 ++stop;
458 }
459 }
460
nstrazcd87d682000-09-21 20:42:31 +0000461 err = check_pids(running, &num_active, keep_active,
462 logfile, orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000463 if (Debug & Drunning) {
nstrazcd87d682000-09-21 20:42:31 +0000464 pids_running(running, keep_active);
465 orphans_running(orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000466 }
467 if (err) {
468 if (fork_in_road)
469 ++go_idle;
470 if (track_exit_stats)
471 exit_stat++;
472 if (has_brakes) {
nstrazcd87d682000-09-21 20:42:31 +0000473 fprintf(stderr, "pan(%s): All stop!%s\n", panname,
nstrazf307d5f2000-09-14 21:54:44 +0000474 go_idle ? " (idling)" : "");
nstrazcd87d682000-09-21 20:42:31 +0000475 wait_handler(SIGINT);
nstrazf307d5f2000-09-14 21:54:44 +0000476 }
477 }
478
479 if (stop && (num_active == 0))
480 break;
481
482 if (go_idle && (num_active == 0)) {
483 go_idle = 0; /* It is idle, now resume scheduling. */
nstrazcd87d682000-09-21 20:42:31 +0000484 wait_handler(0); /* Reset the signal ratchet. */
nstrazf307d5f2000-09-14 21:54:44 +0000485 }
486 }
487
488 /* Wait for orphaned pgrps */
489 while (1) {
490 for (orph = orphans; orph != NULL; orph = orph->next) {
491 if (orph->pgrp == 0)
492 continue;
493 /* Yes, we have orphaned pgrps */
nstrazcd87d682000-09-21 20:42:31 +0000494 sleep(5);
nstrazf307d5f2000-09-14 21:54:44 +0000495 if (!rec_signal) {
496 /* force an artificial signal, move us
497 * through the signal ratchet.
498 */
nstrazcd87d682000-09-21 20:42:31 +0000499 wait_handler(SIGINT);
nstrazf307d5f2000-09-14 21:54:44 +0000500 }
nstrazcd87d682000-09-21 20:42:31 +0000501 propagate_signal(running, keep_active, orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000502 if (Debug & Drunning)
nstrazcd87d682000-09-21 20:42:31 +0000503 orphans_running(orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000504 break;
505 }
506 if (orph == NULL)
507 break;
508 }
509
nstrazcd87d682000-09-21 20:42:31 +0000510 signal(SIGINT, SIG_DFL);
nstrazcde46c82001-03-08 19:13:21 +0000511 if (zoo_clear(zoofile, getpid())) {
512 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazf307d5f2000-09-14 21:54:44 +0000513 ++exit_stat;
514 }
nstrazcd87d682000-09-21 20:42:31 +0000515 fclose(zoofile);
nstrazf307d5f2000-09-14 21:54:44 +0000516
nstrazcd87d682000-09-21 20:42:31 +0000517 if (logfile && (logfile != stdout))
518 fclose(logfile);
519
520 exit(exit_stat);
nstrazf307d5f2000-09-14 21:54:44 +0000521}
522
523
nstrazf307d5f2000-09-14 21:54:44 +0000524
525static void
nstrazcd87d682000-09-21 20:42:31 +0000526propagate_signal(struct tag_pgrp *running, int keep_active,
527 struct orphan_pgrp *orphans)
nstrazf307d5f2000-09-14 21:54:44 +0000528{
529 int i;
530
531 if (Debug & Dshutdown)
nstrazcd87d682000-09-21 20:42:31 +0000532 fprintf(stderr, "pan was signaled with sig %d...\n", rec_signal);
nstrazf307d5f2000-09-14 21:54:44 +0000533
robbiewc1706732002-02-19 18:06:31 +0000534 if (rec_signal == SIGALRM)
535 {
536 printf("PAN stop Alarm was received\n");
537 rec_signal = SIGTERM;
538 }
539
nstrazf307d5f2000-09-14 21:54:44 +0000540 for (i = 0; i < keep_active; ++i) {
541 if (running[i].pgrp == 0)
542 continue;
543
544 if (Debug & Dshutdown)
nstrazcd87d682000-09-21 20:42:31 +0000545 fprintf(stderr, " propagating sig %d to %d\n",
nstrazf307d5f2000-09-14 21:54:44 +0000546 send_signal, -running[i].pgrp);
nstrazcd87d682000-09-21 20:42:31 +0000547 if (kill(-running[i].pgrp, send_signal) != 0) {
548 fprintf(stderr,
549 "pan(%s): kill(%d,%d) failed on tag (%s). errno:%d %s\n",
550 panname, -running[i].pgrp, send_signal,
551 running[i].cmd->name, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000552 }
553 running[i].stopping = 1;
554 }
555
nstrazcd87d682000-09-21 20:42:31 +0000556 check_orphans(orphans, send_signal);
nstrazf307d5f2000-09-14 21:54:44 +0000557
nstrazcd87d682000-09-21 20:42:31 +0000558 signal(rec_signal, wait_handler);
nstrazf307d5f2000-09-14 21:54:44 +0000559 rec_signal = send_signal = 0;
560}
561
562
563static int
nstrazcd87d682000-09-21 20:42:31 +0000564check_pids(struct tag_pgrp *running, int *num_active, int keep_active,
565 FILE * logfile, struct orphan_pgrp *orphans)
nstrazf307d5f2000-09-14 21:54:44 +0000566{
567 int w;
568 pid_t cpid;
569 int stat_loc;
570 int ret = 0;
571 int i;
572 time_t t;
573 char *status;
574 int signaled = 0;
575 struct tms tms1, tms2;
576 clock_t tck;
577
nstrazcd87d682000-09-21 20:42:31 +0000578 check_orphans(orphans, 0);
nstrazf307d5f2000-09-14 21:54:44 +0000579
nstrazcd87d682000-09-21 20:42:31 +0000580 tck = times(&tms1);
nstrazf307d5f2000-09-14 21:54:44 +0000581 if (tck == -1) {
nstrazcd87d682000-09-21 20:42:31 +0000582 fprintf(stderr, "pan(%s): times(&tms1) failed. errno:%d %s\n",
583 panname, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000584 }
nstrazcd87d682000-09-21 20:42:31 +0000585 cpid = wait(&stat_loc);
586 tck = times(&tms2);
nstrazf307d5f2000-09-14 21:54:44 +0000587 if (tck == -1) {
nstrazcd87d682000-09-21 20:42:31 +0000588 fprintf(stderr, "pan(%s): times(&tms2) failed. errno:%d %s\n",
589 panname, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000590 }
591
592 if (cpid < 0) {
593 if (errno == EINTR) {
594 if (Debug)
nstrazcd87d682000-09-21 20:42:31 +0000595 fprintf(stderr, "pan(%s): wait() interrupted\n", panname);
nstrazf307d5f2000-09-14 21:54:44 +0000596 } else if (errno != ECHILD) {
nstrazcd87d682000-09-21 20:42:31 +0000597 fprintf(stderr, "pan(%s): wait() failed. errno:%d %s\n",
598 panname, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000599 }
600 } else if (cpid > 0) {
601
nstrazcd87d682000-09-21 20:42:31 +0000602 if (WIFSIGNALED(stat_loc)) {
603 w = WTERMSIG(stat_loc);
nstrazf307d5f2000-09-14 21:54:44 +0000604 status = "signaled";
605 if (Debug & Dexit)
nstrazcd87d682000-09-21 20:42:31 +0000606 fprintf(stderr, "child %d terminated with signal %d\n", cpid,
607 w);
nstrazf307d5f2000-09-14 21:54:44 +0000608 --*num_active;
609 signaled = 1;
nstrazcd87d682000-09-21 20:42:31 +0000610 } else if (WIFEXITED(stat_loc)) {
611 w = WEXITSTATUS(stat_loc);
nstrazf307d5f2000-09-14 21:54:44 +0000612 status = "exited";
613 if (Debug & Dexit)
nstrazcd87d682000-09-21 20:42:31 +0000614 fprintf(stderr, "child %d exited with status %d\n", cpid, w);
nstrazf307d5f2000-09-14 21:54:44 +0000615 --*num_active;
616 if (w != 0)
617 ret++;
nstrazcd87d682000-09-21 20:42:31 +0000618 } else if (WIFSTOPPED(stat_loc)) { /* should never happen */
619 w = WSTOPSIG(stat_loc);
nstrazf307d5f2000-09-14 21:54:44 +0000620 status = "stopped";
621 ret++;
622 } else { /* should never happen */
623 w = 0;
624 status = "unknown";
625 ret++;
626 }
627
628 for (i = 0; i < keep_active; ++i) {
629 if (running[i].pgrp == cpid) {
630 if ((w == 130) && running[i].stopping &&
nstrazcd87d682000-09-21 20:42:31 +0000631 (strcmp(status, "exited") == 0)) {
nstrazf307d5f2000-09-14 21:54:44 +0000632 /* The child received sigint, but
633 * did not trap for it? Compensate
634 * for it here.
635 */
636 w = 0;
637 ret--; /* undo */
638 if (Debug & Drunning)
nstrazcd87d682000-09-21 20:42:31 +0000639 fprintf(stderr,
640 "pan(%s): tag=%s exited 130, known to be signaled; will give it an exit 0.\n",
641 panname, running[i].cmd->name);
nstrazf307d5f2000-09-14 21:54:44 +0000642 }
plarsdebdbd12001-11-30 19:30:29 +0000643 time(&t);
nstrazf307d5f2000-09-14 21:54:44 +0000644 if (logfile != NULL) {
nstrazcd87d682000-09-21 20:42:31 +0000645 fprintf(logfile,
646 "tag=%s stime=%d dur=%d exit=%s stat=%d core=%s cu=%d cs=%d\n",
647 running[i].cmd->name, (int) (running[i].stime),
648 (int) (t - running[i].stime), status, w,
649 (stat_loc & 0200) ? "yes" : "no",
650 (int) (tms2.tms_cutime - tms1.tms_cutime),
651 (int) (tms2.tms_cstime - tms1.tms_cstime));
652 fflush(logfile);
nstrazf307d5f2000-09-14 21:54:44 +0000653 }
nstrazcd87d682000-09-21 20:42:31 +0000654
655
656 if (running[i].stopping)
657 status = "driver_interrupt";
658
659 if (test_out_dir) {
660 write_test_start(running+i, "ok");
661 copy_buffered_output(running + i);
662 unlink(running[i].output);
663 }
664 write_test_end(running+i, t, status,
665 stat_loc, w, &tms1, &tms2);
666
nstrazf307d5f2000-09-14 21:54:44 +0000667 /* If signaled and we weren't expecting
668 * this to be stopped then the proc
669 * had a problem.
670 */
671 if (signaled && !running[i].stopping)
672 ret++;
673
674 running[i].pgrp = 0;
nstrazcde46c82001-03-08 19:13:21 +0000675 if (zoo_clear(zoofile, cpid)) {
676 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000677 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000678 }
679
680 /* Check for orphaned pgrps */
nstrazcd87d682000-09-21 20:42:31 +0000681 if ((kill(-cpid, 0) == 0) || (errno == EPERM)) {
nstrazcde46c82001-03-08 19:13:21 +0000682 if (zoo_mark_cmdline(zoofile, cpid, "panorphan",
683 running[i].cmd->cmdline)) {
684 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000685 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000686 }
nstrazcd87d682000-09-21 20:42:31 +0000687 mark_orphan(orphans, cpid);
nstrazf307d5f2000-09-14 21:54:44 +0000688 /* status of kill doesn't matter */
nstrazcd87d682000-09-21 20:42:31 +0000689 kill(-cpid, SIGTERM);
nstrazf307d5f2000-09-14 21:54:44 +0000690 }
691
692 break;
693 }
694 }
695 }
696 return ret;
697}
698
699
700static pid_t
nstrazcd87d682000-09-21 20:42:31 +0000701run_child(struct coll_entry *colle, struct tag_pgrp *active)
nstrazf307d5f2000-09-14 21:54:44 +0000702{
703 int cpid;
robbiewf3a83d52002-05-28 16:26:16 +0000704 int c_stdout = -1; /* child's stdout, stderr */
nstrazcd87d682000-09-21 20:42:31 +0000705 int capturing = 0; /* output is going to a file instead of stdout */
nstrazcde46c82001-03-08 19:13:21 +0000706 char *c_cmdline;
nstrazcd87d682000-09-21 20:42:31 +0000707 static long cmdno = 0;
nstrazcd87d682000-09-21 20:42:31 +0000708 int errpipe[2]; /* way to communicate to parent that the tag */
709 char errbuf[1024]; /* didn't actually start */
710 int errlen;
nstrazf307d5f2000-09-14 21:54:44 +0000711
nstrazcd87d682000-09-21 20:42:31 +0000712 /* Try to open the file that will be stdout for the test */
713 if (test_out_dir) {
714 capturing = 1;
715 do {
716 sprintf(active->output, "%s/%s.%ld",
717 test_out_dir, colle->name, cmdno++);
nstraz566e8c82000-09-22 19:52:17 +0000718 c_stdout = open(active->output, O_CREAT | O_RDWR | O_EXCL | O_SYNC, 0666);
nstrazcd87d682000-09-21 20:42:31 +0000719 } while (c_stdout < 0 && errno == EEXIST);
720 if (c_stdout < 0) {
721 fprintf(stderr,
722 "pan(%s): open of stdout file failed (tag %s). errno: %d %s\n file: %s\n",
723 panname, colle->name, errno, strerror(errno),
724 active->output);
725 return -1;
726 }
727 }
728
729 /* get the tag's command line arguments ready. subst_pcnt_f() uses a
730 * static counter, that's why we do it here instead of after we fork.
731 */
732 if (colle->pcnt_f) {
nstrazcde46c82001-03-08 19:13:21 +0000733 c_cmdline = subst_pcnt_f(colle);
nstrazcd87d682000-09-21 20:42:31 +0000734 } else {
nstrazcde46c82001-03-08 19:13:21 +0000735 c_cmdline = colle->cmdline;
nstrazcd87d682000-09-21 20:42:31 +0000736 }
737
738 if (pipe(errpipe) < 0) {
739 fprintf(stderr, "pan(%s): pipe() failed. errno:%d %s\n",
740 panname, errno, strerror(errno));
nstraz6c3f66b2001-09-28 21:56:46 +0000741 if (capturing) {
nstrazcd87d682000-09-21 20:42:31 +0000742 close(c_stdout);
nstraz6c3f66b2001-09-28 21:56:46 +0000743 unlink(active->output);
744 }
nstrazcd87d682000-09-21 20:42:31 +0000745 return -1;
746 }
747
748 if ((cpid = fork()) < 0) {
749 fprintf(stderr, "pan(%s): fork failed (tag %s). errno:%d %s\n",
750 panname, colle->name, errno, strerror(errno));
nstraz6c3f66b2001-09-28 21:56:46 +0000751 if (capturing) {
752 unlink(active->output);
nstrazcd87d682000-09-21 20:42:31 +0000753 close(c_stdout);
nstraz6c3f66b2001-09-28 21:56:46 +0000754 }
nstrazcd87d682000-09-21 20:42:31 +0000755 close(errpipe[0]);
756 close(errpipe[1]);
nstrazf307d5f2000-09-14 21:54:44 +0000757 return -1;
758 } else if (cpid == 0) {
759 /* child */
nstrazf307d5f2000-09-14 21:54:44 +0000760
nstrazcd87d682000-09-21 20:42:31 +0000761 fclose(zoofile);
762 close(errpipe[0]);
763 fcntl(errpipe[1], F_SETFD, 1); /* close the pipe if we succeed */
764 setpgrp();
nstrazf307d5f2000-09-14 21:54:44 +0000765
nstrazcd87d682000-09-21 20:42:31 +0000766 umask(0);
767
768 /* if we're putting output into a buffer file, we need to do the
769 * redirection now. If we fail
770 */
771 if (capturing) {
772 if (dup2(c_stdout, fileno(stdout)) == -1) {
773 errlen = sprintf(errbuf, "pan(%s): couldn't redirect stdout for tag %s. errno:%d %s",
774 panname, colle->name, errno, strerror(errno));
775 write(errpipe[1], &errlen, sizeof(errlen));
776 write(errpipe[1], errbuf, errlen);
777 exit(2);
778 }
779 if (dup2(c_stdout, fileno(stderr)) == -1) {
780 errlen = sprintf(errbuf, "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s",
781 panname, colle->name, errno, strerror(errno));
782 write(errpipe[1], &errlen, sizeof(errlen));
783 write(errpipe[1], errbuf, errlen);
784 exit(2);
785 }
786 } else { /* stderr still needs to be redirected */
787 if (dup2(fileno(stdout), fileno(stderr)) == -1) {
788 errlen = sprintf(errbuf, "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s",
789 panname, colle->name, errno, strerror(errno));
790 write(errpipe[1], &errlen, sizeof(errlen));
791 write(errpipe[1], errbuf, errlen);
792 exit(2);
793 }
nstrazf307d5f2000-09-14 21:54:44 +0000794 }
nstrazcde46c82001-03-08 19:13:21 +0000795 /* If there are any shell-type characters in the cmdline
796 * such as '>', '<', '$', '|', etc, then we exec a shell and
797 * run the cmd under a shell.
798 *
799 * Otherwise, break the cmdline at white space and exec the
800 * cmd directly.
801 */
802 if (strpbrk(c_cmdline, "\"';|<>$\\")) {
803 execlp("sh", "sh", "-c", c_cmdline, 0);
804 errlen = sprintf(errbuf,
805 "pan(%s): execlp of '%s' (tag %s) failed. errno:%d %s",
806 panname, c_cmdline, colle->name, errno, strerror(errno));
807 } else {
808 char **arg_v;
809
810 arg_v = (char **)splitstr(c_cmdline, NULL, NULL);
811
812 execvp(arg_v[0], arg_v);
813 errlen = sprintf(errbuf,
814 "pan(%s): execvp of '%s' (tag %s) failed. errno:%d %s",
815 panname, arg_v[0], colle->name, errno, strerror(errno));
816 }
nstrazcd87d682000-09-21 20:42:31 +0000817 write(errpipe[1], &errlen, sizeof(errlen));
818 write(errpipe[1], errbuf, errlen);
819 exit(errno);
nstrazf307d5f2000-09-14 21:54:44 +0000820 }
821
822 /* parent */
nstrazcd87d682000-09-21 20:42:31 +0000823
nstrazcde46c82001-03-08 19:13:21 +0000824 /* subst_pcnt_f() allocates the command line dynamically
825 * free the malloc to prevent a memory leak
nstrazcd87d682000-09-21 20:42:31 +0000826 */
nstrazcde46c82001-03-08 19:13:21 +0000827 if (colle->pcnt_f) free(c_cmdline);
828
nstrazcd87d682000-09-21 20:42:31 +0000829 close(errpipe[1]);
830 time(&active->stime);
nstrazf307d5f2000-09-14 21:54:44 +0000831 active->cmd = colle;
832
nstrazcd87d682000-09-21 20:42:31 +0000833 /* if the child couldn't go through with the exec,
834 * clean up the mess, note it, and move on
835 */
836 if(read(errpipe[0], &errlen, sizeof(errlen))) {
837 int status;
838 time_t end_time;
839 int termid;
840 char *termtype;
841 struct tms notime = {0, 0, 0, 0};
842
843 read(errpipe[0], errbuf, errlen);
844 close(errpipe[0]);
845 errbuf[errlen] = '\0';
846 /* fprintf(stderr, "%s", errbuf); */
847 waitpid(cpid, &status, 0);
848 if (WIFSIGNALED(status)) {
849 termid = WTERMSIG(status);
850 termtype = "signaled";
851 } else if (WIFEXITED(status)) {
852 termid = WEXITSTATUS(status);
853 termtype = "exited";
854 } else if (WIFSTOPPED(status)) {
855 termid = WSTOPSIG(status);
856 termtype = "stopped";
857 } else {
858 termid = 0;
859 termtype = "unknown";
860 }
861 time(&end_time);
862 write_test_start(active, errbuf);
863 write_test_end(active, end_time, termtype, status,
864 termid, &notime, &notime);
nstraz6c3f66b2001-09-28 21:56:46 +0000865 if (capturing) {
866 close(c_stdout);
867 unlink(active->output);
868 }
nstrazcd87d682000-09-21 20:42:31 +0000869 return -1;
870 }
871
872 close(errpipe[0]);
nstraz6c3f66b2001-09-28 21:56:46 +0000873 if (capturing) close(c_stdout);
nstrazcd87d682000-09-21 20:42:31 +0000874
875 if (!test_out_dir)
876 write_test_start(active, "ok");
877
878 active->pgrp = cpid;
879 active->stopping = 0;
880
nstrazcde46c82001-03-08 19:13:21 +0000881 if (zoo_mark_cmdline(zoofile, cpid, colle->name, colle->cmdline)) {
882 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000883 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000884 }
885
886 if (Debug & Dstartup)
nstrazcd87d682000-09-21 20:42:31 +0000887 fprintf(stderr, "started %s cpid=%d at %s",
888 colle->name, cpid, ctime(&active->stime));
nstrazf307d5f2000-09-14 21:54:44 +0000889
890 if (Debug & Dstart) {
nstrazcde46c82001-03-08 19:13:21 +0000891 fprintf(stderr, "Executing test = %s as %s", colle->name, colle->cmdline);
nstrazcd87d682000-09-21 20:42:31 +0000892 if (capturing)
893 fprintf(stderr, "with output file = %s\n", active->output);
894 else
895 fprintf(stderr, "\n");
nstrazf307d5f2000-09-14 21:54:44 +0000896 }
897
898 return cpid;
899}
900
901
nstrazcde46c82001-03-08 19:13:21 +0000902static char *
nstrazcd87d682000-09-21 20:42:31 +0000903subst_pcnt_f(struct coll_entry *colle)
nstrazf307d5f2000-09-14 21:54:44 +0000904{
nstrazcde46c82001-03-08 19:13:21 +0000905 static int counter = 1;
906 char pid_and_counter[20];
907 char new_cmdline[1024];
nstrazf307d5f2000-09-14 21:54:44 +0000908
nstrazcde46c82001-03-08 19:13:21 +0000909 /* if we get called falsely, do the right thing anyway */
910 if (!colle->pcnt_f)
911 return colle->cmdline;
nstrazf307d5f2000-09-14 21:54:44 +0000912
nstrazcde46c82001-03-08 19:13:21 +0000913 snprintf(pid_and_counter, 20, "%d_%d", getpid(), counter++);
914 snprintf(new_cmdline, 1024, colle->cmdline, pid_and_counter);
915 return strdup(new_cmdline);
nstrazf307d5f2000-09-14 21:54:44 +0000916}
917
918static struct collection *
nstrazcd87d682000-09-21 20:42:31 +0000919get_collection(char *file, int optind, int argc, char **argv)
nstrazf307d5f2000-09-14 21:54:44 +0000920{
921 char *buf, *a, *b;
922 struct coll_entry *head, *p, *n;
923 struct collection *coll;
924 int i;
925
nstrazcd87d682000-09-21 20:42:31 +0000926 buf = slurp(file);
nstrazf307d5f2000-09-14 21:54:44 +0000927
nstrazcd87d682000-09-21 20:42:31 +0000928 coll = (struct collection *) malloc(sizeof(struct collection));
nstrazf307d5f2000-09-14 21:54:44 +0000929 coll->cnt = 0;
930
931 head = p = n = NULL;
932 a = b = buf;
933 while (*b != '\0') {
nstrazcde46c82001-03-08 19:13:21 +0000934 /* set b to the start of the next line and add a NULL character
935 * to separate the two lines */
nstrazcd87d682000-09-21 20:42:31 +0000936 if ((b = strchr(a, '\n')) != NULL)
nstrazf307d5f2000-09-14 21:54:44 +0000937 *b = '\0';
938
nstrazcde46c82001-03-08 19:13:21 +0000939 /* If this is line isn't a comment */
nstrazf307d5f2000-09-14 21:54:44 +0000940 if ((*a != '#') && (*a != '\0') && (*a != ' ')) {
nstrazcde46c82001-03-08 19:13:21 +0000941 n = (struct coll_entry *) malloc(sizeof(struct coll_entry));
942 if ((n->pcnt_f = strstr(a, "%f"))) {
943 n->pcnt_f[1] = 's';
nstrazf307d5f2000-09-14 21:54:44 +0000944 }
nstrazcde46c82001-03-08 19:13:21 +0000945 n->name = strdup(strsep(&a, " \t"));
946 n->cmdline = strdup(a);
947 n->next = NULL;
948
949 if (p) {
950 p->next = n;
951 }
952 if (head == NULL) {
953 head = n;
954 }
955 p = n;
nstrazf307d5f2000-09-14 21:54:44 +0000956 coll->cnt++;
957 }
nstrazcd87d682000-09-21 20:42:31 +0000958 a += strlen(a) + 1;
nstrazf307d5f2000-09-14 21:54:44 +0000959 b = a;
960 }
nstrazcd87d682000-09-21 20:42:31 +0000961 free(buf);
nstrazf307d5f2000-09-14 21:54:44 +0000962
963 /* is there something on the commandline to be counted? */
964 if (optind < argc) {
nstrazcde46c82001-03-08 19:13:21 +0000965 char workstr[1024] = "";
966 int workstr_left = 1023;
967
nstrazf307d5f2000-09-14 21:54:44 +0000968 /* fill arg list */
969 for (i = 0; optind < argc; ++optind, ++i) {
nstrazcde46c82001-03-08 19:13:21 +0000970 strncat(workstr, argv[optind], workstr_left);
971 workstr_left = workstr_left - strlen(argv[optind]);
972 strncat(workstr, " ", workstr_left);
973 workstr_left--;
nstrazf307d5f2000-09-14 21:54:44 +0000974 }
nstrazf307d5f2000-09-14 21:54:44 +0000975
nstrazcde46c82001-03-08 19:13:21 +0000976 n = (struct coll_entry *) malloc(sizeof(struct coll_entry));
977 if ((n->pcnt_f = strstr(workstr, "%f"))) {
978 n->pcnt_f[1] = 's';
979 }
980 n->cmdline = strdup(workstr);
981 n->name = "cmdln";
982 n->next = NULL;
983 if (p) {
nstrazf307d5f2000-09-14 21:54:44 +0000984 p->next = n;
nstrazcde46c82001-03-08 19:13:21 +0000985 }
986 if (head == NULL) {
987 head = n;
nstrazf307d5f2000-09-14 21:54:44 +0000988 }
989 coll->cnt++;
990 }
991
992 /* get an array */
nstrazcd87d682000-09-21 20:42:31 +0000993 coll->ary = (struct coll_entry **) malloc(coll->cnt *
994 sizeof(struct coll_entry *));
nstrazf307d5f2000-09-14 21:54:44 +0000995
996 /* fill the array */
997 i = 0;
998 n = head;
999 while (n != NULL) {
1000 coll->ary[i] = n;
1001 n = n->next;
1002 ++i;
1003 }
1004 if (i != coll->cnt)
nstrazcd87d682000-09-21 20:42:31 +00001005 fprintf(stderr, "pan(%s): i doesn't match cnt\n", panname);
nstrazf307d5f2000-09-14 21:54:44 +00001006
1007 return coll;
1008}
1009
1010
1011static char *
nstrazcd87d682000-09-21 20:42:31 +00001012slurp(char *file)
nstrazf307d5f2000-09-14 21:54:44 +00001013{
1014 char *buf;
1015 int fd;
1016 struct stat sbuf;
1017
nstrazcd87d682000-09-21 20:42:31 +00001018 if ((fd = open(file, O_RDONLY)) < 0) {
1019 fprintf(stderr, "pan(%s): open(%s,O_RDONLY) failed. errno:%d %s\n",
1020 panname, file, errno, strerror(errno));
1021 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +00001022 }
1023
nstrazcd87d682000-09-21 20:42:31 +00001024 if (fstat(fd, &sbuf) < 0) {
1025 fprintf(stderr, "pan(%s): fstat(%s) failed. errno:%d %s\n",
1026 panname, file, errno, strerror(errno));
1027 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +00001028 }
1029
nstrazcd87d682000-09-21 20:42:31 +00001030 buf = (char *) malloc(sbuf.st_size + 1);
1031 if (read(fd, buf, sbuf.st_size) != sbuf.st_size) {
1032 fprintf(stderr, "pan(%s): slurp failed. errno:%d %s\n",
1033 panname, errno, strerror(errno));
1034 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +00001035 }
1036 buf[sbuf.st_size] = '\0';
1037
nstrazcd87d682000-09-21 20:42:31 +00001038 close(fd);
nstrazf307d5f2000-09-14 21:54:44 +00001039 return buf;
1040}
1041
1042static void
nstrazcd87d682000-09-21 20:42:31 +00001043check_orphans(struct orphan_pgrp *orphans, int sig)
nstrazf307d5f2000-09-14 21:54:44 +00001044{
1045 struct orphan_pgrp *orph;
1046
1047 for (orph = orphans; orph != NULL; orph = orph->next) {
1048 if (orph->pgrp == 0)
1049 continue;
1050
1051 if (Debug & Dshutdown)
nstrazcd87d682000-09-21 20:42:31 +00001052 fprintf(stderr, " propagating sig %d to orphaned pgrp %d\n",
nstrazf307d5f2000-09-14 21:54:44 +00001053 sig, -(orph->pgrp));
nstrazcd87d682000-09-21 20:42:31 +00001054 if (kill(-(orph->pgrp), sig) != 0) {
nstrazf307d5f2000-09-14 21:54:44 +00001055 if (errno == ESRCH) {
1056 /* This pgrp is now empty */
nstrazcde46c82001-03-08 19:13:21 +00001057 if (zoo_clear(zoofile, orph->pgrp)) {
1058 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazf307d5f2000-09-14 21:54:44 +00001059 }
1060 orph->pgrp = 0;
1061 } else {
nstrazcd87d682000-09-21 20:42:31 +00001062 fprintf(stderr,
1063 "pan(%s): kill(%d,%d) on orphaned pgrp failed. errno:%d %s\n",
1064 panname, -(orph->pgrp), sig, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +00001065 }
1066 }
1067 }
1068}
1069
1070
1071static void
nstrazcd87d682000-09-21 20:42:31 +00001072mark_orphan(struct orphan_pgrp *orphans, pid_t cpid)
nstrazf307d5f2000-09-14 21:54:44 +00001073{
1074 struct orphan_pgrp *orph;
1075
1076 for (orph = orphans; orph != NULL; orph = orph->next) {
1077 if (orph->pgrp == 0)
1078 break;
1079 }
1080 if (orph == NULL) {
1081 /* make a new struct */
nstrazcd87d682000-09-21 20:42:31 +00001082 orph = (struct orphan_pgrp *) malloc(sizeof(struct orphan_pgrp));
nstrazf307d5f2000-09-14 21:54:44 +00001083
1084 /* plug in the new struct just after the head */
1085 orph->next = orphans->next;
1086 orphans->next = orph;
1087 }
1088 orph->pgrp = cpid;
1089}
1090
1091
nstrazf307d5f2000-09-14 21:54:44 +00001092
nstrazcd87d682000-09-21 20:42:31 +00001093static void
1094copy_buffered_output(struct tag_pgrp *running)
1095{
1096 char *tag_output;
1097
1098 tag_output = slurp(running->output);
1099 if (tag_output) {
1100 printf("%s", tag_output);
1101 /* make sure the output ends with a newline */
1102 if (tag_output[strlen(tag_output) - 1] != '\n')
1103 printf("\n");
1104 fflush(stdout);
1105 free(tag_output);
nstrazf307d5f2000-09-14 21:54:44 +00001106 }
nstrazcd87d682000-09-21 20:42:31 +00001107}
1108
1109
1110static void
1111write_test_start(struct tag_pgrp *running, const char *init_status)
1112{
1113 if (!strcmp(reporttype, "rts")) {
nstrazcd87d682000-09-21 20:42:31 +00001114
1115 printf("%s\ntag=%s stime=%ld\ncmdline=\"%s\"\ncontacts=\"%s\"\nanalysis=%s\ninitiation_status=\"%s\"\n%s\n",
1116 "<<<test_start>>>",
nstrazcde46c82001-03-08 19:13:21 +00001117 running->cmd->name, running->stime, running->cmd->cmdline, "",
nstrazcd87d682000-09-21 20:42:31 +00001118 "exit", init_status,
1119 "<<<test_output>>>");
nstrazcd87d682000-09-21 20:42:31 +00001120 }
1121 fflush(stdout);
1122}
1123
1124
1125static void
1126write_test_end(struct tag_pgrp *running, time_t exit_time,
1127 char *term_type, int stat_loc, int term_id,
1128 struct tms *tms1, struct tms *tms2)
1129{
1130 if (!strcmp(reporttype, "rts")) {
1131 printf("%s\nduration=%ld termination_type=%s termination_id=%d corefile=%s\ncutime=%d cstime=%d\n%s\n",
1132 "<<<execution_status>>>",
1133 (long) (exit_time - running->stime),
1134 term_type, term_id, (stat_loc & 0200) ? "yes" : "no",
1135 (int) (tms2->tms_cutime - tms1->tms_cutime),
1136 (int) (tms2->tms_cstime - tms1->tms_cstime),
1137 "<<<test_end>>>");
1138 }
1139 fflush(stdout);
1140}
1141
1142/* The functions below are all debugging related */
1143
1144static void
1145pids_running(struct tag_pgrp *running, int keep_active)
1146{
1147 int i;
1148
1149 fprintf(stderr, "pids still running: ");
1150 for (i = 0; i < keep_active; ++i) {
1151 if (running[i].pgrp != 0)
1152 fprintf(stderr, "%d ", running[i].pgrp);
1153 }
1154 fprintf(stderr, "\n");
nstrazf307d5f2000-09-14 21:54:44 +00001155}
1156
1157static void
nstrazcd87d682000-09-21 20:42:31 +00001158orphans_running(struct orphan_pgrp *orphans)
1159{
1160 struct orphan_pgrp *orph;
1161
1162 fprintf(stderr, "orphans still running: ");
1163 for (orph = orphans; orph != NULL; orph = orph->next) {
1164 if (orph->pgrp != 0)
1165 fprintf(stderr, "%d ", -(orph->pgrp));
1166 }
1167 fprintf(stderr, "\n");
1168}
1169
1170static void
1171dump_coll(struct collection *coll)
nstrazf307d5f2000-09-14 21:54:44 +00001172{
nstrazcde46c82001-03-08 19:13:21 +00001173 int i;
nstrazf307d5f2000-09-14 21:54:44 +00001174
1175 for (i = 0; i < coll->cnt; ++i) {
nstrazcd87d682000-09-21 20:42:31 +00001176 fprintf(stderr, "coll %d\n", i);
nstrazcde46c82001-03-08 19:13:21 +00001177 fprintf(stderr, " name=%s cmdline=%s\n", coll->ary[i]->name,
1178 coll->ary[i]->cmdline);
1179 }
1180}
1181
1182void
1183wait_handler( int sig )
1184{
1185 static int lastsent = 0;
1186
1187 if( sig == 0 ){
1188 lastsent = 0;
1189 } else {
1190 rec_signal = sig;
1191 if( sig == SIGUSR2 )
1192 return;
1193 if( lastsent == 0 )
1194 send_signal = sig;
1195 else if( lastsent == SIGUSR1 )
1196 send_signal = SIGINT;
1197 else if( lastsent == sig )
1198 send_signal = SIGTERM;
1199 else if( lastsent == SIGTERM )
1200 send_signal = SIGHUP;
1201 else if( lastsent == SIGHUP )
1202 send_signal = SIGKILL;
1203 lastsent = send_signal;
nstrazf307d5f2000-09-14 21:54:44 +00001204 }
1205}