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