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 2
parse_D_opt(char *arg)
107
{
108
        char *p, *q;
109
110 2
        p = arg;
111 2
        q = strchr(p, '=');
112 2
        if (!q)
113 0
                return (0);
114 2
        *q++ = '\0';
115 2
        extmacro_def(p, "%s", q);
116
117 2
        return (1);
118
}
119
120
/**********************************************************************
121
 * Print usage
122
 */
123
124
static void
125 4
usage(void)
126
{
127 4
        fprintf(stderr, "usage: varnishtest [options] file ...\n");
128
#define FMT "    %-28s # %s\n"
129 4
        fprintf(stderr, FMT, "-b size",
130
            "Set internal buffer size (default: 1M)");
131 4
        fprintf(stderr, FMT, "-D name=val", "Define macro");
132 4
        fprintf(stderr, FMT, "-i", "Find varnish binaries in build tree");
133 4
        fprintf(stderr, FMT, "-j jobs", "Run this many tests in parallel");
134 4
        fprintf(stderr, FMT, "-k", "Continue on test failure");
135 4
        fprintf(stderr, FMT, "-L", "Always leave temporary vtc.*");
136 4
        fprintf(stderr, FMT, "-l", "Leave temporary vtc.* if test fails");
137 4
        fprintf(stderr, FMT, "-n iterations", "Run tests this many times");
138 4
        fprintf(stderr, FMT, "-p name=val", "Pass a varnishd parameter");
139 4
        fprintf(stderr, FMT, "-q", "Quiet mode: report only failures");
140 4
        fprintf(stderr, FMT, "-t duration", "Time tests out after this long");
141 4
        fprintf(stderr, FMT, "-v", "Verbose mode: always report test log");
142 4
        fprintf(stderr, FMT, "-W", "Enable the witness facility for locking");
143 4
        exit(1);
144
}
145
146
/**********************************************************************
147
 * CallBack
148
 */
149
150
static int
151 679
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 679
        CAST_OBJ_NOTNULL(jp, ve->priv, JOB_MAGIC);
164
165
        // printf("CB %p %s %d\n", ve, jp->tst->filename, what);
166 679
        if (what == 0) {
167 0
                jp->killed = 1;
168 0
                AZ(kill(-jp->child, SIGKILL)); /* XXX: Timeout */
169
        } else {
170 679
                assert(what & (VEV__RD | VEV__HUP));
171
        }
172
173 679
        *buf = '\0';
174 679
        i = read(ve->fd, buf, sizeof buf);
175 679
        if (i > 0)
176 1
                VSB_bcat(jp->diag, buf, i);
177 679
        if (i == 0) {
178 678
                njob--;
179 678
                px = wait4(jp->child, &stx, 0, NULL);
180 678
                assert(px == jp->child);
181 678
                t = VTIM_mono() - jp->t0;
182 678
                AZ(close(ve->fd));
183
184 678
                ecode = WTERMSIG(stx);
185 678
                if (ecode == 0)
186 678
                        ecode = WEXITSTATUS(stx);
187
188 678
                AZ(VSB_finish(jp->diag));
189 678
                v = VSB_new_auto();
190 678
                AN(v);
191 678
                VSB_cat(v, jp->buf);
192 678
                p = strchr(jp->buf, '\0');
193 678
                if (p > jp->buf && p[-1] != '\n')
194 0
                        VSB_putc(v, '\n');
195 678
                VSB_quote_pfx(v, "*    diag  0.0 ",
196 678
                    VSB_data(jp->diag), -1, VSB_QUOTE_NONL);
197 678
                AZ(VSB_finish(v));
198 678
                VSB_destroy(&jp->diag);
199 678
                AZ(munmap(jp->buf, jp->bufsiz));
200
201 678
                if ((ecode > 1 && vtc_verbosity) || vtc_verbosity > 1)
202 653
                        printf("%s", VSB_data(v));
203
204 678
                if (!ecode)
205 668
                        vtc_good++;
206 10
                else if (ecode == 1)
207 8
                        vtc_skip++;
208
                else
209 2
                        vtc_fail++;
210
211 678
                if (leave_temp == 0 || (leave_temp == 1 && ecode <= 1)) {
212 678
                        bprintf(buf, "rm -rf %s", jp->tmpdir);
213 678
                        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 678
                free(jp->tmpdir);
222 678
                VSB_destroy(&v);
223
224 678
                if (jp->killed)
225 0
                        printf("#    top  TEST %s TIMED OUT (kill -9)\n",
226 0
                            jp->tst->filename);
227 678
                if (ecode > 1) {
228 2
                        printf("#    top  TEST %s FAILED (%.3f)",
229 2
                            jp->tst->filename, t);
230 2
                        if (WIFSIGNALED(stx))
231 0
                                printf(" signal=%d\n", WTERMSIG(stx));
232 2
                        else if (WIFEXITED(stx))
233 2
                                printf(" exit=%d\n", WEXITSTATUS(stx));
234 2
                        if (!vtc_continue) {
235
                                /* XXX kill -9 other jobs ? */
236 2
                                exit(2);
237
                        }
238 676
                } else if (vtc_verbosity) {
239 1348
                        printf("#    top  TEST %s %s (%.3f)\n",
240 674
                            jp->tst->filename,
241
                            ecode ? "skipped" : "passed", t);
242
                }
243 676
                if (jp->evt != NULL)
244 676
                        VEV_Stop(vb, jp->evt);
245
246 676
                FREE_OBJ(jp);
247 676
                return (1);
248
        }
249 1
        return (0);
250
}
251
252
/**********************************************************************
253
 * Start Test
254
 */
