varnish-cache/bin/varnishtest/vtc_main.c
1
/*-
2
 * Copyright (c) 2008-2011 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 */
28
29
#include "config.h"
30
31
#include <sys/mman.h>
32
#include <sys/stat.h>
33
#include <sys/wait.h>
34
35
#include <ctype.h>
36
#include <errno.h>
37
#include <poll.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <unistd.h>
42
43
#include "vtc.h"
44
45
#include "vev.h"
46
#include "vfil.h"
47
#include "vnum.h"
48
#include "vrnd.h"
49
#include "vss.h"
50
#include "vsub.h"
51
#include "vtcp.h"
52
#include "vtim.h"
53
#include "vct.h"
54
55
struct vtc_tst {
56
        unsigned                magic;
57
#define TST_MAGIC               0x618d8b88
58
        VTAILQ_ENTRY(vtc_tst)   list;
59
        const char              *filename;
60
        char                    *script;
61
        unsigned                ntodo;
62
};
63
64
struct vtc_job {
65
        unsigned                magic;
66
#define JOB_MAGIC               0x1b5fc419
67
        struct vtc_tst          *tst;
68
        pid_t                   child;
69
        struct vev              *ev;
70
        struct vev              *evt;
71
        char                    *buf;
72
        char                    *tmpdir;
73
        unsigned                bufsiz;
74
        double                  t0;
75
        struct vsb              *diag;
76
        int                     killed;
77
};
78
79
int iflg = 0;
80
unsigned vtc_maxdur = 60;
81
static unsigned vtc_bufsiz = 1024 * 1024;
82
83
static VTAILQ_HEAD(, vtc_tst) tst_head = VTAILQ_HEAD_INITIALIZER(tst_head);
84
static struct vev_root *vb;
85
static int njob = 0;
86
static int npar = 1;                    /* Number of parallel tests */
87
static int vtc_continue;                /* Continue on error */
88
static int vtc_verbosity = 1;           /* Verbosity Level */
89
static int vtc_good;
90
static int vtc_fail;
91
static int vtc_skip;
92
static char *tmppath;
93
static char *cwd = NULL;
94
char *vmod_path = NULL;
95
struct vsb *params_vsb = NULL;
96
int leave_temp;
97
int vtc_witness = 0;
98
int feature_dns;
99
100
/**********************************************************************
101
 * Parse a -D option argument into a name/val pair, and insert
102
 * into extmacro list
103
 */
104
105
static int
106 4
parse_D_opt(char *arg)
107
{
108
        char *p, *q;
109
110 4
        p = arg;
111 4
        q = strchr(p, '=');
112 4
        if (!q)
113 0
                return (0);
114 4
        *q++ = '\0';
115 4
        extmacro_def(p, "%s", q);
116
117 4
        return (1);
118
}
119
120
/**********************************************************************
121
 * Print usage
122
 */
123
124
static void
125 8
usage(void)
126
{
127 8
        fprintf(stderr, "usage: varnishtest [options] file ...\n");
128
#define FMT "    %-28s # %s\n"
129 8
        fprintf(stderr, FMT, "-b size",
130
            "Set internal buffer size (default: 1M)");
131 8
        fprintf(stderr, FMT, "-D name=val", "Define macro");
132 8
        fprintf(stderr, FMT, "-i", "Find varnish binaries in build tree");
133 8
        fprintf(stderr, FMT, "-j jobs", "Run this many tests in parallel");
134 8
        fprintf(stderr, FMT, "-k", "Continue on test failure");
135 8
        fprintf(stderr, FMT, "-L", "Always leave temporary vtc.*");
136 8
        fprintf(stderr, FMT, "-l", "Leave temporary vtc.* if test fails");
137 8
        fprintf(stderr, FMT, "-n iterations", "Run tests this many times");
138 8
        fprintf(stderr, FMT, "-p name=val", "Pass a varnishd parameter");
139 8
        fprintf(stderr, FMT, "-q", "Quiet mode: report only failures");
140 8
        fprintf(stderr, FMT, "-t duration", "Time tests out after this long");
141 8
        fprintf(stderr, FMT, "-v", "Verbose mode: always report test log");
142 8
        fprintf(stderr, FMT, "-W", "Enable the witness facility for locking");
143 8
        exit(1);
144
}
145
146
/**********************************************************************
147
 * CallBack
148
 */
