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, ¬ime, ¬ime);
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