255
256
static void
257 678
start_test(void)
258
{
259
        struct vtc_tst *tp;
260
        int p[2], retval;
261
        struct vtc_job *jp;
262
        char tmpdir[PATH_MAX];
263
264 678
        ALLOC_OBJ(jp, JOB_MAGIC);
265 678
        AN(jp);
266
267 678
        jp->diag = VSB_new_auto();
268 678
        AN(jp->diag);
269
270 678
        jp->bufsiz = vtc_bufsiz;
271
272 678
        jp->buf = mmap(NULL, jp->bufsiz, PROT_READ|PROT_WRITE,
273
            MAP_ANON | MAP_SHARED, -1, 0);
274 678
        assert(jp->buf != MAP_FAILED);
275 678
        memset(jp->buf, 0, jp->bufsiz);
276
277 678
        VRND_SeedAll();
278 678
        bprintf(tmpdir, "%s/vtc.%d.%08x", tmppath, (int)getpid(),
279
                (unsigned)random());
280 678
        AZ(mkdir(tmpdir, 0711));
281
282 678
        tp = VTAILQ_FIRST(&tst_head);
283 678
        CHECK_OBJ_NOTNULL(tp, TST_MAGIC);
284 678
        AN(tp->ntodo);
285 678
        tp->ntodo--;
286 678
        VTAILQ_REMOVE(&tst_head, tp, list);
287 678
        if (tp->ntodo >0)
288 0
                VTAILQ_INSERT_TAIL(&tst_head, tp, list);
289
290 678
        jp->tst = tp;
291 678
        jp->tmpdir = strdup(tmpdir);
292 678
        AN(jp->tmpdir);
293
294 678
        AZ(pipe(p));
295 678
        assert(p[0] > STDERR_FILENO);
296 678
        assert(p[1] > STDERR_FILENO);
297 678
        jp->t0 = VTIM_mono();
298 678
        jp->child = fork();
299 1356
        assert(jp->child >= 0);
300 1356
        if (jp->child == 0) {
301 678
                AZ(setpgid(getpid(), 0));
302 678
                VFIL_null_fd(STDIN_FILENO);
303 678
                assert(dup2(p[1], STDOUT_FILENO) == STDOUT_FILENO);
304 678
                assert(dup2(p[1], STDERR_FILENO) == STDERR_FILENO);
305 678
                VSUB_closefrom(STDERR_FILENO + 1);
306 1356
                retval = exec_file(jp->tst->filename, jp->tst->script,
307 678
                    jp->tmpdir, jp->buf, jp->bufsiz);
308 676
                exit(retval);
309
        }
310 678
        closefd(&p[1]);
311
312 678
        jp->ev = VEV_Alloc();
313 678
        AN(jp->ev);
314 678
        jp->ev->fd_flags = VEV__RD | VEV__HUP | VEV__ERR;
315 678
        jp->ev->fd = p[0];
316 678
        jp->ev->priv = jp;
317 678
        jp->ev->callback = tst_cb;
318 678
        AZ(VEV_Start(vb, jp->ev));
319
320 678
        jp->evt = VEV_Alloc();
321 678
        AN(jp->evt);
322 678
        jp->evt->fd = -1;
323 678
        jp->evt->timeout = vtc_maxdur;
324 678
        jp->evt->priv = jp;
325 678
        jp->evt->callback = tst_cb;
326 678
        AZ(VEV_Start(vb, jp->evt));
327 678
}
328
329
/**********************************************************************
330
 * i-mode = "we're inside a src-tree"
331
 *
332
 * Find the abs path to top of source dir from Makefile, if that
333
 * fails, fall back on "../../"
334
 *
335
 * Set path to all programs build directories
336
 *
337
 */