149
150
static int
151 1524
tst_cb(const struct vev *ve, int what)
152
{
153
        struct vtc_job *jp;
154
        char buf[BUFSIZ];
155
        int ecode;
156
        int i, stx;
157
        pid_t px;
158
        double t;
159
        FILE *f;
160
        char *p;
161
        struct vsb *v;
162
163 1524
        CAST_OBJ_NOTNULL(jp, ve->priv, JOB_MAGIC);
164
165
        // printf("CB %p %s %d\n", ve, jp->tst->filename, what);
166 1524
        if (what == 0) {
167 0
                jp->killed = 1;
168 0
                AZ(kill(-jp->child, SIGKILL)); /* XXX: Timeout */
169
        } else {
170 1524
                assert(what & (VEV__RD | VEV__HUP));
171
        }
172
173 1524
        *buf = '\0';
174 1524
        i = read(ve->fd, buf, sizeof buf);
175 1524
        if (i > 0)
176 0
                VSB_bcat(jp->diag, buf, i);
177 1524
        if (i == 0) {
178 1524
                njob--;
179 1524
                px = wait4(jp->child, &stx, 0, NULL);
180 1524
                assert(px == jp->child);
181 1524
                t = VTIM_mono() - jp->t0;
182 1524
                AZ(close(ve->fd));
183
184 1524
                ecode = WTERMSIG(stx);
185 1524
                if (ecode == 0)
186 1524
                        ecode = WEXITSTATUS(stx);
187
188 1524
                AZ(VSB_finish(jp->diag));
189 1524
                v = VSB_new_auto();
190 1524
                AN(v);
191 1524
                VSB_cat(v, jp->buf);
192 1524
                p = strchr(jp->buf, '\0');
193 1524
                if (p > jp->buf && p[-1] != '\n')
194 0
                        VSB_putc(v, '\n');
195 1524
                VSB_quote_pfx(v, "*    diag  0.0 ",
196 1524
                    VSB_data(jp->diag), -1, VSB_QUOTE_NONL);
197 1524
                AZ(VSB_finish(v));
198 1524
                VSB_destroy(&jp->diag);
199 1524
                AZ(munmap(jp->buf, jp->bufsiz));
200
201 1524
                if ((ecode > 1 && vtc_verbosity) || vtc_verbosity > 1)
202 1472
                        printf("%s", VSB_data(v));
203
204 1524
                if (!ecode)
205 1502
                        vtc_good++;
206 22
                else if (ecode == 1)
207 18
                        vtc_skip++;
208
                else
209 4
                        vtc_fail++;
210
211 1524
                if (leave_temp == 0 || (leave_temp == 1 && ecode <= 1)) {
212 1524
                        bprintf(buf, "rm -rf %s", jp->tmpdir);
213 1524
                        AZ(system(buf));
214
                } else {
215 0
                        bprintf(buf, "%s/LOG", jp->tmpdir);
216 0
                        f = fopen(buf, "w");
217 0
                        AN(f);
218 0
                        (void)fprintf(f, "%s\n", VSB_data(v));
219 0
                        AZ(fclose(f));
220
                }
221 1524
                free(jp->tmpdir);
222 1524
                VSB_destroy(&v);
223
224 1524
                if (jp->killed)
225 0
                        printf("#    top  TEST %s TIMED OUT (kill -9)\n",
226 0
                            jp->tst->filename);
227 1524
                if (ecode > 1) {
228 4
                        printf("#    top  TEST %s FAILED (%.3f)",
229 4
                            jp->tst->filename, t);
230 4
                        if (WIFSIGNALED(stx))
231 0
                                printf(" signal=%d\n", WTERMSIG(stx));
232 4
                        else if (WIFEXITED(stx))
233 4
                                printf(" exit=%d\n", WEXITSTATUS(stx));
234 4
                        if (!vtc_continue) {
235
                                /* XXX kill -9 other jobs ? */
236 4
                                exit(2);
237
                        }
238 1520
                } else if (vtc_verbosity) {
239 3032
                        printf("#    top  TEST %s %s (%.3f)\n",
240 1516
                            jp->tst->filename,
241
                            ecode ? "skipped" : "passed", t);
242
                }
243 1520
                if (jp->evt != NULL) {
244 1520
                        VEV_Stop(vb, jp->evt);
245 1520
                        free(jp->evt);
246
                }
247 1520
                FREE_OBJ(jp);
248 1520
                return (1);
249
        }
250 0
        return (0);
251
}
252
253
/**********************************************************************
254
 * Start Test
255
 */
