• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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  * Changelog:
33  *
34  *	Added timer options: William Jay Huie, IBM
35  *	01/27/03 - Added: Manoj Iyer, manjo@mail.utexas.edu
36  *			   - option '-p' (pretty printing)i to enabled formatted printing
37  *			     of results.
38  *
39  *	01/27/03 - Added: Manoj Iyer, manjo@mail.utexas.edu
40  *			   - added code to print system information
41  *
42  *	01/28/03 - Added: Manoj Iyer, manjo@mail.utexas.edu
43  *			   - added code to print test exit value.
44  *
45  *	01/29/03 - Added: Manoj Iyer, manjo@mail.utexas.edu
46  *			   - added code supresses test start and test end tags.
47  *
48  * 	07/22/07 - Added: Ricardo Salveti de Araujo, rsalveti@linux.vnet.ibm.com
49  *			   - added option to create a command file with all failed tests.
50  *
51  */
52 /* $Id: ltp-pan.c,v 1.4 2009/10/15 18:45:55 yaberauneya Exp $ */
53 
54 #include <sys/param.h>
55 #include <sys/stat.h>
56 #include <stdarg.h>
57 #include <sys/times.h>
58 #include <sys/types.h>
59 #include <sys/wait.h>
60 #include <sys/utsname.h>
61 #include <errno.h>
62 #include <err.h>
63 #include <limits.h>
64 #include <signal.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <time.h>
68 
69 #include "splitstr.h"
70 #include "zoolib.h"
71 #include "tst_res_flags.h"
72 
73 /* One entry in the command line collection.  */
74 struct coll_entry {
75 	char *name;		/* tag name */
76 	char *cmdline;		/* command line */
77 	char *pcnt_f;		/* location of %f in the command line args, flag */
78 	struct coll_entry *next;
79 };
80 
81 struct collection {
82 	int cnt;
83 	struct coll_entry **ary;
84 };
85 
86 struct tag_pgrp {
87 	int pgrp;
88 	int stopping;
89 	time_t mystime;
90 	struct coll_entry *cmd;
91 	char output[PATH_MAX];
92 };
93 
94 struct orphan_pgrp {
95 	int pgrp;
96 	struct orphan_pgrp *next;
97 };
98 
99 static pid_t run_child(struct coll_entry *colle, struct tag_pgrp *active,
100 		       int quiet_mode, int *failcnt, int fmt_print,
101 		       FILE * logfile, int no_kmsg);
102 static char *slurp(char *file);
103 static struct collection *get_collection(char *file, int optind, int argc,
104 					 char **argv);
105 static void pids_running(struct tag_pgrp *running, int keep_active);
106 static int check_pids(struct tag_pgrp *running, int *num_active,
107 		      int keep_active, FILE * logfile, FILE * failcmdfile,
108 		      FILE *tconfcmdfile, struct orphan_pgrp *orphans,
109 		      int fmt_print, int *failcnt, int *tconfcnt,
110 		      int quiet_mode, int no_kmsg);
111 static void propagate_signal(struct tag_pgrp *running, int keep_active,
112 			     struct orphan_pgrp *orphans);
113 static void dump_coll(struct collection *coll);
114 static char *subst_pcnt_f(struct coll_entry *colle);
115 static void mark_orphan(struct orphan_pgrp *orphans, pid_t cpid);
116 static void orphans_running(struct orphan_pgrp *orphans);
117 static void check_orphans(struct orphan_pgrp *orphans, int sig);
118 
119 static void copy_buffered_output(struct tag_pgrp *running);
120 static void write_test_start(struct tag_pgrp *running, int no_kmsg);
121 static void write_test_end(struct tag_pgrp *running, const char *init_status,
122 			   time_t exit_time, char *term_type, int stat_loc,
123 			   int term_id, struct tms *tms1, struct tms *tms2);
124 
125 //wjh
126 static char PAN_STOP_FILE[] = "PAN_STOP_FILE";
127 
128 static char *panname = NULL;
129 static char *test_out_dir = NULL;	/* dir to buffer output to */
130 zoo_t zoofile;
131 static char *reporttype = NULL;
132 
133 /* Common format string for ltp-pan results */
134 #define ResultFmt	"%-50s %-10.10s"
135 
136 /* zoolib */
137 int rec_signal;			/* received signal */
138 int send_signal;		/* signal to send */
139 
140 /* Debug Bits */
141 int Debug = 0;
142 #define Dbuffile	0x000400	/* buffer file use */
143 #define	Dsetup		0x000200	/* one-time set-up */
144 #define	Dshutdown	0x000100	/* killed by signal */
145 #define	Dexit		0x000020	/* exit status */
146 #define	Drunning	0x000010	/* current pids running */
147 #define	Dstartup	0x000004	/* started command */
148 #define	Dstart		0x000002	/* started command */
149 #define Dwait		0x000001	/* wait interrupted */
150 
main(int argc,char ** argv)151 int main(int argc, char **argv)
152 {
153 	extern char *optarg;
154 	extern int optind;
155 	char *zooname = NULL;	/* name of the zoo file to use */
156 	char *filename = "/dev/null";	/* filename to read test tags from */
157 	char *logfilename = NULL;
158 	char *failcmdfilename = NULL;
159 	char *tconfcmdfilename = NULL;
160 	char *outputfilename = NULL;
161 	struct collection *coll = NULL;
162 	struct tag_pgrp *running;
163 	struct orphan_pgrp *orphans, *orph;
164 	struct utsname unamebuf;
165 	FILE *logfile = NULL;
166 	FILE *failcmdfile = NULL;
167 	FILE *tconfcmdfile = NULL;
168 	int keep_active = 1;
169 	int num_active = 0;
170 	int failcnt = 0;  /* count of total testcases that failed. */
171 	int tconfcnt = 0; /* count of total testcases that return TCONF */
172 	int err, i;
173 	int starts = -1;
174 	int timed = 0;
175 	int run_time = -1;
176 	char modifier = 'm';
177 	int ret = 0;
178 	int stop;
179 	int go_idle;
180 	int has_brakes = 0;	/* stop everything if a test case fails */
181 	int sequential = 0;	/* run tests sequentially */
182 	int fork_in_road = 0;
183 	int exit_stat;
184 	int track_exit_stats = 0;	/* exit non-zero if any test exits non-zero */
185 	int fmt_print = 0;	/* enables formatted printing of logfiles. */
186 	int quiet_mode = 0;	/* supresses test start and test end tags. */
187 	int no_kmsg = 0;	/* don't log into /dev/kmsg */
188 	int c;
189 	pid_t cpid;
190 	struct sigaction sa;
191 
192 	while ((c =
193 		getopt(argc, argv, "AO:Sa:C:QT:d:ef:hl:n:o:pqr:s:t:x:y"))
194 		       != -1) {
195 		switch (c) {
196 		case 'A':	/* all-stop flag */
197 			has_brakes = 1;
198 			track_exit_stats = 1;
199 			break;
200 		case 'O':	/* output buffering directory */
201 			test_out_dir = strdup(optarg);
202 			break;
203 		case 'S':	/* run tests sequentially */
204 			sequential = 1;
205 			break;
206 		case 'a':	/* name of the zoo file to use */
207 			zooname = strdup(optarg);
208 			break;
209 		case 'C':	/* name of the file where all failed commands will be */
210 			failcmdfilename = strdup(optarg);
211 			break;
212 		case 'Q':
213 			no_kmsg = 1;
214 			break;
215 		case 'T':
216 			/*
217 			 * test cases that are not fully tested will be recorded
218 			 * in this file
219 			 */
220 			tconfcmdfilename = strdup(optarg);
221 			break;
222 		case 'd':	/* debug options */
223 			sscanf(optarg, "%i", &Debug);
224 			break;
225 		case 'e':	/* exit non-zero if any test exists non-zero */
226 			track_exit_stats = 1;
227 			break;
228 		case 'f':	/* filename to read test tags from */
229 			filename = strdup(optarg);
230 			break;
231 		case 'h':	/* help */
232 			fprintf(stdout,
233 				"Usage: pan -n name [ -SyAehpqQ ] [ -s starts ]"
234 				" [-t time[s|m|h|d] [ -x nactive ] [ -l logfile ]\n\t"
235 				"[ -a active-file ] [ -f command-file ] "
236 				"[ -C fail-command-file ] "
237 				"[ -d debug-level ]\n\t[-o output-file] "
238 				"[-O output-buffer-directory] [cmd]\n");
239 			exit(0);
240 		case 'l':	/* log file */
241 			logfilename = strdup(optarg);
242 			break;
243 		case 'n':	/* tag given to pan */
244 			panname = strdup(optarg);
245 			break;
246 		case 'o':	/* send test output here */
247 			outputfilename = strdup(optarg);
248 			break;
249 		case 'p':	/* formatted printing. */
250 			fmt_print = 1;
251 			break;
252 		case 'q':	/* supress test start and test end messages */
253 			quiet_mode = 1;
254 			break;
255 		case 'r':	/* reporting type: none, rts */
256 			reporttype = strdup(optarg);
257 			break;
258 		case 's':	/* number of tags to run */
259 			starts = atoi(optarg);
260 			break;
261 		case 't':	/* run_time to run */
262 			ret = sscanf(optarg, "%d%c", &run_time, &modifier);
263 			if (ret == 0) {
264 				fprintf(stderr,
265 					"Need proper time input: ####x where"
266 					"x is one of s,m,h,d\n");
267 				break;
268 			} else if (ret == 1) {
269 				fprintf(stderr, "Only got a time value of %d "
270 					"modifiers need to come immediately after #"
271 					" assuming %c\n", run_time, modifier);
272 			} else {
273 				switch (modifier) {
274 				case 's':
275 					run_time = run_time;
276 					break;
277 				case 'm':
278 					run_time = run_time * 60;
279 					break;
280 				case 'h':
281 					run_time = run_time * 60 * 60;
282 					break;
283 				case 'd':
284 					run_time = run_time * 60 * 60 * 24;
285 					break;
286 				default:
287 					fprintf(stderr,
288 						"Invalid time modifier, try: s|h|m|d\n");
289 					exit(-1);
290 				}
291 				if (!quiet_mode)
292 					printf("PAN will run for %d seconds\n",
293 					       run_time);
294 			}
295 			timed = 1;	//-t implies run as many starts as possible, by default
296 			break;
297 		case 'x':	/* number of tags to keep running */
298 			keep_active = atoi(optarg);
299 			break;
300 		case 'y':	/* restart on failure or signal */
301 			fork_in_road = 1;
302 			break;
303 		}
304 	}
305 
306 	if (panname == NULL) {
307 		fprintf(stderr, "pan: Must supply -n\n");
308 		exit(1);
309 	}
310 	if (zooname == NULL) {
311 		zooname = zoo_getname();
312 		if (zooname == NULL) {
313 			fprintf(stderr,
314 				"pan(%s): Must supply -a or set ZOO env variable\n",
315 				panname);
316 			exit(1);
317 		}
318 	}
319 	if (reporttype) {
320 		/* make sure we understand the report type */
321 		if (strcasecmp(reporttype, "rts")
322 		    && strcasecmp(reporttype, "none")
323 		    /* && strcasecmp(reporttype, "xml") */
324 		    )
325 			reporttype = "rts";
326 	} else {
327 		/* set the default */
328 		reporttype = "rts";
329 	}
330 
331 	if (logfilename != NULL) {
332 		time_t startup;
333 		char *s;
334 
335 		if (!strcmp(logfilename, "-")) {
336 			logfile = stdout;
337 		} else {
338 			if ((logfile = fopen(logfilename, "a+")) == NULL) {
339 				fprintf(stderr,
340 					"pan(%s): Error %s (%d) opening log file '%s'\n",
341 					panname, strerror(errno), errno,
342 					logfilename);
343 				exit(1);
344 			}
345 		}
346 
347 		time(&startup);
348 		s = ctime(&startup);
349 		*(s + strlen(s) - 1) = '\0';
350 		if (!fmt_print)
351 			fprintf(logfile, "startup='%s'\n", s);
352 		else {
353 			fprintf(logfile, "Test Start Time: %s\n", s);
354 			fprintf(logfile,
355 				"-----------------------------------------\n");
356 			fprintf(logfile, ResultFmt" %-10.10s\n",
357 				"Testcase", "Result", "Exit Value");
358 			fprintf(logfile, ResultFmt" %-10.10s\n",
359 				"--------", "------", "------------");
360 		}
361 		fflush(logfile);
362 	}
363 
364 	coll = get_collection(filename, optind, argc, argv);
365 	if (!coll)
366 		exit(1);
367 	if (coll->cnt == 0) {
368 		fprintf(stderr,
369 			"pan(%s): Must supply a file collection or a command\n",
370 			panname);
371 		exit(1);
372 	}
373 
374 	if (Debug & Dsetup)
375 		dump_coll(coll);
376 
377 	/* a place to store the pgrps we're watching */
378 	running =
379 		malloc((keep_active + 1) *
380 			sizeof(struct tag_pgrp));
381 	if (running == NULL) {
382 		fprintf(stderr, "pan(%s): Failed to allocate memory: %s\n",
383 			panname, strerror(errno));
384 		exit(2);
385 	}
386 	memset(running, 0, keep_active * sizeof(struct tag_pgrp));
387 	running[keep_active].pgrp = -1;	/* end sentinel */
388 
389 	/* a head to the orphaned pgrp list */
390 	orphans = malloc(sizeof(struct orphan_pgrp));
391 	memset(orphans, 0, sizeof(struct orphan_pgrp));
392 
393 	srand48(time(NULL) ^ (getpid() + (getpid() << 15)));
394 
395 	/* Supply a default for starts.  If we are in sequential mode, use
396 	 * the number of commands available; otherwise 1.
397 	 */
398 	if (timed == 1 && starts == -1) {	/* timed, infinite by default */
399 		starts = -1;
400 	} else if (starts == -1) {
401 		if (sequential) {
402 			starts = coll->cnt;
403 		} else {
404 			starts = 1;
405 		}
406 	} else if (starts == 0) {	/* if the user specified infinite, set it */
407 		starts = -1;
408 	} else {		/* else, make sure we are starting at least keep_active processes */
409 		if (starts < keep_active)
410 			starts = keep_active;
411 	}
412 
413 	/* if we're buffering output, but we're only running on process at a time,
414 	 * then essentially "turn off buffering"
415 	 */
416 	if (test_out_dir && (keep_active == 1)) {
417 		free(test_out_dir);
418 		test_out_dir = NULL;
419 	}
420 
421 	if (test_out_dir) {
422 		struct stat sbuf;
423 
424 		if (stat(test_out_dir, &sbuf) < 0) {
425 			fprintf(stderr,
426 				"pan(%s): stat of -O arg '%s' failed.  errno: %d  %s\n",
427 				panname, test_out_dir, errno, strerror(errno));
428 			exit(1);
429 		}
430 		if (!S_ISDIR(sbuf.st_mode)) {
431 			fprintf(stderr,
432 				"pan(%s): -O arg '%s' must be a directory.\n",
433 				panname, test_out_dir);
434 			exit(1);
435 		}
436 		if (access(test_out_dir, W_OK | R_OK | X_OK) < 0) {
437 			fprintf(stderr,
438 				"pan(%s): permission denied on -O arg '%s'.  errno: %d  %s\n",
439 				panname, test_out_dir, errno, strerror(errno));
440 			exit(1);
441 		}
442 	}
443 
444 	if (outputfilename) {
445 		if (!freopen(outputfilename, "a+", stdout)) {
446 			fprintf(stderr,
447 				"pan(%s): Error %s (%d) opening output file '%s'\n",
448 				panname, strerror(errno), errno,
449 				outputfilename);
450 			exit(1);
451 		}
452 	}
453 
454 	if (failcmdfilename) {
455 		if (!(failcmdfile = fopen(failcmdfilename, "a+"))) {
456 			fprintf(stderr,
457 				"pan(%s): Error %s (%d) opening fail cmd file '%s'\n",
458 				panname, strerror(errno), errno,
459 				failcmdfilename);
460 			exit(1);
461 		}
462 	}
463 
464 	if (tconfcmdfilename) {
465 		tconfcmdfile = fopen(tconfcmdfilename, "a+");
466 		if (!tconfcmdfile) {
467 			fprintf(stderr, "pan(%s): Error %s (%d) opening "
468 				"tconf cmd file '%s'\n", panname,
469 				strerror(errno), errno, tconfcmdfilename);
470 			exit(1);
471 		}
472 	}
473 
474 	if ((zoofile = zoo_open(zooname)) == NULL) {
475 		fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
476 		exit(1);
477 	}
478 	if (zoo_mark_args(zoofile, getpid(), panname, argc, argv)) {
479 		fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
480 		exit(1);
481 	}
482 
483 	/* Allocate N spaces for max-arg commands.
484 	 * this is an "active file cleanliness" thing
485 	 */
486 	{
487 		for (c = 0; c < keep_active; c++) {
488 			if (zoo_mark_cmdline(zoofile, c, panname, "")) {
489 				fprintf(stderr, "pan(%s): %s\n", panname,
490 					zoo_error);
491 				exit(1);
492 			}
493 		}
494 		for (c = 0; c < keep_active; c++) {
495 			if (zoo_clear(zoofile, c)) {
496 				fprintf(stderr, "pan(%s): %s\n", panname,
497 					zoo_error);
498 				exit(1);
499 			}
500 		}
501 	}
502 
503 	rec_signal = send_signal = 0;
504 	if (run_time != -1) {
505 		alarm(run_time);
506 	}
507 
508 	sigemptyset(&sa.sa_mask);
509 	sa.sa_flags = 0;
510 	sa.sa_handler = wait_handler;
511 
512 	sigaction(SIGALRM, &sa, NULL);
513 	sigaction(SIGINT, &sa, NULL);
514 	sigaction(SIGTERM, &sa, NULL);
515 	sigaction(SIGHUP, &sa, NULL);
516 	sigaction(SIGUSR1, &sa, NULL);	/* ignore fork_in_road */
517 	sigaction(SIGUSR2, &sa, NULL);	/* stop the scheduler */
518 
519 	c = 0;			/* in this loop, c is the command index */
520 	stop = 0;
521 	exit_stat = 0;
522 	go_idle = 0;
523 	while (1) {
524 
525 		while ((num_active < keep_active) && (starts != 0)) {
526 			if (stop || rec_signal || go_idle)
527 				break;
528 
529 			if (!sequential)
530 				c = lrand48() % coll->cnt;
531 
532 			/* find a slot for the child */
533 			for (i = 0; i < keep_active; ++i) {
534 				if (running[i].pgrp == 0)
535 					break;
536 			}
537 			if (i == keep_active) {
538 				fprintf(stderr,
539 					"pan(%s): Aborting: i == keep_active = %d\n",
540 					panname, i);
541 				wait_handler(SIGINT);
542 				exit_stat++;
543 				break;
544 			}
545 
546 			cpid =
547 			    run_child(coll->ary[c], running + i, quiet_mode,
548 				      &failcnt, fmt_print, logfile, no_kmsg);
549 			if (cpid != -1)
550 				++num_active;
551 			if ((cpid != -1 || sequential) && starts > 0)
552 				--starts;
553 
554 			if (sequential)
555 				if (++c >= coll->cnt)
556 					c = 0;
557 
558 		}		/* while ((num_active < keep_active) && (starts != 0)) */
559 
560 		if (starts == 0) {
561 			if (!quiet_mode)
562 				printf("incrementing stop\n");
563 			++stop;
564 		} else if (starts == -1)	//wjh
565 		{
566 			FILE *f = (FILE *) - 1;
567 			if ((f = fopen(PAN_STOP_FILE, "r")) != 0) {
568 				printf("Got %s Stopping!\n", PAN_STOP_FILE);
569 				fclose(f);
570 				unlink(PAN_STOP_FILE);
571 				stop++;
572 			}
573 		}
574 
575 		if (rec_signal) {
576 			/* propagate everything except sigusr2 */
577 
578 			if (rec_signal == SIGUSR2) {
579 				if (fork_in_road)
580 					++go_idle;
581 				else
582 					++stop;
583 				rec_signal = send_signal = 0;
584 			} else {
585 				if (rec_signal == SIGUSR1)
586 					fork_in_road = 0;
587 				propagate_signal(running, keep_active, orphans);
588 				if (fork_in_road)
589 					++go_idle;
590 				else
591 					++stop;
592 			}
593 		}
594 
595 		err = check_pids(running, &num_active, keep_active, logfile,
596 				 failcmdfile, tconfcmdfile, orphans, fmt_print,
597 				 &failcnt, &tconfcnt, quiet_mode, no_kmsg);
598 		if (Debug & Drunning) {
599 			pids_running(running, keep_active);
600 			orphans_running(orphans);
601 		}
602 		if (err) {
603 			if (fork_in_road)
604 				++go_idle;
605 			if (track_exit_stats)
606 				exit_stat++;
607 			if (has_brakes) {
608 				fprintf(stderr, "pan(%s): All stop!%s\n",
609 					panname, go_idle ? " (idling)" : "");
610 				wait_handler(SIGINT);
611 			}
612 		}
613 
614 		if (stop && (num_active == 0))
615 			break;
616 
617 		if (go_idle && (num_active == 0)) {
618 			go_idle = 0;	/* It is idle, now resume scheduling. */
619 			wait_handler(0);	/* Reset the signal ratchet. */
620 		}
621 	}
622 
623 	/* Wait for orphaned pgrps */
624 	while (1) {
625 		for (orph = orphans; orph != NULL; orph = orph->next) {
626 			if (orph->pgrp == 0)
627 				continue;
628 			/* Yes, we have orphaned pgrps */
629 			sleep(5);
630 			if (!rec_signal) {
631 				/* force an artificial signal, move us
632 				 * through the signal ratchet.
633 				 */
634 				wait_handler(SIGINT);
635 			}
636 			propagate_signal(running, keep_active, orphans);
637 			if (Debug & Drunning)
638 				orphans_running(orphans);
639 			break;
640 		}
641 		if (orph == NULL)
642 			break;
643 	}
644 
645 	if (zoo_clear(zoofile, getpid())) {
646 		fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
647 		++exit_stat;
648 	}
649 	fclose(zoofile);
650 	if (logfile && fmt_print) {
651 		if (uname(&unamebuf) == -1)
652 			fprintf(stderr, "ERROR: uname(): %s\n",
653 				strerror(errno));
654 		fprintf(logfile,
655 			"\n-----------------------------------------------\n");
656 		fprintf(logfile, "Total Tests: %d\n", coll->cnt);
657 		fprintf(logfile, "Total Skipped Tests: %d\n", tconfcnt);
658 		fprintf(logfile, "Total Failures: %d\n", failcnt);
659 		fprintf(logfile, "Kernel Version: %s\n", unamebuf.release);
660 		fprintf(logfile, "Machine Architecture: %s\n",
661 			unamebuf.machine);
662 		fprintf(logfile, "Hostname: %s\n\n", unamebuf.nodename);
663 	}
664 	if (logfile && (logfile != stdout))
665 		fclose(logfile);
666 
667 	if (failcmdfile)
668 		fclose(failcmdfile);
669 
670 	if (tconfcmdfile)
671 		fclose(tconfcmdfile);
672 	exit(exit_stat);
673 }
674 
675 static void
propagate_signal(struct tag_pgrp * running,int keep_active,struct orphan_pgrp * orphans)676 propagate_signal(struct tag_pgrp *running, int keep_active,
677 		 struct orphan_pgrp *orphans)
678 {
679 	int i;
680 
681 	if (Debug & Dshutdown)
682 		fprintf(stderr, "pan was signaled with sig %d...\n",
683 			rec_signal);
684 
685 	if (rec_signal == SIGALRM) {
686 		printf("PAN stop Alarm was received\n");
687 		rec_signal = SIGTERM;
688 	}
689 
690 	for (i = 0; i < keep_active; ++i) {
691 		if (running[i].pgrp == 0)
692 			continue;
693 
694 		if (Debug & Dshutdown)
695 			fprintf(stderr, "  propagating sig %d to %d\n",
696 				send_signal, -running[i].pgrp);
697 		if (kill(-running[i].pgrp, send_signal) != 0) {
698 			fprintf(stderr,
699 				"pan(%s): kill(%d,%d) failed on tag (%s).  errno:%d  %s\n",
700 				panname, -running[i].pgrp, send_signal,
701 				running[i].cmd->name, errno, strerror(errno));
702 		}
703 		running[i].stopping = 1;
704 	}
705 
706 	check_orphans(orphans, send_signal);
707 
708 	rec_signal = send_signal = 0;
709 }
710 
711 static int
check_pids(struct tag_pgrp * running,int * num_active,int keep_active,FILE * logfile,FILE * failcmdfile,FILE * tconfcmdfile,struct orphan_pgrp * orphans,int fmt_print,int * failcnt,int * tconfcnt,int quiet_mode,int no_kmsg)712 check_pids(struct tag_pgrp *running, int *num_active, int keep_active,
713 	   FILE *logfile, FILE *failcmdfile, FILE *tconfcmdfile,
714 	   struct orphan_pgrp *orphans, int fmt_print, int *failcnt,
715 	   int *tconfcnt, int quiet_mode, int no_kmsg)
716 {
717 	int w;
718 	pid_t cpid;
719 	int stat_loc;
720 	int ret = 0;
721 	int i;
722 	time_t t;
723 	char *status;
724 	char *result_str;
725 	int signaled = 0;
726 	struct tms tms1, tms2;
727 	clock_t tck;
728 
729 	check_orphans(orphans, 0);
730 
731 	tck = times(&tms1);
732 	if (tck == -1) {
733 		fprintf(stderr, "pan(%s): times(&tms1) failed.  errno:%d  %s\n",
734 			panname, errno, strerror(errno));
735 	}
736 	cpid = wait(&stat_loc);
737 	tck = times(&tms2);
738 	if (tck == -1) {
739 		fprintf(stderr, "pan(%s): times(&tms2) failed.  errno:%d  %s\n",
740 			panname, errno, strerror(errno));
741 	}
742 
743 	if (cpid < 0) {
744 		if (errno == EINTR) {
745 			if (Debug)
746 				fprintf(stderr, "pan(%s): wait() interrupted\n",
747 					panname);
748 		} else if (errno != ECHILD) {
749 			fprintf(stderr,
750 				"pan(%s): wait() failed.  errno:%d  %s\n",
751 				panname, errno, strerror(errno));
752 		}
753 	} else if (cpid > 0) {
754 
755 		if (WIFSIGNALED(stat_loc)) {
756 			w = WTERMSIG(stat_loc);
757 			status = "signaled";
758 			if (Debug & Dexit)
759 				fprintf(stderr,
760 					"child %d terminated with signal %d\n",
761 					cpid, w);
762 			--*num_active;
763 			signaled = 1;
764 		} else if (WIFEXITED(stat_loc)) {
765 			w = WEXITSTATUS(stat_loc);
766 			status = "exited";
767 			if (Debug & Dexit)
768 				fprintf(stderr,
769 					"child %d exited with status %d\n",
770 					cpid, w);
771 			--*num_active;
772 			if (w != 0 && w != TCONF)
773 				ret++;
774 		} else if (WIFSTOPPED(stat_loc)) {	/* should never happen */
775 			w = WSTOPSIG(stat_loc);
776 			status = "stopped";
777 			ret++;
778 		} else {	/* should never happen */
779 			w = 0;
780 			status = "unknown";
781 			ret++;
782 		}
783 
784 		for (i = 0; i < keep_active; ++i) {
785 			if (running[i].pgrp == cpid) {
786 				if ((w == 130) && running[i].stopping &&
787 				    (strcmp(status, "exited") == 0)) {
788 					/* The child received sigint, but
789 					 * did not trap for it?  Compensate
790 					 * for it here.
791 					 */
792 					w = 0;
793 					ret--;	/* undo */
794 					if (Debug & Drunning)
795 						fprintf(stderr,
796 							"pan(%s): tag=%s exited 130, known to be signaled; will give it an exit 0.\n",
797 							panname,
798 							running[i].cmd->name);
799 				}
800 				time(&t);
801 				if (logfile != NULL) {
802 					if (!fmt_print)
803 						fprintf(logfile,
804 							"tag=%s stime=%d dur=%d exit=%s stat=%d core=%s cu=%d cs=%d\n",
805 							running[i].cmd->name,
806 							(int)(running[i].
807 							      mystime),
808 							(int)(t -
809 							      running[i].
810 							      mystime), status,
811 							w,
812 							(stat_loc & 0200) ?
813 							"yes" : "no",
814 							(int)(tms2.tms_cutime -
815 							      tms1.tms_cutime),
816 							(int)(tms2.tms_cstime -
817 							      tms1.tms_cstime));
818 					else {
819 						if (strcmp(status, "exited") ==
820 						    0 && w == TCONF) {
821 							++*tconfcnt;
822 							result_str = "CONF";
823 						} else if (w != 0) {
824 							++*failcnt;
825 							result_str = "FAIL";
826 						} else {
827 							result_str = "PASS";
828 						}
829 
830 						fprintf(logfile,
831 							ResultFmt" %-5d\n",
832 							running[i].cmd->name,
833 							result_str,
834 							w);
835 					}
836 
837 					fflush(logfile);
838 				}
839 
840 				if (w != 0) {
841 					if (tconfcmdfile != NULL &&
842 					    w == TCONF) {
843 						fprintf(tconfcmdfile, "%s %s\n",
844 						running[i].cmd->name,
845 						running[i].cmd->cmdline);
846 					} else if (failcmdfile != NULL) {
847 						fprintf(failcmdfile, "%s %s\n",
848 						running[i].cmd->name,
849 						running[i].cmd->cmdline);
850 					}
851 				}
852 
853 				if (running[i].stopping)
854 					status = "driver_interrupt";
855 
856 				if (test_out_dir) {
857 					if (!quiet_mode)
858 						write_test_start(running + i, no_kmsg);
859 					copy_buffered_output(running + i);
860 					unlink(running[i].output);
861 				}
862 				if (!quiet_mode)
863 					write_test_end(running + i, "ok", t,
864 						       status, stat_loc, w,
865 						       &tms1, &tms2);
866 
867 				/* If signaled and we weren't expecting
868 				 * this to be stopped then the proc
869 				 * had a problem.
870 				 */
871 				if (signaled && !running[i].stopping)
872 					ret++;
873 
874 				running[i].pgrp = 0;
875 				if (zoo_clear(zoofile, cpid)) {
876 					fprintf(stderr, "pan(%s): %s\n",
877 						panname, zoo_error);
878 					exit(1);
879 				}
880 
881 				/* Check for orphaned pgrps */
882 				if ((kill(-cpid, 0) == 0) || (errno == EPERM)) {
883 					if (zoo_mark_cmdline
884 					    (zoofile, cpid, "panorphan",
885 					     running[i].cmd->cmdline)) {
886 						fprintf(stderr, "pan(%s): %s\n",
887 							panname, zoo_error);
888 						exit(1);
889 					}
890 					mark_orphan(orphans, cpid);
891 					/* status of kill doesn't matter */
892 					kill(-cpid, SIGTERM);
893 				}
894 
895 				break;
896 			}
897 		}
898 	}
899 	return ret;
900 }
901 
902 static pid_t
run_child(struct coll_entry * colle,struct tag_pgrp * active,int quiet_mode,int * failcnt,int fmt_print,FILE * logfile,int no_kmsg)903 run_child(struct coll_entry *colle, struct tag_pgrp *active, int quiet_mode,
904 	  int *failcnt, int fmt_print, FILE * logfile, int no_kmsg)
905 {
906 	ssize_t errlen;
907 	int cpid;
908 	int c_stdout = -1;	/* child's stdout, stderr */
909 	int capturing = 0;	/* output is going to a file instead of stdout */
910 	char *c_cmdline;
911 	static long cmdno = 0;
912 	int errpipe[2];		/* way to communicate to parent that the tag  */
913 	char errbuf[1024];	/* didn't actually start */
914 
915 	/* Try to open the file that will be stdout for the test */
916 	if (test_out_dir) {
917 		capturing = 1;
918 		do {
919 			sprintf(active->output, "%s/%s.%ld",
920 				test_out_dir, colle->name, cmdno++);
921 			c_stdout =
922 			    open(active->output,
923 				 O_CREAT | O_RDWR | O_EXCL | O_SYNC, 0666);
924 		} while (c_stdout < 0 && errno == EEXIST);
925 		if (c_stdout < 0) {
926 			fprintf(stderr,
927 				"pan(%s): open of stdout file failed (tag %s).  errno: %d  %s\n  file: %s\n",
928 				panname, colle->name, errno, strerror(errno),
929 				active->output);
930 			return -1;
931 		}
932 	}
933 
934 	/* get the tag's command line arguments ready.  subst_pcnt_f() uses a
935 	 * static counter, that's why we do it here instead of after we fork.
936 	 */
937 	if (colle->pcnt_f) {
938 		c_cmdline = subst_pcnt_f(colle);
939 	} else {
940 		c_cmdline = colle->cmdline;
941 	}
942 
943 	if (pipe(errpipe) < 0) {
944 		fprintf(stderr, "pan(%s): pipe() failed. errno:%d %s\n",
945 			panname, errno, strerror(errno));
946 		if (capturing) {
947 			close(c_stdout);
948 			unlink(active->output);
949 		}
950 		return -1;
951 	}
952 
953 	time(&active->mystime);
954 	active->cmd = colle;
955 
956 	if (!test_out_dir && !quiet_mode)
957 		write_test_start(active, no_kmsg);
958 
959 	fflush(NULL);
960 
961 	if ((cpid = fork()) == -1) {
962 		fprintf(stderr,
963 			"pan(%s): fork failed (tag %s).  errno:%d  %s\n",
964 			panname, colle->name, errno, strerror(errno));
965 		if (capturing) {
966 			unlink(active->output);
967 			close(c_stdout);
968 		}
969 		close(errpipe[0]);
970 		close(errpipe[1]);
971 		return -1;
972 	} else if (cpid == 0) {
973 		/* child */
974 
975 		fclose(zoofile);
976 		close(errpipe[0]);
977 		fcntl(errpipe[1], F_SETFD, 1);	/* close the pipe if we succeed */
978 		setpgrp();
979 
980 		umask(0);
981 
982 #define WRITE_OR_DIE(fd, buf, buflen) do {				\
983 	if (write((fd), (buf), (buflen)) != (buflen)) {			\
984 		err(1, "failed to write out %zd bytes at line %d",	\
985 		    buflen, __LINE__);					\
986 	}								\
987 } while(0)
988 
989 		/* if we're putting output into a buffer file, we need to do the
990 		 * redirection now.  If we fail
991 		 */
992 		if (capturing) {
993 			if (dup2(c_stdout, fileno(stdout)) == -1) {
994 				errlen =
995 				    sprintf(errbuf,
996 					    "pan(%s): couldn't redirect stdout for tag %s.  errno:%d  %s",
997 					    panname, colle->name, errno,
998 					    strerror(errno));
999 				WRITE_OR_DIE(errpipe[1], &errlen,
1000 					     sizeof(errlen));
1001 				WRITE_OR_DIE(errpipe[1], errbuf, errlen);
1002 				exit(2);
1003 			}
1004 			if (dup2(c_stdout, fileno(stderr)) == -1) {
1005 				errlen =
1006 				    sprintf(errbuf,
1007 					    "pan(%s): couldn't redirect stderr for tag %s.  errno:%d  %s",
1008 					    panname, colle->name, errno,
1009 					    strerror(errno));
1010 				WRITE_OR_DIE(errpipe[1], &errlen,
1011 					     sizeof(errlen));
1012 				WRITE_OR_DIE(errpipe[1], errbuf, errlen);
1013 				exit(2);
1014 			}
1015 		} else {	/* stderr still needs to be redirected */
1016 			if (dup2(fileno(stdout), fileno(stderr)) == -1) {
1017 				errlen =
1018 				    sprintf(errbuf,
1019 					    "pan(%s): couldn't redirect stderr for tag %s.  errno:%d  %s",
1020 					    panname, colle->name, errno,
1021 					    strerror(errno));
1022 				WRITE_OR_DIE(errpipe[1], &errlen,
1023 					     sizeof(errlen));
1024 				WRITE_OR_DIE(errpipe[1], errbuf, errlen);
1025 				exit(2);
1026 			}
1027 		}
1028 		/* If there are any shell-type characters in the cmdline
1029 		 * such as '>', '<', '$', '|', etc, then we exec a shell and
1030 		 * run the cmd under a shell.
1031 		 *
1032 		 * Otherwise, break the cmdline at white space and exec the
1033 		 * cmd directly.
1034 		 */
1035 		if (strpbrk(c_cmdline, "\"';|<>$\\")) {
1036 			execlp("sh", "sh", "-c", c_cmdline, NULL);
1037 			errlen = sprintf(errbuf,
1038 					 "pan(%s): execlp of '%s' (tag %s) failed.  errno:%d %s",
1039 					 panname, c_cmdline, colle->name, errno,
1040 					 strerror(errno));
1041 		} else {
1042 			char **arg_v;
1043 
1044 			arg_v = (char **)splitstr(c_cmdline, NULL, NULL);
1045 
1046 			execvp(arg_v[0], arg_v);
1047 			errlen = sprintf(errbuf,
1048 					 "pan(%s): execvp of '%s' (tag %s) failed.  errno:%d  %s",
1049 					 panname, arg_v[0], colle->name, errno,
1050 					 strerror(errno));
1051 		}
1052 		WRITE_OR_DIE(errpipe[1], &errlen, sizeof(errlen));
1053 		WRITE_OR_DIE(errpipe[1], errbuf, errlen);
1054 		exit(errno);
1055 	}
1056 
1057 	/* parent */
1058 
1059 	/* subst_pcnt_f() allocates the command line dynamically
1060 	 * free the malloc to prevent a memory leak
1061 	 */
1062 	if (colle->pcnt_f)
1063 		free(c_cmdline);
1064 
1065 	close(errpipe[1]);
1066 
1067 	/* if the child couldn't go through with the exec,
1068 	 * clean up the mess, note it, and move on
1069 	 */
1070 	if (read(errpipe[0], &errlen, sizeof(errlen))) {
1071 		int status;
1072 		time_t end_time;
1073 		int termid;
1074 		char *termtype;
1075 		struct tms notime = { 0, 0, 0, 0 };
1076 
1077 		if (read(errpipe[0], errbuf, errlen) < 0)
1078 			fprintf(stderr, "Failed to read from errpipe[0]\n");
1079 		close(errpipe[0]);
1080 		errbuf[errlen] = '\0';
1081 		/* fprintf(stderr, "%s", errbuf); */
1082 		waitpid(cpid, &status, 0);
1083 		if (WIFSIGNALED(status)) {
1084 			termid = WTERMSIG(status);
1085 			termtype = "signaled";
1086 		} else if (WIFEXITED(status)) {
1087 			termid = WEXITSTATUS(status);
1088 			termtype = "exited";
1089 		} else if (WIFSTOPPED(status)) {
1090 			termid = WSTOPSIG(status);
1091 			termtype = "stopped";
1092 		} else {
1093 			termid = 0;
1094 			termtype = "unknown";
1095 		}
1096 		time(&end_time);
1097 		if (logfile != NULL) {
1098 			if (!fmt_print) {
1099 				fprintf(logfile,
1100 					"tag=%s stime=%d dur=%d exit=%s "
1101 					"stat=%d core=%s cu=%d cs=%d\n",
1102 					colle->name, (int)(active->mystime),
1103 					(int)(end_time - active->mystime),
1104 					termtype, termid,
1105 					(status & 0200) ? "yes" : "no", 0, 0);
1106 			} else {
1107 				if (termid != 0)
1108 					++ * failcnt;
1109 
1110 				fprintf(logfile, ResultFmt" %-5d\n",
1111 					colle->name,
1112 					((termid != 0) ? "FAIL" : "PASS"),
1113 					termid);
1114 			}
1115 			fflush(logfile);
1116 		}
1117 
1118 		if (!quiet_mode) {
1119 			write_test_end(active, errbuf, end_time, termtype,
1120 				       status, termid, &notime, &notime);
1121 		}
1122 		if (capturing) {
1123 			close(c_stdout);
1124 			unlink(active->output);
1125 		}
1126 		return -1;
1127 	}
1128 
1129 	close(errpipe[0]);
1130 	if (capturing)
1131 		close(c_stdout);
1132 
1133 	active->pgrp = cpid;
1134 	active->stopping = 0;
1135 
1136 	if (zoo_mark_cmdline(zoofile, cpid, colle->name, colle->cmdline)) {
1137 		fprintf(stderr, "pan(%s): %s\n", panname, zoo_error);
1138 		exit(1);
1139 	}
1140 
1141 	if (Debug & Dstartup)
1142 		fprintf(stderr, "started %s cpid=%d at %s",
1143 			colle->name, cpid, ctime(&active->mystime));
1144 
1145 	if (Debug & Dstart) {
1146 		fprintf(stderr, "Executing test = %s as %s", colle->name,
1147 			colle->cmdline);
1148 		if (capturing)
1149 			fprintf(stderr, "with output file = %s\n",
1150 				active->output);
1151 		else
1152 			fprintf(stderr, "\n");
1153 	}
1154 
1155 	return cpid;
1156 }
1157 
subst_pcnt_f(struct coll_entry * colle)1158 static char *subst_pcnt_f(struct coll_entry *colle)
1159 {
1160 	static int counter = 1;
1161 	char pid_and_counter[20];
1162 	char new_cmdline[1024];
1163 
1164 	/* if we get called falsely, do the right thing anyway */
1165 	if (!colle->pcnt_f)
1166 		return colle->cmdline;
1167 
1168 	snprintf(pid_and_counter, 20, "%d_%d", getpid(), counter++);
1169 	snprintf(new_cmdline, 1024, colle->cmdline, pid_and_counter);
1170 	return strdup(new_cmdline);
1171 }
1172 
get_collection(char * file,int optind,int argc,char ** argv)1173 static struct collection *get_collection(char *file, int optind, int argc,
1174 					 char **argv)
1175 {
1176 	char *buf, *a, *b;
1177 	struct coll_entry *head, *p, *n;
1178 	struct collection *coll;
1179 	int i;
1180 
1181 	buf = slurp(file);
1182 	if (!buf)
1183 		return NULL;
1184 
1185 	coll = malloc(sizeof(struct collection));
1186 	coll->cnt = 0;
1187 
1188 	head = p = n = NULL;
1189 	a = b = buf;
1190 	while (a) {
1191 		/* set b to the start of the next line and add a NULL character
1192 		 * to separate the two lines */
1193 		if ((b = strchr(a, '\n')) != NULL)
1194 			*b++ = '\0';
1195 
1196 		/* If this is line isn't a comment */
1197 		if ((*a != '#') && (*a != '\0') && (*a != ' ')) {
1198 			n = malloc(sizeof(struct coll_entry));
1199 			if ((n->pcnt_f = strstr(a, "%f"))) {
1200 				n->pcnt_f[1] = 's';
1201 			}
1202 			n->name = strdup(strsep(&a, " \t"));
1203 			n->cmdline = strdup(a);
1204 			n->next = NULL;
1205 
1206 			if (p) {
1207 				p->next = n;
1208 			}
1209 			if (head == NULL) {
1210 				head = n;
1211 			}
1212 			p = n;
1213 			coll->cnt++;
1214 		}
1215 		a = b;
1216 	}
1217 	free(buf);
1218 
1219 	/* is there something on the commandline to be counted? */
1220 	if (optind < argc) {
1221 		char workstr[1024] = "";
1222 		int workstr_left = 1023;
1223 
1224 		/* fill arg list */
1225 		for (i = 0; optind < argc; ++optind, ++i) {
1226 			strncat(workstr, argv[optind], workstr_left);
1227 			workstr_left = workstr_left - strlen(argv[optind]);
1228 			strncat(workstr, " ", workstr_left);
1229 			workstr_left--;
1230 		}
1231 
1232 		n = malloc(sizeof(struct coll_entry));
1233 		if ((n->pcnt_f = strstr(workstr, "%f"))) {
1234 			n->pcnt_f[1] = 's';
1235 		}
1236 		n->cmdline = strdup(workstr);
1237 		n->name = "cmdln";
1238 		n->next = NULL;
1239 		if (p) {
1240 			p->next = n;
1241 		}
1242 		if (head == NULL) {
1243 			head = n;
1244 		}
1245 		coll->cnt++;
1246 	}
1247 
1248 	/* get an array */
1249 	coll->ary = malloc(coll->cnt * sizeof(struct coll_entry *));
1250 
1251 	/* fill the array */
1252 	i = 0;
1253 	n = head;
1254 	while (n != NULL) {
1255 		coll->ary[i] = n;
1256 		n = n->next;
1257 		++i;
1258 	}
1259 	if (i != coll->cnt)
1260 		fprintf(stderr, "pan(%s): i doesn't match cnt\n", panname);
1261 
1262 	return coll;
1263 }
1264 
slurp(char * file)1265 static char *slurp(char *file)
1266 {
1267 	char *buf;
1268 	int fd;
1269 	struct stat sbuf;
1270 
1271 	if ((fd = open(file, O_RDONLY)) < 0) {
1272 		fprintf(stderr,
1273 			"pan(%s): open(%s,O_RDONLY) failed.  errno:%d  %s\n",
1274 			panname, file, errno, strerror(errno));
1275 		return NULL;
1276 	}
1277 
1278 	if (fstat(fd, &sbuf) < 0) {
1279 		fprintf(stderr, "pan(%s): fstat(%s) failed.  errno:%d  %s\n",
1280 			panname, file, errno, strerror(errno));
1281 		return NULL;
1282 	}
1283 
1284 	buf = malloc(sbuf.st_size + 1);
1285 	if (read(fd, buf, sbuf.st_size) != sbuf.st_size) {
1286 		fprintf(stderr, "pan(%s): slurp failed.  errno:%d  %s\n",
1287 			panname, errno, strerror(errno));
1288 		free(buf);
1289 		return NULL;
1290 	}
1291 	buf[sbuf.st_size] = '\0';
1292 
1293 	close(fd);
1294 	return buf;
1295 }
1296 
check_orphans(struct orphan_pgrp * orphans,int sig)1297 static void check_orphans(struct orphan_pgrp *orphans, int sig)
1298 {
1299 	struct orphan_pgrp *orph;
1300 
1301 	for (orph = orphans; orph != NULL; orph = orph->next) {
1302 		if (orph->pgrp == 0)
1303 			continue;
1304 
1305 		if (Debug & Dshutdown)
1306 			fprintf(stderr,
1307 				"  propagating sig %d to orphaned pgrp %d\n",
1308 				sig, -(orph->pgrp));
1309 		if (kill(-(orph->pgrp), sig) != 0) {
1310 			if (errno == ESRCH) {
1311 				/* This pgrp is now empty */
1312 				if (zoo_clear(zoofile, orph->pgrp)) {
1313 					fprintf(stderr, "pan(%s): %s\n",
1314 						panname, zoo_error);
1315 				}
1316 				orph->pgrp = 0;
1317 			} else {
1318 				fprintf(stderr,
1319 					"pan(%s): kill(%d,%d) on orphaned pgrp failed.  errno:%d  %s\n",
1320 					panname, -(orph->pgrp), sig, errno,
1321 					strerror(errno));
1322 			}
1323 		}
1324 	}
1325 }
1326 
mark_orphan(struct orphan_pgrp * orphans,pid_t cpid)1327 static void mark_orphan(struct orphan_pgrp *orphans, pid_t cpid)
1328 {
1329 	struct orphan_pgrp *orph;
1330 
1331 	for (orph = orphans; orph != NULL; orph = orph->next) {
1332 		if (orph->pgrp == 0)
1333 			break;
1334 	}
1335 	if (orph == NULL) {
1336 		/* make a new struct */
1337 		orph = malloc(sizeof(struct orphan_pgrp));
1338 
1339 		/* plug in the new struct just after the head */
1340 		orph->next = orphans->next;
1341 		orphans->next = orph;
1342 	}
1343 	orph->pgrp = cpid;
1344 }
1345 
copy_buffered_output(struct tag_pgrp * running)1346 static void copy_buffered_output(struct tag_pgrp *running)
1347 {
1348 	char *tag_output;
1349 
1350 	tag_output = slurp(running->output);
1351 	if (tag_output) {
1352 		printf("%s", tag_output);
1353 		/* make sure the output ends with a newline */
1354 		if (tag_output[strlen(tag_output) - 1] != '\n')
1355 			printf("\n");
1356 		fflush(stdout);
1357 		free(tag_output);
1358 	}
1359 }
1360 
write_kmsg(const char * fmt,...)1361 static void write_kmsg(const char *fmt, ...)
1362 {
1363 	FILE *kmsg;
1364 	va_list ap;
1365 
1366 	if ((kmsg = fopen("/dev/kmsg", "r+")) == NULL) {
1367 		fprintf(stderr, "Error %s: (%d) opening /dev/kmsg\n",
1368 				strerror(errno), errno);
1369 		exit(1);
1370 	}
1371 
1372 	va_start(ap, fmt);
1373 	vfprintf(kmsg, fmt, ap);
1374 	va_end(ap);
1375 	fclose(kmsg);
1376 }
1377 
write_test_start(struct tag_pgrp * running,int no_kmsg)1378 static void write_test_start(struct tag_pgrp *running, int no_kmsg)
1379 {
1380 	if (!strcmp(reporttype, "rts")) {
1381 
1382 		printf
1383 		    ("%s\ntag=%s stime=%ld\ncmdline=\"%s\"\ncontacts=\"%s\"\nanalysis=%s\n%s\n",
1384 		     "<<<test_start>>>", running->cmd->name, running->mystime,
1385 		     running->cmd->cmdline, "", "exit", "<<<test_output>>>");
1386 	}
1387 	fflush(stdout);
1388 	if (no_kmsg)
1389 		return;
1390 
1391 	if (strcmp(running->cmd->name, running->cmd->cmdline))
1392 		write_kmsg("LTP: starting %s (%s)\n", running->cmd->name,
1393 			   running->cmd->cmdline);
1394 	else
1395 		write_kmsg("LTP: starting %s\n", running->cmd->name);
1396 }
1397 
1398 static void
write_test_end(struct tag_pgrp * running,const char * init_status,time_t exit_time,char * term_type,int stat_loc,int term_id,struct tms * tms1,struct tms * tms2)1399 write_test_end(struct tag_pgrp *running, const char *init_status,
1400 	       time_t exit_time, char *term_type, int stat_loc,
1401 	       int term_id, struct tms *tms1, struct tms *tms2)
1402 {
1403 	if (!strcmp(reporttype, "rts")) {
1404 		printf
1405 		    ("%s\ninitiation_status=\"%s\"\nduration=%ld termination_type=%s "
1406 		     "termination_id=%d corefile=%s\ncutime=%d cstime=%d\n%s\n",
1407 		     "<<<execution_status>>>", init_status,
1408 		     (long)(exit_time - running->mystime), term_type, term_id,
1409 		     (stat_loc & 0200) ? "yes" : "no",
1410 		     (int)(tms2->tms_cutime - tms1->tms_cutime),
1411 		     (int)(tms2->tms_cstime - tms1->tms_cstime),
1412 		     "<<<test_end>>>");
1413 	}
1414 	fflush(stdout);
1415 }
1416 
1417 /* The functions below are all debugging related */
1418 
pids_running(struct tag_pgrp * running,int keep_active)1419 static void pids_running(struct tag_pgrp *running, int keep_active)
1420 {
1421 	int i;
1422 
1423 	fprintf(stderr, "pids still running: ");
1424 	for (i = 0; i < keep_active; ++i) {
1425 		if (running[i].pgrp != 0)
1426 			fprintf(stderr, "%d ", running[i].pgrp);
1427 	}
1428 	fprintf(stderr, "\n");
1429 }
1430 
orphans_running(struct orphan_pgrp * orphans)1431 static void orphans_running(struct orphan_pgrp *orphans)
1432 {
1433 	struct orphan_pgrp *orph;
1434 
1435 	fprintf(stderr, "orphans still running: ");
1436 	for (orph = orphans; orph != NULL; orph = orph->next) {
1437 		if (orph->pgrp != 0)
1438 			fprintf(stderr, "%d ", -(orph->pgrp));
1439 	}
1440 	fprintf(stderr, "\n");
1441 }
1442 
dump_coll(struct collection * coll)1443 static void dump_coll(struct collection *coll)
1444 {
1445 	int i;
1446 
1447 	for (i = 0; i < coll->cnt; ++i) {
1448 		fprintf(stderr, "coll %d\n", i);
1449 		fprintf(stderr, "  name=%s cmdline=%s\n", coll->ary[i]->name,
1450 			coll->ary[i]->cmdline);
1451 	}
1452 }
1453 
wait_handler(int sig)1454 void wait_handler(int sig)
1455 {
1456 	static int lastsent = 0;
1457 
1458 	if (sig == 0) {
1459 		lastsent = 0;
1460 	} else {
1461 		rec_signal = sig;
1462 		if (sig == SIGUSR2)
1463 			return;
1464 		if (lastsent == 0)
1465 			send_signal = sig;
1466 		else if (lastsent == SIGUSR1)
1467 			send_signal = SIGINT;
1468 		else if (lastsent == sig)
1469 			send_signal = SIGTERM;
1470 		else if (lastsent == SIGTERM)
1471 			send_signal = SIGHUP;
1472 		else if (lastsent == SIGHUP)
1473 			send_signal = SIGKILL;
1474 		lastsent = send_signal;
1475 	}
1476 }
1477