diff options
author | subrata_modak <subrata_modak> | 2009-05-19 09:39:11 +0000 |
---|---|---|
committer | subrata_modak <subrata_modak> | 2009-05-19 09:39:11 +0000 |
commit | 14390fd5298724c529b3f5e5158bd0d3776b6933 (patch) | |
tree | 1f3dd8ef061bfcaf9e91cf27268547e6501eeff9 /pan | |
parent | 7a1d01cbc460bdc4a06666fb80d1f9382d603604 (diff) |
Attached (against ltp-full-20090430.tgz) patch renames binaries in pan directory to have ltp- prefix as plain pan when installed in /usr/bin/ directory conflict with gnome pan. It also fixes all occurrences of pan in scripts and howtos. Signed-off-by: Cyril Hrubis <chrubis@suse.cz>.
Diffstat (limited to 'pan')
-rw-r--r-- | pan/Makefile | 18 | ||||
-rw-r--r-- | pan/ltp-bump.c (renamed from pan/bump.c) | 54 | ||||
-rw-r--r-- | pan/ltp-pan.c | 1394 | ||||
-rw-r--r-- | pan/ltp-scanner.c (renamed from pan/scanner.c) | 75 | ||||
-rw-r--r-- | pan/pan.c | 1309 |
5 files changed, 1462 insertions, 1388 deletions
diff --git a/pan/Makefile b/pan/Makefile index 68f68caf5..234f9d42c 100644 --- a/pan/Makefile +++ b/pan/Makefile @@ -4,21 +4,21 @@ LFLAGS += -l -w CFLAGS += -w PREFIX = /opt/ltp -all: pan bump scanner +all: ltp-pan ltp-bump ltp-scanner -pan: pan.o zoolib.o splitstr.o +ltp-pan: ltp-pan.o zoolib.o splitstr.o -bump: bump.o zoolib.o +ltp-bump: ltp-bump.o zoolib.o -scanner: scan.o scanner.o reporter.o tag_report.o symbol.o splitstr.o debug.o +ltp-scanner: scan.o ltp-scanner.o reporter.o tag_report.o symbol.o splitstr.o debug.o -install: pan bump scanner - install -D scanner $(DESTDIR)/$(PREFIX)/bin/scanner - install -D pan $(DESTDIR)/$(PREFIX)/bin/pan - install -D bump $(DESTDIR)/$(PREFIX)/bin/bump +install: ltp-pan ltp-bump ltp-scanner + install -D ltp-scanner $(DESTDIR)/$(PREFIX)/bin/ltp-scanner + install -D ltp-pan $(DESTDIR)/$(PREFIX)/bin/ltp-pan + install -D ltp-bump $(DESTDIR)/$(PREFIX)/bin/ltp-bump clean: - rm -f *.o pan bump scanner + rm -f *.o ltp-pan ltp-bump ltp-scanner diff --git a/pan/bump.c b/pan/ltp-bump.c index 04c89ac37..5ab6584db 100644 --- a/pan/bump.c +++ b/pan/ltp-bump.c @@ -30,30 +30,28 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ * */ -/* $Id: bump.c,v 1.4 2001/03/08 19:13:21 nstraz Exp $ */ +/* $Id: ltp-bump.c,v 1.1 2009/05/19 09:39:11 subrata_modak Exp $ */ #include <stdio.h> #include <errno.h> #include <sys/signal.h> #include <string.h> #include <stdlib.h> +#include <unistd.h> #include "zoolib.h" -pid_t -read_active( FILE *fp, char *name ); +pid_t read_active(FILE *fp, char *name); -int -main( int argc, char **argv ){ - extern char *optarg; - extern int optind; +int main(int argc, char **argv) +{ int c; char *active = NULL; pid_t nanny; zoo_t zoo; int sig = SIGINT; - while( (c = getopt(argc, argv, "a:s:12")) != -1 ){ - switch(c){ + while((c = getopt(argc, argv, "a:s:12")) != -1) { + switch(c) { case 'a': active = (char*)malloc(strlen(optarg)+1); strcpy( active, optarg ); @@ -70,37 +68,38 @@ main( int argc, char **argv ){ } } - if( active == NULL ){ + if (active == NULL) { active = zoo_getname(); - if( active == NULL ){ - fprintf(stderr, "bump: Must supply -a or set ZOO env variable\n"); + if (active == NULL) { + fprintf(stderr, "ltp-bump: Must supply -a or set ZOO env variable\n"); exit(1); } } - if( optind == argc ){ - fprintf( stderr, "bump: Must supply names\n"); + + if (optind == argc) { + fprintf(stderr, "ltp-bump: Must supply names\n"); exit(1); } /* need r+ here because we're using write-locks */ - if( (zoo = zoo_open(active)) == NULL ){ - fprintf(stderr, "bump: %s\n", zoo_error); + if ((zoo = zoo_open(active)) == NULL) { + fprintf(stderr, "ltp-bump: %s\n", zoo_error); exit(1); } - while( optind < argc ){ + + while (optind < argc) { /*printf("argv[%d] = (%s)\n", optind, argv[optind] );*/ nanny = zoo_getpid(zoo, argv[optind]); - if( nanny == -1 ){ - fprintf(stderr, "bump: Did not find tag '%s'\n", - argv[optind] ); - } - else{ - if (kill( nanny, sig ) == -1){ - if (errno == ESRCH){ - fprintf(stderr,"bump: Tag %s (pid %d) seems to be dead already.\n", - argv[optind], nanny ); + if (nanny == -1) { + fprintf(stderr, "ltp-bump: Did not find tag '%s'\n", + argv[optind]); + } else { + if (kill( nanny, sig ) == -1) { + if (errno == ESRCH) { + fprintf(stderr,"ltp-bump: Tag %s (pid %d) seems to be dead already.\n", + argv[optind], nanny); if (zoo_clear(zoo, nanny)) - fprintf(stderr,"bump: %s\n", zoo_error); + fprintf(stderr,"ltp-bump: %s\n", zoo_error); } } } @@ -110,4 +109,3 @@ main( int argc, char **argv ){ exit(0); } - diff --git a/pan/ltp-pan.c b/pan/ltp-pan.c new file mode 100644 index 000000000..15d314420 --- /dev/null +++ b/pan/ltp-pan.c @@ -0,0 +1,1394 @@ +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of version 2 of the GNU General Public License as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it would be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Further, this software is distributed without any warranty that it is + * free of the rightful claim of any third person regarding infringement + * or the like. Any license provided herein, whether implied or + * otherwise, applies only to this software file. Patent licenses, if + * any, provided herein do not apply to combinations of this program with + * other software, or any other product whatsoever. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston MA 02111-1307, USA. + * + * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, + * Mountain View, CA 94043, or: + * + * http://www.sgi.com + * + * For further information regarding this notice, see: + * + * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + * + * Changelog: + * + * Added timer options: William Jay Huie, IBM + * 01/27/03 - Added: Manoj Iyer, manjo@mail.utexas.edu + * - option '-p' (pretty printing)i to enabled formatted printing + * of results. + * + * 01/27/03 - Added: Manoj Iyer, manjo@mail.utexas.edu + * - added code to print system information + * + * 01/28/03 - Added: Manoj Iyer, manjo@mail.utexas.edu + * - added code to print test exit value. + * + * 01/29/03 - Added: Manoj Iyer, manjo@mail.utexas.edu + * - added code supresses test start and test end tags. + * + * 07/22/07 - Added: Ricardo Salveti de Araujo, rsalveti@linux.vnet.ibm.com + * - added option to create a command file with all failed tests. + * + */ +/* $Id: ltp-pan.c,v 1.1 2009/05/19 09:39:11 subrata_modak Exp $ */ + +#include <errno.h> +#include <string.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/times.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <time.h> +#include <stdlib.h> +#include <limits.h> +#include <sys/utsname.h> +#include <unistd.h> + +#include "splitstr.h" +#include "zoolib.h" + +/* One entry in the command line collection. */ +struct coll_entry +{ + char *name; /* tag name */ + char *cmdline; /* command line */ + char *pcnt_f; /* location of %f in the command line args, flag */ + struct coll_entry *next; +}; + +struct collection +{ + int cnt; + struct coll_entry **ary; +}; + +struct tag_pgrp +{ + int pgrp; + int stopping; + time_t mystime; + struct coll_entry *cmd; + char output[PATH_MAX]; +}; + +struct orphan_pgrp +{ + int pgrp; + struct orphan_pgrp *next; +}; + +static pid_t run_child(struct coll_entry *colle, struct tag_pgrp *active, + int quiet_mode); +static char *slurp(char *file); +static struct collection *get_collection(char *file, int optind, int argc, + char **argv); +static void pids_running(struct tag_pgrp *running, int keep_active); +static int check_pids(struct tag_pgrp *running, int *num_active, + int keep_active, FILE * logfile, FILE * failcmdfile, + struct orphan_pgrp *orphans, int fmt_print, + int *failcnt, int quiet_mode); +static void propagate_signal(struct tag_pgrp *running, int keep_active, + struct orphan_pgrp *orphans); +static void dump_coll(struct collection *coll); +static char *subst_pcnt_f(struct coll_entry *colle); +static void mark_orphan(struct orphan_pgrp *orphans, pid_t cpid); +static void orphans_running(struct orphan_pgrp *orphans); +static void check_orphans(struct orphan_pgrp *orphans, int sig); +static void copy_buffered_output(struct tag_pgrp *running); +static void write_test_start(struct tag_pgrp *running, const char *init_status); +static void write_test_end(struct tag_pgrp *running, + time_t exit_time, char *term_type, int stat_loc, + int term_id, struct tms *tms1, struct tms *tms2); + +static char PAN_STOP_FILE[] = "PAN_STOP_FILE"; + +static char *panname = NULL; +static char *test_out_dir = NULL; /* dir to buffer output to */ +zoo_t zoofile; +static char *reporttype = NULL; + +/* zoolib */ +int rec_signal; /* received signal */ +int send_signal; /* signal to send */ + +/* Debug Bits */ +int Debug = 0; +#define Dbuffile 0x000400 /* buffer file use */ +#define Dsetup 0x000200 /* one-time set-up */ +#define Dshutdown 0x000100 /* killed by signal */ +#define Dexit 0x000020 /* exit status */ +#define Drunning 0x000010 /* current pids running */ +#define Dstartup 0x000004 /* started command */ +#define Dstart 0x000002 /* started command */ +#define Dwait 0x000001 /* wait interrupted */ + +/* + * Print help and exit. + */ +static void print_help(void) +{ + fprintf(stdout, "Usage: ltp-pan -n name [ -SyAehpq ] [ -s starts ]" + " [-t time[s|m|h|d] [ -x nactive ] [ -l logfile ]\n\t" + "[ -a active-file ] [ -f command-file ] " + "[ -C fail-command-file ] " + "[ -d debug-level ]\n\t[-o output-file] " + "[-O output-buffer-directory] [cmd]\n"); + exit(0); +} + +/* + * Parse time from string. + */ +static void parse_time(const char *str, int *run_time, int *timed, int quiet_mode) +{ + char modifier = 'm'; + int ret = sscanf(str, "%d%c", run_time, &modifier); + + if (ret == 0) { + fprintf(stderr, "Need proper time input: ####x where" + "x is one of s,m,h,d\n"); + return; + } + + if (ret == 1) { + fprintf(stderr, "Only got a time value of %d " + "modifiers need to come immediately after #" + " assuming %c\n", run_time, modifier); + } + + switch (modifier) { + case 's': *run_time = *run_time; break; + case 'm': *run_time = *run_time * 60; break; + case 'h': *run_time = *run_time * 60 * 60; break; + case 'd': *run_time = *run_time * 60 * 60 * 24; break; + default: + fprintf(stderr, "Invalid time modifier, try: s|h|m|d\n"); exit(-1); + } + + if (!quiet_mode) + printf("PAN will run for %d seconds\n", run_time); + + timed = 1; /* -t implies run as many starts as possible, by default */ +} + +/* + * Prepares logfile. + */ +static void open_logfile(const char *logfilename, FILE **logfile, int fmt_print) +{ + time_t startup; + char *s; + + if (logfilename != NULL) { + if (logfilename[0] != "-") { + *logfile = stdout; + } else { + if ((*logfile = fopen(logfilename, "a+")) == NULL) { + fprintf(stderr, "ltp-pan(%s): Error %s (%d) opening log file '%s'\n", + panname, strerror(errno), errno, logfilename); + exit(1); + } + } + + time(&startup); + s = ctime(&startup); + s[strlen(s) - 1] = '\0'; + + if (!fmt_print) + fprintf(logfile, "startup='%s'\n", s); + else { + fprintf(logfile, "Test Start Time: %s\n", s); + fprintf(logfile, "-----------------------------------------\n"); + fprintf(logfile, "%-30.20s %-10.10s %-10.10s\n", + "Testcase", "Result", "Exit Value"); + fprintf(logfile, "%-30.20s %-10.10s %-10.10s\n", + "--------", "------", "------------"); + } + } +} + + +int main(int argc, char **argv) +{ + char *zooname = NULL; /* name of the zoo file to use */ + char *filename = "/dev/null"; /* filename to read test tags from */ + char *logfilename = NULL; + char *failcmdfilename = NULL; + char *outputfilename = NULL; + struct collection *coll = NULL; + struct tag_pgrp *running; + struct orphan_pgrp *orphans, *orph; + struct utsname unamebuf; + FILE *logfile = NULL; + FILE *failcmdfile = NULL; + int keep_active = 1; + int num_active = 0; + int failcnt = 0; /* count of total testcases that failed. */ + int err, i; + int starts = -1; + int timed = 0; + int run_time = -1; + int ret = 0; + int stop; + int go_idle; + int has_brakes = 0; /* stop everything if a test case fails */ + int sequential = 0; /* run tests sequentially */ + int fork_in_road = 0; + int exit_stat; + int track_exit_stats = 0; /* exit non-zero if any test exits non-zero */ + int fmt_print = 0; /* enables formatted printing of logfiles. */ + int quiet_mode = 0; /* supresses test start and test end tags. */ + int c; + pid_t cpid; + struct sigaction sa; + + while ((c = getopt(argc, argv, "AO:Sa:C:d:ef:hl:n:o:pqr:s:t:x:y")) != -1) { + switch (c) { + case 'A': /* all-stop flag */ + has_brakes = 1; + track_exit_stats = 1; + break; + case 'O': /* output buffering directory */ + test_out_dir = strdup(optarg); + break; + case 'S': /* run tests sequentially */ + sequential = 1; + break; + case 'a': /* name of the zoo file to use */ + zooname = strdup(optarg); + break; + case 'C': /* name of the file where all failed commands will be */ + failcmdfilename = strdup(optarg); + break; + case 'd': /* debug options */ + sscanf(optarg, "%i", &Debug); + break; + case 'e': /* exit non-zero if any test exists non-zero */ + track_exit_stats = 1; + break; + case 'f': /* filename to read test tags from */ + filename = strdup(optarg); + break; + case 'h': /* help */ + print_help(); + case 'l': /* log file */ + logfilename = strdup(optarg); + break; + case 'n': /* tag given to ltp-pan */ + panname = strdup(optarg); + break; + case 'o': /* send test output here */ + outputfilename = strdup(optarg); + break; + case 'p': /* formatted printing. */ + fmt_print = 1; + break; + case 'q': /* supress test start and test end messages */ + quiet_mode = 1; + break; + case 'r': /* reporting type: none, rts */ + reporttype = strdup(optarg); + break; + case 's': /* number of tags to run */ + starts = atoi(optarg); + break; + case 't': /* run_time to run */ + parse_time(optarg, &run_time, &timed, quiet_mode); + case 'x': /* number of tags to keep running */ + keep_active = atoi(optarg); + break; + case 'y': /* restart on failure or signal */ + fork_in_road = 1; + break; + } + } + + if (panname == NULL) { + fprintf(stderr, "ltp-pan: Must supply -n\n"); + exit(1); + } + + if (zooname == NULL) { + zooname = zoo_getname(); + if (zooname == NULL) { + fprintf(stderr, + "ltp-pan(%s): Must supply -a or set ZOO env variable\n", + panname); + exit(1); + } + } + + /* make sure we understand the report type */ + if (reporttype) { + if (strcasecmp(reporttype, "rts") && strcasecmp(reporttype, "none")) + reporttype = "rts"; + } else + /* set the default */ + reporttype = "rts"; + + open_logfile(logfilename, &logfile, fmt_print); + + coll = get_collection(filename, optind, argc, argv); + + if(!coll) + exit(1); + + if (coll->cnt == 0) { + fprintf(stderr, + "ltp-pan(%s): Must supply a file collection or a command\n", + panname); + exit(1); + } + + if (Debug & Dsetup) + dump_coll(coll); + + /* a place to store the pgrps we're watching */ + running = malloc((keep_active + 1) * sizeof(struct tag_pgrp)); + if (running == NULL) { + fprintf(stderr, "ltp-pan: malloc failed.\n"); + exit(1); + } + memset(running, 0, keep_active * sizeof(struct tag_pgrp)); + running[keep_active].pgrp = -1; /* end sentinel */ + + /* a head to the orphaned pgrp list */ + orphans = malloc(sizeof(struct orphan_pgrp)); + if (orphans == NULL) { + fprintf(stderr, "ltp-pan: malloc failed.\n"); + exit(1); + } + memset(orphans, 0, sizeof(struct orphan_pgrp)); + + srand48(time(NULL) ^ (getpid() + (getpid() << 15))); + + /* Supply a default for starts. If we are in sequential mode, use + * the number of commands available; otherwise 1. + */ + if (timed != 1 || starts != -1) { /* timed, infinite by default */ + if (starts == -1) { + if (sequential) + starts = coll->cnt; + else + starts = 1; + } else { + if (starts == 0) /* if the user specified infinite, set it */ + starts = -1; + else /* else, make sure we are starting at least keep_active processes */ + if (starts < keep_active) + starts = keep_active; + } + } + + /* if we're buffering output, but we're only running on process at a time, + * then essentially "turn off buffering" + */ + if (test_out_dir && (keep_active == 1)) { + free(test_out_dir); + test_out_dir = NULL; + } + + if (test_out_dir) { + struct stat sbuf; + + if (stat(test_out_dir, &sbuf) < 0) { + fprintf(stderr, + "ltp-pan(%s): stat of -O arg '%s' failed. errno: %d %s\n", + panname, test_out_dir, errno, strerror(errno)); + exit(1); + } + if (!S_ISDIR(sbuf.st_mode)) { + fprintf(stderr, "ltp-pan(%s): -O arg '%s' must be a directory.\n", + panname, test_out_dir); + exit(1); + } + if (access(test_out_dir, W_OK | R_OK | X_OK) < 0) { + fprintf(stderr, + "ltp-pan(%s): permission denied on -O arg '%s'. errno: %d %s\n", + panname, test_out_dir, errno, strerror(errno)); + exit(1); + } + } + + if (outputfilename) { + if (!freopen(outputfilename, "a+", stdout)) { + fprintf(stderr, + "ltp-pan(%s): Error %s (%d) openning output file '%s'\n", + panname, strerror(errno), errno, outputfilename); + exit(1); + } + } + + if (failcmdfilename) { + if (!(failcmdfile = fopen(failcmdfilename, "a+"))) { + fprintf(stderr, + "ltp-pan(%s): Error %s (%d) opening fail cmd file '%s'\n", + panname, strerror(errno), errno, failcmdfilename); + exit(1); + } + } + + if ((zoofile = zoo_open(zooname)) == NULL) { + fprintf(stderr, "ltp-pan(%s): %s\n", panname, zoo_error); + exit(1); + } + + if (zoo_mark_args(zoofile, getpid(), panname, argc, argv)) { + fprintf(stderr, "ltp-pan(%s): %s\n", panname, zoo_error); + exit(1); + } + + /* Allocate N spaces for max-arg commands. + * this is an "active file cleanliness" thing + */ + { + char *av[2], bigarg[82]; + + memset(bigarg, '.', 81); + bigarg[81] = '\0'; + av[0] = bigarg; + av[1] = NULL; + + for (c = 0; c < keep_active; c++) { + if (zoo_mark_cmdline(zoofile, c, panname, "")) { + fprintf(stderr, "ltp-pan(%s): %s\n", panname, zoo_error); + exit(1); + } + } + + for (c = 0; c < keep_active; c++) { + if (zoo_clear(zoofile, c)) { + fprintf(stderr, "ltp-pan(%s): %s\n", panname, zoo_error); + exit(1); + } + } + } + + rec_signal = send_signal = 0; + if (run_time != -1) + alarm(run_time); + + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = wait_handler; + + sigaction(SIGALRM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGUSR1, &sa, NULL); /* ignore fork_in_road */ + sigaction(SIGUSR2, &sa, NULL); /* stop the scheduler */ + + c = 0; /* in this loop, c is the command index */ + stop = 0; + exit_stat = 0; + go_idle = 0; + + while (1) { + + while ((num_active < keep_active) && (starts != 0)) { + if (stop || rec_signal || go_idle) + break; + + if (!sequential) + c = lrand48() % coll->cnt; + + /* find a slot for the child */ + for (i = 0; i < keep_active; ++i) + if (running[i].pgrp == 0) + break; + + if (i == keep_active) { + fprintf(stderr, "ltp-pan(%s): Aborting: i == keep_active = %d\n", + panname, i); + wait_handler(SIGINT); + exit_stat++; + break; + } + + cpid = run_child(coll->ary[c], running + i, quiet_mode); + + if (cpid != -1) + ++num_active; + if ((cpid != -1 || sequential) && starts > 0) + --starts; + + if (sequential) + if (++c >= coll->cnt) + c = 0; + + } + + if (starts == 0) + { + if (!quiet_mode) + printf("incrementing stop\n"); + ++stop; + } else + if (starts == -1) { + FILE *f = (FILE*)-1; + if ((f = fopen(PAN_STOP_FILE, "r")) != 0) { + printf("Got %s Stopping!\n", PAN_STOP_FILE); + fclose(f); + unlink(PAN_STOP_FILE); + stop++; + } + } + + if (rec_signal) { + /* propagate everything except sigusr2 */ + + if (rec_signal == SIGUSR2) { + if (fork_in_road) + ++go_idle; + else + ++stop; + rec_signal = send_signal = 0; + } else { + if (rec_signal == SIGUSR1) + fork_in_road = 0; + propagate_signal(running, keep_active, orphans); + + if (fork_in_road) + ++go_idle; + else + ++stop; + } + } + + err = check_pids(running, &num_active, keep_active, logfile, + failcmdfile, orphans, fmt_print, &failcnt, quiet_mode); + + if (Debug & Drunning) { + pids_running(running, keep_active); + orphans_running(orphans); + } + + if (err) { + if (fork_in_road) + ++go_idle; + + if (track_exit_stats) + exit_stat++; + + if (has_brakes) { + fprintf(stderr, "ltp-pan(%s): All stop!%s\n", panname, + go_idle ? " (idling)" : ""); + wait_handler(SIGINT); + } + } + + if (stop && (num_active == 0)) + break; + + if (go_idle && (num_active == 0)) { + go_idle = 0; /* It is idle, now resume scheduling. */ + wait_handler(0); /* Reset the signal ratchet. */ + } + } + + /* Wait for orphaned pgrps */ + while (1) { + + for (orph = orphans; orph != NULL; orph = orph->next) { + + if (orph->pgrp == 0) + continue; + + /* Yes, we have orphaned pgrps */ + sleep(5); + + if (!rec_signal) { + + /* force an artificial signal, move us + * through the signal ratchet. + */ + wait_handler(SIGINT); + } + + propagate_signal(running, keep_active, orphans); + + if (Debug & Drunning) + orphans_running(orphans); + + break; + } + + + if (orph == NULL) + break; + } + + + if (zoo_clear(zoofile, getpid())) { + fprintf(stderr, "ltp-pan(%s): %s\n", panname, zoo_error); + ++exit_stat; + } + + fclose(zoofile); + + if (logfile && fmt_print) { + if (uname(&unamebuf) == -1) + fprintf(stderr, "ERROR: uname(): %s\n", strerror(errno)); + + fprintf(logfile, "\n-----------------------------------------------\n"); + fprintf(logfile, "Total Tests: %d\n", coll->cnt); + fprintf(logfile, "Total Failures: %d\n", failcnt); + fprintf(logfile, "Kernel Version: %s\n", unamebuf.release); + fprintf(logfile, "Machine Architecture: %s\n", unamebuf.machine); + fprintf(logfile, "Hostname: %s\n\n", unamebuf.nodename); + } + + if (logfile && (logfile != stdout)) + fclose(logfile); + + exit(exit_stat); +} + + + +static void propagate_signal(struct tag_pgrp *running, int keep_active, + struct orphan_pgrp *orphans) +{ + int i; + + if (Debug & Dshutdown) + fprintf(stderr, "ltp-pan was signaled with sig %d...\n", rec_signal); + + if (rec_signal == SIGALRM) { + printf("PAN stop Alarm was received\n"); + rec_signal = SIGTERM; + } + + for (i = 0; i < keep_active; ++i) { + if (running[i].pgrp == 0) + continue; + + if (Debug & Dshutdown) + fprintf(stderr, " propagating sig %d to %d\n", + send_signal, -running[i].pgrp); + + if (kill(-running[i].pgrp, send_signal) != 0) { + fprintf(stderr, + "ltp-pan(%s): kill(%d,%d) failed on tag (%s). errno:%d %s\n", + panname, -running[i].pgrp, send_signal, + running[i].cmd->name, errno, strerror(errno)); + } + + running[i].stopping = 1; + } + + check_orphans(orphans, send_signal); + + rec_signal = send_signal = 0; +} + + +static int check_pids(struct tag_pgrp *running, int *num_active, int + keep_active, FILE * logfile, FILE * failcmdfile, + struct orphan_pgrp *orphans, int fmt_print, + int *failcnt, int quiet_mode) +{ + int w; + pid_t cpid; + int stat_loc; + int ret = 0; + int i; + time_t t; + char *status; + int signaled = 0; + struct tms tms1, tms2; + clock_t tck; + + check_orphans(orphans, 0); + + tck = times(&tms1); + + if (tck == -1) + fprintf(stderr, "ltp-pan(%s): times(&tms1) failed. errno:%d %s\n", + panname, errno, strerror(errno)); + + cpid = wait(&stat_loc); + tck = times(&tms2); + + if (tck == -1) + fprintf(stderr, "ltp-pan(%s): times(&tms2) failed. errno:%d %s\n", + panname, errno, strerror(errno)); + + if (cpid < 0) { + if (errno == EINTR) { + if (Debug) + fprintf(stderr, "ltp-pan(%s): wait() interrupted\n", panname); + } else + if (errno != ECHILD) { + fprintf(stderr, "ltp-pan(%s): wait() failed. errno:%d %s\n", + panname, errno, strerror(errno)); + } + } else + if (cpid > 0) { + + if (WIFSIGNALED(stat_loc)) { + w = WTERMSIG(stat_loc); + status = "signaled"; + if (Debug & Dexit) + fprintf(stderr, "child %d terminated with signal %d\n", cpid, w); + --*num_active; + signaled = 1; + } else + if (WIFEXITED(stat_loc)) { + w = WEXITSTATUS(stat_loc); + status = "exited"; + if (Debug & Dexit) + fprintf(stderr, "child %d exited with status %d\n", cpid, w); + --*num_active; + if (w != 0) + ret++; + } else + if (WIFSTOPPED(stat_loc)) { /* should never happen */ + w = WSTOPSIG(stat_loc); + status = "stopped"; + ret++; + } else { /* should never happen */ + w = 0; + status = "unknown"; + ret++; + } + + for (i = 0; i < keep_active; ++i) { + if (running[i].pgrp == cpid) { + if ((w == 130) && running[i].stopping && (strcmp(status, "exited") == 0)) { + /* The child received sigint, but + * did not trap for it? Compensate + * for it here. + */ + w = 0; + ret--; /* undo */ + if (Debug & Drunning) + fprintf(stderr, + "ltp-pan(%s): tag=%s exited 130, known to be signaled; will give it an exit 0.\n", + panname, running[i].cmd->name); + } + time(&t); + + if (logfile != NULL) { + if (!fmt_print) + fprintf(logfile, "tag=%s stime=%d dur=%d exit=%s stat=%d core=%s cu=%d cs=%d\n", + running[i].cmd->name, (int) (running[i].mystime), + (int) (t - running[i].mystime), status, w, + (stat_loc & 0200) ? "yes" : "no", + (int) (tms2.tms_cutime - tms1.tms_cutime), + (int) (tms2.tms_cstime - tms1.tms_cstime)); + else { + if (w != 0) + ++*failcnt; + + fprintf(logfile, "%-30.30s %-10.10s %-5d\n", + running[i].cmd->name, ((w != 0) ? "FAIL" : "PASS"), w); + } + + fflush(logfile); + } + + if ((failcmdfile != NULL) && (w !=0)) + fprintf(failcmdfile, "%s %s\n", running[i].cmd->name, running[i].cmd->cmdline); + + if (running[i].stopping) + status = "driver_interrupt"; + + if (test_out_dir) { + if (!quiet_mode) + write_test_start(running+i, "ok"); + copy_buffered_output(running + i); + unlink(running[i].output); + } + + if (!quiet_mode) + write_test_end(running+i, t, status, stat_loc, w, &tms1, &tms2); + + /* If signaled and we weren't expecting + * this to be stopped then the proc + * had a problem. + */ + if (signaled && !running[i].stopping) + ret++; + + running[i].pgrp = 0; + + if (zoo_clear(zoofile, cpid)) { + fprintf(stderr, "ltp-pan(%s): %s\n", panname, zoo_error); + exit(1); + } + + /* Check for orphaned pgrps */ + if ((kill(-cpid, 0) == 0) || (errno == EPERM)) { + if (zoo_mark_cmdline(zoofile, cpid, "panorphan", running[i].cmd->cmdline)) { + fprintf(stderr, "ltp-pan(%s): %s\n", panname, zoo_error); + exit(1); + } + + mark_orphan(orphans, cpid); + /* status of kill doesn't matter */ + kill(-cpid, SIGTERM); + } + + break; + } + } + } + + return ret; +} + + +static pid_t run_child(struct coll_entry *colle, struct tag_pgrp *active, int quiet_mode) +{ + int cpid; + int c_stdout = -1; /* child's stdout, stderr */ + int capturing = 0; /* output is going to a file instead of stdout */ + char *c_cmdline; + static long cmdno = 0; + int errpipe[2]; /* way to communicate to parent that the tag */ + char errbuf[1024]; /* didn't actually start */ + int errlen; + + /* Try to open the file that will be stdout for the test */ + if (test_out_dir) { + capturing = 1; + + do { + sprintf(active->output, "%s/%s.%ld", + test_out_dir, colle->name, cmdno++); + c_stdout = open(active->output, O_CREAT | O_RDWR | O_EXCL | O_SYNC, 0666); + } while (c_stdout < 0 && errno == EEXIST); + + if (c_stdout < 0) { + fprintf(stderr, + "ltp-pan(%s): open of stdout file failed (tag %s). errno: %d %s\n file: %s\n", + panname, colle->name, errno, strerror(errno), + active->output); + return -1; + } + } + + /* get the tag's command line arguments ready. subst_pcnt_f() uses a + * static counter, that's why we do it here instead of after we fork. + */ + if (colle->pcnt_f) + c_cmdline = subst_pcnt_f(colle); + else + c_cmdline = colle->cmdline; + + if (pipe(errpipe) < 0) { + fprintf(stderr, "ltp-pan(%s): pipe() failed. errno:%d %s\n", + panname, errno, strerror(errno)); + if (capturing) { + close(c_stdout); + unlink(active->output); + } + + return -1; + } + + if ((cpid = fork()) < 0) { + fprintf(stderr, "ltp-pan(%s): fork failed (tag %s). errno:%d %s\n", + panname, colle->name, errno, strerror(errno)); + + if (capturing) { + unlink(active->output); + close(c_stdout); + } + + close(errpipe[0]); + close(errpipe[1]); + + return -1; + } else + if (cpid == 0) { + /* child */ + fclose(zoofile); + close(errpipe[0]); + fcntl(errpipe[1], F_SETFD, 1); /* close the pipe if we succeed */ + setpgrp(); + umask(0); + + /* if we're putting output into a buffer file, we need to do the + * redirection now. If we fail + */ + if (capturing) { + if (dup2(c_stdout, fileno(stdout)) == -1) { + errlen = sprintf(errbuf, "ltp-pan(%s): couldn't redirect stdout for tag %s. errno:%d %s", + panname, colle->name, errno, strerror(errno)); + write(errpipe[1], &errlen, sizeof(errlen)); + write(errpipe[1], errbuf, errlen); + exit(2); + } + + if (dup2(c_stdout, fileno(stderr)) == -1) { + errlen = sprintf(errbuf, "ltp-pan(%s): couldn't redirect stderr for tag %s. errno:%d %s", + panname, colle->name, errno, strerror(errno)); + write(errpipe[1], &errlen, sizeof(errlen)); + write(errpipe[1], errbuf, errlen); + exit(2); + } + } else { /* stderr still needs to be redirected */ + if (dup2(fileno(stdout), fileno(stderr)) == -1) { + errlen = sprintf(errbuf, "ltp-pan(%s): couldn't redirect stderr for tag %s. errno:%d %s", + panname, colle->name, errno, strerror(errno)); + write(errpipe[1], &errlen, sizeof(errlen)); + write(errpipe[1], errbuf, errlen); + exit(2); + } + } + + /* If there are any shell-type characters in the cmdline + * such as '>', '<', '$', '|', etc, then we exec a shell and + * run the cmd under a shell. + * + * Otherwise, break the cmdline at white space and exec the + * cmd directly. + */ + if (strpbrk(c_cmdline, "\"';|<>$\\")) { + execlp("sh", "sh", "-c", c_cmdline, (char*)0); + errlen = sprintf(errbuf, + "ltp-pan(%s): execlp of '%s' (tag %s) failed. errno:%d %s", + panname, c_cmdline, colle->name, errno, strerror(errno)); + } else { + char **arg_v; + + arg_v = (char **)splitstr(c_cmdline, NULL, NULL); + + execvp(arg_v[0], arg_v); + errlen = sprintf(errbuf, + "ltp-pan(%s): execvp of '%s' (tag %s) failed. errno:%d %s", + panname, arg_v[0], colle->name, errno, strerror(errno)); + } + + write(errpipe[1], &errlen, sizeof(errlen)); + write(errpipe[1], errbuf, errlen); + exit(errno); + } + + /* parent */ + + /* subst_pcnt_f() allocates the command line dynamically + * free the malloc to prevent a memory leak + */ + if (colle->pcnt_f) + free(c_cmdline); + + close(errpipe[1]); + time(&active->mystime); + active->cmd = colle; + + /* if the child couldn't go through with the exec, + * clean up the mess, note it, and move on + */ + if(read(errpipe[0], &errlen, sizeof(errlen))) { + int status; + time_t end_time; + int termid; + char *termtype; + struct tms notime = {0, 0, 0, 0}; + + read(errpipe[0], errbuf, errlen); + close(errpipe[0]); + errbuf[errlen] = '\0'; + /* fprintf(stderr, "%s", errbuf); */ + waitpid(cpid, &status, 0); + if (WIFSIGNALED(status)) { + termid = WTERMSIG(status); + termtype = "signaled"; + } else + if (WIFEXITED(status)) { + termid = WEXITSTATUS(status); + termtype = "exited"; + } else + if (WIFSTOPPED(status)) { + termid = WSTOPSIG(status); + termtype = "stopped"; + } else { + termid = 0; + termtype = "unknown"; + } + + time(&end_time); + if (!quiet_mode) + { + write_test_start(active, errbuf); + write_test_end(active, end_time, termtype, status, + termid, ¬ime, ¬ime); + } + + if (capturing) { + close(c_stdout); + unlink(active->output); + } + + return -1; + } + + close(errpipe[0]); + + if (capturing) + close(c_stdout); + + if (!test_out_dir && !quiet_mode) + write_test_start(active, "ok"); + + active->pgrp = cpid; + active->stopping = 0; + + if (zoo_mark_cmdline(zoofile, cpid, colle->name, colle->cmdline)) { + fprintf(stderr, "ltp-pan(%s): %s\n", panname, zoo_error); + exit(1); + } + + if (Debug & Dstartup) + fprintf(stderr, "started %s cpid=%d at %s", + colle->name, cpid, ctime(&active->mystime)); + + if (Debug & Dstart) { + + fprintf(stderr, "Executing test = %s as %s", colle->name, colle->cmdline); + + if (capturing) + fprintf(stderr, "with output file = %s\n", active->output); + else + fprintf(stderr, "\n"); + } + + return cpid; +} + + +static char *subst_pcnt_f(struct coll_entry *colle) +{ + static int counter = 1; + char pid_and_counter[20]; + char new_cmdline[1024]; + + /* if we get called falsely, do the right thing anyway */ + if (!colle->pcnt_f) + return colle->cmdline; + + snprintf(pid_and_counter, 20, "%d_%d", getpid(), counter++); + snprintf(new_cmdline, 1024, colle->cmdline, pid_and_counter); + return strdup(new_cmdline); +} + +/* + * This code is broken as it's doesn't check NULL from malloc, strdup and so; + * but I'm just too lazy to rewrite this as pan is broken by design. + */ +static struct collection *get_collection(char *file, int optind, int argc, char **argv) +{ + char *buf, *a, *b; + struct coll_entry *head, *p, *n; + struct collection *coll; + int i; + + buf = slurp(file); + + if(!buf) + return NULL; + + coll = malloc(sizeof(struct collection)); + coll->cnt = 0; + + head = p = n = NULL; + a = b = buf; + + while (a) { + /* set b to the start of the next line and add a NULL character + * to separate the two lines */ + if ((b = strchr(a, '\n')) != NULL) + *b++ = '\0'; + + /* If this is line isn't a comment */ + if ((*a != '#') && (*a != '\0') && (*a != ' ')) { + n = malloc(sizeof(struct coll_entry)); + + if ((n->pcnt_f = strstr(a, "%f"))) + n->pcnt_f[1] = 's'; + + n->name = strdup(strsep(&a, " \t")); + n->cmdline = strdup(a); + n->next = NULL; + + if (p) + p->next = n; + + if (head == NULL) + head = n; + + p = n; + coll->cnt++; + } + + a = b; + } + + free(buf); + + /* is there something on the commandline to be counted? */ + if (optind < argc) { + char workstr[1024] = ""; + int workstr_left = 1023; + + /* fill arg list */ + for (i = 0; optind < argc; ++optind, ++i) { + strncat(workstr, argv[optind], workstr_left); + workstr_left = workstr_left - strlen(argv[optind]); + strncat(workstr, " ", workstr_left); + workstr_left--; + } + + n = (struct coll_entry *) malloc(sizeof(struct coll_entry)); + + if ((n->pcnt_f = strstr(workstr, "%f"))) + n->pcnt_f[1] = 's'; + + n->cmdline = strdup(workstr); + n->name = "cmdln"; + n->next = NULL; + + if (p) + p->next = n; + + if (head == NULL) + head = n; + + coll->cnt++; + } + + /* get an array */ + coll->ary = malloc(coll->cnt * sizeof(struct coll_entry *)); + + /* fill the array */ + i = 0; + n = head; + + while (n != NULL) { + coll->ary[i] = n; + n = n->next; + ++i; + } + + if (i != coll->cnt) + fprintf(stderr, "ltp-pan(%s): i doesn't match cnt\n", panname); + + return coll; +} + +static char *slurp(char *file) +{ + char *buf; + int fd; + struct stat sbuf; + + if ((fd = open(file, O_RDONLY)) < 0) { + fprintf(stderr, "ltp-pan(%s): open(%s,O_RDONLY) failed. errno:%d %s\n", + panname, file, errno, strerror(errno)); + return NULL; + } + + if (fstat(fd, &sbuf) < 0) { + fprintf(stderr, "ltp-pan(%s): fstat(%s) failed. errno:%d %s\n", + panname, file, errno, strerror(errno)); + return NULL; + } + + buf = malloc(sbuf.st_size + 1); + + if (read(fd, buf, sbuf.st_size) != sbuf.st_size) { + fprintf(stderr, "ltp-pan(%s): slurp failed. errno:%d %s\n", + panname, errno, strerror(errno)); + return NULL; + } + + buf[sbuf.st_size] = '\0'; + + close(fd); + return buf; +} + +static void check_orphans(struct orphan_pgrp *orphans, int sig) +{ + struct orphan_pgrp *orph; + + for (orph = orphans; orph != NULL; orph = orph->next) { + if (orph->pgrp == 0) + continue; + + if (Debug & Dshutdown) + fprintf(stderr, " propagating sig %d to orphaned pgrp %d\n", + sig, -(orph->pgrp)); + if (kill(-(orph->pgrp), sig) != 0) { + if (errno == ESRCH) { + /* This pgrp is now empty */ + if (zoo_clear(zoofile, orph->pgrp)) + fprintf(stderr, "ltp-pan(%s): %s\n", panname, zoo_error); + orph->pgrp = 0; + } else { + fprintf(stderr, + "ltp-pan(%s): kill(%d,%d) on orphaned pgrp failed. errno:%d %s\n", + panname, -(orph->pgrp), sig, errno, strerror(errno)); + } + } + } +} + + +static void mark_orphan(struct orphan_pgrp *orphans, pid_t cpid) +{ + struct orphan_pgrp *orph; + + for (orph = orphans; orph != NULL; orph = orph->next) + if (orph->pgrp == 0) + break; + + if (orph == NULL) { + /* make a new struct */ + orph = (struct orphan_pgrp *) malloc(sizeof(struct orphan_pgrp)); + + /* plug in the new struct just after the head */ + orph->next = orphans->next; + orphans->next = orph; + } + + orph->pgrp = cpid; +} + + + +static void copy_buffered_output(struct tag_pgrp *running) +{ + char *tag_output; + + tag_output = slurp(running->output); + + if (tag_output) { + printf("%s", tag_output); + /* make sure the output ends with a newline */ + if (tag_output[strlen(tag_output) - 1] != '\n') + printf("\n"); + fflush(stdout); + free(tag_output); + } +} + + +static void write_test_start(struct tag_pgrp *running, const char *init_status) +{ + if (!strcmp(reporttype, "rts")) + printf("%s\ntag=%s stime=%ld\ncmdline=\"%s\"\ncontacts=\"%s\"\nanalysis=%s\ninitiation_status=\"%s\"\n%s\n", + "<<<test_start>>>", + running->cmd->name, running->mystime, running->cmd->cmdline, "", + "exit", init_status, + "<<<test_output>>>"); + + fflush(stdout); +} + + +static void write_test_end(struct tag_pgrp *running, time_t exit_time, + char *term_type, int stat_loc, int term_id, + struct tms *tms1, struct tms *tms2) +{ + if (!strcmp(reporttype, "rts")) + printf("%s\nduration=%ld termination_type=%s termination_id=%d corefile=%s\ncutime=%d cstime=%d\n%s\n", + "<<<execution_status>>>", + (long) (exit_time - running->mystime), + term_type, term_id, (stat_loc & 0200) ? "yes" : "no", + (int) (tms2->tms_cutime - tms1->tms_cutime), + (int) (tms2->tms_cstime - tms1->tms_cstime), + "<<<test_end>>>"); + + fflush(stdout); +} + +/* Debugging functions */ + +static void pids_running(struct tag_pgrp *running, int keep_active) +{ + int i; + + fprintf(stderr, "pids still running: "); + for (i = 0; i < keep_active; ++i) { + if (running[i].pgrp != 0) + fprintf(stderr, "%d ", running[i].pgrp); + } + fprintf(stderr, "\n"); +} + +static void orphans_running(struct orphan_pgrp *orphans) +{ + struct orphan_pgrp *orph; + + fprintf(stderr, "orphans still running: "); + + for (orph = orphans; orph != NULL; orph = orph->next) { + if (orph->pgrp != 0) + fprintf(stderr, "%d ", -(orph->pgrp)); + } + fprintf(stderr, "\n"); +} + +static void dump_coll(struct collection *coll) +{ + int i; + + for (i = 0; i < coll->cnt; ++i) { + fprintf(stderr, "coll %d\n", i); + fprintf(stderr, " name=%s cmdline=%s\n", coll->ary[i]->name, + coll->ary[i]->cmdline); + } +} + +void wait_handler(int sig) +{ + int lastsent = 0; + + if (sig == 0) { + lastsent = 0; + return; + } + + rec_signal = sig; + + if(sig == SIGUSR2) + return; + + if(lastsent == 0) + send_signal = sig; + else if(lastsent == SIGUSR1) + send_signal = SIGINT; + else if(lastsent == sig) + send_signal = SIGTERM; + else if(lastsent == SIGTERM) + send_signal = SIGHUP; + else if(lastsent == SIGHUP) + send_signal = SIGKILL; + + lastsent = send_signal; +} diff --git a/pan/scanner.c b/pan/ltp-scanner.c index 4236017f1..20177cf0f 100644 --- a/pan/scanner.c +++ b/pan/ltp-scanner.c @@ -30,7 +30,7 @@ * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ * */ -/* $Id: scanner.c,v 1.1 2000/09/21 21:35:06 alaffin Exp $ */ +/* $Id: ltp-scanner.c,v 1.1 2009/05/19 09:39:11 subrata_modak Exp $ */ /* * An RTS/pan driver output processing program. * @@ -41,7 +41,7 @@ * it's reports. * * Synopsis: - * scanner [ -e ] [ -D area:level ] [ -h ] + * ltp-scanner [ -e ] [ -D area:level ] [ -h ] * * Description: * Scanner is part of the RTS 2.0 reporting mechanism or pan. @@ -125,59 +125,50 @@ #include <unistd.h> #include <stdarg.h> #include <string.h> +#include <getopt.h> #include "scan.h" #include "debug.h" #include "reporter.h" #include "symbol.h" -char *cfn; /* current filename */ -int extended=0; /* -e option */ +char *cnf; /* current filename */ +int extended=0; /* -e option */ -int -main(argc, argv) - int argc; - char **argv; +int main(int argc, char *argv[]) { - SYM tags; /* tag data */ + SYM tags; /* tag data */ + int c; - /* Argument parsing */ - int r; - char c; - extern char *optarg; - extern int optind, opterr, optopt; - - while(( r = getopt(argc, argv, "D:ehi")) != -1) { - c = (char) r; - switch(c) { - case 'i': - set_iscanner(); - break; - case 'D': - set_debug(optarg); - break; - case 'e': - extended++; - break; - case 'h': - fprintf(stderr, "%s [-e] [-i] [ -D area, level ] input-filenames\n", - argv[0]); - exit(0); - break; - default: - fprintf(stderr, "invalid argument, %c\n", c); - exit(1); + while ((c = getopt(argc, argv, "D:ehi")) != -1) { + switch(c) { + case 'i': + set_iscanner(); + break; + case 'D': + set_debug(optarg); + break; + case 'e': + extended++; + break; + case 'h': + fprintf(stderr, "%s [-e] [-i] [ -D area, level ] input-filenames\n", + argv[0]); + exit(0); + default: + fprintf(stderr, "invalid argument, %c\n", c); + exit(1); + } } - } - lex_files(&argv[optind]); /* I hope that argv[argc+1] == NULL */ - tags = sym_open(0, 0, 0); + lex_files(&argv[optind]); /* I hope that argv[argc+1] == NULL */ + tags = sym_open(0, 0, 0); - scanner(tags); + scanner(tags); #ifdef DEBUGGING - DEBUG(D_INIT, 1) + DEBUG(D_INIT, 1) sym_dump_s(tags, 0); #endif - reporter(tags); + reporter(tags); - exit(0); + exit(0); } diff --git a/pan/pan.c b/pan/pan.c deleted file mode 100644 index 3c2ae4d52..000000000 --- a/pan/pan.c +++ /dev/null @@ -1,1309 +0,0 @@ -/* - * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., 59 - * Temple Place - Suite 330, Boston MA 02111-1307, USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * - * Changelog: - * - * Added timer options: William Jay Huie, IBM - * 01/27/03 - Added: Manoj Iyer, manjo@mail.utexas.edu - * - option '-p' (pretty printing)i to enabled formatted printing - * of results. - * - * 01/27/03 - Added: Manoj Iyer, manjo@mail.utexas.edu - * - added code to print system information - * - * 01/28/03 - Added: Manoj Iyer, manjo@mail.utexas.edu - * - added code to print test exit value. - * - * 01/29/03 - Added: Manoj Iyer, manjo@mail.utexas.edu - * - added code supresses test start and test end tags. - * - * 07/22/07 - Added: Ricardo Salveti de Araujo, rsalveti@linux.vnet.ibm.com - * - added option to create a command file with all failed tests. - * - */ -/* $Id: pan.c,v 1.32 2009/02/23 10:43:35 subrata_modak Exp $ */ - -#include <errno.h> -#include <string.h> -#include <sys/param.h> -#include <sys/types.h> -#include <sys/times.h> -#include <sys/wait.h> -#include <sys/stat.h> -#include <time.h> -#include <stdlib.h> -#include <limits.h> -#include <sys/utsname.h> - -#include "splitstr.h" -#include "zoolib.h" - -/* One entry in the command line collection. */ -struct coll_entry -{ - char *name; /* tag name */ - char *cmdline; /* command line */ - char *pcnt_f; /* location of %f in the command line args, flag */ - struct coll_entry *next; -}; - -struct collection -{ - int cnt; - struct coll_entry **ary; -}; - -struct tag_pgrp -{ - int pgrp; - int stopping; - time_t mystime; - struct coll_entry *cmd; - char output[PATH_MAX]; -}; - -struct orphan_pgrp -{ - int pgrp; - struct orphan_pgrp *next; -}; - -static pid_t run_child(struct coll_entry *colle, struct tag_pgrp *active, - int quiet_mode); -static char *slurp(char *file); -static struct collection *get_collection(char *file, int optind, int argc, - char **argv); -static void pids_running(struct tag_pgrp *running, int keep_active); -static int check_pids(struct tag_pgrp *running, int *num_active, - int keep_active, FILE * logfile, FILE * failcmdfile, - struct orphan_pgrp *orphans, int fmt_print, - int *failcnt, int quiet_mode); -static void propagate_signal(struct tag_pgrp *running, int keep_active, - struct orphan_pgrp *orphans); -static void dump_coll(struct collection *coll); -static char *subst_pcnt_f(struct coll_entry *colle); -static void mark_orphan(struct orphan_pgrp *orphans, pid_t cpid); -static void orphans_running(struct orphan_pgrp *orphans); -static void check_orphans(struct orphan_pgrp *orphans, int sig); - -static void copy_buffered_output(struct tag_pgrp *running); -static void write_test_start(struct tag_pgrp *running, const char *init_status); -static void write_test_end(struct tag_pgrp *running, - time_t exit_time, char *term_type, int stat_loc, - int term_id, struct tms *tms1, struct tms *tms2); - -//wjh -static char PAN_STOP_FILE[] = "PAN_STOP_FILE"; - -static char *panname = NULL; -static char *test_out_dir = NULL; /* dir to buffer output to */ -zoo_t zoofile; -static char *reporttype = NULL; - -/* zoolib */ -int rec_signal; /* received signal */ -int send_signal; /* signal to send */ - -/* Debug Bits */ -int Debug = 0; -#define Dbuffile 0x000400 /* buffer file use */ -#define Dsetup 0x000200 /* one-time set-up */ -#define Dshutdown 0x000100 /* killed by signal */ -#define Dexit 0x000020 /* exit status */ -#define Drunning 0x000010 /* current pids running */ -#define Dstartup 0x000004 /* started command */ -#define Dstart 0x000002 /* started command */ -#define Dwait 0x000001 /* wait interrupted */ - -int -main(int argc, char **argv) -{ - extern char *optarg; - extern int optind; - char *zooname = NULL; /* name of the zoo file to use */ - char *filename = "/dev/null"; /* filename to read test tags from */ - char *logfilename = NULL; - char *failcmdfilename = NULL; - char *outputfilename = NULL; - struct collection *coll = NULL; - struct tag_pgrp *running; - struct orphan_pgrp *orphans, *orph; - struct utsname unamebuf; - FILE *logfile = NULL; - FILE *failcmdfile = NULL; - int keep_active = 1; - int num_active = 0; - int failcnt = 0; /* count of total testcases that failed. */ - int err, i; - int starts = -1; - int timed = 0; - int run_time = -1; char modifier = 'm'; int ret = 0; - int stop; - int go_idle; - int has_brakes = 0; /* stop everything if a test case fails */ - int sequential = 0; /* run tests sequentially */ - int fork_in_road = 0; - int exit_stat; - int track_exit_stats = 0; /* exit non-zero if any test exits non-zero */ - int fmt_print = 0; /* enables formatted printing of logfiles. */ - int quiet_mode = 0; /* supresses test start and test end tags. */ - int c; - pid_t cpid; - struct sigaction sa; - - while ((c = getopt(argc, argv, "AO:Sa:C:d:ef:hl:n:o:pqr:s:t:x:y")) != -1) { - switch (c) { - case 'A': /* all-stop flag */ - has_brakes = 1; - track_exit_stats = 1; - break; - case 'O': /* output buffering directory */ - test_out_dir = strdup(optarg); - break; - case 'S': /* run tests sequentially */ - sequential = 1; - break; - case 'a': /* name of the zoo file to use */ - zooname = strdup(optarg); - break; - case 'C': /* name of the file where all failed commands will be */ - failcmdfilename = strdup(optarg); - break; - case 'd': /* debug options */ - sscanf(optarg, "%i", &Debug); - break; - case 'e': /* exit non-zero if any test exists non-zero */ - track_exit_stats = 1; - break; - case 'f': /* filename to read test tags from */ - filename = strdup(optarg); - break; - case 'h': /* help */ - fprintf(stdout, "Usage: pan -n name [ -SyAehpq ] [ -s starts ]" - " [-t time[s|m|h|d] [ -x nactive ] [ -l logfile ]\n\t" - "[ -a active-file ] [ -f command-file ] " - "[ -C fail-command-file ] " - "[ -d debug-level ]\n\t[-o output-file] " - "[-O output-buffer-directory] [cmd]\n"); - exit(0); - case 'l': /* log file */ - logfilename = strdup(optarg); - break; - case 'n': /* tag given to pan */ - panname = strdup(optarg); - break; - case 'o': /* send test output here */ - outputfilename = strdup(optarg); - break; - case 'p': /* formatted printing. */ - fmt_print = 1; - break; - case 'q': /* supress test start and test end messages */ - quiet_mode = 1; - break; - case 'r': /* reporting type: none, rts */ - reporttype = strdup(optarg); - break; - case 's': /* number of tags to run */ - starts = atoi(optarg); - break; - case 't': /* run_time to run */ - ret = sscanf(optarg, "%d%c", &run_time, &modifier); - if (ret == 0) { fprintf(stderr, "Need proper time input: ####x where" - "x is one of s,m,h,d\n"); break; } - else if (ret == 1) { fprintf(stderr, "Only got a time value of %d " - "modifiers need to come immediately after #" - " assuming %c\n", run_time, modifier); } - else - { - switch (modifier) - { - case 's': run_time = run_time; break; - case 'm': run_time = run_time * 60; break; - case 'h': run_time = run_time * 60 * 60; break; - case 'd': run_time = run_time * 60 * 60 * 24; break; - default: - fprintf(stderr, "Invalid time modifier, try: s|h|m|d\n"); exit(-1); - } - if (!quiet_mode) - printf("PAN will run for %d seconds\n", run_time); - } - timed = 1; //-t implies run as many starts as possible, by default - break; - case 'x': /* number of tags to keep running */ - keep_active = atoi(optarg); - break; - case 'y': /* restart on failure or signal */ - fork_in_road = 1; - break; - } - } - - if (panname == NULL) { - fprintf(stderr, "pan: Must supply -n\n"); - exit(1); - } - if (zooname == NULL) { - zooname = zoo_getname(); - if (zooname == NULL) { - fprintf(stderr, - "pan(%s): Must supply -a or set ZOO env variable\n", - panname); - exit(1); - } - } - if (reporttype) { - /* make sure we understand the report type */ - if (strcasecmp(reporttype, "rts") - && strcasecmp(reporttype, "none") - /* && strcasecmp(reporttype, "xml")*/) - reporttype = "rts"; - } else { - /* set the default */ - reporttype = "rts"; - } - - if (logfilename != NULL) { - time_t startup; - char *s; - - if (!strcmp(logfilename, "-")) { - logfile = stdout; - } else { - if ((logfile = fopen(logfilename, "a+")) == NULL) { - fprintf(stderr, - "pan(%s): Error %s (%d) opening log file '%s'\n", - panname, strerror(errno), errno, logfilename); - exit(1); - } - } - - time(&startup); - s = ctime(&startup); - *(s + strlen(s) - 1) = '\0'; - if (!fmt_print) - fprintf(logfile, "startup='%s'\n", s); - else - { - fprintf(logfile, "Test Start Time: %s\n", s); - fprintf(logfile, "-----------------------------------------\n"); - fprintf(logfile, "%-30.20s %-10.10s %-10.10s\n", - "Testcase", "Result", "Exit Value"); - fprintf(logfile, "%-30.20s %-10.10s %-10.10s\n", - "--------", "------", "------------"); - } - } - - coll = get_collection(filename, optind, argc, argv); - if(!coll) - exit(1); - if (coll->cnt == 0) { - fprintf(stderr, - "pan(%s): Must supply a file collection or a command\n", - panname); - exit(1); - } - - if (Debug & Dsetup) - dump_coll(coll); - - /* a place to store the pgrps we're watching */ - running = (struct tag_pgrp *)malloc((keep_active + 1) * sizeof(struct tag_pgrp)); - memset(running, 0, keep_active * sizeof(struct tag_pgrp)); - running[keep_active].pgrp = -1; /* end sentinel */ - - /* a head to the orphaned pgrp list */ - orphans = (struct orphan_pgrp *) malloc(sizeof(struct orphan_pgrp)); - memset(orphans, 0, sizeof(struct orphan_pgrp)); - - srand48(time(NULL) ^ (getpid() + (getpid() << 15))); - - /* Supply a default for starts. If we are in sequential mode, use - * the number of commands available; otherwise 1. - */ - if (timed == 1 && starts == -1) { /* timed, infinite by default */ - starts = -1; - } else if (starts == -1) { - if (sequential) { - starts = coll->cnt; - } else { - starts = 1; - } - } else if (starts == 0) { /* if the user specified infinite, set it */ - starts = -1; - } else { /* else, make sure we are starting at least keep_active processes */ - if (starts < keep_active) - starts = keep_active; - } - - /* if we're buffering output, but we're only running on process at a time, - * then essentially "turn off buffering" - */ - if (test_out_dir && (keep_active == 1)) { - free(test_out_dir); - test_out_dir = NULL; - } - - if (test_out_dir) { - struct stat sbuf; - - if (stat(test_out_dir, &sbuf) < 0) { - fprintf(stderr, - "pan(%s): stat of -O arg '%s' failed. errno: %d %s\n", - panname, test_out_dir, errno, strerror(errno)); - exit(1); - } - if (!S_ISDIR(sbuf.st_mode)) { - fprintf(stderr, "pan(%s): -O arg '%s' must be a directory.\n", - panname, test_out_dir); - exit(1); - } - if (access(test_out_dir, W_OK | R_OK | X_OK) < 0) { - fprintf(stderr, - "pan(%s): permission denied on -O arg '%s'. errno: %d %s\n", - panname, test_out_dir, errno, strerror(errno)); - exit(1); - } - } - - if (outputfilename) { - if (!freopen(outputfilename, "a+", stdout)) { - fprintf(stderr, - "pan(%s): Error %s (%d) openning output file '%s'\n", - panname, strerror(errno), errno, outputfilename); - exit(1); - } - } - - if (failcmdfilename) { - if (!(failcmdfile = fopen(failcmdfilename, "a+"))) { - fprintf(stderr, - "pan(%s): Error %s (%d) opening fail cmd file '%s'\n", - panname, strerror(errno), errno, failcmdfilename); - exit(1); - } - } - - if ((zoofile = zoo_open(zooname)) == NULL) { - fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); - exit(1); - } - if (zoo_mark_args(zoofile, getpid(), panname, argc, argv)) { - fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); - exit(1); - } - - /* Allocate N spaces for max-arg commands. - * this is an "active file cleanliness" thing - */ - { - char *av[2], bigarg[82]; - - memset(bigarg, '.', 81); - bigarg[81] = '\0'; - av[0] = bigarg; - av[1] = NULL; - - for (c = 0; c < keep_active; c++) { - if (zoo_mark_cmdline(zoofile, c, panname, "")) { - fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); - exit(1); - } - } - for (c = 0; c < keep_active; c++) { - if (zoo_clear(zoofile, c)) { - fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); - exit(1); - } - } - } - - rec_signal = send_signal = 0; - if (run_time != -1) { alarm(run_time); } - - sigemptyset(&sa.sa_mask); - sa.sa_flags = 0; - sa.sa_handler = wait_handler; - - sigaction(SIGALRM, &sa, NULL); - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); - sigaction(SIGHUP, &sa, NULL); - sigaction(SIGUSR1, &sa, NULL); /* ignore fork_in_road */ - sigaction(SIGUSR2, &sa, NULL); /* stop the scheduler */ - - c = 0; /* in this loop, c is the command index */ - stop = 0; - exit_stat = 0; - go_idle = 0; - while (1) { - - while ((num_active < keep_active) && (starts != 0)) { - if (stop || rec_signal || go_idle) - break; - - if (!sequential) - c = lrand48() % coll->cnt; - - /* find a slot for the child */ - for (i = 0; i < keep_active; ++i) { - if (running[i].pgrp == 0) - break; - } - if (i == keep_active) { - fprintf(stderr, "pan(%s): Aborting: i == keep_active = %d\n", - panname, i); - wait_handler(SIGINT); - exit_stat++; - break; - } - - cpid = run_child(coll->ary[c], running + i, quiet_mode); - if (cpid != -1) - ++num_active; - if ((cpid != -1 || sequential) && starts > 0) - --starts; - - if (sequential) - if (++c >= coll->cnt) - c = 0; - - } /* while( (num_active < keep_active) && (starts != 0) ) */ - - if (starts == 0) - { - if (!quiet_mode) - printf("incrementing stop\n"); - ++stop; - } - else if (starts == -1) //wjh - { - FILE *f = (FILE*)-1; - if ((f = fopen(PAN_STOP_FILE, "r")) != 0) - { printf("Got %s Stopping!\n", PAN_STOP_FILE); - fclose(f); unlink(PAN_STOP_FILE); stop++; - } - } - - if (rec_signal) { - /* propagate everything except sigusr2 */ - - if (rec_signal == SIGUSR2) { - if (fork_in_road) - ++go_idle; - else - ++stop; - rec_signal = send_signal = 0; - } else { - if (rec_signal == SIGUSR1) - fork_in_road = 0; - propagate_signal(running, keep_active, orphans); - if (fork_in_road) - ++go_idle; - else - ++stop; - } - } - - err = check_pids(running, &num_active, keep_active, logfile, - failcmdfile, orphans, fmt_print, &failcnt, quiet_mode); - if (Debug & Drunning) { - pids_running(running, keep_active); - orphans_running(orphans); - } - if (err) { - if (fork_in_road) - ++go_idle; - if (track_exit_stats) - exit_stat++; - if (has_brakes) { - fprintf(stderr, "pan(%s): All stop!%s\n", panname, - go_idle ? " (idling)" : ""); - wait_handler(SIGINT); - } - } - - if (stop && (num_active == 0)) - break; - - if (go_idle && (num_active == 0)) { - go_idle = 0; /* It is idle, now resume scheduling. */ - wait_handler(0); /* Reset the signal ratchet. */ - } - } - - /* Wait for orphaned pgrps */ - while (1) { - for (orph = orphans; orph != NULL; orph = orph->next) { - if (orph->pgrp == 0) - continue; - /* Yes, we have orphaned pgrps */ - sleep(5); - if (!rec_signal) { - /* force an artificial signal, move us - * through the signal ratchet. - */ - wait_handler(SIGINT); - } - propagate_signal(running, keep_active, orphans); - if (Debug & Drunning) - orphans_running(orphans); - break; - } - if (orph == NULL) - break; - } - - if (zoo_clear(zoofile, getpid())) { - fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); - ++exit_stat; - } - fclose(zoofile); - if (logfile && fmt_print) - { - if (uname(&unamebuf) == -1) - fprintf(stderr, "ERROR: uname(): %s\n", strerror(errno)); - fprintf(logfile, "\n-----------------------------------------------\n"); - fprintf(logfile, "Total Tests: %d\n", coll->cnt); - fprintf(logfile, "Total Failures: %d\n", failcnt); - fprintf(logfile, "Kernel Version: %s\n", unamebuf.release); - fprintf(logfile, "Machine Architecture: %s\n", unamebuf.machine); - fprintf(logfile, "Hostname: %s\n\n", unamebuf.nodename); - } - if (logfile && (logfile != stdout)) - fclose(logfile); - - exit(exit_stat); -} - - - -static void -propagate_signal(struct tag_pgrp *running, int keep_active, - struct orphan_pgrp *orphans) -{ - int i; - - if (Debug & Dshutdown) - fprintf(stderr, "pan was signaled with sig %d...\n", rec_signal); - - if (rec_signal == SIGALRM) - { - printf("PAN stop Alarm was received\n"); - rec_signal = SIGTERM; - } - - for (i = 0; i < keep_active; ++i) { - if (running[i].pgrp == 0) - continue; - - if (Debug & Dshutdown) - fprintf(stderr, " propagating sig %d to %d\n", - send_signal, -running[i].pgrp); - if (kill(-running[i].pgrp, send_signal) != 0) { - fprintf(stderr, - "pan(%s): kill(%d,%d) failed on tag (%s). errno:%d %s\n", - panname, -running[i].pgrp, send_signal, - running[i].cmd->name, errno, strerror(errno)); - } - running[i].stopping = 1; - } - - check_orphans(orphans, send_signal); - - rec_signal = send_signal = 0; -} - - -static int -check_pids(struct tag_pgrp *running, int *num_active, int keep_active, - FILE * logfile, FILE * failcmdfile, struct orphan_pgrp *orphans, - int fmt_print, int *failcnt, int quiet_mode) -{ - int w; - pid_t cpid; - int stat_loc; - int ret = 0; - int i; - time_t t; - char *status; - int signaled = 0; - struct tms tms1, tms2; - clock_t tck; - - check_orphans(orphans, 0); - - tck = times(&tms1); - if (tck == -1) { - fprintf(stderr, "pan(%s): times(&tms1) failed. errno:%d %s\n", - panname, errno, strerror(errno)); - } - cpid = wait(&stat_loc); - tck = times(&tms2); - if (tck == -1) { - fprintf(stderr, "pan(%s): times(&tms2) failed. errno:%d %s\n", - panname, errno, strerror(errno)); - } - - if (cpid < 0) { - if (errno == EINTR) { - if (Debug) - fprintf(stderr, "pan(%s): wait() interrupted\n", panname); - } else if (errno != ECHILD) { - fprintf(stderr, "pan(%s): wait() failed. errno:%d %s\n", - panname, errno, strerror(errno)); - } - } else if (cpid > 0) { - - if (WIFSIGNALED(stat_loc)) { - w = WTERMSIG(stat_loc); - status = "signaled"; - if (Debug & Dexit) - fprintf(stderr, "child %d terminated with signal %d\n", cpid, - w); - --*num_active; - signaled = 1; - } else if (WIFEXITED(stat_loc)) { - w = WEXITSTATUS(stat_loc); - status = "exited"; - if (Debug & Dexit) - fprintf(stderr, "child %d exited with status %d\n", cpid, w); - --*num_active; - if (w != 0) - ret++; - } else if (WIFSTOPPED(stat_loc)) { /* should never happen */ - w = WSTOPSIG(stat_loc); - status = "stopped"; - ret++; - } else { /* should never happen */ - w = 0; - status = "unknown"; - ret++; - } - - for (i = 0; i < keep_active; ++i) { - if (running[i].pgrp == cpid) { - if ((w == 130) && running[i].stopping && - (strcmp(status, "exited") == 0)) { - /* The child received sigint, but - * did not trap for it? Compensate - * for it here. - */ - w = 0; - ret--; /* undo */ - if (Debug & Drunning) - fprintf(stderr, - "pan(%s): tag=%s exited 130, known to be signaled; will give it an exit 0.\n", - panname, running[i].cmd->name); - } - time(&t); - if (logfile != NULL) { - if (!fmt_print) - fprintf(logfile, - "tag=%s stime=%d dur=%d exit=%s stat=%d core=%s cu=%d cs=%d\n", - running[i].cmd->name, (int) (running[i].mystime), - (int) (t - running[i].mystime), status, w, - (stat_loc & 0200) ? "yes" : "no", - (int) (tms2.tms_cutime - tms1.tms_cutime), - (int) (tms2.tms_cstime - tms1.tms_cstime)); - else - { - if (w != 0) - ++*failcnt; - fprintf(logfile, "%-30.30s %-10.10s %-5d\n", - running[i].cmd->name, ((w != 0) ? "FAIL" : "PASS"), - w); - } - - fflush(logfile); - } - - if ((failcmdfile != NULL) && (w !=0)) { - fprintf(failcmdfile, "%s %s\n", running[i].cmd->name, running[i].cmd->cmdline); - } - - if (running[i].stopping) - status = "driver_interrupt"; - - if (test_out_dir) { - if (!quiet_mode) - write_test_start(running+i, "ok"); - copy_buffered_output(running + i); - unlink(running[i].output); - } - if (!quiet_mode) - write_test_end(running+i, t, status, - stat_loc, w, &tms1, &tms2); - - /* If signaled and we weren't expecting - * this to be stopped then the proc - * had a problem. - */ - if (signaled && !running[i].stopping) - ret++; - - running[i].pgrp = 0; - if (zoo_clear(zoofile, cpid)) { - fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); - exit(1); - } - - /* Check for orphaned pgrps */ - if ((kill(-cpid, 0) == 0) || (errno == EPERM)) { - if (zoo_mark_cmdline(zoofile, cpid, "panorphan", - running[i].cmd->cmdline)) { - fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); - exit(1); - } - mark_orphan(orphans, cpid); - /* status of kill doesn't matter */ - kill(-cpid, SIGTERM); - } - - break; - } - } - } - return ret; -} - - -static pid_t -run_child(struct coll_entry *colle, struct tag_pgrp *active, int quiet_mode) -{ - int cpid; - int c_stdout = -1; /* child's stdout, stderr */ - int capturing = 0; /* output is going to a file instead of stdout */ - char *c_cmdline; - static long cmdno = 0; - int errpipe[2]; /* way to communicate to parent that the tag */ - char errbuf[1024]; /* didn't actually start */ - int errlen; - - /* Try to open the file that will be stdout for the test */ - if (test_out_dir) { - capturing = 1; - do { - sprintf(active->output, "%s/%s.%ld", - test_out_dir, colle->name, cmdno++); - c_stdout = open(active->output, O_CREAT | O_RDWR | O_EXCL | O_SYNC, 0666); - } while (c_stdout < 0 && errno == EEXIST); - if (c_stdout < 0) { - fprintf(stderr, - "pan(%s): open of stdout file failed (tag %s). errno: %d %s\n file: %s\n", - panname, colle->name, errno, strerror(errno), - active->output); - return -1; - } - } - - /* get the tag's command line arguments ready. subst_pcnt_f() uses a - * static counter, that's why we do it here instead of after we fork. - */ - if (colle->pcnt_f) { - c_cmdline = subst_pcnt_f(colle); - } else { - c_cmdline = colle->cmdline; - } - - if (pipe(errpipe) < 0) { - fprintf(stderr, "pan(%s): pipe() failed. errno:%d %s\n", - panname, errno, strerror(errno)); - if (capturing) { - close(c_stdout); - unlink(active->output); - } - return -1; - } - - if ((cpid = fork()) < 0) { - fprintf(stderr, "pan(%s): fork failed (tag %s). errno:%d %s\n", - panname, colle->name, errno, strerror(errno)); - if (capturing) { - unlink(active->output); - close(c_stdout); - } - close(errpipe[0]); - close(errpipe[1]); - return -1; - } else if (cpid == 0) { - /* child */ - - fclose(zoofile); - close(errpipe[0]); - fcntl(errpipe[1], F_SETFD, 1); /* close the pipe if we succeed */ - setpgrp(); - - umask(0); - - /* if we're putting output into a buffer file, we need to do the - * redirection now. If we fail - */ - if (capturing) { - if (dup2(c_stdout, fileno(stdout)) == -1) { - errlen = sprintf(errbuf, "pan(%s): couldn't redirect stdout for tag %s. errno:%d %s", - panname, colle->name, errno, strerror(errno)); - write(errpipe[1], &errlen, sizeof(errlen)); - write(errpipe[1], errbuf, errlen); - exit(2); - } - if (dup2(c_stdout, fileno(stderr)) == -1) { - errlen = sprintf(errbuf, "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s", - panname, colle->name, errno, strerror(errno)); - write(errpipe[1], &errlen, sizeof(errlen)); - write(errpipe[1], errbuf, errlen); - exit(2); - } - } else { /* stderr still needs to be redirected */ - if (dup2(fileno(stdout), fileno(stderr)) == -1) { - errlen = sprintf(errbuf, "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s", - panname, colle->name, errno, strerror(errno)); - write(errpipe[1], &errlen, sizeof(errlen)); - write(errpipe[1], errbuf, errlen); - exit(2); - } - } - /* If there are any shell-type characters in the cmdline - * such as '>', '<', '$', '|', etc, then we exec a shell and - * run the cmd under a shell. - * - * Otherwise, break the cmdline at white space and exec the - * cmd directly. - */ - if (strpbrk(c_cmdline, "\"';|<>$\\")) { - execlp("sh", "sh", "-c", c_cmdline, (char*)0); - errlen = sprintf(errbuf, - "pan(%s): execlp of '%s' (tag %s) failed. errno:%d %s", - panname, c_cmdline, colle->name, errno, strerror(errno)); - } else { - char **arg_v; - - arg_v = (char **)splitstr(c_cmdline, NULL, NULL); - - execvp(arg_v[0], arg_v); - errlen = sprintf(errbuf, - "pan(%s): execvp of '%s' (tag %s) failed. errno:%d %s", - panname, arg_v[0], colle->name, errno, strerror(errno)); - } - write(errpipe[1], &errlen, sizeof(errlen)); - write(errpipe[1], errbuf, errlen); - exit(errno); - } - - /* parent */ - - /* subst_pcnt_f() allocates the command line dynamically - * free the malloc to prevent a memory leak - */ - if (colle->pcnt_f) free(c_cmdline); - - close(errpipe[1]); - time(&active->mystime); - active->cmd = colle; - - /* if the child couldn't go through with the exec, - * clean up the mess, note it, and move on - */ - if(read(errpipe[0], &errlen, sizeof(errlen))) { - int status; - time_t end_time; - int termid; - char *termtype; - struct tms notime = {0, 0, 0, 0}; - - read(errpipe[0], errbuf, errlen); - close(errpipe[0]); - errbuf[errlen] = '\0'; - /* fprintf(stderr, "%s", errbuf); */ - waitpid(cpid, &status, 0); - if (WIFSIGNALED(status)) { - termid = WTERMSIG(status); - termtype = "signaled"; - } else if (WIFEXITED(status)) { - termid = WEXITSTATUS(status); - termtype = "exited"; - } else if (WIFSTOPPED(status)) { - termid = WSTOPSIG(status); - termtype = "stopped"; - } else { - termid = 0; - termtype = "unknown"; - } - time(&end_time); - if (!quiet_mode) - { - write_test_start(active, errbuf); - write_test_end(active, end_time, termtype, status, - termid, ¬ime, ¬ime); - } - if (capturing) { - close(c_stdout); - unlink(active->output); - } - return -1; - } - - close(errpipe[0]); - if (capturing) close(c_stdout); - - if (!test_out_dir) - if (!quiet_mode) - write_test_start(active, "ok"); - - active->pgrp = cpid; - active->stopping = 0; - - if (zoo_mark_cmdline(zoofile, cpid, colle->name, colle->cmdline)) { - fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); - exit(1); - } - - if (Debug & Dstartup) - fprintf(stderr, "started %s cpid=%d at %s", - colle->name, cpid, ctime(&active->mystime)); - - if (Debug & Dstart) { - fprintf(stderr, "Executing test = %s as %s", colle->name, colle->cmdline); - if (capturing) - fprintf(stderr, "with output file = %s\n", active->output); - else - fprintf(stderr, "\n"); - } - - return cpid; -} - - -static char * -subst_pcnt_f(struct coll_entry *colle) -{ - static int counter = 1; - char pid_and_counter[20]; - char new_cmdline[1024]; - - /* if we get called falsely, do the right thing anyway */ - if (!colle->pcnt_f) - return colle->cmdline; - - snprintf(pid_and_counter, 20, "%d_%d", getpid(), counter++); - snprintf(new_cmdline, 1024, colle->cmdline, pid_and_counter); - return strdup(new_cmdline); -} - -static struct collection * -get_collection(char *file, int optind, int argc, char **argv) -{ - char *buf, *a, *b; - struct coll_entry *head, *p, *n; - struct collection *coll; - int i; - - buf = slurp(file); - if(!buf) - return NULL; - - coll = (struct collection *) malloc(sizeof(struct collection)); - coll->cnt = 0; - - head = p = n = NULL; - a = b = buf; - while (a) { - /* set b to the start of the next line and add a NULL character - * to separate the two lines */ - if ((b = strchr(a, '\n')) != NULL) - *b++ = '\0'; - - /* If this is line isn't a comment */ - if ((*a != '#') && (*a != '\0') && (*a != ' ')) { - n = (struct coll_entry *) malloc(sizeof(struct coll_entry)); - if ((n->pcnt_f = strstr(a, "%f"))) { - n->pcnt_f[1] = 's'; - } - n->name = strdup(strsep(&a, " \t")); - n->cmdline = strdup(a); - n->next = NULL; - - if (p) { - p->next = n; - } - if (head == NULL) { - head = n; - } - p = n; - coll->cnt++; - } - a = b; - } - free(buf); - - /* is there something on the commandline to be counted? */ - if (optind < argc) { - char workstr[1024] = ""; - int workstr_left = 1023; - - /* fill arg list */ - for (i = 0; optind < argc; ++optind, ++i) { - strncat(workstr, argv[optind], workstr_left); - workstr_left = workstr_left - strlen(argv[optind]); - strncat(workstr, " ", workstr_left); - workstr_left--; - } - - n = (struct coll_entry *) malloc(sizeof(struct coll_entry)); - if ((n->pcnt_f = strstr(workstr, "%f"))) { - n->pcnt_f[1] = 's'; - } - n->cmdline = strdup(workstr); - n->name = "cmdln"; - n->next = NULL; - if (p) { - p->next = n; - } - if (head == NULL) { - head = n; - } - coll->cnt++; - } - - /* get an array */ - coll->ary = (struct coll_entry **) malloc(coll->cnt * - sizeof(struct coll_entry *)); - - /* fill the array */ - i = 0; - n = head; - while (n != NULL) { - coll->ary[i] = n; - n = n->next; - ++i; - } - if (i != coll->cnt) - fprintf(stderr, "pan(%s): i doesn't match cnt\n", panname); - - return coll; -} - - -static char * -slurp(char *file) -{ - char *buf; - int fd; - struct stat sbuf; - - if ((fd = open(file, O_RDONLY)) < 0) { - fprintf(stderr, "pan(%s): open(%s,O_RDONLY) failed. errno:%d %s\n", - panname, file, errno, strerror(errno)); - return NULL; - } - - if (fstat(fd, &sbuf) < 0) { - fprintf(stderr, "pan(%s): fstat(%s) failed. errno:%d %s\n", - panname, file, errno, strerror(errno)); - return NULL; - } - - buf = (char *) malloc(sbuf.st_size + 1); - if (read(fd, buf, sbuf.st_size) != sbuf.st_size) { - fprintf(stderr, "pan(%s): slurp failed. errno:%d %s\n", - panname, errno, strerror(errno)); - return NULL; - } - buf[sbuf.st_size] = '\0'; - - close(fd); - return buf; -} - -static void -check_orphans(struct orphan_pgrp *orphans, int sig) -{ - struct orphan_pgrp *orph; - - for (orph = orphans; orph != NULL; orph = orph->next) { - if (orph->pgrp == 0) - continue; - - if (Debug & Dshutdown) - fprintf(stderr, " propagating sig %d to orphaned pgrp %d\n", - sig, -(orph->pgrp)); - if (kill(-(orph->pgrp), sig) != 0) { - if (errno == ESRCH) { - /* This pgrp is now empty */ - if (zoo_clear(zoofile, orph->pgrp)) { - fprintf(stderr, "pan(%s): %s\n", panname, zoo_error); - } - orph->pgrp = 0; - } else { - fprintf(stderr, - "pan(%s): kill(%d,%d) on orphaned pgrp failed. errno:%d %s\n", - panname, -(orph->pgrp), sig, errno, strerror(errno)); - } - } - } -} - - -static void -mark_orphan(struct orphan_pgrp *orphans, pid_t cpid) -{ - struct orphan_pgrp *orph; - - for (orph = orphans; orph != NULL; orph = orph->next) { - if (orph->pgrp == 0) - break; - } - if (orph == NULL) { - /* make a new struct */ - orph = (struct orphan_pgrp *) malloc(sizeof(struct orphan_pgrp)); - - /* plug in the new struct just after the head */ - orph->next = orphans->next; - orphans->next = orph; - } - orph->pgrp = cpid; -} - - - -static void -copy_buffered_output(struct tag_pgrp *running) -{ - char *tag_output; - - tag_output = slurp(running->output); - if (tag_output) { - printf("%s", tag_output); - /* make sure the output ends with a newline */ - if (tag_output[strlen(tag_output) - 1] != '\n') - printf("\n"); - fflush(stdout); - free(tag_output); - } -} - - -static void -write_test_start(struct tag_pgrp *running, const char *init_status) -{ - if (!strcmp(reporttype, "rts")) { - - printf("%s\ntag=%s stime=%ld\ncmdline=\"%s\"\ncontacts=\"%s\"\nanalysis=%s\ninitiation_status=\"%s\"\n%s\n", - "<<<test_start>>>", - running->cmd->name, running->mystime, running->cmd->cmdline, "", - "exit", init_status, - "<<<test_output>>>"); - } - fflush(stdout); -} - - -static void -write_test_end(struct tag_pgrp *running, time_t exit_time, - char *term_type, int stat_loc, int term_id, - struct tms *tms1, struct tms *tms2) -{ - if (!strcmp(reporttype, "rts")) { - printf("%s\nduration=%ld termination_type=%s termination_id=%d corefile=%s\ncutime=%d cstime=%d\n%s\n", - "<<<execution_status>>>", - (long) (exit_time - running->mystime), - term_type, term_id, (stat_loc & 0200) ? "yes" : "no", - (int) (tms2->tms_cutime - tms1->tms_cutime), - (int) (tms2->tms_cstime - tms1->tms_cstime), - "<<<test_end>>>"); - } - fflush(stdout); -} - -/* The functions below are all debugging related */ - -static void -pids_running(struct tag_pgrp *running, int keep_active) -{ - int i; - - fprintf(stderr, "pids still running: "); - for (i = 0; i < keep_active; ++i) { - if (running[i].pgrp != 0) - fprintf(stderr, "%d ", running[i].pgrp); - } - fprintf(stderr, "\n"); -} - -static void -orphans_running(struct orphan_pgrp *orphans) -{ - struct orphan_pgrp *orph; - - fprintf(stderr, "orphans still running: "); - for (orph = orphans; orph != NULL; orph = orph->next) { - if (orph->pgrp != 0) - fprintf(stderr, "%d ", -(orph->pgrp)); - } - fprintf(stderr, "\n"); -} - -static void -dump_coll(struct collection *coll) -{ - int i; - - for (i = 0; i < coll->cnt; ++i) { - fprintf(stderr, "coll %d\n", i); - fprintf(stderr, " name=%s cmdline=%s\n", coll->ary[i]->name, - coll->ary[i]->cmdline); - } -} - -void -wait_handler( int sig ) -{ - static int lastsent = 0; - - if( sig == 0 ){ - lastsent = 0; - } else { - rec_signal = sig; - if( sig == SIGUSR2 ) - return; - if( lastsent == 0 ) - send_signal = sig; - else if( lastsent == SIGUSR1 ) - send_signal = SIGINT; - else if( lastsent == sig ) - send_signal = SIGTERM; - else if( lastsent == SIGTERM ) - send_signal = SIGHUP; - else if( lastsent == SIGHUP ) - send_signal = SIGKILL; - lastsent = send_signal; - } -} |