256
257
static void
258 1524
start_test(void)
259
{
260
        struct vtc_tst *tp;
261
        int p[2], retval;
262
        struct vtc_job *jp;
263
        char tmpdir[PATH_MAX];
264
265 1524
        ALLOC_OBJ(jp, JOB_MAGIC);
266 1524
        AN(jp);
267
268 1524
        jp->diag = VSB_new_auto();
269 1524
        AN(jp->diag);
270
271 1524
        jp->bufsiz = vtc_bufsiz;
272
273 1524
        jp->buf = mmap(NULL, jp->bufsiz, PROT_READ|PROT_WRITE,
274
            MAP_ANON | MAP_SHARED, -1, 0);
275 1524
        assert(jp->buf != MAP_FAILED);
276 1524
        memset(jp->buf, 0, jp->bufsiz);
277
278 1524
        VRND_SeedAll();
279 1524
        bprintf(tmpdir, "%s/vtc.%d.%08x", tmppath, (int)getpid(),
280
                (unsigned)random());
281 1524
        AZ(mkdir(tmpdir, 0711));
282
283 1524
        tp = VTAILQ_FIRST(&tst_head);
284 1524
        CHECK_OBJ_NOTNULL(tp, TST_MAGIC);
285 1524
        AN(tp->ntodo);
286 1524
        tp->ntodo--;
287 1524
        VTAILQ_REMOVE(&tst_head, tp, list);
288 1524
        if (tp->ntodo >0)
289 0
                VTAILQ_INSERT_TAIL(&tst_head, tp, list);
290
291 1524
        jp->tst = tp;
292 1524
        jp->tmpdir = strdup(tmpdir);
293 1524
        AN(jp->tmpdir);
294
295 1524
        AZ(pipe(p));
296 1524
        assert(p[0] > STDERR_FILENO);
297 1524
        assert(p[1] > STDERR_FILENO);
298 1524
        jp->t0 = VTIM_mono();
299 1524
        jp->child = fork();
300 3048
        assert(jp->child >= 0);
301 3048
        if (jp->child == 0) {
302 1524
                AZ(setpgid(getpid(), 0));
303 1524
                VFIL_null_fd(STDIN_FILENO);
304 1524
                assert(dup2(p[1], STDOUT_FILENO) == STDOUT_FILENO);
305 1524
                assert(dup2(p[1], STDERR_FILENO) == STDERR_FILENO);
306 1524
                VSUB_closefrom(STDERR_FILENO + 1);
307 3048
                retval = exec_file(jp->tst->filename, jp->tst->script,
308 1524
                    jp->tmpdir, jp->buf, jp->bufsiz);
309 1520
                exit(retval);
310
        }
311 1524
        closefd(&p[1]);
312
313 1524
        jp->ev = VEV_Alloc();
314 1524
        AN(jp->ev);
315 1524
        jp->ev->fd_flags = VEV__RD | VEV__HUP | VEV__ERR;
316 1524
        jp->ev->fd = p[0];
317 1524
        jp->ev->priv = jp;
318 1524
        jp->ev->callback = tst_cb;
319 1524
        AZ(VEV_Start(vb, jp->ev));
320
321 1524
        jp->evt = VEV_Alloc();
322 1524
        AN(jp->evt);
323 1524
        jp->evt->fd = -1;
324 1524
        jp->evt->timeout = vtc_maxdur;
325 1524
        jp->evt->priv = jp;
326 1524
        jp->evt->callback = tst_cb;
327 1524
        AZ(VEV_Start(vb, jp->evt));
328 1524
}
329
330
/**********************************************************************
331
 * i-mode = "we're inside a src-tree"
332
 *
333
 * Find the abs path to top of source dir from Makefile, if that
334
 * fails, fall back on "../../"
335
 *
336
 * Set path to all programs build directories
337
 *
338
 */