338
339
static void
340 649
i_mode(void)
341
{
342
        const char *sep;
343
        struct vsb *vsb;
344
        char *p, *q;
345
        char *topbuild;
346
347
        /*
348
         * This code has a rather intimate knowledge of auto* generated
349
         * makefiles.
350
         */
351
352 649
        vsb = VSB_new_auto();
353 649
        AN(vsb);
354
355 649
        q = p = VFIL_readfile(NULL, "Makefile", NULL);
356 649
        if (p == NULL) {
357 0
                fprintf(stderr, "No Makefile to search for -i flag.\n");
358 0
                VSB_printf(vsb, "%s/../..", cwd);
359 0
                AZ(VSB_finish(vsb));
360 0
                topbuild = strdup(VSB_data(vsb));
361 0
                VSB_clear(vsb);
362
        } else {
363 649
                p = strstr(p, "\nabs_top_builddir");
364 649
                if (p == NULL) {
365 0
                        fprintf(stderr,
366
                            "could not find 'abs_top_builddir' in Makefile\n");
367 0
                        exit(2);
368
                }
369 649
                topbuild =  strchr(p + 1, '\n');
370 649
                if (topbuild == NULL) {
371 0
                        fprintf(stderr,
372
                            "No NL after 'abs_top_builddir' in Makefile\n");
373 0
                        exit(2);
374
                }
375 649
                *topbuild = '\0';
376 649
                topbuild = strchr(p, '/');
377 649
                if (topbuild == NULL) {
378 0
                        fprintf(stderr,
379
                            "No '/' after 'abs_top_builddir' in Makefile\n");
380 0
                        exit(2);
381
                }
382 649
                topbuild = strdup(topbuild);
383 649
                free(q);
384
385
        }
386 649
        AN(topbuild);
387 649
        extmacro_def("topbuild", "%s", topbuild);
388
        /*
389
         * Build $PATH which can find all programs in the build tree
390
         */
391 649
        VSB_printf(vsb, "PATH=");
392 649
        sep = "";
393
#define VTC_PROG(l)                                                     \
394
        do {                                                            \
395
                VSB_printf(vsb, "%s%s/bin/" #l, sep, topbuild);         \
396
                sep = ":";                                              \
397
        } while (0);
398
#include "programs.h"
399
400 649
        VSB_printf(vsb, ":%s", getenv("PATH"));
401 649
        AZ(VSB_finish(vsb));
402
403 649
        AZ(putenv(strdup(VSB_data(vsb))));
404
405
        /*
406
         * Build vmod_path which can find all VMODs in the build tree
407
         */
408 649
        VSB_clear(vsb);
409 649
        sep = "";
410
#define VTC_VMOD(l)                                                     \
411
        do {                                                            \
412
                VSB_printf(vsb, "%s%s/lib/libvmod_" #l "/.libs",        \
413
                    sep, topbuild);                                     \
414
                sep = ":";                                              \
415
        } while (0);
416
#include "vmods.h"
417
#undef VTC_VMOD
418 649
        AZ(VSB_finish(vsb));
419 649
        vmod_path = strdup(VSB_data(vsb));
420 649
        AN(vmod_path);
421 649
        free(topbuild);
422 649
        VSB_destroy(&vsb);
423
424
        /*
425
         * strict jemalloc checking
426
         */
427 649
        AZ(putenv(strdup("MALLOC_CONF=abort:true,junk:true")));
428 649
}
429
430
/**********************************************************************
431
 * Most test-cases use only numeric IP#'s but a few requires non-demented
432
 * DNS services.  This is a basic sanity check for those.
433
 */
434
435
static int v_matchproto_(vss_resolved_f)
436 658
dns_cb(void *priv, const struct suckaddr *sa)
437
{
438
        char abuf[VTCP_ADDRBUFSIZE];
439
        char pbuf[VTCP_PORTBUFSIZE];
440 658
        int *ret = priv;
441
442 658
        VTCP_name(sa, abuf, sizeof abuf, pbuf, sizeof pbuf);
443 658
        if (strcmp(abuf, "130.225.244.222")) {
444 0
                fprintf(stderr, "DNS-test: Wrong response: %s\n", abuf);
445 0
                *ret = -1;
446 658
        } else if (*ret == 0)
447 658
                *ret = 1;
448 658
        return (0);
449
}
450
451
static int
452 658
dns_works(void)
453
{
454 658
        int ret = 0, error;
455
        const char *msg;
456
457 658
        error = VSS_resolver("phk.freebsd.dk", NULL, dns_cb, &ret, &msg);
458 658
        if (error || msg != NULL || ret != 1)
459 0
                return (0);
460 658
        return (1);
461
}
462
463
/**********************************************************************
464
 * Figure out what IP related magic
465
 */
466
467
static int v_matchproto_(vss_resolved_f)
468 658
bind_cb(void *priv, const struct suckaddr *sa)
469
{
470
        (void)priv;
471 658
        return (VTCP_bind(sa, NULL));
472
}
473
474
static void
475 658
ip_magic(void)
476
{
477
        const char *p;
478
        int fd;
479
        char abuf[VTCP_ADDRBUFSIZE];
480
        char pbuf[VTCP_PORTBUFSIZE];
481
482
        /*
483
         * In FreeBSD jails localhost/127.0.0.1 becomes the jails IP#
484
         * XXX: IPv6-only hosts would have similar issue, but it is not
485
         * XXX: obvious how to cope.  Ideally "127.0.0.1" would be
486
         * XXX: "localhost", but that doesn't work out of the box.
487
         * XXX: Things like "prefer_ipv6" parameter complicates things.
488
         */
489 658
        fd = VSS_resolver("127.0.0.1", NULL, bind_cb, NULL, &p);
490 658
        assert(fd >= 0);
491 658
        VTCP_myname(fd, abuf, sizeof abuf, pbuf, sizeof(pbuf));
492 658
        extmacro_def("localhost", "%s", abuf);
493
494
        /* Expose a backend that is forever down. */
495 658
        extmacro_def("bad_backend", "%s %s", abuf, pbuf);
496
497
        /*
498
         * We need an IP number which will not repond, ever, and that is a
499
         * lot harder than it sounds.  This IP# is from RFC5737 and a
500
         * C-class broadcast at that.
501
         * If tests involving ${bad_ip} fails and you run linux, you should
502
         * check your /proc/sys/net/ipv4/ip_nonlocal_bind setting.
503
         */
504
505 658
        extmacro_def("bad_ip", "%s", "192.0.2.255");
506 658
}
507
508
/**********************************************************************
509
 * Main
510
 */
511
512
static int
513 682
read_file(const char *fn, int ntest)
514
{
515
        struct vtc_tst *tp;
516
        char *p, *q;
517
518 682
        p = VFIL_readfile(NULL, fn, NULL);
519 682
        if (p == NULL) {
520 0
                fprintf(stderr, "Cannot stat file \"%s\": %s\n",
521 0
                    fn, strerror(errno));
522 0
                return (2);
523
        }
524 698
        for (q = p ;q != NULL && *q != '\0'; q++) {
525 698
                if (vct_islws(*q))
526 10
                        continue;
527 688
                if (*q != '#')
528 682
                        break;
529 6
                q = strchr(q, '\n');
530 6
                if (q == NULL)
531 0
                        break;
532
        }
533
534 682
        if (q == NULL || *q == '\0') {
535 0
                fprintf(stderr, "File \"%s\" has no content.\n", fn);
536 0
                free(p);
537 0
                return (2);
538
        }
539
540 682
        if (strncmp(q, "varnishtest", 11) || !isspace(q[11])) {
541 4
                fprintf(stderr,
542
                    "File \"%s\" doesn't start with 'varnishtest'\n", fn);
543 4
                free(p);
544 4
                vtc_skip++;
545 4
                return(2);
546
        }
547 678
        ALLOC_OBJ(tp, TST_MAGIC);
548 678
        AN(tp);
549 678
        tp->filename = fn;
550 678
        tp->script = p;
551 678
        tp->ntodo = ntest;
552 678
        VTAILQ_INSERT_TAIL(&tst_head, tp, list);
553 678
        return(0);
554
}
555
556
/**********************************************************************
557
 * Main
558
 */
559
560
int
561 664
main(int argc, char * const *argv)
562
{
563
        int ch, i;
564 664
        int ntest = 1;                  /* Run tests this many times */
565
        uintmax_t bufsiz;
566
        const char *p;
567
568 664
        if (getenv("TMPDIR") != NULL)
569 662
                tmppath = strdup(getenv("TMPDIR"));
570
        else
571 2
                tmppath = strdup("/tmp");
572
573 664
        cwd = getcwd(NULL, PATH_MAX);
574 664
        extmacro_def("pwd", "%s", cwd);
575
576 664
        vmod_path = NULL;
577
578 664
        params_vsb = VSB_new_auto();
579 664
        AN(params_vsb);
580 664
        p = getenv("VARNISHTEST_DURATION");
581 664
        if (p != NULL)
582 0
                vtc_maxdur = atoi(p);
583
584 664
        setbuf(stdout, NULL);
585 664
        setbuf(stderr, NULL);
586 2640
        while ((ch = getopt(argc, argv, "b:D:hij:kLln:p:qt:vW")) != -1) {
587 1316
                switch (ch) {
588
                case 'b':
589 0
                        if (VNUM_2bytes(optarg, &bufsiz, 0)) {
590 0
                                fprintf(stderr, "Cannot parse b opt '%s'\n",
591
                                    optarg);
592 0
                                exit(2);
593
                        }
594 0
                        if (bufsiz > UINT_MAX) {
595 0
                                fprintf(stderr, "Invalid b opt '%s'\n",
596
                                    optarg);
597 0
                                exit(2);
598
                        }
599 0
                        vtc_bufsiz = (unsigned)bufsiz;
600 0
                        break;
601
                case 'D':
602 2
                        if (!parse_D_opt(optarg)) {
603 0
                                fprintf(stderr, "Cannot parse D opt '%s'\n",
604
                                    optarg);
605 0
                                exit(2);
606
                        }
607 2
                        break;
608
                case 'i':
609 649
                        iflg = 1;
610 649
                        break;
611
                case 'j':
612 0
                        npar = strtoul(optarg, NULL, 0);
613 0
                        break;
614
                case 'L':
615 0
                        leave_temp = 2;
616 0
                        break;
617
                case 'l':
618 0
                        leave_temp = 1;
619 0
                        break;
620
                case 'k':
621 2
                        vtc_continue = !vtc_continue;
622 2
                        break;
623
                case 'n':
624 0
                        ntest = strtoul(optarg, NULL, 0);
625 0
                        break;
626
                case 'p':
627 1
                        VSB_printf(params_vsb, " -p ");
628 1
                        VSB_quote(params_vsb, optarg, -1, 0);
629 1
                        break;
630
                case 'q':
631 2
                        if (vtc_verbosity > 0)
632 2
                                vtc_verbosity--;
633 2
                        break;
634
                case 't':
635 1
                        vtc_maxdur = strtoul(optarg, NULL, 0);
636 1
                        break;
637
                case 'v':
638 655
                        if (vtc_verbosity < 2)
639 655
                                vtc_verbosity++;
640 655
                        break;
641
                case 'W':
642 0
                        vtc_witness++;
643 0
                        break;
644
                default:
645 4
                        usage();
646
                }
647
        }
648 660
        argc -= optind;
649 660
        argv += optind;
650
651 660
        if (argc < 1)
652 0
                usage();
653
654 1340
        for (; argc > 0; argc--, argv++) {
655 682
                if (!read_file(*argv, ntest))
656 678
                        continue;
657 4
                if (!vtc_continue)
658 2
                        exit(2);
659
        }
660
661 658
        AZ(VSB_finish(params_vsb));
662
663 658
        feature_dns = dns_works();
664 658
        ip_magic();
665
666 658
        if (iflg)
667 649
                i_mode();
668
669 658
        vb = VEV_New();
670
671 658
        i = 0;
672 3325
        while (!VTAILQ_EMPTY(&tst_head) || i) {
673 2011
                if (!VTAILQ_EMPTY(&tst_head) && njob < npar) {
674 678
                        start_test();
675 678
                        njob++;
676
                        /* Stagger ramp-up */
677 678
                        if (njob < npar)
678 0
                                (void)usleep(random() % 100000L);
679 678
                        i = 1;
680 678
                        continue;
681
                }
682 1333
                i = VEV_Once(vb);
683
        }
684 656
        if (vtc_continue)
685 2
                fprintf(stderr,
686
                    "%d tests failed, %d tests skipped, %d tests passed\n",
687
                    vtc_fail, vtc_skip, vtc_good);
688 656
        if (vtc_fail)
689 0
                return (1);
690 656
        if (vtc_skip && !vtc_good)
691 10
                return (77);
692 646
        return (0);
693
}