• Home
  • History
  • Annotate
  • 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