339
340
static void
341 1464
i_mode(void)
342
{
343
        const char *sep;
344
        struct vsb *vsb;
345
        char *p, *q;
346
        char *topbuild;
347
348
        /*
349
         * This code has a rather intimate knowledge of auto* generated
350
         * makefiles.
351
         */
352
353 1464
        vsb = VSB_new_auto();
354 1464
        AN(vsb);
355
356 1464
        q = p = VFIL_readfile(NULL, "Makefile", NULL);
357 1464
        if (p == NULL) {
358 0
                fprintf(stderr, "No Makefile to search for -i flag.\n");
359 0
                VSB_printf(vsb, "%s/../..", cwd);
360 0
                AZ(VSB_finish(vsb));
361 0
                topbuild = strdup(VSB_data(vsb));
362 0
                VSB_clear(vsb);
363
        } else {
364 1464
                p = strstr(p, "\nabs_top_builddir");
365 1464
                if (p == NULL) {
366 0
                        fprintf(stderr,
367
                            "could not find 'abs_top_builddir' in Makefile\n");
368 0
                        exit(2);
369
                }
370 1464
                topbuild =  strchr(p + 1, '\n');
371 1464
                if (topbuild == NULL) {
372 0
                        fprintf(stderr,
373
                            "No NL after 'abs_top_builddir' in Makefile\n");
374 0
                        exit(2);
375
                }
376 1464
                *topbuild = '\0';
377 1464
                topbuild = strchr(p, '/');
378 1464
                if (topbuild == NULL) {
379 0
                        fprintf(stderr,
380
                            "No '/' after 'abs_top_builddir' in Makefile\n");
381 0
                        exit(2);
382
                }
383 1464
                topbuild = strdup(topbuild);
384 1464
                free(q);
385
386
        }
387 1464
        AN(topbuild);
388 1464
        extmacro_def("topbuild", "%s", topbuild);
389
        /*
390
         * Build $PATH which can find all programs in the build tree
391
         */
392 1464
        VSB_printf(vsb, "PATH=");
393 1464
        sep = "";
394
#define VTC_PROG(l)                                                     \
395
        do {                                                            \
396
                VSB_printf(vsb, "%s%s/bin/" #l, sep, topbuild);         \
397
                sep = ":";                                              \
398
        } while (0);
399
#include "programs.h"
400
401 1464
        VSB_printf(vsb, ":%s", getenv("PATH"));
402 1464
        AZ(VSB_finish(vsb));
403
404 1464
        AZ(putenv(strdup(VSB_data(vsb))));
405
406
        /*
407
         * Build vmod_path which can find all VMODs in the build tree
408
         */
409 1464
        VSB_clear(vsb);
410 1464
        sep = "";
411
#define VTC_VMOD(l)                                                     \
412
        do {                                                            \
413
                VSB_printf(vsb, "%s%s/lib/libvmod_" #l "/.libs",        \
414
                    sep, topbuild);                                     \
415
                sep = ":";                                              \
416
        } while (0);
417
#include "vmods.h"
418
#undef VTC_VMOD
419 1464
        AZ(VSB_finish(vsb));
420 1464
        vmod_path = strdup(VSB_data(vsb));
421 1464
        AN(vmod_path);
422 1464
        free(topbuild);
423 1464
        VSB_destroy(&vsb);
424
425
        /*
426
         * strict jemalloc checking
427
         */
428 1464
        AZ(putenv(strdup("MALLOC_CONF=abort:true,junk:true")));
429 1464
}
430
431
/**********************************************************************
432
 * Most test-cases use only numeric IP#'s but a few requires non-demented
433
 * DNS services.  This is a basic sanity check for those.
434
 */
435
436
static int v_matchproto_(vss_resolved_f)
437 1482
dns_cb(void *priv, const struct suckaddr *sa)
438
{
439
        char abuf[VTCP_ADDRBUFSIZE];
440
        char pbuf[VTCP_PORTBUFSIZE];
441 1482
        int *ret = priv;
442
443 1482
        VTCP_name(sa, abuf, sizeof abuf, pbuf, sizeof pbuf);
444 1482
        if (strcmp(abuf, "130.225.244.222")) {
445 0
                fprintf(stderr, "DNS-test: Wrong response: %s\n", abuf);
446 0
                *ret = -1;
447 1482
        } else if (*ret == 0)
448 1482
                *ret = 1;
449 1482
        return (0);
450
}
451
452
static int
453 1482
dns_works(void)
454
{
455 1482
        int ret = 0, error;
456
        const char *msg;
457
458 1482
        error = VSS_resolver("phk.freebsd.dk", NULL, dns_cb, &ret, &msg);
459 1482
        if (error || msg != NULL || ret != 1)
460 0
                return (0);
461 1482
        return (1);
462
}
463
464
/**********************************************************************
465
 * Figure out what IP related magic
466
 */
467
468
static int v_matchproto_(vss_resolved_f)
469 1482
bind_cb(void *priv, const struct suckaddr *sa)
470
{
471
        (void)priv;
472 1482
        return (VTCP_bind(sa, NULL));
473
}
474
475
static void
476 1482
ip_magic(void)
477
{
478
        const char *p;
479
        int fd;
480
        char abuf[VTCP_ADDRBUFSIZE];
481
        char pbuf[VTCP_PORTBUFSIZE];
482
483
        /*
484
         * In FreeBSD jails localhost/127.0.0.1 becomes the jails IP#
485
         * XXX: IPv6-only hosts would have similar issue, but it is not
486
         * XXX: obvious how to cope.  Ideally "127.0.0.1" would be
487
         * XXX: "localhost", but that doesn't work out of the box.
488
         * XXX: Things like "prefer_ipv6" parameter complicates things.
489
         */
490 1482
        fd = VSS_resolver("127.0.0.1", NULL, bind_cb, NULL, &p);
491 1482
        assert(fd >= 0);
492 1482
        VTCP_myname(fd, abuf, sizeof abuf, pbuf, sizeof(pbuf));
493 1482
        extmacro_def("localhost", "%s", abuf);
494
495
#if defined (__APPLE__)
496
        /*
497
         * In MacOS a bound socket that is not listening will timeout
498
         * instead of refusing the connection so close it and hope
499
         * for the best.
500
         */
501
        VTCP_close(&fd);
502
#endif
503
504
        /* Expose a backend that is forever down. */
505 1482
        extmacro_def("bad_backend", "%s %s", abuf, pbuf);
506
507
        /*
508
         * We need an IP number which will not repond, ever, and that is a
509
         * lot harder than it sounds.  This IP# is from RFC5737 and a
510
         * C-class broadcast at that.
511
         * If tests involving ${bad_ip} fails and you run linux, you should
512
         * check your /proc/sys/net/ipv4/ip_nonlocal_bind setting.
513
         */
514
515 1482
        extmacro_def("bad_ip", "%s", "192.0.2.255");
516 1482
}
517
518
/**********************************************************************
519
 * Main
520
 */
521
522
static int
523 1532
read_file(const char *fn, int ntest)
524
{
525
        struct vtc_tst *tp;
526
        char *p, *q;
527
528 1532
        p = VFIL_readfile(NULL, fn, NULL);
529 1532
        if (p == NULL) {
530 0
                fprintf(stderr, "Cannot stat file \"%s\": %s\n",
531 0
                    fn, strerror(errno));
532 0
                return (2);
533
        }
534 1532
        for (q = p ;q != NULL && *q != '\0'; q++) {
535 1532
                if (vct_islws(*q))
536 0
                        continue;
537 1532
                if (*q != '#')
538 1532
                        break;
539 0
                q = strchr(q, '\n');
540 0
                if (q == NULL)
541 0
                        break;
542
        }
543
544 1532
        if (q == NULL || *q == '\0') {
545 0
                fprintf(stderr, "File \"%s\" has no content.\n", fn);
546 0
                free(p);
547 0
                return (2);
548
        }
549
550 1532
        if (strncmp(q, "varnishtest", 11) || !isspace(q[11])) {
551 8
                fprintf(stderr,
552
                    "File \"%s\" doesn't start with 'varnishtest'\n", fn);
553 8
                free(p);
554 8
                vtc_skip++;
555 8
                return(2);
556
        }
557 1524
        ALLOC_OBJ(tp, TST_MAGIC);
558 1524
        AN(tp);
559 1524
        tp->filename = fn;
560 1524
        tp->script = p;
561 1524
        tp->ntodo = ntest;
562 1524
        VTAILQ_INSERT_TAIL(&tst_head, tp, list);
563 1524
        return(0);
564
}
565
566
/**********************************************************************
567
 * Main
568
 */
569
570
int
571 1494
main(int argc, char * const *argv)
572
{
573
        int ch, i;
574 1494
        int ntest = 1;                  /* Run tests this many times */
575
        uintmax_t bufsiz;
576
        const char *p;
577
578 1494
        if (getenv("TMPDIR") != NULL)
579 1490
                tmppath = strdup(getenv("TMPDIR"));
580
        else
581 4
                tmppath = strdup("/tmp");
582
583 1494
        cwd = getcwd(NULL, PATH_MAX);
584 1494
        extmacro_def("pwd", "%s", cwd);
585
586 1494
        vmod_path = NULL;
587
588 1494
        params_vsb = VSB_new_auto();
589 1494
        AN(params_vsb);
590 1494
        p = getenv("VARNISHTEST_DURATION");
591 1494
        if (p != NULL)
592 0
                vtc_maxdur = atoi(p);
593
594 1494
        setbuf(stdout, NULL);
595 1494
        setbuf(stderr, NULL);
596 5944
        while ((ch = getopt(argc, argv, "b:D:hij:kLln:p:qt:vW")) != -1) {
597 2964
                switch (ch) {
598
                case 'b':
599 0
                        if (VNUM_2bytes(optarg, &bufsiz, 0)) {
600 0
                                fprintf(stderr, "Cannot parse b opt '%s'\n",
601
                                    optarg);
602 0
                                exit(2);
603
                        }
604 0
                        if (bufsiz > UINT_MAX) {
605 0
                                fprintf(stderr, "Invalid b opt '%s'\n",
606
                                    optarg);
607 0
                                exit(2);
608
                        }
609 0
                        vtc_bufsiz = (unsigned)bufsiz;
610 0
                        break;
611
                case 'D':
612 4
                        if (!parse_D_opt(optarg)) {
613 0
                                fprintf(stderr, "Cannot parse D opt '%s'\n",
614
                                    optarg);
615 0
                                exit(2);
616
                        }
617 4
                        break;
618
                case 'i':
619 1464
                        iflg = 1;
620 1464
                        break;
621
                case 'j':
622 0
                        npar = strtoul(optarg, NULL, 0);
623 0
                        break;
624
                case 'L':
625 0
                        leave_temp = 2;
626 0
                        break;
627
                case 'l':
628 0
                        leave_temp = 1;
629 0
                        break;
630
                case 'k':
631 4
                        vtc_continue = !vtc_continue;
632 4
                        break;
633
                case 'n':
634 0
                        ntest = strtoul(optarg, NULL, 0);
635 0
                        break;
636
                case 'p':
637 2
                        VSB_printf(params_vsb, " -p ");
638 2
                        VSB_quote(params_vsb, optarg, -1, 0);
639 2
                        break;
640
                case 'q':
641 4
                        if (vtc_verbosity > 0)
642 4
                                vtc_verbosity--;
643 4
                        break;
644
                case 't':
645 2
                        vtc_maxdur = strtoul(optarg, NULL, 0);
646 2
                        break;
647
                case 'v':
648 1476
                        if (vtc_verbosity < 2)
649 1476
                                vtc_verbosity++;
650 1476
                        break;
651
                case 'W':
652 0
                        vtc_witness++;
653 0
                        break;
654
                default:
655 8
                        usage();
656
                }
657
        }
658 1486
        argc -= optind;
659 1486
        argv += optind;
660
661 1486
        if (argc < 1)
662 0
                usage();
663
664 3014
        for (; argc > 0; argc--, argv++) {
665 1532
                if (!read_file(*argv, ntest))
666 1524
                        continue;
667 8
                if (!vtc_continue)
668 4
                        exit(2);
669
        }
670
671 1482
        AZ(VSB_finish(params_vsb));
672
673 1482
        feature_dns = dns_works();
674 1482
        ip_magic();
675
676 1482
        if (iflg)
677 1464
                i_mode();
678
679 1482
        vb = VEV_New();
680
681 1482
        i = 0;
682 7482
        while (!VTAILQ_EMPTY(&tst_head) || i) {
683 4522
                if (!VTAILQ_EMPTY(&tst_head) && njob < npar) {
684 1524
                        start_test();
685 1524
                        njob++;
686
                        /* Stagger ramp-up */
687 1524
                        if (njob < npar)
688 0
                                (void)usleep(random() % 100000L);
689 1524
                        i = 1;
690 1524
                        continue;
691
                }
692 2998
                i = VEV_Once(vb);
693
        }
694 1478
        if (vtc_continue)
695 4
                fprintf(stderr,
696
                    "%d tests failed, %d tests skipped, %d tests passed\n",
697
                    vtc_fail, vtc_skip, vtc_good);
698 1478
        if (vtc_fail)
699 0
                return (1);
700 1478
        if (vtc_skip && !vtc_good)
701 22
                return (77);
702 1456
        return (0);
703
}