blob: be218db8b780226f263558a5df889ef30bd4a482 [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 */
nstrazcd87d682000-09-21 20:42:31 +000033/* $Id: pan.c,v 1.2 2000/09/21 20:42:31 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>
42#include <math.h> /* log10() for subst_pcnt_f */
nstrazcd87d682000-09-21 20:42:31 +000043#include <stdlib.h>
44#include <limits.h>
nstrazf307d5f2000-09-14 21:54:44 +000045
nstrazcd87d682000-09-21 20:42:31 +000046#include "splitstr.h"
nstrazf307d5f2000-09-14 21:54:44 +000047#include "zoolib.h"
48
49struct coll_entry
50{
51 char *name;
52 char **argv;
53 int argc;
54 char *pcnt_f;
55 struct coll_entry *next;
56};
57
58struct collection
59{
60 int cnt;
61 struct coll_entry **ary;
62};
63
nstrazcd87d682000-09-21 20:42:31 +000064struct tag_pgrp
nstrazf307d5f2000-09-14 21:54:44 +000065{
66 int pgrp;
67 int stopping;
68 time_t stime;
69 struct coll_entry *cmd;
nstrazcd87d682000-09-21 20:42:31 +000070 char output[PATH_MAX];
nstrazf307d5f2000-09-14 21:54:44 +000071};
72
73struct orphan_pgrp
74{
75 int pgrp;
76 struct orphan_pgrp *next;
77};
78
nstrazcd87d682000-09-21 20:42:31 +000079static pid_t run_child(struct coll_entry *colle, struct tag_pgrp *active);
80static char *slurp(char *file);
81static struct collection *get_collection(char *file, int optind, int argc,
82 char **argv);
83static void pids_running(struct tag_pgrp *running, int keep_active);
84static int check_pids(struct tag_pgrp *running, int *num_active,
85 int keep_active, FILE * logfile, struct orphan_pgrp *orphans);
86static void propagate_signal(struct tag_pgrp *running, int keep_active,
87 struct orphan_pgrp *orphans);
88static void dump_coll(struct collection *coll);
89static char **subst_pcnt_f(struct coll_entry *colle);
90static void mark_orphan(struct orphan_pgrp *orphans, pid_t cpid);
91static void orphans_running(struct orphan_pgrp *orphans);
92static void check_orphans(struct orphan_pgrp *orphans, int sig);
nstrazf307d5f2000-09-14 21:54:44 +000093
nstrazcd87d682000-09-21 20:42:31 +000094static void copy_buffered_output(struct tag_pgrp *running);
95static void write_test_start(struct tag_pgrp *running, const char *init_status);
96static void write_test_end(struct tag_pgrp *running,
97 time_t exit_time, char *term_type, int stat_loc,
98 int term_id, struct tms *tms1, struct tms *tms2);
nstrazf307d5f2000-09-14 21:54:44 +000099
100static char *panname = NULL;
nstrazcd87d682000-09-21 20:42:31 +0000101static char *test_out_dir = NULL;
102FILE *zoofile;
103static char *reporttype = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000104static char *errmsg;
105
106/* Debug Bits */
107int Debug = 0;
nstrazcd87d682000-09-21 20:42:31 +0000108#define Dbuffile 0x000400 /* buffer file use */
nstrazf307d5f2000-09-14 21:54:44 +0000109#define Dsetup 0x000200 /* one-time set-up */
110#define Dshutdown 0x000100 /* killed by signal */
111#define Dexit 0x000020 /* exit status */
112#define Drunning 0x000010 /* current pids running */
113#define Dstartup 0x000004 /* started command */
114#define Dstart 0x000002 /* started command */
115#define Dwait 0x000001 /* wait interrupted */
116
nstrazcd87d682000-09-21 20:42:31 +0000117int
118main(int argc, char **argv)
nstrazf307d5f2000-09-14 21:54:44 +0000119{
120 extern char *optarg;
121 extern int optind;
122 int c;
nstrazcd87d682000-09-21 20:42:31 +0000123 char *zooname = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000124 char *filename = "/dev/null";
125 char *logfilename = NULL;
126 FILE *logfile = NULL;
nstrazcd87d682000-09-21 20:42:31 +0000127 char *outputfilename = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000128 struct collection *coll = NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000129 pid_t cpid;
nstrazcd87d682000-09-21 20:42:31 +0000130 struct tag_pgrp *running;
nstrazf307d5f2000-09-14 21:54:44 +0000131 struct orphan_pgrp *orphans, *orph;
132 int keep_active = 1;
133 int num_active = 0;
134 int err, i;
135 int starts = -1;
136 int stop;
137 int go_idle;
138 int has_brakes = 0;
139 int sequential = 0;
140 int fork_in_road = 0;
nstrazf307d5f2000-09-14 21:54:44 +0000141 int exit_stat;
142 int track_exit_stats = 0;
143
nstrazcd87d682000-09-21 20:42:31 +0000144 while ((c = getopt(argc, argv, "AO:Sa:d:ef:hl:n:o:r:s:x:y")) != -1) {
nstrazf307d5f2000-09-14 21:54:44 +0000145 switch (c) {
146 case 'A':
147 has_brakes = 1;
148 track_exit_stats = 1;
149 break;
nstrazcd87d682000-09-21 20:42:31 +0000150 case 'O':
151 test_out_dir = strdup(optarg);
nstrazf307d5f2000-09-14 21:54:44 +0000152 break;
153 case 'S':
154 sequential = 1;
155 break;
nstrazcd87d682000-09-21 20:42:31 +0000156 case 'a':
157 zooname = strdup(optarg);
nstrazf307d5f2000-09-14 21:54:44 +0000158 break;
nstrazcd87d682000-09-21 20:42:31 +0000159 case 'd':
160 sscanf(optarg, "%i", &Debug);
nstrazf307d5f2000-09-14 21:54:44 +0000161 break;
162 case 'e':
163 track_exit_stats = 1;
164 break;
nstrazcd87d682000-09-21 20:42:31 +0000165 case 'f':
166 filename = strdup(optarg);
167 break;
nstrazf307d5f2000-09-14 21:54:44 +0000168 case 'h':
169 printf
170 ("Usage: pan -n name [ -SyAeh ] [ -s starts ] [ -x nactive ] [ -l logfile ]\n\t[ -a active-file ] [ -f command-file ] [ -d debug-level ] [cmd]\n");
nstrazcd87d682000-09-21 20:42:31 +0000171 exit(0);
172 case 'l':
173 logfilename = strdup(optarg);
174 break;
175 case 'n':
176 panname = strdup(optarg);
177 break;
178 case 'o':
179 outputfilename = strdup(optarg);
180 break;
181 case 'r':
182 reporttype = strdup(optarg);
183 break;
184 case 's':
185 starts = atoi(optarg);
186 break;
187 case 'x':
188 keep_active = atoi(optarg);
189 break;
190 case 'y':
191 fork_in_road = 1;
192 break;
nstrazf307d5f2000-09-14 21:54:44 +0000193 }
194 }
195
196 if (panname == NULL) {
nstrazcd87d682000-09-21 20:42:31 +0000197 fprintf(stderr, "pan: Must supply -n\n");
198 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000199 }
nstrazcd87d682000-09-21 20:42:31 +0000200 if (zooname == NULL) {
201 zooname = zoo_active();
202 if (zooname == NULL) {
203 fprintf(stderr,
204 "pan(%s): Must supply -a or set ZOO env variable\n",
205 panname);
206 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000207 }
208 }
nstrazcd87d682000-09-21 20:42:31 +0000209 if (reporttype) {
210 /* make sure we understand the report type */
211 if (strcasecmp(reporttype, "rts")
212 && strcasecmp(reporttype, "none")
213 /* && strcasecmp(reporttype, "xml")*/)
214 reporttype = "rts";
215 } else {
216 /* set the default */
217 reporttype = "rts";
218 }
nstrazf307d5f2000-09-14 21:54:44 +0000219
220 if (logfilename != NULL) {
221 time_t startup;
222 char *s;
223
nstrazcd87d682000-09-21 20:42:31 +0000224 if (!strcmp(logfilename, "-")) {
nstrazf307d5f2000-09-14 21:54:44 +0000225 logfile = stdout;
226 } else {
nstrazcd87d682000-09-21 20:42:31 +0000227 if ((logfile = fopen(logfilename, "a+")) == NULL) {
228 fprintf(stderr,
229 "pan(%s): Error %s (%d) opening log file '%s'\n",
230 panname, strerror(errno), errno, logfilename);
231 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000232 }
233 }
234
nstrazcd87d682000-09-21 20:42:31 +0000235 time(&startup);
236 s = ctime(&startup);
237 *(s + strlen(s) - 1) = '\0';
238 fprintf(logfile, "startup='%s'\n", s);
nstrazf307d5f2000-09-14 21:54:44 +0000239 }
240
nstrazcd87d682000-09-21 20:42:31 +0000241 coll = get_collection(filename, optind, argc, argv);
nstrazf307d5f2000-09-14 21:54:44 +0000242 if (coll->cnt == 0) {
nstrazcd87d682000-09-21 20:42:31 +0000243 fprintf(stderr,
244 "pan(%s): Must supply a file collection or a command\n",
245 panname);
246 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000247 }
248
249 if (Debug & Dsetup)
nstrazcd87d682000-09-21 20:42:31 +0000250 dump_coll(coll);
nstrazf307d5f2000-09-14 21:54:44 +0000251
252 /* a place to store the pgrps we're watching */
nstrazcd87d682000-09-21 20:42:31 +0000253 running = (struct tag_pgrp *)malloc((keep_active + 1) * sizeof(struct tag_pgrp));
254 memset(running, 0, keep_active * sizeof(struct tag_pgrp));
nstrazf307d5f2000-09-14 21:54:44 +0000255 running[keep_active].pgrp = -1; /* end sentinel */
256
257 /* a head to the orphaned pgrp list */
nstrazcd87d682000-09-21 20:42:31 +0000258 orphans = (struct orphan_pgrp *) malloc(sizeof(struct orphan_pgrp));
259 memset(orphans, 0, sizeof(struct orphan_pgrp));
nstrazf307d5f2000-09-14 21:54:44 +0000260
nstrazcd87d682000-09-21 20:42:31 +0000261 srand48(time(NULL) ^ (getpid() + (getpid() << 15)));
nstrazf307d5f2000-09-14 21:54:44 +0000262
263 /* Supply a default for starts. If we are in sequential mode, use
264 * the number of commands available; otherwise 1.
265 */
nstrazcd87d682000-09-21 20:42:31 +0000266 if (starts == -1) {
267 if (sequential) {
nstrazf307d5f2000-09-14 21:54:44 +0000268 starts = coll->cnt;
nstrazcd87d682000-09-21 20:42:31 +0000269 } else {
nstrazf307d5f2000-09-14 21:54:44 +0000270 starts = 1;
nstrazcd87d682000-09-21 20:42:31 +0000271 }
272 } else if (starts == 0) { /* if the user specified infinite, set it */
273 starts = -1;
274 } else { /* else, make sure we are starting at least keep_active processes */
275 if (starts < keep_active)
276 starts = keep_active;
nstrazf307d5f2000-09-14 21:54:44 +0000277 }
nstrazcd87d682000-09-21 20:42:31 +0000278
279 /* if we're buffering output, but we're only running on process at a time,
280 * then essentially "turn off buffering"
281 */
282 if (test_out_dir && (keep_active == 1)) {
283 free(test_out_dir);
284 test_out_dir = NULL;
285 }
286
287 if (test_out_dir) {
288 struct stat sbuf;
289
290 if (stat(test_out_dir, &sbuf) < 0) {
291 fprintf(stderr,
292 "pan(%s): stat of -O arg '%s' failed. errno: %d %s\n",
293 panname, test_out_dir, errno, strerror(errno));
294 exit(1);
295 }
296 if (!S_ISDIR(sbuf.st_mode)) {
297 fprintf(stderr, "pan(%s): -O arg '%s' must be a directory.\n",
298 panname, test_out_dir);
299 exit(1);
300 }
301 if (access(test_out_dir, W_OK | R_OK | X_OK) < 0) {
302 fprintf(stderr,
303 "pan(%s): permission denied on -O arg '%s'. errno: %d %s\n",
304 panname, test_out_dir, errno, strerror(errno));
305 exit(1);
306 }
307 }
308
309 if (outputfilename) {
310 if (!freopen(outputfilename, "a+", stdout)) {
311 fprintf(stderr,
312 "pan(%s): Error %s (%d) openning output file '%s'\n",
313 panname, strerror(errno), errno, outputfilename);
314 exit(1);
315 }
316 }
317
318 if ((zoofile = open_file(zooname, "r+", &errmsg)) == NULL) {
319 fprintf(stderr, "pan(%s): %s\n", panname, errmsg);
320 exit(1);
321 }
322 if (write_active_args(zoofile, getpid(), panname, argc, argv, &errmsg) ==
323 -1) {
324 fprintf(stderr, "pan(%s): %s\n", panname, errmsg);
325 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000326 }
327
328 /* Allocate N spaces for max-arg commands.
329 * this is an "active file cleanliness" thing
330 */
331 {
332 char *av[2], bigarg[82];
333 int t;
334
335 t = 1;
nstrazcd87d682000-09-21 20:42:31 +0000336 memset(bigarg, '.', 81);
nstrazf307d5f2000-09-14 21:54:44 +0000337 bigarg[81] = '\0';
338 av[0] = bigarg;
339 av[1] = NULL;
340
341 for (c = 0; c < keep_active; c++) {
nstrazcd87d682000-09-21 20:42:31 +0000342 if (write_active_args(zoofile, t, panname, 1, av, &errmsg) == -1) {
343 fprintf(stderr, "pan(%s): %s\n", panname, errmsg);
344 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000345 }
346 }
347 for (c = 0; c < keep_active; c++) {
nstrazcd87d682000-09-21 20:42:31 +0000348 if (clear_active(zoofile, t, &errmsg) != 1) {
349 fprintf(stderr, "pan(%s): %s\n", panname, errmsg);
350 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000351 }
352 }
353 }
354
355 rec_signal = send_signal = 0;
nstrazcd87d682000-09-21 20:42:31 +0000356 signal(SIGINT, wait_handler);
357 signal(SIGTERM, wait_handler);
358 signal(SIGHUP, wait_handler);
359 signal(SIGUSR1, wait_handler); /* ignore fork_in_road */
360 signal(SIGUSR2, wait_handler); /* stop the scheduler */
nstrazf307d5f2000-09-14 21:54:44 +0000361
362 c = 0; /* in this loop, c is the command index */
363 stop = 0;
364 exit_stat = 0;
365 go_idle = 0;
366 while (1) {
367
368 while ((num_active < keep_active) && (starts != 0)) {
369 if (stop || rec_signal || go_idle)
370 break;
371
372 if (!sequential)
nstrazcd87d682000-09-21 20:42:31 +0000373 c = lrand48() % coll->cnt;
nstrazf307d5f2000-09-14 21:54:44 +0000374
375 /* find a slot for the child */
376 for (i = 0; i < keep_active; ++i) {
377 if (running[i].pgrp == 0)
378 break;
379 }
380 if (i == keep_active) {
nstrazcd87d682000-09-21 20:42:31 +0000381 fprintf(stderr, "pan(%s): Aborting: i == keep_active = %d\n",
382 panname, i);
383 wait_handler(SIGINT);
nstrazf307d5f2000-09-14 21:54:44 +0000384 exit_stat++;
385 break;
386 }
387
nstrazcd87d682000-09-21 20:42:31 +0000388 cpid = run_child(coll->ary[c], running + i);
nstrazf307d5f2000-09-14 21:54:44 +0000389 if (cpid != -1) {
390 ++num_active;
391 if (starts > 0)
392 --starts;
393 }
394
395 if (sequential)
396 if (++c >= coll->cnt)
397 c = 0;
398
399 } /* while( (num_active < keep_active) && (starts != 0) ) */
400
401 if (starts == 0)
402 ++stop;
403
404 if (rec_signal) {
405 /* propagate everything except sigusr2 */
406
407 if (rec_signal == SIGUSR2) {
408 if (fork_in_road)
409 ++go_idle;
410 else
411 ++stop;
nstrazcd87d682000-09-21 20:42:31 +0000412 signal(rec_signal, wait_handler);
nstrazf307d5f2000-09-14 21:54:44 +0000413 rec_signal = send_signal = 0;
414 } else {
415 if (rec_signal == SIGUSR1)
416 fork_in_road = 0;
nstrazcd87d682000-09-21 20:42:31 +0000417 propagate_signal(running, keep_active, orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000418 if (fork_in_road)
419 ++go_idle;
420 else
421 ++stop;
422 }
423 }
424
nstrazcd87d682000-09-21 20:42:31 +0000425 err = check_pids(running, &num_active, keep_active,
426 logfile, orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000427 if (Debug & Drunning) {
nstrazcd87d682000-09-21 20:42:31 +0000428 pids_running(running, keep_active);
429 orphans_running(orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000430 }
431 if (err) {
432 if (fork_in_road)
433 ++go_idle;
434 if (track_exit_stats)
435 exit_stat++;
436 if (has_brakes) {
nstrazcd87d682000-09-21 20:42:31 +0000437 fprintf(stderr, "pan(%s): All stop!%s\n", panname,
nstrazf307d5f2000-09-14 21:54:44 +0000438 go_idle ? " (idling)" : "");
nstrazcd87d682000-09-21 20:42:31 +0000439 wait_handler(SIGINT);
nstrazf307d5f2000-09-14 21:54:44 +0000440 }
441 }
442
443 if (stop && (num_active == 0))
444 break;
445
446 if (go_idle && (num_active == 0)) {
447 go_idle = 0; /* It is idle, now resume scheduling. */
nstrazcd87d682000-09-21 20:42:31 +0000448 wait_handler(0); /* Reset the signal ratchet. */
nstrazf307d5f2000-09-14 21:54:44 +0000449 }
450 }
451
452 /* Wait for orphaned pgrps */
453 while (1) {
454 for (orph = orphans; orph != NULL; orph = orph->next) {
455 if (orph->pgrp == 0)
456 continue;
457 /* Yes, we have orphaned pgrps */
nstrazcd87d682000-09-21 20:42:31 +0000458 sleep(5);
nstrazf307d5f2000-09-14 21:54:44 +0000459 if (!rec_signal) {
460 /* force an artificial signal, move us
461 * through the signal ratchet.
462 */
nstrazcd87d682000-09-21 20:42:31 +0000463 wait_handler(SIGINT);
nstrazf307d5f2000-09-14 21:54:44 +0000464 }
nstrazcd87d682000-09-21 20:42:31 +0000465 propagate_signal(running, keep_active, orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000466 if (Debug & Drunning)
nstrazcd87d682000-09-21 20:42:31 +0000467 orphans_running(orphans);
nstrazf307d5f2000-09-14 21:54:44 +0000468 break;
469 }
470 if (orph == NULL)
471 break;
472 }
473
nstrazcd87d682000-09-21 20:42:31 +0000474 signal(SIGINT, SIG_DFL);
475 if (clear_active(zoofile, getpid(), &errmsg) != 1) {
476 fprintf(stderr, "pan(%s): %s\n", panname, errmsg);
nstrazf307d5f2000-09-14 21:54:44 +0000477 ++exit_stat;
478 }
nstrazcd87d682000-09-21 20:42:31 +0000479 fclose(zoofile);
nstrazf307d5f2000-09-14 21:54:44 +0000480
nstrazcd87d682000-09-21 20:42:31 +0000481 if (logfile && (logfile != stdout))
482 fclose(logfile);
483
484 exit(exit_stat);
nstrazf307d5f2000-09-14 21:54:44 +0000485}
486
487
nstrazf307d5f2000-09-14 21:54:44 +0000488
489static void
nstrazcd87d682000-09-21 20:42:31 +0000490propagate_signal(struct tag_pgrp *running, int keep_active,
491 struct orphan_pgrp *orphans)
nstrazf307d5f2000-09-14 21:54:44 +0000492{
493 int i;
494
495 if (Debug & Dshutdown)
nstrazcd87d682000-09-21 20:42:31 +0000496 fprintf(stderr, "pan was signaled with sig %d...\n", rec_signal);
nstrazf307d5f2000-09-14 21:54:44 +0000497
498 for (i = 0; i < keep_active; ++i) {
499 if (running[i].pgrp == 0)
500 continue;
501
502 if (Debug & Dshutdown)
nstrazcd87d682000-09-21 20:42:31 +0000503 fprintf(stderr, " propagating sig %d to %d\n",
nstrazf307d5f2000-09-14 21:54:44 +0000504 send_signal, -running[i].pgrp);
nstrazcd87d682000-09-21 20:42:31 +0000505 if (kill(-running[i].pgrp, send_signal) != 0) {
506 fprintf(stderr,
507 "pan(%s): kill(%d,%d) failed on tag (%s). errno:%d %s\n",
508 panname, -running[i].pgrp, send_signal,
509 running[i].cmd->name, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000510 }
511 running[i].stopping = 1;
512 }
513
nstrazcd87d682000-09-21 20:42:31 +0000514 check_orphans(orphans, send_signal);
nstrazf307d5f2000-09-14 21:54:44 +0000515
nstrazcd87d682000-09-21 20:42:31 +0000516 signal(rec_signal, wait_handler);
nstrazf307d5f2000-09-14 21:54:44 +0000517 rec_signal = send_signal = 0;
518}
519
520
521static int
nstrazcd87d682000-09-21 20:42:31 +0000522check_pids(struct tag_pgrp *running, int *num_active, int keep_active,
523 FILE * logfile, struct orphan_pgrp *orphans)
nstrazf307d5f2000-09-14 21:54:44 +0000524{
525 int w;
526 pid_t cpid;
527 int stat_loc;
528 int ret = 0;
529 int i;
530 time_t t;
531 char *status;
532 int signaled = 0;
533 struct tms tms1, tms2;
534 clock_t tck;
535
nstrazcd87d682000-09-21 20:42:31 +0000536 check_orphans(orphans, 0);
nstrazf307d5f2000-09-14 21:54:44 +0000537
nstrazcd87d682000-09-21 20:42:31 +0000538 tck = times(&tms1);
nstrazf307d5f2000-09-14 21:54:44 +0000539 if (tck == -1) {
nstrazcd87d682000-09-21 20:42:31 +0000540 fprintf(stderr, "pan(%s): times(&tms1) failed. errno:%d %s\n",
541 panname, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000542 }
nstrazcd87d682000-09-21 20:42:31 +0000543 cpid = wait(&stat_loc);
544 tck = times(&tms2);
nstrazf307d5f2000-09-14 21:54:44 +0000545 if (tck == -1) {
nstrazcd87d682000-09-21 20:42:31 +0000546 fprintf(stderr, "pan(%s): times(&tms2) failed. errno:%d %s\n",
547 panname, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000548 }
549
550 if (cpid < 0) {
551 if (errno == EINTR) {
552 if (Debug)
nstrazcd87d682000-09-21 20:42:31 +0000553 fprintf(stderr, "pan(%s): wait() interrupted\n", panname);
nstrazf307d5f2000-09-14 21:54:44 +0000554 } else if (errno != ECHILD) {
nstrazcd87d682000-09-21 20:42:31 +0000555 fprintf(stderr, "pan(%s): wait() failed. errno:%d %s\n",
556 panname, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +0000557 }
558 } else if (cpid > 0) {
559
nstrazcd87d682000-09-21 20:42:31 +0000560 if (WIFSIGNALED(stat_loc)) {
561 w = WTERMSIG(stat_loc);
nstrazf307d5f2000-09-14 21:54:44 +0000562 status = "signaled";
563 if (Debug & Dexit)
nstrazcd87d682000-09-21 20:42:31 +0000564 fprintf(stderr, "child %d terminated with signal %d\n", cpid,
565 w);
nstrazf307d5f2000-09-14 21:54:44 +0000566 --*num_active;
567 signaled = 1;
nstrazcd87d682000-09-21 20:42:31 +0000568 } else if (WIFEXITED(stat_loc)) {
569 w = WEXITSTATUS(stat_loc);
nstrazf307d5f2000-09-14 21:54:44 +0000570 status = "exited";
571 if (Debug & Dexit)
nstrazcd87d682000-09-21 20:42:31 +0000572 fprintf(stderr, "child %d exited with status %d\n", cpid, w);
nstrazf307d5f2000-09-14 21:54:44 +0000573 --*num_active;
574 if (w != 0)
575 ret++;
nstrazcd87d682000-09-21 20:42:31 +0000576 } else if (WIFSTOPPED(stat_loc)) { /* should never happen */
577 w = WSTOPSIG(stat_loc);
nstrazf307d5f2000-09-14 21:54:44 +0000578 status = "stopped";
579 ret++;
580 } else { /* should never happen */
581 w = 0;
582 status = "unknown";
583 ret++;
584 }
585
586 for (i = 0; i < keep_active; ++i) {
587 if (running[i].pgrp == cpid) {
588 if ((w == 130) && running[i].stopping &&
nstrazcd87d682000-09-21 20:42:31 +0000589 (strcmp(status, "exited") == 0)) {
nstrazf307d5f2000-09-14 21:54:44 +0000590 /* The child received sigint, but
591 * did not trap for it? Compensate
592 * for it here.
593 */
594 w = 0;
595 ret--; /* undo */
596 if (Debug & Drunning)
nstrazcd87d682000-09-21 20:42:31 +0000597 fprintf(stderr,
598 "pan(%s): tag=%s exited 130, known to be signaled; will give it an exit 0.\n",
599 panname, running[i].cmd->name);
nstrazf307d5f2000-09-14 21:54:44 +0000600 }
601 if (logfile != NULL) {
nstrazcd87d682000-09-21 20:42:31 +0000602 time(&t);
603 fprintf(logfile,
604 "tag=%s stime=%d dur=%d exit=%s stat=%d core=%s cu=%d cs=%d\n",
605 running[i].cmd->name, (int) (running[i].stime),
606 (int) (t - running[i].stime), status, w,
607 (stat_loc & 0200) ? "yes" : "no",
608 (int) (tms2.tms_cutime - tms1.tms_cutime),
609 (int) (tms2.tms_cstime - tms1.tms_cstime));
610 fflush(logfile);
nstrazf307d5f2000-09-14 21:54:44 +0000611 }
nstrazcd87d682000-09-21 20:42:31 +0000612
613
614 if (running[i].stopping)
615 status = "driver_interrupt";
616
617 if (test_out_dir) {
618 write_test_start(running+i, "ok");
619 copy_buffered_output(running + i);
620 unlink(running[i].output);
621 }
622 write_test_end(running+i, t, status,
623 stat_loc, w, &tms1, &tms2);
624
nstrazf307d5f2000-09-14 21:54:44 +0000625 /* If signaled and we weren't expecting
626 * this to be stopped then the proc
627 * had a problem.
628 */
629 if (signaled && !running[i].stopping)
630 ret++;
631
632 running[i].pgrp = 0;
nstrazcd87d682000-09-21 20:42:31 +0000633 if (clear_active(zoofile, cpid, &errmsg) == -1) {
634 fprintf(stderr, "pan(%s): %s\n", panname, errmsg);
635 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000636 }
637
638 /* Check for orphaned pgrps */
nstrazcd87d682000-09-21 20:42:31 +0000639 if ((kill(-cpid, 0) == 0) || (errno == EPERM)) {
640 if (write_active_args(zoofile, cpid, "panorphan",
641 running[i].cmd->argc,
642 running[i].cmd->argv,
643 &errmsg) == -1) {
644 fprintf(stderr, "pan(%s): %s\n", panname, errmsg);
645 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000646 }
nstrazcd87d682000-09-21 20:42:31 +0000647 mark_orphan(orphans, cpid);
nstrazf307d5f2000-09-14 21:54:44 +0000648 /* status of kill doesn't matter */
nstrazcd87d682000-09-21 20:42:31 +0000649 kill(-cpid, SIGTERM);
nstrazf307d5f2000-09-14 21:54:44 +0000650 }
651
652 break;
653 }
654 }
655 }
656 return ret;
657}
658
659
660static pid_t
nstrazcd87d682000-09-21 20:42:31 +0000661run_child(struct coll_entry *colle, struct tag_pgrp *active)
nstrazf307d5f2000-09-14 21:54:44 +0000662{
663 int cpid;
nstrazcd87d682000-09-21 20:42:31 +0000664 int c_stdout; /* child's stdout, stderr */
665 int capturing = 0; /* output is going to a file instead of stdout */
666 char **eargv;
667 static long cmdno = 0;
668 int i;
669 int errpipe[2]; /* way to communicate to parent that the tag */
670 char errbuf[1024]; /* didn't actually start */
671 int errlen;
nstrazf307d5f2000-09-14 21:54:44 +0000672
nstrazcd87d682000-09-21 20:42:31 +0000673 /* Try to open the file that will be stdout for the test */
674 if (test_out_dir) {
675 capturing = 1;
676 do {
677 sprintf(active->output, "%s/%s.%ld",
678 test_out_dir, colle->name, cmdno++);
679 c_stdout = open(active->output, O_CREAT | O_RDWR | O_EXCL, 0666);
680 } while (c_stdout < 0 && errno == EEXIST);
681 if (c_stdout < 0) {
682 fprintf(stderr,
683 "pan(%s): open of stdout file failed (tag %s). errno: %d %s\n file: %s\n",
684 panname, colle->name, errno, strerror(errno),
685 active->output);
686 return -1;
687 }
688 }
689
690 /* get the tag's command line arguments ready. subst_pcnt_f() uses a
691 * static counter, that's why we do it here instead of after we fork.
692 */
693 if (colle->pcnt_f) {
694 eargv = subst_pcnt_f(colle);
695 } else {
696 eargv = colle->argv;
697 }
698
699 if (pipe(errpipe) < 0) {
700 fprintf(stderr, "pan(%s): pipe() failed. errno:%d %s\n",
701 panname, errno, strerror(errno));
702 if (capturing)
703 close(c_stdout);
704 return -1;
705 }
706
707 if ((cpid = fork()) < 0) {
708 fprintf(stderr, "pan(%s): fork failed (tag %s). errno:%d %s\n",
709 panname, colle->name, errno, strerror(errno));
710 if (capturing)
711 close(c_stdout);
712 close(errpipe[0]);
713 close(errpipe[1]);
nstrazf307d5f2000-09-14 21:54:44 +0000714 return -1;
715 } else if (cpid == 0) {
716 /* child */
nstrazf307d5f2000-09-14 21:54:44 +0000717
nstrazcd87d682000-09-21 20:42:31 +0000718 fclose(zoofile);
719 close(errpipe[0]);
720 fcntl(errpipe[1], F_SETFD, 1); /* close the pipe if we succeed */
721 setpgrp();
nstrazf307d5f2000-09-14 21:54:44 +0000722
nstrazcd87d682000-09-21 20:42:31 +0000723 umask(0);
724
725 /* if we're putting output into a buffer file, we need to do the
726 * redirection now. If we fail
727 */
728 if (capturing) {
729 if (dup2(c_stdout, fileno(stdout)) == -1) {
730 errlen = sprintf(errbuf, "pan(%s): couldn't redirect stdout for tag %s. errno:%d %s",
731 panname, colle->name, errno, strerror(errno));
732 write(errpipe[1], &errlen, sizeof(errlen));
733 write(errpipe[1], errbuf, errlen);
734 exit(2);
735 }
736 if (dup2(c_stdout, fileno(stderr)) == -1) {
737 errlen = sprintf(errbuf, "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s",
738 panname, colle->name, errno, strerror(errno));
739 write(errpipe[1], &errlen, sizeof(errlen));
740 write(errpipe[1], errbuf, errlen);
741 exit(2);
742 }
743 } else { /* stderr still needs to be redirected */
744 if (dup2(fileno(stdout), fileno(stderr)) == -1) {
745 errlen = sprintf(errbuf, "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s",
746 panname, colle->name, errno, strerror(errno));
747 write(errpipe[1], &errlen, sizeof(errlen));
748 write(errpipe[1], errbuf, errlen);
749 exit(2);
750 }
nstrazf307d5f2000-09-14 21:54:44 +0000751 }
nstrazf307d5f2000-09-14 21:54:44 +0000752 /* execute command */
nstrazcd87d682000-09-21 20:42:31 +0000753 execvp(eargv[0], eargv);
754 errlen = sprintf(errbuf,
755 "pan(%s): execvp of '%s' (tag %s) failed. errno:%d %s",
756 panname, eargv[0], colle->name, errno, strerror(errno));
757 write(errpipe[1], &errlen, sizeof(errlen));
758 write(errpipe[1], errbuf, errlen);
759 exit(errno);
nstrazf307d5f2000-09-14 21:54:44 +0000760 }
761
762 /* parent */
nstrazcd87d682000-09-21 20:42:31 +0000763
764 /* subst_pcnt_f() allocates dynamically any arguments with %f in it.
765 * free the mallocs now to prevent memory leak
766 */
767 if (colle->pcnt_f) {
768 for (i = 0; i < colle->argc; ++i)
769 if (strstr(colle->argv[i], "%f"))
770 free(eargv[i]);
771 free(eargv);
772 }
773 close(errpipe[1]);
774 time(&active->stime);
nstrazf307d5f2000-09-14 21:54:44 +0000775 active->cmd = colle;
776
nstrazcd87d682000-09-21 20:42:31 +0000777 /* if the child couldn't go through with the exec,
778 * clean up the mess, note it, and move on
779 */
780 if(read(errpipe[0], &errlen, sizeof(errlen))) {
781 int status;
782 time_t end_time;
783 int termid;
784 char *termtype;
785 struct tms notime = {0, 0, 0, 0};
786
787 read(errpipe[0], errbuf, errlen);
788 close(errpipe[0]);
789 errbuf[errlen] = '\0';
790 /* fprintf(stderr, "%s", errbuf); */
791 waitpid(cpid, &status, 0);
792 if (WIFSIGNALED(status)) {
793 termid = WTERMSIG(status);
794 termtype = "signaled";
795 } else if (WIFEXITED(status)) {
796 termid = WEXITSTATUS(status);
797 termtype = "exited";
798 } else if (WIFSTOPPED(status)) {
799 termid = WSTOPSIG(status);
800 termtype = "stopped";
801 } else {
802 termid = 0;
803 termtype = "unknown";
804 }
805 time(&end_time);
806 write_test_start(active, errbuf);
807 write_test_end(active, end_time, termtype, status,
808 termid, &notime, &notime);
809 return -1;
810 }
811
812 close(errpipe[0]);
813
814 if (!test_out_dir)
815 write_test_start(active, "ok");
816
817 active->pgrp = cpid;
818 active->stopping = 0;
819
nstrazf307d5f2000-09-14 21:54:44 +0000820 if (write_active_args
nstrazcd87d682000-09-21 20:42:31 +0000821 (zoofile, cpid, colle->name, colle->argc, colle->argv, &errmsg) == -1) {
822 fprintf(stderr, "pan(%s): %s\n", panname, errmsg);
823 exit(1);
nstrazf307d5f2000-09-14 21:54:44 +0000824 }
825
826 if (Debug & Dstartup)
nstrazcd87d682000-09-21 20:42:31 +0000827 fprintf(stderr, "started %s cpid=%d at %s",
828 colle->name, cpid, ctime(&active->stime));
nstrazf307d5f2000-09-14 21:54:44 +0000829
830 if (Debug & Dstart) {
831 int ac;
nstrazcd87d682000-09-21 20:42:31 +0000832 fprintf(stderr, "Executing test = %s as ", colle->name);
nstrazf307d5f2000-09-14 21:54:44 +0000833 for (ac = 0; ac < colle->argc; ac++) {
nstrazcd87d682000-09-21 20:42:31 +0000834 fprintf(stderr, "%s ", colle->argv[ac]);
nstrazf307d5f2000-09-14 21:54:44 +0000835 }
nstrazcd87d682000-09-21 20:42:31 +0000836 if (capturing)
837 fprintf(stderr, "with output file = %s\n", active->output);
838 else
839 fprintf(stderr, "\n");
nstrazf307d5f2000-09-14 21:54:44 +0000840 }
841
842 return cpid;
843}
844
845
846static char **
nstrazcd87d682000-09-21 20:42:31 +0000847subst_pcnt_f(struct coll_entry *colle)
nstrazf307d5f2000-09-14 21:54:44 +0000848{
849 char **eargv;
850 char *p;
851 int i;
852
nstrazcd87d682000-09-21 20:42:31 +0000853 eargv = (char **) malloc((colle->argc + 1) * sizeof(char *));
nstrazf307d5f2000-09-14 21:54:44 +0000854
855 for (i = 0; i < colle->argc; ++i) {
nstrazcd87d682000-09-21 20:42:31 +0000856 if ((p = strstr(colle->argv[i], "%f")) != NULL) {
nstrazf307d5f2000-09-14 21:54:44 +0000857 /* simple, for now */
858 static int counter = 1;
859 char *b, *p2;
860 int pidlen, counterlen;
861
862 *p = '\0'; /* cut off at % */
863 p2 = p + 2; /* stuff that follows %f */
864
nstrazcd87d682000-09-21 20:42:31 +0000865 pidlen = 1 + (int) log10((double) getpid());
866 counterlen = 1 + (int) log10((double) counter);
nstrazf307d5f2000-09-14 21:54:44 +0000867
nstrazcd87d682000-09-21 20:42:31 +0000868 b = (char *) malloc(strlen(colle->argv[i]) +
869 pidlen + 1 + counterlen + strlen(p2) + 1);
870 sprintf(b, "%s%d_%d%s", colle->argv[i], getpid(), counter++, p2);
nstrazf307d5f2000-09-14 21:54:44 +0000871 *p = '%'; /* restore % */
872 eargv[i] = b;
873 } else {
874 eargv[i] = colle->argv[i];
875 }
876 }
877 eargv[i] = NULL;
878 return eargv;
879}
880
881static struct collection *
nstrazcd87d682000-09-21 20:42:31 +0000882get_collection(char *file, int optind, int argc, char **argv)
nstrazf307d5f2000-09-14 21:54:44 +0000883{
884 char *buf, *a, *b;
885 struct coll_entry *head, *p, *n;
886 struct collection *coll;
887 int i;
888
nstrazcd87d682000-09-21 20:42:31 +0000889 buf = slurp(file);
nstrazf307d5f2000-09-14 21:54:44 +0000890
nstrazcd87d682000-09-21 20:42:31 +0000891 coll = (struct collection *) malloc(sizeof(struct collection));
nstrazf307d5f2000-09-14 21:54:44 +0000892 coll->cnt = 0;
893
894 head = p = n = NULL;
895 a = b = buf;
896 while (*b != '\0') {
nstrazcd87d682000-09-21 20:42:31 +0000897 if ((b = strchr(a, '\n')) != NULL)
nstrazf307d5f2000-09-14 21:54:44 +0000898 *b = '\0';
899
900 if ((*a != '#') && (*a != '\0') && (*a != ' ')) {
901 if (head == NULL) {
902 head =
nstrazcd87d682000-09-21 20:42:31 +0000903 (struct coll_entry *) malloc(sizeof(struct coll_entry));
904 head->pcnt_f = strstr(a, "%f");
905 head->argv = (char **) splitstr(a, NULL, &head->argc);
nstrazf307d5f2000-09-14 21:54:44 +0000906 head->name = head->argv[0];
907 head->argv++; /* remove name from command */
908 head->argc--;
909 head->next = NULL;
910 p = head;
911 } else {
nstrazcd87d682000-09-21 20:42:31 +0000912 n = (struct coll_entry *) malloc(sizeof(struct coll_entry));
nstrazf307d5f2000-09-14 21:54:44 +0000913 p->next = n;
nstrazcd87d682000-09-21 20:42:31 +0000914 n->pcnt_f = strstr(a, "%f");
915 n->argv = (char **) splitstr(a, NULL, &n->argc);
nstrazf307d5f2000-09-14 21:54:44 +0000916 n->name = n->argv[0];
917 n->argv++; /* remove name from command */
918 n->argc--;
919 n->next = NULL;
920 p = n;
921 }
922 coll->cnt++;
923 }
nstrazcd87d682000-09-21 20:42:31 +0000924 a += strlen(a) + 1;
nstrazf307d5f2000-09-14 21:54:44 +0000925 b = a;
926 }
nstrazcd87d682000-09-21 20:42:31 +0000927 free(buf);
nstrazf307d5f2000-09-14 21:54:44 +0000928
929 /* is there something on the commandline to be counted? */
930 if (optind < argc) {
931 char **args;
932 char *pcnt_f = NULL;
933
nstrazcd87d682000-09-21 20:42:31 +0000934 args = (char **) malloc((argc - optind + 1) * sizeof(char *));
nstrazf307d5f2000-09-14 21:54:44 +0000935 /* fill arg list */
936 for (i = 0; optind < argc; ++optind, ++i) {
937 args[i] = argv[optind];
nstrazcd87d682000-09-21 20:42:31 +0000938 if ((pcnt_f == NULL) && ((strstr(args[i], "%f")) != NULL)) {
nstrazf307d5f2000-09-14 21:54:44 +0000939 pcnt_f = args[i];
940 }
941 }
942 args[i] = NULL;
943
944 if (head == NULL) {
nstrazcd87d682000-09-21 20:42:31 +0000945 head = (struct coll_entry *) malloc(sizeof(struct coll_entry));
nstrazf307d5f2000-09-14 21:54:44 +0000946 head->pcnt_f = pcnt_f;
947 head->argv = args;
948 head->name = "cmdln";
949 head->argc = i;
950 head->next = NULL;
951 } else {
nstrazcd87d682000-09-21 20:42:31 +0000952 n = (struct coll_entry *) malloc(sizeof(struct coll_entry));
nstrazf307d5f2000-09-14 21:54:44 +0000953 p->next = n;
954 n->pcnt_f = pcnt_f;
955 n->argv = args;
956 n->name = "cmdln";
957 n->argc = i;
958 n->next = NULL;
959 }
960 coll->cnt++;
961 }
962
963 /* get an array */
nstrazcd87d682000-09-21 20:42:31 +0000964 coll->ary = (struct coll_entry **) malloc(coll->cnt *
965 sizeof(struct coll_entry *));
nstrazf307d5f2000-09-14 21:54:44 +0000966
967 /* fill the array */
968 i = 0;
969 n = head;
970 while (n != NULL) {
971 coll->ary[i] = n;
972 n = n->next;
973 ++i;
974 }
975 if (i != coll->cnt)
nstrazcd87d682000-09-21 20:42:31 +0000976 fprintf(stderr, "pan(%s): i doesn't match cnt\n", panname);
nstrazf307d5f2000-09-14 21:54:44 +0000977
978 return coll;
979}
980
981
982static char *
nstrazcd87d682000-09-21 20:42:31 +0000983slurp(char *file)
nstrazf307d5f2000-09-14 21:54:44 +0000984{
985 char *buf;
986 int fd;
987 struct stat sbuf;
988
nstrazcd87d682000-09-21 20:42:31 +0000989 if ((fd = open(file, O_RDONLY)) < 0) {
990 fprintf(stderr, "pan(%s): open(%s,O_RDONLY) failed. errno:%d %s\n",
991 panname, file, errno, strerror(errno));
992 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000993 }
994
nstrazcd87d682000-09-21 20:42:31 +0000995 if (fstat(fd, &sbuf) < 0) {
996 fprintf(stderr, "pan(%s): fstat(%s) failed. errno:%d %s\n",
997 panname, file, errno, strerror(errno));
998 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +0000999 }
1000
nstrazcd87d682000-09-21 20:42:31 +00001001 buf = (char *) malloc(sbuf.st_size + 1);
1002 if (read(fd, buf, sbuf.st_size) != sbuf.st_size) {
1003 fprintf(stderr, "pan(%s): slurp failed. errno:%d %s\n",
1004 panname, errno, strerror(errno));
1005 return NULL;
nstrazf307d5f2000-09-14 21:54:44 +00001006 }
1007 buf[sbuf.st_size] = '\0';
1008
nstrazcd87d682000-09-21 20:42:31 +00001009 close(fd);
nstrazf307d5f2000-09-14 21:54:44 +00001010 return buf;
1011}
1012
1013static void
nstrazcd87d682000-09-21 20:42:31 +00001014check_orphans(struct orphan_pgrp *orphans, int sig)
nstrazf307d5f2000-09-14 21:54:44 +00001015{
1016 struct orphan_pgrp *orph;
1017
1018 for (orph = orphans; orph != NULL; orph = orph->next) {
1019 if (orph->pgrp == 0)
1020 continue;
1021
1022 if (Debug & Dshutdown)
nstrazcd87d682000-09-21 20:42:31 +00001023 fprintf(stderr, " propagating sig %d to orphaned pgrp %d\n",
nstrazf307d5f2000-09-14 21:54:44 +00001024 sig, -(orph->pgrp));
nstrazcd87d682000-09-21 20:42:31 +00001025 if (kill(-(orph->pgrp), sig) != 0) {
nstrazf307d5f2000-09-14 21:54:44 +00001026 if (errno == ESRCH) {
1027 /* This pgrp is now empty */
nstrazcd87d682000-09-21 20:42:31 +00001028 if (clear_active(zoofile, orph->pgrp, &errmsg) == -1) {
1029 fprintf(stderr, "pan(%s): %s\n", panname, errmsg);
nstrazf307d5f2000-09-14 21:54:44 +00001030 }
1031 orph->pgrp = 0;
1032 } else {
nstrazcd87d682000-09-21 20:42:31 +00001033 fprintf(stderr,
1034 "pan(%s): kill(%d,%d) on orphaned pgrp failed. errno:%d %s\n",
1035 panname, -(orph->pgrp), sig, errno, strerror(errno));
nstrazf307d5f2000-09-14 21:54:44 +00001036 }
1037 }
1038 }
1039}
1040
1041
1042static void
nstrazcd87d682000-09-21 20:42:31 +00001043mark_orphan(struct orphan_pgrp *orphans, pid_t cpid)
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 break;
1050 }
1051 if (orph == NULL) {
1052 /* make a new struct */
nstrazcd87d682000-09-21 20:42:31 +00001053 orph = (struct orphan_pgrp *) malloc(sizeof(struct orphan_pgrp));
nstrazf307d5f2000-09-14 21:54:44 +00001054
1055 /* plug in the new struct just after the head */
1056 orph->next = orphans->next;
1057 orphans->next = orph;
1058 }
1059 orph->pgrp = cpid;
1060}
1061
1062
nstrazf307d5f2000-09-14 21:54:44 +00001063
nstrazcd87d682000-09-21 20:42:31 +00001064static void
1065copy_buffered_output(struct tag_pgrp *running)
1066{
1067 char *tag_output;
1068
1069 tag_output = slurp(running->output);
1070 if (tag_output) {
1071 printf("%s", tag_output);
1072 /* make sure the output ends with a newline */
1073 if (tag_output[strlen(tag_output) - 1] != '\n')
1074 printf("\n");
1075 fflush(stdout);
1076 free(tag_output);
nstrazf307d5f2000-09-14 21:54:44 +00001077 }
nstrazcd87d682000-09-21 20:42:31 +00001078}
1079
1080
1081static void
1082write_test_start(struct tag_pgrp *running, const char *init_status)
1083{
1084 if (!strcmp(reporttype, "rts")) {
1085 char *args = NULL;
1086
1087 args = cat_args(running->cmd->argc, running->cmd->argv, &errmsg);
1088 if (!args) args = "Unable_to_malloc_cmdline";
1089
1090 printf("%s\ntag=%s stime=%ld\ncmdline=\"%s\"\ncontacts=\"%s\"\nanalysis=%s\ninitiation_status=\"%s\"\n%s\n",
1091 "<<<test_start>>>",
1092 running->cmd->name, running->stime, args, "",
1093 "exit", init_status,
1094 "<<<test_output>>>");
1095 if (args) free(args);
1096 }
1097 fflush(stdout);
1098}
1099
1100
1101static void
1102write_test_end(struct tag_pgrp *running, time_t exit_time,
1103 char *term_type, int stat_loc, int term_id,
1104 struct tms *tms1, struct tms *tms2)
1105{
1106 if (!strcmp(reporttype, "rts")) {
1107 printf("%s\nduration=%ld termination_type=%s termination_id=%d corefile=%s\ncutime=%d cstime=%d\n%s\n",
1108 "<<<execution_status>>>",
1109 (long) (exit_time - running->stime),
1110 term_type, term_id, (stat_loc & 0200) ? "yes" : "no",
1111 (int) (tms2->tms_cutime - tms1->tms_cutime),
1112 (int) (tms2->tms_cstime - tms1->tms_cstime),
1113 "<<<test_end>>>");
1114 }
1115 fflush(stdout);
1116}
1117
1118/* The functions below are all debugging related */
1119
1120static void
1121pids_running(struct tag_pgrp *running, int keep_active)
1122{
1123 int i;
1124
1125 fprintf(stderr, "pids still running: ");
1126 for (i = 0; i < keep_active; ++i) {
1127 if (running[i].pgrp != 0)
1128 fprintf(stderr, "%d ", running[i].pgrp);
1129 }
1130 fprintf(stderr, "\n");
nstrazf307d5f2000-09-14 21:54:44 +00001131}
1132
1133static void
nstrazcd87d682000-09-21 20:42:31 +00001134orphans_running(struct orphan_pgrp *orphans)
1135{
1136 struct orphan_pgrp *orph;
1137
1138 fprintf(stderr, "orphans still running: ");
1139 for (orph = orphans; orph != NULL; orph = orph->next) {
1140 if (orph->pgrp != 0)
1141 fprintf(stderr, "%d ", -(orph->pgrp));
1142 }
1143 fprintf(stderr, "\n");
1144}
1145
1146static void
1147dump_coll(struct collection *coll)
nstrazf307d5f2000-09-14 21:54:44 +00001148{
1149 int x, i;
1150
1151 for (i = 0; i < coll->cnt; ++i) {
nstrazcd87d682000-09-21 20:42:31 +00001152 fprintf(stderr, "coll %d\n", i);
1153 fprintf(stderr, " name=%s #args=%d\n", coll->ary[i]->name,
nstrazf307d5f2000-09-14 21:54:44 +00001154 coll->ary[i]->argc);
1155 for (x = 0; coll->ary[i]->argv[x]; ++x) {
nstrazcd87d682000-09-21 20:42:31 +00001156 fprintf(stderr, " argv[%d] = (%s)\n", x, coll->ary[i]->argv[x]);
nstrazf307d5f2000-09-14 21:54:44 +00001157 }
1158 }
1159}