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