2 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
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.
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.
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.
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., 59
21 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
23 * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24 * Mountain View, CA 94043, or:
28 * For further information regarding this notice, see:
30 * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
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
39 * 01/27/03 - Added: Manoj Iyer, manjo@mail.utexas.edu
40 * - added code to print system information
42 * 01/28/03 - Added: Manoj Iyer, manjo@mail.utexas.edu
43 * - added code to print test exit value.
45 * 01/29/03 - Added: Manoj Iyer, manjo@mail.utexas.edu
46 * - added code supresses test start and test end tags.
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.
52 /* $Id: ltp-pan.c,v 1.4 2009/10/15 18:45:55 yaberauneya Exp $ */
56 #include <sys/param.h>
57 #include <sys/types.h>
58 #include <sys/times.h>
64 #include <sys/utsname.h>
69 /* One entry in the command line collection. */
72 char *name
; /* tag name */
73 char *cmdline
; /* command line */
74 char *pcnt_f
; /* location of %f in the command line args, flag */
75 struct coll_entry
*next
;
81 struct coll_entry
**ary
;
89 struct coll_entry
*cmd
;
90 char output
[PATH_MAX
];
96 struct orphan_pgrp
*next
;
99 static pid_t
run_child(struct coll_entry
*colle
, struct tag_pgrp
*active
,
101 static char *slurp(char *file
);
102 static struct collection
*get_collection(char *file
, int optind
, int argc
,
104 static void pids_running(struct tag_pgrp
*running
, int keep_active
);
105 static int check_pids(struct tag_pgrp
*running
, int *num_active
,
106 int keep_active
, FILE * logfile
, FILE * failcmdfile
,
107 struct orphan_pgrp
*orphans
, int fmt_print
,
108 int *failcnt
, int quiet_mode
);
109 static void propagate_signal(struct tag_pgrp
*running
, int keep_active
,
110 struct orphan_pgrp
*orphans
);
111 static void dump_coll(struct collection
*coll
);
112 static char *subst_pcnt_f(struct coll_entry
*colle
);
113 static void mark_orphan(struct orphan_pgrp
*orphans
, pid_t cpid
);
114 static void orphans_running(struct orphan_pgrp
*orphans
);
115 static void check_orphans(struct orphan_pgrp
*orphans
, int sig
);
117 static void copy_buffered_output(struct tag_pgrp
*running
);
118 static void write_test_start(struct tag_pgrp
*running
);
119 static void write_test_end(struct tag_pgrp
*running
, const char *init_status
,
120 time_t exit_time
, char *term_type
, int stat_loc
,
121 int term_id
, struct tms
*tms1
, struct tms
*tms2
);
124 static char PAN_STOP_FILE
[] = "PAN_STOP_FILE";
126 static char *panname
= NULL
;
127 static char *test_out_dir
= NULL
; /* dir to buffer output to */
129 static char *reporttype
= NULL
;
132 int rec_signal
; /* received signal */
133 int send_signal
; /* signal to send */
137 #define Dbuffile 0x000400 /* buffer file use */
138 #define Dsetup 0x000200 /* one-time set-up */
139 #define Dshutdown 0x000100 /* killed by signal */
140 #define Dexit 0x000020 /* exit status */
141 #define Drunning 0x000010 /* current pids running */
142 #define Dstartup 0x000004 /* started command */
143 #define Dstart 0x000002 /* started command */
144 #define Dwait 0x000001 /* wait interrupted */
147 main(int argc
, char **argv
)
151 char *zooname
= NULL
; /* name of the zoo file to use */
152 char *filename
= "/dev/null"; /* filename to read test tags from */
153 char *logfilename
= NULL
;
154 char *failcmdfilename
= NULL
;
155 char *outputfilename
= NULL
;
156 struct collection
*coll
= NULL
;
157 struct tag_pgrp
*running
;
158 struct orphan_pgrp
*orphans
, *orph
;
159 struct utsname unamebuf
;
160 FILE *logfile
= NULL
;
161 FILE *failcmdfile
= NULL
;
164 int failcnt
= 0; /* count of total testcases that failed. */
168 int run_time
= -1; char modifier
= 'm'; int ret
= 0;
171 int has_brakes
= 0; /* stop everything if a test case fails */
172 int sequential
= 0; /* run tests sequentially */
173 int fork_in_road
= 0;
175 int track_exit_stats
= 0; /* exit non-zero if any test exits non-zero */
176 int fmt_print
= 0; /* enables formatted printing of logfiles. */
177 int quiet_mode
= 0; /* supresses test start and test end tags. */
182 while ((c
= getopt(argc
, argv
, "AO:Sa:C:d:ef:hl:n:o:pqr:s:t:x:y")) != -1) {
184 case 'A': /* all-stop flag */
186 track_exit_stats
= 1;
188 case 'O': /* output buffering directory */
189 test_out_dir
= strdup(optarg
);
191 case 'S': /* run tests sequentially */
194 case 'a': /* name of the zoo file to use */
195 zooname
= strdup(optarg
);
197 case 'C': /* name of the file where all failed commands will be */
198 failcmdfilename
= strdup(optarg
);
200 case 'd': /* debug options */
201 sscanf(optarg
, "%i", &Debug
);
203 case 'e': /* exit non-zero if any test exists non-zero */
204 track_exit_stats
= 1;
206 case 'f': /* filename to read test tags from */
207 filename
= strdup(optarg
);
210 fprintf(stdout
, "Usage: pan -n name [ -SyAehpq ] [ -s starts ]"
211 " [-t time[s|m|h|d] [ -x nactive ] [ -l logfile ]\n\t"
212 "[ -a active-file ] [ -f command-file ] "
213 "[ -C fail-command-file ] "
214 "[ -d debug-level ]\n\t[-o output-file] "
215 "[-O output-buffer-directory] [cmd]\n");
217 case 'l': /* log file */
218 logfilename
= strdup(optarg
);
220 case 'n': /* tag given to pan */
221 panname
= strdup(optarg
);
223 case 'o': /* send test output here */
224 outputfilename
= strdup(optarg
);
226 case 'p': /* formatted printing. */
229 case 'q': /* supress test start and test end messages */
232 case 'r': /* reporting type: none, rts */
233 reporttype
= strdup(optarg
);
235 case 's': /* number of tags to run */
236 starts
= atoi(optarg
);
238 case 't': /* run_time to run */
239 ret
= sscanf(optarg
, "%d%c", &run_time
, &modifier
);
240 if (ret
== 0) { fprintf(stderr
, "Need proper time input: ####x where"
241 "x is one of s,m,h,d\n"); break; }
242 else if (ret
== 1) { fprintf(stderr
, "Only got a time value of %d "
243 "modifiers need to come immediately after #"
244 " assuming %c\n", run_time
, modifier
); }
249 case 's': run_time
= run_time
; break;
250 case 'm': run_time
= run_time
* 60; break;
251 case 'h': run_time
= run_time
* 60 * 60; break;
252 case 'd': run_time
= run_time
* 60 * 60 * 24; break;
254 fprintf(stderr
, "Invalid time modifier, try: s|h|m|d\n"); exit(-1);
257 printf("PAN will run for %d seconds\n", run_time
);
259 timed
= 1; //-t implies run as many starts as possible, by default
261 case 'x': /* number of tags to keep running */
262 keep_active
= atoi(optarg
);
264 case 'y': /* restart on failure or signal */
270 if (panname
== NULL
) {
271 fprintf(stderr
, "pan: Must supply -n\n");
274 if (zooname
== NULL
) {
275 zooname
= zoo_getname();
276 if (zooname
== NULL
) {
278 "pan(%s): Must supply -a or set ZOO env variable\n",
284 /* make sure we understand the report type */
285 if (strcasecmp(reporttype
, "rts")
286 && strcasecmp(reporttype
, "none")
287 /* && strcasecmp(reporttype, "xml")*/)
290 /* set the default */
294 if (logfilename
!= NULL
) {
298 if (!strcmp(logfilename
, "-")) {
301 if ((logfile
= fopen(logfilename
, "a+")) == NULL
) {
303 "pan(%s): Error %s (%d) opening log file '%s'\n",
304 panname
, strerror(errno
), errno
, logfilename
);
311 *(s
+ strlen(s
) - 1) = '\0';
313 fprintf(logfile
, "startup='%s'\n", s
);
316 fprintf(logfile
, "Test Start Time: %s\n", s
);
317 fprintf(logfile
, "-----------------------------------------\n");
318 fprintf(logfile
, "%-30.20s %-10.10s %-10.10s\n",
319 "Testcase", "Result", "Exit Value");
320 fprintf(logfile
, "%-30.20s %-10.10s %-10.10s\n",
321 "--------", "------", "------------");
325 coll
= get_collection(filename
, optind
, argc
, argv
);
328 if (coll
->cnt
== 0) {
330 "pan(%s): Must supply a file collection or a command\n",
338 /* a place to store the pgrps we're watching */
339 running
= (struct tag_pgrp
*)malloc((keep_active
+ 1) * sizeof(struct tag_pgrp
));
340 if (running
== NULL
) {
341 fprintf(stderr
, "pan(%s): Failed to allocate memory: %s\n", panname
,
345 memset(running
, 0, keep_active
* sizeof(struct tag_pgrp
));
346 running
[keep_active
].pgrp
= -1; /* end sentinel */
348 /* a head to the orphaned pgrp list */
349 orphans
= (struct orphan_pgrp
*) malloc(sizeof(struct orphan_pgrp
));
350 memset(orphans
, 0, sizeof(struct orphan_pgrp
));
352 srand48(time(NULL
) ^ (getpid() + (getpid() << 15)));
354 /* Supply a default for starts. If we are in sequential mode, use
355 * the number of commands available; otherwise 1.
357 if (timed
== 1 && starts
== -1) { /* timed, infinite by default */
359 } else if (starts
== -1) {
365 } else if (starts
== 0) { /* if the user specified infinite, set it */
367 } else { /* else, make sure we are starting at least keep_active processes */
368 if (starts
< keep_active
)
369 starts
= keep_active
;
372 /* if we're buffering output, but we're only running on process at a time,
373 * then essentially "turn off buffering"
375 if (test_out_dir
&& (keep_active
== 1)) {
383 if (stat(test_out_dir
, &sbuf
) < 0) {
385 "pan(%s): stat of -O arg '%s' failed. errno: %d %s\n",
386 panname
, test_out_dir
, errno
, strerror(errno
));
389 if (!S_ISDIR(sbuf
.st_mode
)) {
390 fprintf(stderr
, "pan(%s): -O arg '%s' must be a directory.\n",
391 panname
, test_out_dir
);
394 if (access(test_out_dir
, W_OK
| R_OK
| X_OK
) < 0) {
396 "pan(%s): permission denied on -O arg '%s'. errno: %d %s\n",
397 panname
, test_out_dir
, errno
, strerror(errno
));
402 if (outputfilename
) {
403 if (!freopen(outputfilename
, "a+", stdout
)) {
405 "pan(%s): Error %s (%d) opening output file '%s'\n",
406 panname
, strerror(errno
), errno
, outputfilename
);
411 if (failcmdfilename
) {
412 if (!(failcmdfile
= fopen(failcmdfilename
, "a+"))) {
414 "pan(%s): Error %s (%d) opening fail cmd file '%s'\n",
415 panname
, strerror(errno
), errno
, failcmdfilename
);
420 if ((zoofile
= zoo_open(zooname
)) == NULL
) {
421 fprintf(stderr
, "pan(%s): %s\n", panname
, zoo_error
);
424 if (zoo_mark_args(zoofile
, getpid(), panname
, argc
, argv
)) {
425 fprintf(stderr
, "pan(%s): %s\n", panname
, zoo_error
);
429 /* Allocate N spaces for max-arg commands.
430 * this is an "active file cleanliness" thing
433 char *av
[2], bigarg
[82];
435 memset(bigarg
, '.', 81);
440 for (c
= 0; c
< keep_active
; c
++) {
441 if (zoo_mark_cmdline(zoofile
, c
, panname
, "")) {
442 fprintf(stderr
, "pan(%s): %s\n", panname
, zoo_error
);
446 for (c
= 0; c
< keep_active
; c
++) {
447 if (zoo_clear(zoofile
, c
)) {
448 fprintf(stderr
, "pan(%s): %s\n", panname
, zoo_error
);
454 rec_signal
= send_signal
= 0;
455 if (run_time
!= -1) { alarm(run_time
); }
457 sigemptyset(&sa
.sa_mask
);
459 sa
.sa_handler
= wait_handler
;
461 sigaction(SIGALRM
, &sa
, NULL
);
462 sigaction(SIGINT
, &sa
, NULL
);
463 sigaction(SIGTERM
, &sa
, NULL
);
464 sigaction(SIGHUP
, &sa
, NULL
);
465 sigaction(SIGUSR1
, &sa
, NULL
); /* ignore fork_in_road */
466 sigaction(SIGUSR2
, &sa
, NULL
); /* stop the scheduler */
468 c
= 0; /* in this loop, c is the command index */
474 while ((num_active
< keep_active
) && (starts
!= 0)) {
475 if (stop
|| rec_signal
|| go_idle
)
479 c
= lrand48() % coll
->cnt
;
481 /* find a slot for the child */
482 for (i
= 0; i
< keep_active
; ++i
) {
483 if (running
[i
].pgrp
== 0)
486 if (i
== keep_active
) {
487 fprintf(stderr
, "pan(%s): Aborting: i == keep_active = %d\n",
489 wait_handler(SIGINT
);
494 cpid
= run_child(coll
->ary
[c
], running
+ i
, quiet_mode
);
497 if ((cpid
!= -1 || sequential
) && starts
> 0)
501 if (++c
>= coll
->cnt
)
504 } /* while( (num_active < keep_active) && (starts != 0) ) */
509 printf("incrementing stop\n");
512 else if (starts
== -1) //wjh
515 if ((f
= fopen(PAN_STOP_FILE
, "r")) != 0)
516 { printf("Got %s Stopping!\n", PAN_STOP_FILE
);
517 fclose(f
); unlink(PAN_STOP_FILE
); stop
++;
522 /* propagate everything except sigusr2 */
524 if (rec_signal
== SIGUSR2
) {
529 rec_signal
= send_signal
= 0;
531 if (rec_signal
== SIGUSR1
)
533 propagate_signal(running
, keep_active
, orphans
);
541 err
= check_pids(running
, &num_active
, keep_active
, logfile
,
542 failcmdfile
, orphans
, fmt_print
, &failcnt
, quiet_mode
);
543 if (Debug
& Drunning
) {
544 pids_running(running
, keep_active
);
545 orphans_running(orphans
);
550 if (track_exit_stats
)
553 fprintf(stderr
, "pan(%s): All stop!%s\n", panname
,
554 go_idle
? " (idling)" : "");
555 wait_handler(SIGINT
);
559 if (stop
&& (num_active
== 0))
562 if (go_idle
&& (num_active
== 0)) {
563 go_idle
= 0; /* It is idle, now resume scheduling. */
564 wait_handler(0); /* Reset the signal ratchet. */
568 /* Wait for orphaned pgrps */
570 for (orph
= orphans
; orph
!= NULL
; orph
= orph
->next
) {
573 /* Yes, we have orphaned pgrps */
576 /* force an artificial signal, move us
577 * through the signal ratchet.
579 wait_handler(SIGINT
);
581 propagate_signal(running
, keep_active
, orphans
);
582 if (Debug
& Drunning
)
583 orphans_running(orphans
);
590 if (zoo_clear(zoofile
, getpid())) {
591 fprintf(stderr
, "pan(%s): %s\n", panname
, zoo_error
);
595 if (logfile
&& fmt_print
)
597 if (uname(&unamebuf
) == -1)
598 fprintf(stderr
, "ERROR: uname(): %s\n", strerror(errno
));
599 fprintf(logfile
, "\n-----------------------------------------------\n");
600 fprintf(logfile
, "Total Tests: %d\n", coll
->cnt
);
601 fprintf(logfile
, "Total Failures: %d\n", failcnt
);
602 fprintf(logfile
, "Kernel Version: %s\n", unamebuf
.release
);
603 fprintf(logfile
, "Machine Architecture: %s\n", unamebuf
.machine
);
604 fprintf(logfile
, "Hostname: %s\n\n", unamebuf
.nodename
);
606 if (logfile
&& (logfile
!= stdout
))
615 propagate_signal(struct tag_pgrp
*running
, int keep_active
,
616 struct orphan_pgrp
*orphans
)
620 if (Debug
& Dshutdown
)
621 fprintf(stderr
, "pan was signaled with sig %d...\n", rec_signal
);
623 if (rec_signal
== SIGALRM
)
625 printf("PAN stop Alarm was received\n");
626 rec_signal
= SIGTERM
;
629 for (i
= 0; i
< keep_active
; ++i
) {
630 if (running
[i
].pgrp
== 0)
633 if (Debug
& Dshutdown
)
634 fprintf(stderr
, " propagating sig %d to %d\n",
635 send_signal
, -running
[i
].pgrp
);
636 if (kill(-running
[i
].pgrp
, send_signal
) != 0) {
638 "pan(%s): kill(%d,%d) failed on tag (%s). errno:%d %s\n",
639 panname
, -running
[i
].pgrp
, send_signal
,
640 running
[i
].cmd
->name
, errno
, strerror(errno
));
642 running
[i
].stopping
= 1;
645 check_orphans(orphans
, send_signal
);
647 rec_signal
= send_signal
= 0;
652 check_pids(struct tag_pgrp
*running
, int *num_active
, int keep_active
,
653 FILE * logfile
, FILE * failcmdfile
, struct orphan_pgrp
*orphans
,
654 int fmt_print
, int *failcnt
, int quiet_mode
)
664 struct tms tms1
, tms2
;
667 check_orphans(orphans
, 0);
671 fprintf(stderr
, "pan(%s): times(&tms1) failed. errno:%d %s\n",
672 panname
, errno
, strerror(errno
));
674 cpid
= wait(&stat_loc
);
677 fprintf(stderr
, "pan(%s): times(&tms2) failed. errno:%d %s\n",
678 panname
, errno
, strerror(errno
));
682 if (errno
== EINTR
) {
684 fprintf(stderr
, "pan(%s): wait() interrupted\n", panname
);
685 } else if (errno
!= ECHILD
) {
686 fprintf(stderr
, "pan(%s): wait() failed. errno:%d %s\n",
687 panname
, errno
, strerror(errno
));
689 } else if (cpid
> 0) {
691 if (WIFSIGNALED(stat_loc
)) {
692 w
= WTERMSIG(stat_loc
);
695 fprintf(stderr
, "child %d terminated with signal %d\n", cpid
,
699 } else if (WIFEXITED(stat_loc
)) {
700 w
= WEXITSTATUS(stat_loc
);
703 fprintf(stderr
, "child %d exited with status %d\n", cpid
, w
);
707 } else if (WIFSTOPPED(stat_loc
)) { /* should never happen */
708 w
= WSTOPSIG(stat_loc
);
711 } else { /* should never happen */
717 for (i
= 0; i
< keep_active
; ++i
) {
718 if (running
[i
].pgrp
== cpid
) {
719 if ((w
== 130) && running
[i
].stopping
&&
720 (strcmp(status
, "exited") == 0)) {
721 /* The child received sigint, but
722 * did not trap for it? Compensate
727 if (Debug
& Drunning
)
729 "pan(%s): tag=%s exited 130, known to be signaled; will give it an exit 0.\n",
730 panname
, running
[i
].cmd
->name
);
733 if (logfile
!= NULL
) {
736 "tag=%s stime=%d dur=%d exit=%s stat=%d core=%s cu=%d cs=%d\n",
737 running
[i
].cmd
->name
, (int) (running
[i
].mystime
),
738 (int) (t
- running
[i
].mystime
), status
, w
,
739 (stat_loc
& 0200) ? "yes" : "no",
740 (int) (tms2
.tms_cutime
- tms1
.tms_cutime
),
741 (int) (tms2
.tms_cstime
- tms1
.tms_cstime
));
746 fprintf(logfile
, "%-30.30s %-10.10s %-5d\n",
747 running
[i
].cmd
->name
, ((w
!= 0) ? "FAIL" : "PASS"),
754 if ((failcmdfile
!= NULL
) && (w
!=0)) {
755 fprintf(failcmdfile
, "%s %s\n", running
[i
].cmd
->name
, running
[i
].cmd
->cmdline
);
758 if (running
[i
].stopping
)
759 status
= "driver_interrupt";
763 write_test_start(running
+i
);
764 copy_buffered_output(running
+ i
);
765 unlink(running
[i
].output
);
768 write_test_end(running
+i
, "ok", t
, status
,
769 stat_loc
, w
, &tms1
, &tms2
);
771 /* If signaled and we weren't expecting
772 * this to be stopped then the proc
775 if (signaled
&& !running
[i
].stopping
)
779 if (zoo_clear(zoofile
, cpid
)) {
780 fprintf(stderr
, "pan(%s): %s\n", panname
, zoo_error
);
784 /* Check for orphaned pgrps */
785 if ((kill(-cpid
, 0) == 0) || (errno
== EPERM
)) {
786 if (zoo_mark_cmdline(zoofile
, cpid
, "panorphan",
787 running
[i
].cmd
->cmdline
)) {
788 fprintf(stderr
, "pan(%s): %s\n", panname
, zoo_error
);
791 mark_orphan(orphans
, cpid
);
792 /* status of kill doesn't matter */
793 kill(-cpid
, SIGTERM
);
805 run_child(struct coll_entry
*colle
, struct tag_pgrp
*active
, int quiet_mode
)
808 int c_stdout
= -1; /* child's stdout, stderr */
809 int capturing
= 0; /* output is going to a file instead of stdout */
811 static long cmdno
= 0;
812 int errpipe
[2]; /* way to communicate to parent that the tag */
813 char errbuf
[1024]; /* didn't actually start */
816 /* Try to open the file that will be stdout for the test */
820 sprintf(active
->output
, "%s/%s.%ld",
821 test_out_dir
, colle
->name
, cmdno
++);
822 c_stdout
= open(active
->output
, O_CREAT
| O_RDWR
| O_EXCL
| O_SYNC
, 0666);
823 } while (c_stdout
< 0 && errno
== EEXIST
);
826 "pan(%s): open of stdout file failed (tag %s). errno: %d %s\n file: %s\n",
827 panname
, colle
->name
, errno
, strerror(errno
),
833 /* get the tag's command line arguments ready. subst_pcnt_f() uses a
834 * static counter, that's why we do it here instead of after we fork.
837 c_cmdline
= subst_pcnt_f(colle
);
839 c_cmdline
= colle
->cmdline
;
842 if (pipe(errpipe
) < 0) {
843 fprintf(stderr
, "pan(%s): pipe() failed. errno:%d %s\n",
844 panname
, errno
, strerror(errno
));
847 unlink(active
->output
);
852 time(&active
->mystime
);
857 write_test_start(active
);
859 if ((cpid
= fork()) < 0) {
860 fprintf(stderr
, "pan(%s): fork failed (tag %s). errno:%d %s\n",
861 panname
, colle
->name
, errno
, strerror(errno
));
863 unlink(active
->output
);
869 } else if (cpid
== 0) {
874 fcntl(errpipe
[1], F_SETFD
, 1); /* close the pipe if we succeed */
879 /* if we're putting output into a buffer file, we need to do the
880 * redirection now. If we fail
883 if (dup2(c_stdout
, fileno(stdout
)) == -1) {
884 errlen
= sprintf(errbuf
, "pan(%s): couldn't redirect stdout for tag %s. errno:%d %s",
885 panname
, colle
->name
, errno
, strerror(errno
));
886 write(errpipe
[1], &errlen
, sizeof(errlen
));
887 write(errpipe
[1], errbuf
, errlen
);
890 if (dup2(c_stdout
, fileno(stderr
)) == -1) {
891 errlen
= sprintf(errbuf
, "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s",
892 panname
, colle
->name
, errno
, strerror(errno
));
893 write(errpipe
[1], &errlen
, sizeof(errlen
));
894 write(errpipe
[1], errbuf
, errlen
);
897 } else { /* stderr still needs to be redirected */
898 if (dup2(fileno(stdout
), fileno(stderr
)) == -1) {
899 errlen
= sprintf(errbuf
, "pan(%s): couldn't redirect stderr for tag %s. errno:%d %s",
900 panname
, colle
->name
, errno
, strerror(errno
));
901 write(errpipe
[1], &errlen
, sizeof(errlen
));
902 write(errpipe
[1], errbuf
, errlen
);
906 /* If there are any shell-type characters in the cmdline
907 * such as '>', '<', '$', '|', etc, then we exec a shell and
908 * run the cmd under a shell.
910 * Otherwise, break the cmdline at white space and exec the
913 if (strpbrk(c_cmdline
, "\"';|<>$\\")) {
914 execlp("sh", "sh", "-c", c_cmdline
, (char*)0);
915 errlen
= sprintf(errbuf
,
916 "pan(%s): execlp of '%s' (tag %s) failed. errno:%d %s",
917 panname
, c_cmdline
, colle
->name
, errno
, strerror(errno
));
921 arg_v
= (char **)splitstr(c_cmdline
, NULL
, NULL
);
923 execvp(arg_v
[0], arg_v
);
924 errlen
= sprintf(errbuf
,
925 "pan(%s): execvp of '%s' (tag %s) failed. errno:%d %s",
926 panname
, arg_v
[0], colle
->name
, errno
, strerror(errno
));
928 write(errpipe
[1], &errlen
, sizeof(errlen
));
929 write(errpipe
[1], errbuf
, errlen
);
935 /* subst_pcnt_f() allocates the command line dynamically
936 * free the malloc to prevent a memory leak
938 if (colle
->pcnt_f
) free(c_cmdline
);
942 /* if the child couldn't go through with the exec,
943 * clean up the mess, note it, and move on
945 if(read(errpipe
[0], &errlen
, sizeof(errlen
))) {
950 struct tms notime
= {0, 0, 0, 0};
952 read(errpipe
[0], errbuf
, errlen
);
954 errbuf
[errlen
] = '\0';
955 /* fprintf(stderr, "%s", errbuf); */
956 waitpid(cpid
, &status
, 0);
957 if (WIFSIGNALED(status
)) {
958 termid
= WTERMSIG(status
);
959 termtype
= "signaled";
960 } else if (WIFEXITED(status
)) {
961 termid
= WEXITSTATUS(status
);
963 } else if (WIFSTOPPED(status
)) {
964 termid
= WSTOPSIG(status
);
965 termtype
= "stopped";
968 termtype
= "unknown";
973 //write_test_start(active, errbuf);
974 write_test_end(active
, errbuf
, end_time
, termtype
, status
,
975 termid
, ¬ime
, ¬ime
);
979 unlink(active
->output
);
985 if (capturing
) close(c_stdout
);
988 active
->stopping
= 0;
990 if (zoo_mark_cmdline(zoofile
, cpid
, colle
->name
, colle
->cmdline
)) {
991 fprintf(stderr
, "pan(%s): %s\n", panname
, zoo_error
);
995 if (Debug
& Dstartup
)
996 fprintf(stderr
, "started %s cpid=%d at %s",
997 colle
->name
, cpid
, ctime(&active
->mystime
));
999 if (Debug
& Dstart
) {
1000 fprintf(stderr
, "Executing test = %s as %s", colle
->name
, colle
->cmdline
);
1002 fprintf(stderr
, "with output file = %s\n", active
->output
);
1004 fprintf(stderr
, "\n");
1012 subst_pcnt_f(struct coll_entry
*colle
)
1014 static int counter
= 1;
1015 char pid_and_counter
[20];
1016 char new_cmdline
[1024];
1018 /* if we get called falsely, do the right thing anyway */
1020 return colle
->cmdline
;
1022 snprintf(pid_and_counter
, 20, "%d_%d", getpid(), counter
++);
1023 snprintf(new_cmdline
, 1024, colle
->cmdline
, pid_and_counter
);
1024 return strdup(new_cmdline
);
1027 static struct collection
*
1028 get_collection(char *file
, int optind
, int argc
, char **argv
)
1031 struct coll_entry
*head
, *p
, *n
;
1032 struct collection
*coll
;
1039 coll
= (struct collection
*) malloc(sizeof(struct collection
));
1042 head
= p
= n
= NULL
;
1045 /* set b to the start of the next line and add a NULL character
1046 * to separate the two lines */
1047 if ((b
= strchr(a
, '\n')) != NULL
)
1050 /* If this is line isn't a comment */
1051 if ((*a
!= '#') && (*a
!= '\0') && (*a
!= ' ')) {
1052 n
= (struct coll_entry
*) malloc(sizeof(struct coll_entry
));
1053 if ((n
->pcnt_f
= strstr(a
, "%f"))) {
1056 n
->name
= strdup(strsep(&a
, " \t"));
1057 n
->cmdline
= strdup(a
);
1073 /* is there something on the commandline to be counted? */
1074 if (optind
< argc
) {
1075 char workstr
[1024] = "";
1076 int workstr_left
= 1023;
1079 for (i
= 0; optind
< argc
; ++optind
, ++i
) {
1080 strncat(workstr
, argv
[optind
], workstr_left
);
1081 workstr_left
= workstr_left
- strlen(argv
[optind
]);
1082 strncat(workstr
, " ", workstr_left
);
1086 n
= (struct coll_entry
*) malloc(sizeof(struct coll_entry
));
1087 if ((n
->pcnt_f
= strstr(workstr
, "%f"))) {
1090 n
->cmdline
= strdup(workstr
);
1103 coll
->ary
= (struct coll_entry
**) malloc(coll
->cnt
*
1104 sizeof(struct coll_entry
*));
1106 /* fill the array */
1115 fprintf(stderr
, "pan(%s): i doesn't match cnt\n", panname
);
1128 if ((fd
= open(file
, O_RDONLY
)) < 0) {
1129 fprintf(stderr
, "pan(%s): open(%s,O_RDONLY) failed. errno:%d %s\n",
1130 panname
, file
, errno
, strerror(errno
));
1134 if (fstat(fd
, &sbuf
) < 0) {
1135 fprintf(stderr
, "pan(%s): fstat(%s) failed. errno:%d %s\n",
1136 panname
, file
, errno
, strerror(errno
));
1140 buf
= (char *) malloc(sbuf
.st_size
+ 1);
1141 if (read(fd
, buf
, sbuf
.st_size
) != sbuf
.st_size
) {
1142 fprintf(stderr
, "pan(%s): slurp failed. errno:%d %s\n",
1143 panname
, errno
, strerror(errno
));
1146 buf
[sbuf
.st_size
] = '\0';
1153 check_orphans(struct orphan_pgrp
*orphans
, int sig
)
1155 struct orphan_pgrp
*orph
;
1157 for (orph
= orphans
; orph
!= NULL
; orph
= orph
->next
) {
1158 if (orph
->pgrp
== 0)
1161 if (Debug
& Dshutdown
)
1162 fprintf(stderr
, " propagating sig %d to orphaned pgrp %d\n",
1163 sig
, -(orph
->pgrp
));
1164 if (kill(-(orph
->pgrp
), sig
) != 0) {
1165 if (errno
== ESRCH
) {
1166 /* This pgrp is now empty */
1167 if (zoo_clear(zoofile
, orph
->pgrp
)) {
1168 fprintf(stderr
, "pan(%s): %s\n", panname
, zoo_error
);
1173 "pan(%s): kill(%d,%d) on orphaned pgrp failed. errno:%d %s\n",
1174 panname
, -(orph
->pgrp
), sig
, errno
, strerror(errno
));
1182 mark_orphan(struct orphan_pgrp
*orphans
, pid_t cpid
)
1184 struct orphan_pgrp
*orph
;
1186 for (orph
= orphans
; orph
!= NULL
; orph
= orph
->next
) {
1187 if (orph
->pgrp
== 0)
1191 /* make a new struct */
1192 orph
= (struct orphan_pgrp
*) malloc(sizeof(struct orphan_pgrp
));
1194 /* plug in the new struct just after the head */
1195 orph
->next
= orphans
->next
;
1196 orphans
->next
= orph
;
1204 copy_buffered_output(struct tag_pgrp
*running
)
1208 tag_output
= slurp(running
->output
);
1210 printf("%s", tag_output
);
1211 /* make sure the output ends with a newline */
1212 if (tag_output
[strlen(tag_output
) - 1] != '\n')
1221 write_test_start(struct tag_pgrp
*running
)
1223 if (!strcmp(reporttype
, "rts")) {
1225 printf("%s\ntag=%s stime=%ld\ncmdline=\"%s\"\ncontacts=\"%s\"\nanalysis=%s\n%s\n",
1227 running
->cmd
->name
, running
->mystime
, running
->cmd
->cmdline
, "",
1229 "<<<test_output>>>");
1236 write_test_end(struct tag_pgrp
*running
, const char *init_status
,
1237 time_t exit_time
, char *term_type
, int stat_loc
,
1238 int term_id
, struct tms
*tms1
, struct tms
*tms2
)
1240 if (!strcmp(reporttype
, "rts")) {
1241 printf("%s\ninitiation_status=\"%s\"\nduration=%ld termination_type=%s "
1242 "termination_id=%d corefile=%s\ncutime=%d cstime=%d\n%s\n",
1243 "<<<execution_status>>>", init_status
,
1244 (long) (exit_time
- running
->mystime
),
1245 term_type
, term_id
, (stat_loc
& 0200) ? "yes" : "no",
1246 (int) (tms2
->tms_cutime
- tms1
->tms_cutime
),
1247 (int) (tms2
->tms_cstime
- tms1
->tms_cstime
),
1253 /* The functions below are all debugging related */
1256 pids_running(struct tag_pgrp
*running
, int keep_active
)
1260 fprintf(stderr
, "pids still running: ");
1261 for (i
= 0; i
< keep_active
; ++i
) {
1262 if (running
[i
].pgrp
!= 0)
1263 fprintf(stderr
, "%d ", running
[i
].pgrp
);
1265 fprintf(stderr
, "\n");
1269 orphans_running(struct orphan_pgrp
*orphans
)
1271 struct orphan_pgrp
*orph
;
1273 fprintf(stderr
, "orphans still running: ");
1274 for (orph
= orphans
; orph
!= NULL
; orph
= orph
->next
) {
1275 if (orph
->pgrp
!= 0)
1276 fprintf(stderr
, "%d ", -(orph
->pgrp
));
1278 fprintf(stderr
, "\n");
1282 dump_coll(struct collection
*coll
)
1286 for (i
= 0; i
< coll
->cnt
; ++i
) {
1287 fprintf(stderr
, "coll %d\n", i
);
1288 fprintf(stderr
, " name=%s cmdline=%s\n", coll
->ary
[i
]->name
,
1289 coll
->ary
[i
]->cmdline
);
1294 wait_handler( int sig
)
1296 static int lastsent
= 0;
1302 if( sig
== SIGUSR2
)
1306 else if( lastsent
== SIGUSR1
)
1307 send_signal
= SIGINT
;
1308 else if( lastsent
== sig
)
1309 send_signal
= SIGTERM
;
1310 else if( lastsent
== SIGTERM
)
1311 send_signal
= SIGHUP
;
1312 else if( lastsent
== SIGHUP
)
1313 send_signal
= SIGKILL
;
1314 lastsent
= send_signal
;