blob: 7ff50882c0010ab420d44f7c28e66d2d6807e6bb [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 *
32 */
nstraz6c3f66b2001-09-28 21:56:46 +000033/* $Id: pan.c,v 1.7 2001/09/28 21:56:46 nstraz Exp $ */
nstrazf307d5f2000-09-14 21:54:44 +000034
35#include <errno.h>
36#include <string.h>
nstrazf307d5f2000-09-14 21:54:44 +000037#include <sys/types.h>
nstrazcd87d682000-09-21 20:42:31 +000038#include <sys/times.h>
nstrazf307d5f2000-09-14 21:54:44 +000039#include <sys/wait.h>
40#include <sys/stat.h>
nstrazf307d5f2000-09-14 21:54:44 +000041#include <time.h>
nstrazcd87d682000-09-21 20:42:31 +000042#include <stdlib.h>
43#include <limits.h>
nstrazf307d5f2000-09-14 21:54:44 +000044
nstrazcd87d682000-09-21 20:42:31 +000045#include "splitstr.h"
nstrazf307d5f2000-09-14 21:54:44 +000046#include "zoolib.h"
47
nstrazcde46c82001-03-08 19:13:21 +000048/* One entry in the command line collection. */
nstrazf307d5f2000-09-14 21:54:44 +000049struct coll_entry
50{
nstrazcde46c82001-03-08 19:13:21 +000051 char *name; /* tag name */
52 char *cmdline; /* command line */
53 char *pcnt_f; /* location of %f in the command line args, flag */
nstrazf307d5f2000-09-14 21:54:44 +000054 struct coll_entry *next;
55};
56
57struct collection
58{
59 int cnt;
60 struct coll_entry **ary;
61};
62
nstrazcd87d682000-09-21 20:42:31 +000063struct tag_pgrp
nstrazf307d5f2000-09-14 21:54:44 +000064{
65 int pgrp;
66 int stopping;
67 time_t stime;
68 struct coll_entry *cmd;
nstrazcd87d682000-09-21 20:42:31 +000069 char output[PATH_MAX];
nstrazf307d5f2000-09-14 21:54:44 +000070};
71
72struct orphan_pgrp
73{
74 int pgrp;
75 struct orphan_pgrp *next;
76};
77
nstrazcd87d682000-09-21 20:42:31 +000078static pid_t run_child(struct coll_entry *colle, struct tag_pgrp *active);
79static char *slurp(char *file);
80static struct collection *get_collection(char *file, int optind, int argc,
81 char **argv);
82static void pids_running(struct tag_pgrp *running, int keep_active);
83static int check_pids(struct tag_pgrp *running, int *num_active,
84 int keep_active, FILE * logfile, struct orphan_pgrp *orphans);
85static void propagate_signal(struct tag_pgrp *running, int keep_active,
86 struct orphan_pgrp *orphans);
87static void dump_coll(struct collection *coll);
nstrazcde46c82001-03-08 19:13:21 +000088static char *subst_pcnt_f(struct coll_entry *colle);
nstrazcd87d682000-09-21 20:42:31 +000089static void mark_orphan(struct orphan_pgrp *orphans, pid_t cpid);
90static void orphans_running(struct orphan_pgrp *orphans);
91static void check_orphans(struct orphan_pgrp *orphans, int sig);
nstrazf307d5f2000-09-14 21:54:44 +000092
nstrazcd87d682000-09-21 20:42:31 +000093static void copy_buffered_output(struct tag_pgrp *running);
94static void write_test_start(struct tag_pgrp *running, const char *init_status);
95static void write_test_end(struct tag_pgrp *running,
96 time_t exit_time, char *term_type, int stat_loc,
97 int term_id, struct tms *tms1, struct tms *tms2);
nstrazf307d5f2000-09-14 21:54:44 +000098
99static char *panname = NULL;
nstrazfef21be2001-03-15 21:23:27 +0000100static char *test_out_dir = NULL; /* dir to buffer output to */
101zoo_t zoofile;
nstrazcd87d682000-09-21 20:42:31 +0000102static char *reporttype = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000103
104/* Debug Bits */
105int Debug = 0;
nstrazcd87d682000-09-21 20:42:31 +0000106#define Dbuffile 0x000400 /* buffer file use */
nstrazf307d5f2000-09-14 21:54:44 +0000107#define Dsetup 0x000200 /* one-time set-up */
108#define Dshutdown 0x000100 /* killed by signal */
109#define Dexit 0x000020 /* exit status */
110#define Drunning 0x000010 /* current pids running */
111#define Dstartup 0x000004 /* started command */
112#define Dstart 0x000002 /* started command */
113#define Dwait 0x000001 /* wait interrupted */
114
nstrazcd87d682000-09-21 20:42:31 +0000115int
116main(int argc, char **argv)
nstrazf307d5f2000-09-14 21:54:44 +0000117{
118 extern char *optarg;
119 extern int optind;
120 int c;
nstrazfef21be2001-03-15 21:23:27 +0000121 char *zooname = NULL; /* name of the zoo file to use */
122 char *filename = "/dev/null"; /* filename to read test tags from */
nstrazf307d5f2000-09-14 21:54:44 +0000123 char *logfilename = NULL;
124 FILE *logfile = NULL;
nstrazcd87d682000-09-21 20:42:31 +0000125 char *outputfilename = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000126 struct collection *coll = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000127 pid_t cpid;
nstrazcd87d682000-09-21 20:42:31 +0000128 struct tag_pgrp *running;
nstrazf307d5f2000-09-14 21:54:44 +0000129 struct orphan_pgrp *orphans, *orph;
130 int keep_active = 1;
131 int num_active = 0;
132 int err, i;
133 int starts = -1;
134 int stop;
135 int go_idle;
nstrazfef21be2001-03-15 21:23:27 +0000136 int has_brakes = 0; /* stop everything if a test case fails */
137 int sequential = 0; /* run tests sequentially */
nstrazf307d5f2000-09-14 21:54:44 +0000138 int fork_in_road = 0;
nstrazf307d5f2000-09-14 21:54:44 +0000139 int exit_stat;
nstrazfef21be2001-03-15 21:23:27 +0000140 int track_exit_stats = 0; /* exit non-zero if any test exits non-zero */
nstrazf307d5f2000-09-14 21:54:44 +0000141
nstrazcd87d682000-09-21 20:42:31 +0000142 while ((c = getopt(argc, argv, "AO:Sa:d:ef:hl:n:o:r:s:x:y")) != -1) {
nstrazf307d5f2000-09-14 21:54:44 +0000143 switch (c) {
nstrazfef21be2001-03-15 21:23:27 +0000144 case 'A': /* all-stop flag */
nstrazf307d5f2000-09-14 21:54:44 +0000145 has_brakes = 1;
146 track_exit_stats = 1;
147 break;
nstrazfef21be2001-03-15 21:23:27 +0000148 case 'O': /* output buffering directory */
nstrazcd87d682000-09-21 20:42:31 +0000149 test_out_dir = strdup(optarg);
nstrazf307d5f2000-09-14 21:54:44 +0000150 break;
nstrazfef21be2001-03-15 21:23:27 +0000151 case 'S': /* run tests sequentially */
nstrazf307d5f2000-09-14 21:54:44 +0000152 sequential = 1;
153 break;
nstrazfef21be2001-03-15 21:23:27 +0000154 case 'a': /* name of the zoo file to use */
nstrazcd87d682000-09-21 20:42:31 +0000155 zooname = strdup(optarg);
nstrazf307d5f2000-09-14 21:54:44 +0000156 break;
nstrazfef21be2001-03-15 21:23:27 +0000157 case 'd': /* debug options */
nstrazcd87d682000-09-21 20:42:31 +0000158 sscanf(optarg, "%i", &Debug);
nstrazf307d5f2000-09-14 21:54:44 +0000159 break;
nstrazfef21be2001-03-15 21:23:27 +0000160 case 'e': /* exit non-zero if any test exists non-zero */
nstrazf307d5f2000-09-14 21:54:44 +0000161 track_exit_stats = 1;
162 break;
nstrazfef21be2001-03-15 21:23:27 +0000163 case 'f': /* filename to read test tags from */
nstrazcd87d682000-09-21 20:42:31 +0000164 filename = strdup(optarg);
165 break;
nstrazfef21be2001-03-15 21:23:27 +0000166 case 'h': /* help */
nstrazf307d5f2000-09-14 21:54:44 +0000167 printf
nstraz830a65b2000-10-12 16:39:25 +0000168 ("Usage: pan -n name [ -SyAeh ] [ -s starts ] [ -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 +0000169 exit(0);
nstrazfef21be2001-03-15 21:23:27 +0000170 case 'l': /* log file */
nstrazcd87d682000-09-21 20:42:31 +0000171 logfilename = strdup(optarg);
172 break;
nstrazfef21be2001-03-15 21:23:27 +0000173 case 'n': /* tag given to pan */
nstrazcd87d682000-09-21 20:42:31 +0000174 panname = strdup(optarg);
175 break;
nstrazfef21be2001-03-15 21:23:27 +0000176 case 'o': /* send test output here */
nstrazcd87d682000-09-21 20:42:31 +0000177 outputfilename = strdup(optarg);
178 break;
nstrazfef21be2001-03-15 21:23:27 +0000179 case 'r': /* reporting type: none, rts */
nstrazcd87d682000-09-21 20:42:31 +0000180 reporttype = strdup(optarg);
181 break;
nstrazfef21be2001-03-15 21:23:27 +0000182 case 's': /* number of tags to run */
nstrazcd87d682000-09-21 20:42:31 +0000183 starts = atoi(optarg);
184 break;
nstrazfef21be2001-03-15 21:23:27 +0000185 case 'x': /* number of tags to keep running */
nstrazcd87d682000-09-21 20:42:31 +0000186 keep_active = atoi(optarg);
187 break;
nstrazfef21be2001-03-15 21:23:27 +0000188 case 'y': /* restart on failure or signal */
nstrazcd87d682000-09-21 20:42:31 +0000189 fork_in_road = 1;
190 break;
nstrazf307d5f2000-09-14 21:54:44 +0000191 }
192 }
193
194 if (panname == NULL) {
nstrazcd87d682000-09-21 20:42:31 +0000195 fprintf(stderr, "pan: Must supply -n\n");
196 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000197 }
nstrazcd87d682000-09-21 20:42:31 +0000198 if (zooname == NULL) {
nstrazcde46c82001-03-08 19:13:21 +0000199 zooname = zoo_getname();
nstrazcd87d682000-09-21 20:42:31 +0000200 if (zooname == NULL) {
201 fprintf(stderr,
202 "pan(%s): Must supply -a or set ZOO env variable\n",
203 panname);
204 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000205 }
206 }
nstrazcd87d682000-09-21 20:42:31 +0000207 if (reporttype) {
208 /* make sure we understand the report type */
209 if (strcasecmp(reporttype, "rts")
210 && strcasecmp(reporttype, "none")
211 /* && strcasecmp(reporttype, "xml")*/)
212 reporttype = "rts";
213 } else {
214 /* set the default */
215 reporttype = "rts";
216 }
nstrazf307d5f2000-09-14 21:54:44 +0000217
218 if (logfilename != NULL) {
219 time_t startup;
220 char *s;
221
nstrazcd87d682000-09-21 20:42:31 +0000222 if (!strcmp(logfilename, "-")) {
nstrazf307d5f2000-09-14 21:54:44 +0000223 logfile = stdout;
224 } else {
nstrazcd87d682000-09-21 20:42:31 +0000225 if ((logfile = fopen(logfilename, "a+")) == NULL) {
226 fprintf(stderr,
227 "pan(%s): Error %s (%d) opening log file '%s'\n",
228 panname, strerror(errno), errno, logfilename);
229 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000230 }
231 }
232
nstrazcd87d682000-09-21 20:42:31 +0000233 time(&startup);
234 s = ctime(&startup);
235 *(s + strlen(s) - 1) = '\0';
236 fprintf(logfile, "startup='%s'\n", s);
nstrazf307d5f2000-09-14 21:54:44 +0000237 }
238
nstrazcd87d682000-09-21 20:42:31 +0000239 coll = get_collection(filename, optind, argc, argv);
nstrazf307d5f2000-09-14 21:54:44 +0000240 if (coll->cnt == 0) {
nstrazcd87d682000-09-21 20:42:31 +0000241 fprintf(stderr,
242 "pan(%s): Must supply a file collection or a command\n",
243 panname);
244 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000245 }
246
247 if (Debug & Dsetup)
nstrazcd87d682000-09-21 20:42:31 +0000248 dump_coll(coll);
nstrazf307d5f2000-09-14 21:54:44 +0000249
250 /* a place to store the pgrps we're watching */
nstrazcd87d682000-09-21 20:42:31 +0000251 running = (struct tag_pgrp *)malloc((keep_active + 1) * sizeof(struct tag_pgrp));
252 memset(running, 0, keep_active * sizeof(struct tag_pgrp));
nstrazf307d5f2000-09-14 21:54:44 +0000253 running[keep_active].pgrp = -1; /* end sentinel */
254
255 /* a head to the orphaned pgrp list */
nstrazcd87d682000-09-21 20:42:31 +0000256 orphans = (struct orphan_pgrp *) malloc(sizeof(struct orphan_pgrp));
257 memset(orphans, 0, sizeof(struct orphan_pgrp));
nstrazf307d5f2000-09-14 21:54:44 +0000258
nstrazcd87d682000-09-21 20:42:31 +0000259 srand48(time(NULL) ^ (getpid() + (getpid() << 15)));
nstrazf307d5f2000-09-14 21:54:44 +0000260
261 /* Supply a default for starts. If we are in sequential mode, use
262 * the number of commands available; otherwise 1.
263 */
nstrazcd87d682000-09-21 20:42:31 +0000264 if (starts == -1) {
265 if (sequential) {
nstrazf307d5f2000-09-14 21:54:44 +0000266 starts = coll->cnt;
nstrazcd87d682000-09-21 20:42:31 +0000267 } else {
nstrazf307d5f2000-09-14 21:54:44 +0000268 starts = 1;
nstrazcd87d682000-09-21 20:42:31 +0000269 }
270 } else if (starts == 0) { /* if the user specified infinite, set it */
271 starts = -1;
272 } else { /* else, make sure we are starting at least keep_active processes */
273 if (starts < keep_active)
274 starts = keep_active;
nstrazf307d5f2000-09-14 21:54:44 +0000275 }
nstrazcd87d682000-09-21 20:42:31 +0000276
277 /* if we're buffering output, but we're only running on process at a time,
278 * then essentially "turn off buffering"
279 */
280 if (test_out_dir && (keep_active == 1)) {
281 free(test_out_dir);
282 test_out_dir = NULL;
283 }
284
285 if (test_out_dir) {
286 struct stat sbuf;
287
288 if (stat(test_out_dir, &sbuf) < 0) {
289 fprintf(stderr,
290 "pan(%s): stat of -O arg '%s' failed. errno: %d %s\n",
291 panname, test_out_dir, errno, strerror(errno));
292 exit(1);
293 }
294 if (!S_ISDIR(sbuf.st_mode)) {
295 fprintf(stderr, "pan(%s): -O arg '%s' must be a directory.\n",
296 panname, test_out_dir);
297 exit(1);
298 }
299 if (access(test_out_dir, W_OK | R_OK | X_OK) < 0) {
300 fprintf(stderr,
301 "pan(%s): permission denied on -O arg '%s'. errno: %d %s\n",
302 panname, test_out_dir, errno, strerror(errno));
303 exit(1);
304 }
305 }
306
307 if (outputfilename) {
308 if (!freopen(outputfilename, "a+", stdout)) {
309 fprintf(stderr,
310 "pan(%s): Error %s (%d) openning output file '%s'\n",
311 panname, strerror(errno), errno, outputfilename);
312 exit(1);
313 }
314 }
315
nstrazcde46c82001-03-08 19:13:21 +0000316 if ((zoofile = zoo_open(zooname)) == NULL) {
317 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000318 exit(1);
319 }
nstrazcde46c82001-03-08 19:13:21 +0000320 if (zoo_mark_args(zoofile, getpid(), panname, argc, argv)) {
321 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000322 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000323 }
324
325 /* Allocate N spaces for max-arg commands.
326 * this is an "active file cleanliness" thing
327 */
328 {
329 char *av[2], bigarg[82];
nstrazf307d5f2000-09-14 21:54:44 +0000330
nstrazcd87d682000-09-21 20:42:31 +0000331 memset(bigarg, '.', 81);
nstrazf307d5f2000-09-14 21:54:44 +0000332 bigarg[81] = '\0';
333 av[0] = bigarg;
334 av[1] = NULL;
335
336 for (c = 0; c < keep_active; c++) {
nstrazcde46c82001-03-08 19:13:21 +0000337 if (zoo_mark_cmdline(zoofile, c, panname, "")) {
338 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000339 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000340 }
341 }
342 for (c = 0; c < keep_active; c++) {
nstrazcde46c82001-03-08 19:13:21 +0000343 if (zoo_clear(zoofile, c)) {
344 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000345 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000346 }
347 }
348 }
349
350 rec_signal = send_signal = 0;
nstrazcd87d682000-09-21 20:42:31 +0000351 signal(SIGINT, wait_handler);
352 signal(SIGTERM, wait_handler);
353 signal(SIGHUP, wait_handler);
354 signal(SIGUSR1, wait_handler); /* ignore fork_in_road */
355 signal(SIGUSR2, wait_handler); /* stop the scheduler */
nstrazf307d5f2000-09-14 21:54:44 +0000356
357 c = 0; /* in this loop, c is the command index */
358 stop = 0;
359 exit_stat = 0;
360 go_idle = 0;
361 while (1) {
362
363 while ((num_active < keep_active) && (starts != 0)) {
364 if (stop || rec_signal || go_idle)
365 break;
366
367 if (!sequential)
nstrazcd87d682000-09-21 20:42:31 +0000368 c = lrand48() % coll->cnt;
nstrazf307d5f2000-09-14 21:54:44 +0000369
370 /* find a slot for the child */
371 for (i = 0; i < keep_active; ++i) {
372 if (running[i].pgrp == 0)
373 break;
374 }
375 if (i == keep_active) {
nstrazcd87d682000-09-21 20:42:31 +0000376 fprintf(stderr, "pan(%s): Aborting: i == keep_active = %d\n",
377 panname, i);
378 wait_handler(SIGINT);
nstrazf307d5f2000-09-14 21:54:44 +0000379 exit_stat++;
380 break;
381 }
382
nstrazcd87d682000-09-21 20:42:31 +0000383 cpid = run_child(coll->ary[c], running + i);
nstrazf307d5f2000-09-14 21:54:44 +0000384 if (cpid != -1) {
385 ++num_active;
386 if (starts > 0)
387 --starts;
388 }
389
390 if (sequential)
391 if (++c >= coll->cnt)
392 c = 0;
393
394 } /* while( (num_active < keep_active) && (starts != 0) ) */
395
396 if (starts == 0)
397 ++stop;
398
399 if (rec_signal) {
400 /* propagate everything except sigusr2 */
401
402 if (rec_signal == SIGUSR2) {
403 if (fork_in_road)
404 ++go_idle;
405 else
406 ++stop;
nstrazcd87d682000-09-21 20:42:31 +0000407 signal(rec_signal, wait_handler);
nstrazf307d5f2000-09-14 21:54:44 +0000408 rec_signal = send_signal = 0;
409 } else {
410 if (rec_signal == SIGUSR1)
411 fork_in_road = 0;
nstrazcd87d682000-09-21 20:42:31 +0000412 propagate_signal(running, keep_active, orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000413 if (fork_in_road)
414 ++go_idle;
415 else
416 ++stop;
417 }
418 }
419
nstrazcd87d682000-09-21 20:42:31 +0000420 err = check_pids(running, &num_active, keep_active,
421 logfile, orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000422 if (Debug & Drunning) {
nstrazcd87d682000-09-21 20:42:31 +0000423 pids_running(running, keep_active);
424 orphans_running(orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000425 }
426 if (err) {
427 if (fork_in_road)
428 ++go_idle;
429 if (track_exit_stats)
430 exit_stat++;
431 if (has_brakes) {
nstrazcd87d682000-09-21 20:42:31 +0000432 fprintf(stderr, "pan(%s): All stop!%s\n", panname,
nstrazf307d5f2000-09-14 21:54:44 +0000433 go_idle ? " (idling)" : "");
nstrazcd87d682000-09-21 20:42:31 +0000434 wait_handler(SIGINT);
nstrazf307d5f2000-09-14 21:54:44 +0000435 }
436 }
437
438 if (stop && (num_active == 0))
439 break;
440
441 if (go_idle && (num_active == 0)) {
442 go_idle = 0; /* It is idle, now resume scheduling. */
nstrazcd87d682000-09-21 20:42:31 +0000443 wait_handler(0); /* Reset the signal ratchet. */
nstrazf307d5f2000-09-14 21:54:44 +0000444 }
445 }
446
447 /* Wait for orphaned pgrps */
448 while (1) {
449 for (orph = orphans; orph != NULL; orph = orph->next) {
450 if (orph->pgrp == 0)
451 continue;
452 /* Yes, we have orphaned pgrps */
nstrazcd87d682000-09-21 20:42:31 +0000453 sleep(5);
nstrazf307d5f2000-09-14 21:54:44 +0000454 if (!rec_signal) {
455 /* force an artificial signal, move us
456 * through the signal ratchet.
457 */
nstrazcd87d682000-09-21 20:42:31 +0000458 wait_handler(SIGINT);
nstrazf307d5f2000-09-14 21:54:44 +0000459 }
nstrazcd87d682000-09-21 20:42:31 +0000460 propagate_signal(running, keep_active, orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000461 if (Debug & Drunning)
nstrazcd87d682000-09-21 20:42:31 +0000462 orphans_running(orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000463 break;
464 }
465 if (orph == NULL)
466 break;
467 }
468
nstrazcd87d682000-09-21 20:42:31 +0000469 signal(SIGINT, SIG_DFL);
nstrazcde46c82001-03-08 19:13:21 +0000470 if (zoo_clear(zoofile, getpid())) {
471 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazf307d5f2000-09-14 21:54:44 +0000472 ++exit_stat;
473 }
nstrazcd87d682000-09-21 20:42:31 +0000474 fclose(zoofile);
nstrazf307d5f2000-09-14 21:54:44 +0000475
nstrazcd87d682000-09-21 20:42:31 +0000476 if (logfile && (logfile != stdout))
477 fclose(logfile);
478
479 exit(exit_stat);
nstrazf307d5f2000-09-14 21:54:44 +0000480}
481
482
nstrazf307d5f2000-09-14 21:54:44 +0000483
484static void
nstrazcd87d682000-09-21 20:42:31 +0000485propagate_signal(struct tag_pgrp *running, int keep_active,
486 struct orphan_pgrp *orphans)
nstrazf307d5f2000-09-14 21:54:44 +0000487{
488 int i;
489
490 if (Debug & Dshutdown)
nstrazcd87d682000-09-21 20:42:31 +0000491 fprintf(stderr, "pan was signaled with sig %d...\n", rec_signal);
nstrazf307d5f2000-09-14 21:54:44 +0000492
493 for (i = 0; i < keep_active; ++i) {
494 if (running[i].pgrp == 0)
495 continue;
496
497 if (Debug & Dshutdown)
nstrazcd87d682000-09-21 20:42:31 +0000498 fprintf(stderr, " propagating sig %d to %d\n",
nstrazf307d5f2000-09-14 21:54:44 +0000499 send_signal, -running[i].pgrp);
nstrazcd87d682000-09-21 20:42:31 +0000500 if (kill(-running[i].pgrp, send_signal) != 0) {
501 fprintf(stderr,
502 "pan(%s): kill(%d,%d) failed on tag (%s). errno:%d %s\n",
503 panname, -running[i].pgrp, send_signal,
504 running[i].cmd->name, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000505 }
506 running[i].stopping = 1;
507 }
508
nstrazcd87d682000-09-21 20:42:31 +0000509 check_orphans(orphans, send_signal);
nstrazf307d5f2000-09-14 21:54:44 +0000510
nstrazcd87d682000-09-21 20:42:31 +0000511 signal(rec_signal, wait_handler);
nstrazf307d5f2000-09-14 21:54:44 +0000512 rec_signal = send_signal = 0;
513}
514
515
516static int
nstrazcd87d682000-09-21 20:42:31 +0000517check_pids(struct tag_pgrp *running, int *num_active, int keep_active,
518 FILE * logfile, struct orphan_pgrp *orphans)
nstrazf307d5f2000-09-14 21:54:44 +0000519{
520 int w;
521 pid_t cpid;
522 int stat_loc;
523 int ret = 0;
524 int i;
525 time_t t;
526 char *status;
527 int signaled = 0;
528 struct tms tms1, tms2;
529 clock_t tck;
530
nstrazcd87d682000-09-21 20:42:31 +0000531 check_orphans(orphans, 0);
nstrazf307d5f2000-09-14 21:54:44 +0000532
nstrazcd87d682000-09-21 20:42:31 +0000533 tck = times(&tms1);
nstrazf307d5f2000-09-14 21:54:44 +0000534 if (tck == -1) {
nstrazcd87d682000-09-21 20:42:31 +0000535 fprintf(stderr, "pan(%s): times(&tms1) failed. errno:%d %s\n",
536 panname, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000537 }
nstrazcd87d682000-09-21 20:42:31 +0000538 cpid = wait(&stat_loc);
539 tck = times(&tms2);
nstrazf307d5f2000-09-14 21:54:44 +0000540 if (tck == -1) {
nstrazcd87d682000-09-21 20:42:31 +0000541 fprintf(stderr, "pan(%s): times(&tms2) failed. errno:%d %s\n",
542 panname, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000543 }
544
545 if (cpid < 0) {
546 if (errno == EINTR) {
547 if (Debug)
nstrazcd87d682000-09-21 20:42:31 +0000548 fprintf(stderr, "pan(%s): wait() interrupted\n", panname);
nstrazf307d5f2000-09-14 21:54:44 +0000549 } else if (errno != ECHILD) {
nstrazcd87d682000-09-21 20:42:31 +0000550 fprintf(stderr, "pan(%s): wait() failed. errno:%d %s\n",
551 panname, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000552 }
553 } else if (cpid > 0) {
554
nstrazcd87d682000-09-21 20:42:31 +0000555 if (WIFSIGNALED(stat_loc)) {
556 w = WTERMSIG(stat_loc);
nstrazf307d5f2000-09-14 21:54:44 +0000557 status = "signaled";
558 if (Debug & Dexit)
nstrazcd87d682000-09-21 20:42:31 +0000559 fprintf(stderr, "child %d terminated with signal %d\n", cpid,
560 w);
nstrazf307d5f2000-09-14 21:54:44 +0000561 --*num_active;
562 signaled = 1;
nstrazcd87d682000-09-21 20:42:31 +0000563 } else if (WIFEXITED(stat_loc)) {
564 w = WEXITSTATUS(stat_loc);
nstrazf307d5f2000-09-14 21:54:44 +0000565 status = "exited";
566 if (Debug & Dexit)
nstrazcd87d682000-09-21 20:42:31 +0000567 fprintf(stderr, "child %d exited with status %d\n", cpid, w);
nstrazf307d5f2000-09-14 21:54:44 +0000568 --*num_active;
569 if (w != 0)
570 ret++;
nstrazcd87d682000-09-21 20:42:31 +0000571 } else if (WIFSTOPPED(stat_loc)) { /* should never happen */
572 w = WSTOPSIG(stat_loc);
nstrazf307d5f2000-09-14 21:54:44 +0000573 status = "stopped";
574 ret++;
575 } else { /* should never happen */
576 w = 0;
577 status = "unknown";
578 ret++;
579 }
580
581 for (i = 0; i < keep_active; ++i) {
582 if (running[i].pgrp == cpid) {
583 if ((w == 130) && running[i].stopping &&
nstrazcd87d682000-09-21 20:42:31 +0000584 (strcmp(status, "exited") == 0)) {
nstrazf307d5f2000-09-14 21:54:44 +0000585 /* The child received sigint, but
586 * did not trap for it? Compensate
587 * for it here.
588 */
589 w = 0;
590 ret--; /* undo */
591 if (Debug & Drunning)
nstrazcd87d682000-09-21 20:42:31 +0000592 fprintf(stderr,
593 "pan(%s): tag=%s exited 130, known to be signaled; will give it an exit 0.\n",
594 panname, running[i].cmd->name);
nstrazf307d5f2000-09-14 21:54:44 +0000595 }
596 if (logfile != NULL) {
nstrazcd87d682000-09-21 20:42:31 +0000597 time(&t);
598 fprintf(logfile,
599 "tag=%s stime=%d dur=%d exit=%s stat=%d core=%s cu=%d cs=%d\n",
600 running[i].cmd->name, (int) (running[i].stime),
601 (int) (t - running[i].stime), status, w,
602 (stat_loc & 0200) ? "yes" : "no",
603 (int) (tms2.tms_cutime - tms1.tms_cutime),
604 (int) (tms2.tms_cstime - tms1.tms_cstime));
605 fflush(logfile);
nstrazf307d5f2000-09-14 21:54:44 +0000606 }
nstrazcd87d682000-09-21 20:42:31 +0000607
608
609 if (running[i].stopping)
610 status = "driver_interrupt";
611
612 if (test_out_dir) {
613 write_test_start(running+i, "ok");
614 copy_buffered_output(running + i);
615 unlink(running[i].output);
616 }
617 write_test_end(running+i, t, status,
618 stat_loc, w, &tms1, &tms2);
619
nstrazf307d5f2000-09-14 21:54:44 +0000620 /* If signaled and we weren't expecting
621 * this to be stopped then the proc
622 * had a problem.
623 */
624 if (signaled && !running[i].stopping)
625 ret++;
626
627 running[i].pgrp = 0;
nstrazcde46c82001-03-08 19:13:21 +0000628 if (zoo_clear(zoofile, cpid)) {
629 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000630 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000631 }
632
633 /* Check for orphaned pgrps */
nstrazcd87d682000-09-21 20:42:31 +0000634 if ((kill(-cpid, 0) == 0) || (errno == EPERM)) {
nstrazcde46c82001-03-08 19:13:21 +0000635 if (zoo_mark_cmdline(zoofile, cpid, "panorphan",
636 running[i].cmd->cmdline)) {
637 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000638 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000639 }
nstrazcd87d682000-09-21 20:42:31 +0000640 mark_orphan(orphans, cpid);
nstrazf307d5f2000-09-14 21:54:44 +0000641 /* status of kill doesn't matter */
nstrazcd87d682000-09-21 20:42:31 +0000642 kill(-cpid, SIGTERM);
nstrazf307d5f2000-09-14 21:54:44 +0000643 }
644
645 break;
646 }
647 }
648 }
649 return ret;
650}
651
652
653static pid_t
nstrazcd87d682000-09-21 20:42:31 +0000654run_child(struct coll_entry *colle, struct tag_pgrp *active)
nstrazf307d5f2000-09-14 21:54:44 +0000655{
656 int cpid;
nstrazcd87d682000-09-21 20:42:31 +0000657 int c_stdout; /* child's stdout, stderr */
658 int capturing = 0; /* output is going to a file instead of stdout */
nstrazcde46c82001-03-08 19:13:21 +0000659 char *c_cmdline;
nstrazcd87d682000-09-21 20:42:31 +0000660 static long cmdno = 0;
nstrazcd87d682000-09-21 20:42:31 +0000661 int errpipe[2]; /* way to communicate to parent that the tag */
662 char errbuf[1024]; /* didn't actually start */
663 int errlen;
nstrazf307d5f2000-09-14 21:54:44 +0000664
nstrazcd87d682000-09-21 20:42:31 +0000665 /* Try to open the file that will be stdout for the test */
666 if (test_out_dir) {
667 capturing = 1;
668 do {
669 sprintf(active->output, "%s/%s.%ld",
670 test_out_dir, colle->name, cmdno++);
nstraz566e8c82000-09-22 19:52:17 +0000671 c_stdout = open(active->output, O_CREAT | O_RDWR | O_EXCL | O_SYNC, 0666);
nstrazcd87d682000-09-21 20:42:31 +0000672 } while (c_stdout < 0 && errno == EEXIST);
673 if (c_stdout < 0) {
674 fprintf(stderr,
675 "pan(%s): open of stdout file failed (tag %s). errno: %d %s\n file: %s\n",
676 panname, colle->name, errno, strerror(errno),
677 active->output);
678 return -1;
679 }
680 }
681
682 /* get the tag's command line arguments ready. subst_pcnt_f() uses a
683 * static counter, that's why we do it here instead of after we fork.
684 */
685 if (colle->pcnt_f) {
nstrazcde46c82001-03-08 19:13:21 +0000686 c_cmdline = subst_pcnt_f(colle);
nstrazcd87d682000-09-21 20:42:31 +0000687 } else {
nstrazcde46c82001-03-08 19:13:21 +0000688 c_cmdline = colle->cmdline;
nstrazcd87d682000-09-21 20:42:31 +0000689 }
690
691 if (pipe(errpipe) < 0) {
692 fprintf(stderr, "pan(%s): pipe() failed. errno:%d %s\n",
693 panname, errno, strerror(errno));
nstraz6c3f66b2001-09-28 21:56:46 +0000694 if (capturing) {
nstrazcd87d682000-09-21 20:42:31 +0000695 close(c_stdout);
nstraz6c3f66b2001-09-28 21:56:46 +0000696 unlink(active->output);
697 }
nstrazcd87d682000-09-21 20:42:31 +0000698 return -1;
699 }
700
701 if ((cpid = fork()) < 0) {
702 fprintf(stderr, "pan(%s): fork failed (tag %s). errno:%d %s\n",
703 panname, colle->name, errno, strerror(errno));
nstraz6c3f66b2001-09-28 21:56:46 +0000704 if (capturing) {
705 unlink(active->output);
nstrazcd87d682000-09-21 20:42:31 +0000706 close(c_stdout);
nstraz6c3f66b2001-09-28 21:56:46 +0000707 }
nstrazcd87d682000-09-21 20:42:31 +0000708 close(errpipe[0]);
709 close(errpipe[1]);
nstrazf307d5f2000-09-14 21:54:44 +0000710 return -1;
711 } else if (cpid == 0) {
712 /* child */
nstrazf307d5f2000-09-14 21:54:44 +0000713
nstrazcd87d682000-09-21 20:42:31 +0000714 fclose(zoofile);
715 close(errpipe[0]);
716 fcntl(errpipe[1], F_SETFD, 1); /* close the pipe if we succeed */
717 setpgrp();
nstrazf307d5f2000-09-14 21:54:44 +0000718
nstrazcd87d682000-09-21 20:42:31 +0000719 umask(0);
720
721 /* if we're putting output into a buffer file, we need to do the
722 * redirection now. If we fail
723 */
724 if (capturing) {
725 if (dup2(c_stdout, fileno(stdout)) == -1) {
726 errlen = sprintf(errbuf, "pan(%s): couldn't redirect stdout for tag %s. errno:%d %s",
727 panname, colle->name, errno, strerror(errno));
728 write(errpipe[1], &errlen, sizeof(errlen));
729 write(errpipe[1], errbuf, errlen);
730 exit(2);
731 }
732 if (dup2(c_stdout, fileno(stderr)) == -1) {
733 errlen = sprintf(errbuf, "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s",
734 panname, colle->name, errno, strerror(errno));
735 write(errpipe[1], &errlen, sizeof(errlen));
736 write(errpipe[1], errbuf, errlen);
737 exit(2);
738 }
739 } else { /* stderr still needs to be redirected */
740 if (dup2(fileno(stdout), fileno(stderr)) == -1) {
741 errlen = sprintf(errbuf, "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s",
742 panname, colle->name, errno, strerror(errno));
743 write(errpipe[1], &errlen, sizeof(errlen));
744 write(errpipe[1], errbuf, errlen);
745 exit(2);
746 }
nstrazf307d5f2000-09-14 21:54:44 +0000747 }
nstrazcde46c82001-03-08 19:13:21 +0000748 /* If there are any shell-type characters in the cmdline
749 * such as '>', '<', '$', '|', etc, then we exec a shell and
750 * run the cmd under a shell.
751 *
752 * Otherwise, break the cmdline at white space and exec the
753 * cmd directly.
754 */
755 if (strpbrk(c_cmdline, "\"';|<>$\\")) {
756 execlp("sh", "sh", "-c", c_cmdline, 0);
757 errlen = sprintf(errbuf,
758 "pan(%s): execlp of '%s' (tag %s) failed. errno:%d %s",
759 panname, c_cmdline, colle->name, errno, strerror(errno));
760 } else {
761 char **arg_v;
762
763 arg_v = (char **)splitstr(c_cmdline, NULL, NULL);
764
765 execvp(arg_v[0], arg_v);
766 errlen = sprintf(errbuf,
767 "pan(%s): execvp of '%s' (tag %s) failed. errno:%d %s",
768 panname, arg_v[0], colle->name, errno, strerror(errno));
769 }
nstrazcd87d682000-09-21 20:42:31 +0000770 write(errpipe[1], &errlen, sizeof(errlen));
771 write(errpipe[1], errbuf, errlen);
772 exit(errno);
nstrazf307d5f2000-09-14 21:54:44 +0000773 }
774
775 /* parent */
nstrazcd87d682000-09-21 20:42:31 +0000776
nstrazcde46c82001-03-08 19:13:21 +0000777 /* subst_pcnt_f() allocates the command line dynamically
778 * free the malloc to prevent a memory leak
nstrazcd87d682000-09-21 20:42:31 +0000779 */
nstrazcde46c82001-03-08 19:13:21 +0000780 if (colle->pcnt_f) free(c_cmdline);
781
nstrazcd87d682000-09-21 20:42:31 +0000782 close(errpipe[1]);
783 time(&active->stime);
nstrazf307d5f2000-09-14 21:54:44 +0000784 active->cmd = colle;
785
nstrazcd87d682000-09-21 20:42:31 +0000786 /* if the child couldn't go through with the exec,
787 * clean up the mess, note it, and move on
788 */
789 if(read(errpipe[0], &errlen, sizeof(errlen))) {
790 int status;
791 time_t end_time;
792 int termid;
793 char *termtype;
794 struct tms notime = {0, 0, 0, 0};
795
796 read(errpipe[0], errbuf, errlen);
797 close(errpipe[0]);
798 errbuf[errlen] = '\0';
799 /* fprintf(stderr, "%s", errbuf); */
800 waitpid(cpid, &status, 0);
801 if (WIFSIGNALED(status)) {
802 termid = WTERMSIG(status);
803 termtype = "signaled";
804 } else if (WIFEXITED(status)) {
805 termid = WEXITSTATUS(status);
806 termtype = "exited";
807 } else if (WIFSTOPPED(status)) {
808 termid = WSTOPSIG(status);
809 termtype = "stopped";
810 } else {
811 termid = 0;
812 termtype = "unknown";
813 }
814 time(&end_time);
815 write_test_start(active, errbuf);
816 write_test_end(active, end_time, termtype, status,
817 termid, &notime, &notime);
nstraz6c3f66b2001-09-28 21:56:46 +0000818 if (capturing) {
819 close(c_stdout);
820 unlink(active->output);
821 }
nstrazcd87d682000-09-21 20:42:31 +0000822 return -1;
823 }
824
825 close(errpipe[0]);
nstraz6c3f66b2001-09-28 21:56:46 +0000826 if (capturing) close(c_stdout);
nstrazcd87d682000-09-21 20:42:31 +0000827
828 if (!test_out_dir)
829 write_test_start(active, "ok");
830
831 active->pgrp = cpid;
832 active->stopping = 0;
833
nstrazcde46c82001-03-08 19:13:21 +0000834 if (zoo_mark_cmdline(zoofile, cpid, colle->name, colle->cmdline)) {
835 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazcd87d682000-09-21 20:42:31 +0000836 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000837 }
838
839 if (Debug & Dstartup)
nstrazcd87d682000-09-21 20:42:31 +0000840 fprintf(stderr, "started %s cpid=%d at %s",
841 colle->name, cpid, ctime(&active->stime));
nstrazf307d5f2000-09-14 21:54:44 +0000842
843 if (Debug & Dstart) {
nstrazcde46c82001-03-08 19:13:21 +0000844 fprintf(stderr, "Executing test = %s as %s", colle->name, colle->cmdline);
nstrazcd87d682000-09-21 20:42:31 +0000845 if (capturing)
846 fprintf(stderr, "with output file = %s\n", active->output);
847 else
848 fprintf(stderr, "\n");
nstrazf307d5f2000-09-14 21:54:44 +0000849 }
850
851 return cpid;
852}
853
854
nstrazcde46c82001-03-08 19:13:21 +0000855static char *
nstrazcd87d682000-09-21 20:42:31 +0000856subst_pcnt_f(struct coll_entry *colle)
nstrazf307d5f2000-09-14 21:54:44 +0000857{
nstrazcde46c82001-03-08 19:13:21 +0000858 static int counter = 1;
859 char pid_and_counter[20];
860 char new_cmdline[1024];
nstrazf307d5f2000-09-14 21:54:44 +0000861
nstrazcde46c82001-03-08 19:13:21 +0000862 /* if we get called falsely, do the right thing anyway */
863 if (!colle->pcnt_f)
864 return colle->cmdline;
nstrazf307d5f2000-09-14 21:54:44 +0000865
nstrazcde46c82001-03-08 19:13:21 +0000866 snprintf(pid_and_counter, 20, "%d_%d", getpid(), counter++);
867 snprintf(new_cmdline, 1024, colle->cmdline, pid_and_counter);
868 return strdup(new_cmdline);
nstrazf307d5f2000-09-14 21:54:44 +0000869}
870
871static struct collection *
nstrazcd87d682000-09-21 20:42:31 +0000872get_collection(char *file, int optind, int argc, char **argv)
nstrazf307d5f2000-09-14 21:54:44 +0000873{
874 char *buf, *a, *b;
875 struct coll_entry *head, *p, *n;
876 struct collection *coll;
877 int i;
878
nstrazcd87d682000-09-21 20:42:31 +0000879 buf = slurp(file);
nstrazf307d5f2000-09-14 21:54:44 +0000880
nstrazcd87d682000-09-21 20:42:31 +0000881 coll = (struct collection *) malloc(sizeof(struct collection));
nstrazf307d5f2000-09-14 21:54:44 +0000882 coll->cnt = 0;
883
884 head = p = n = NULL;
885 a = b = buf;
886 while (*b != '\0') {
nstrazcde46c82001-03-08 19:13:21 +0000887 /* set b to the start of the next line and add a NULL character
888 * to separate the two lines */
nstrazcd87d682000-09-21 20:42:31 +0000889 if ((b = strchr(a, '\n')) != NULL)
nstrazf307d5f2000-09-14 21:54:44 +0000890 *b = '\0';
891
nstrazcde46c82001-03-08 19:13:21 +0000892 /* If this is line isn't a comment */
nstrazf307d5f2000-09-14 21:54:44 +0000893 if ((*a != '#') && (*a != '\0') && (*a != ' ')) {
nstrazcde46c82001-03-08 19:13:21 +0000894 n = (struct coll_entry *) malloc(sizeof(struct coll_entry));
895 if ((n->pcnt_f = strstr(a, "%f"))) {
896 n->pcnt_f[1] = 's';
nstrazf307d5f2000-09-14 21:54:44 +0000897 }
nstrazcde46c82001-03-08 19:13:21 +0000898 n->name = strdup(strsep(&a, " \t"));
899 n->cmdline = strdup(a);
900 n->next = NULL;
901
902 if (p) {
903 p->next = n;
904 }
905 if (head == NULL) {
906 head = n;
907 }
908 p = n;
nstrazf307d5f2000-09-14 21:54:44 +0000909 coll->cnt++;
910 }
nstrazcd87d682000-09-21 20:42:31 +0000911 a += strlen(a) + 1;
nstrazf307d5f2000-09-14 21:54:44 +0000912 b = a;
913 }
nstrazcd87d682000-09-21 20:42:31 +0000914 free(buf);
nstrazf307d5f2000-09-14 21:54:44 +0000915
916 /* is there something on the commandline to be counted? */
917 if (optind < argc) {
nstrazcde46c82001-03-08 19:13:21 +0000918 char workstr[1024] = "";
919 int workstr_left = 1023;
920
nstrazf307d5f2000-09-14 21:54:44 +0000921 /* fill arg list */
922 for (i = 0; optind < argc; ++optind, ++i) {
nstrazcde46c82001-03-08 19:13:21 +0000923 strncat(workstr, argv[optind], workstr_left);
924 workstr_left = workstr_left - strlen(argv[optind]);
925 strncat(workstr, " ", workstr_left);
926 workstr_left--;
nstrazf307d5f2000-09-14 21:54:44 +0000927 }
nstrazf307d5f2000-09-14 21:54:44 +0000928
nstrazcde46c82001-03-08 19:13:21 +0000929 n = (struct coll_entry *) malloc(sizeof(struct coll_entry));
930 if ((n->pcnt_f = strstr(workstr, "%f"))) {
931 n->pcnt_f[1] = 's';
932 }
933 n->cmdline = strdup(workstr);
934 n->name = "cmdln";
935 n->next = NULL;
936 if (p) {
nstrazf307d5f2000-09-14 21:54:44 +0000937 p->next = n;
nstrazcde46c82001-03-08 19:13:21 +0000938 }
939 if (head == NULL) {
940 head = n;
nstrazf307d5f2000-09-14 21:54:44 +0000941 }
942 coll->cnt++;
943 }
944
945 /* get an array */
nstrazcd87d682000-09-21 20:42:31 +0000946 coll->ary = (struct coll_entry **) malloc(coll->cnt *
947 sizeof(struct coll_entry *));
nstrazf307d5f2000-09-14 21:54:44 +0000948
949 /* fill the array */
950 i = 0;
951 n = head;
952 while (n != NULL) {
953 coll->ary[i] = n;
954 n = n->next;
955 ++i;
956 }
957 if (i != coll->cnt)
nstrazcd87d682000-09-21 20:42:31 +0000958 fprintf(stderr, "pan(%s): i doesn't match cnt\n", panname);
nstrazf307d5f2000-09-14 21:54:44 +0000959
960 return coll;
961}
962
963
964static char *
nstrazcd87d682000-09-21 20:42:31 +0000965slurp(char *file)
nstrazf307d5f2000-09-14 21:54:44 +0000966{
967 char *buf;
968 int fd;
969 struct stat sbuf;
970
nstrazcd87d682000-09-21 20:42:31 +0000971 if ((fd = open(file, O_RDONLY)) < 0) {
972 fprintf(stderr, "pan(%s): open(%s,O_RDONLY) failed. errno:%d %s\n",
973 panname, file, errno, strerror(errno));
974 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000975 }
976
nstrazcd87d682000-09-21 20:42:31 +0000977 if (fstat(fd, &sbuf) < 0) {
978 fprintf(stderr, "pan(%s): fstat(%s) failed. errno:%d %s\n",
979 panname, file, errno, strerror(errno));
980 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000981 }
982
nstrazcd87d682000-09-21 20:42:31 +0000983 buf = (char *) malloc(sbuf.st_size + 1);
984 if (read(fd, buf, sbuf.st_size) != sbuf.st_size) {
985 fprintf(stderr, "pan(%s): slurp failed. errno:%d %s\n",
986 panname, errno, strerror(errno));
987 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000988 }
989 buf[sbuf.st_size] = '\0';
990
nstrazcd87d682000-09-21 20:42:31 +0000991 close(fd);
nstrazf307d5f2000-09-14 21:54:44 +0000992 return buf;
993}
994
995static void
nstrazcd87d682000-09-21 20:42:31 +0000996check_orphans(struct orphan_pgrp *orphans, int sig)
nstrazf307d5f2000-09-14 21:54:44 +0000997{
998 struct orphan_pgrp *orph;
999
1000 for (orph = orphans; orph != NULL; orph = orph->next) {
1001 if (orph->pgrp == 0)
1002 continue;
1003
1004 if (Debug & Dshutdown)
nstrazcd87d682000-09-21 20:42:31 +00001005 fprintf(stderr, " propagating sig %d to orphaned pgrp %d\n",
nstrazf307d5f2000-09-14 21:54:44 +00001006 sig, -(orph->pgrp));
nstrazcd87d682000-09-21 20:42:31 +00001007 if (kill(-(orph->pgrp), sig) != 0) {
nstrazf307d5f2000-09-14 21:54:44 +00001008 if (errno == ESRCH) {
1009 /* This pgrp is now empty */
nstrazcde46c82001-03-08 19:13:21 +00001010 if (zoo_clear(zoofile, orph->pgrp)) {
1011 fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
nstrazf307d5f2000-09-14 21:54:44 +00001012 }
1013 orph->pgrp = 0;
1014 } else {
nstrazcd87d682000-09-21 20:42:31 +00001015 fprintf(stderr,
1016 "pan(%s): kill(%d,%d) on orphaned pgrp failed. errno:%d %s\n",
1017 panname, -(orph->pgrp), sig, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +00001018 }
1019 }
1020 }
1021}
1022
1023
1024static void
nstrazcd87d682000-09-21 20:42:31 +00001025mark_orphan(struct orphan_pgrp *orphans, pid_t cpid)
nstrazf307d5f2000-09-14 21:54:44 +00001026{
1027 struct orphan_pgrp *orph;
1028
1029 for (orph = orphans; orph != NULL; orph = orph->next) {
1030 if (orph->pgrp == 0)
1031 break;
1032 }
1033 if (orph == NULL) {
1034 /* make a new struct */
nstrazcd87d682000-09-21 20:42:31 +00001035 orph = (struct orphan_pgrp *) malloc(sizeof(struct orphan_pgrp));
nstrazf307d5f2000-09-14 21:54:44 +00001036
1037 /* plug in the new struct just after the head */
1038 orph->next = orphans->next;
1039 orphans->next = orph;
1040 }
1041 orph->pgrp = cpid;
1042}
1043
1044
nstrazf307d5f2000-09-14 21:54:44 +00001045
nstrazcd87d682000-09-21 20:42:31 +00001046static void
1047copy_buffered_output(struct tag_pgrp *running)
1048{
1049 char *tag_output;
1050
1051 tag_output = slurp(running->output);
1052 if (tag_output) {
1053 printf("%s", tag_output);
1054 /* make sure the output ends with a newline */
1055 if (tag_output[strlen(tag_output) - 1] != '\n')
1056 printf("\n");
1057 fflush(stdout);
1058 free(tag_output);
nstrazf307d5f2000-09-14 21:54:44 +00001059 }
nstrazcd87d682000-09-21 20:42:31 +00001060}
1061
1062
1063static void
1064write_test_start(struct tag_pgrp *running, const char *init_status)
1065{
1066 if (!strcmp(reporttype, "rts")) {
nstrazcd87d682000-09-21 20:42:31 +00001067
1068 printf("%s\ntag=%s stime=%ld\ncmdline=\"%s\"\ncontacts=\"%s\"\nanalysis=%s\ninitiation_status=\"%s\"\n%s\n",
1069 "<<<test_start>>>",
nstrazcde46c82001-03-08 19:13:21 +00001070 running->cmd->name, running->stime, running->cmd->cmdline, "",
nstrazcd87d682000-09-21 20:42:31 +00001071 "exit", init_status,
1072 "<<<test_output>>>");
nstrazcd87d682000-09-21 20:42:31 +00001073 }
1074 fflush(stdout);
1075}
1076
1077
1078static void
1079write_test_end(struct tag_pgrp *running, time_t exit_time,
1080 char *term_type, int stat_loc, int term_id,
1081 struct tms *tms1, struct tms *tms2)
1082{
1083 if (!strcmp(reporttype, "rts")) {
1084 printf("%s\nduration=%ld termination_type=%s termination_id=%d corefile=%s\ncutime=%d cstime=%d\n%s\n",
1085 "<<<execution_status>>>",
1086 (long) (exit_time - running->stime),
1087 term_type, term_id, (stat_loc & 0200) ? "yes" : "no",
1088 (int) (tms2->tms_cutime - tms1->tms_cutime),
1089 (int) (tms2->tms_cstime - tms1->tms_cstime),
1090 "<<<test_end>>>");
1091 }
1092 fflush(stdout);
1093}
1094
1095/* The functions below are all debugging related */
1096
1097static void
1098pids_running(struct tag_pgrp *running, int keep_active)
1099{
1100 int i;
1101
1102 fprintf(stderr, "pids still running: ");
1103 for (i = 0; i < keep_active; ++i) {
1104 if (running[i].pgrp != 0)
1105 fprintf(stderr, "%d ", running[i].pgrp);
1106 }
1107 fprintf(stderr, "\n");
nstrazf307d5f2000-09-14 21:54:44 +00001108}
1109
1110static void
nstrazcd87d682000-09-21 20:42:31 +00001111orphans_running(struct orphan_pgrp *orphans)
1112{
1113 struct orphan_pgrp *orph;
1114
1115 fprintf(stderr, "orphans still running: ");
1116 for (orph = orphans; orph != NULL; orph = orph->next) {
1117 if (orph->pgrp != 0)
1118 fprintf(stderr, "%d ", -(orph->pgrp));
1119 }
1120 fprintf(stderr, "\n");
1121}
1122
1123static void
1124dump_coll(struct collection *coll)
nstrazf307d5f2000-09-14 21:54:44 +00001125{
nstrazcde46c82001-03-08 19:13:21 +00001126 int i;
nstrazf307d5f2000-09-14 21:54:44 +00001127
1128 for (i = 0; i < coll->cnt; ++i) {
nstrazcd87d682000-09-21 20:42:31 +00001129 fprintf(stderr, "coll %d\n", i);
nstrazcde46c82001-03-08 19:13:21 +00001130 fprintf(stderr, " name=%s cmdline=%s\n", coll->ary[i]->name,
1131 coll->ary[i]->cmdline);
1132 }
1133}
1134
1135void
1136wait_handler( int sig )
1137{
1138 static int lastsent = 0;
1139
1140 if( sig == 0 ){
1141 lastsent = 0;
1142 } else {
1143 rec_signal = sig;
1144 if( sig == SIGUSR2 )
1145 return;
1146 if( lastsent == 0 )
1147 send_signal = sig;
1148 else if( lastsent == SIGUSR1 )
1149 send_signal = SIGINT;
1150 else if( lastsent == sig )
1151 send_signal = SIGTERM;
1152 else if( lastsent == SIGTERM )
1153 send_signal = SIGHUP;
1154 else if( lastsent == SIGHUP )
1155 send_signal = SIGKILL;
1156 lastsent = send_signal;
nstrazf307d5f2000-09-14 21:54:44 +00001157 }
1158}