varnish-cache/bin/varnishtest/vtc_misc.c
0
/*-
1
 * Copyright (c) 2008-2011 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include "config.h"
31
32
#include <sys/wait.h>
33
#include <sys/socket.h>
34
35
#include <grp.h>
36
#include <math.h>
37
#include <pwd.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <sys/un.h>
42
#include <unistd.h>
43
44
#ifdef HAVE_SYS_PERSONALITY_H
45
#  include <sys/personality.h>
46
#endif
47
48
#include "vtc.h"
49
50
#include "vfil.h"
51
#include "vnum.h"
52
#include "vre.h"
53
#include "vtcp.h"
54
#include "vsa.h"
55
#include "vss.h"
56
#include "vtim.h"
57
#include "vus.h"
58
59
/* SECTION: vtest vtest
60
 *
61
 * This should be the first command in your vtc as it will identify the test
62
 * case with a short yet descriptive sentence. It takes exactly one argument, a
63
 * string, eg::
64
 *
65
 *         vtest "Check that vtest is actually a valid command"
66
 *
67
 * It will also print that string in the log.
68
 */
69
70
void v_matchproto_(cmd_f)
71 8080
cmd_vtest(CMD_ARGS)
72
{
73
74 8080
        (void)priv;
75 8080
        (void)vl;
76
77 8080
        if (av == NULL)
78 8064
                return;
79 16
        AZ(strcmp(av[0], "vtest"));
80
81 16
        vtc_log(vl, 1, "VTEST %s", av[1]);
82 16
        AZ(av[2]);
83 8080
}
84
85
/* SECTION: varnishtest varnishtest
86
 *
87
 * Alternate name for 'vtest', see above.
88
 *
89
 */
90
91
void v_matchproto_(cmd_f)
92 16112
cmd_varnishtest(CMD_ARGS)
93
{
94
95 16112
        (void)priv;
96 16112
        (void)vl;
97
98 16112
        if (av == NULL)
99 8064
                return;
100 8048
        AZ(strcmp(av[0], "varnishtest"));
101
102 8048
        vtc_log(vl, 1, "VTEST %s", av[1]);
103 8048
        AZ(av[2]);
104 16112
}
105
106
/* SECTION: shell shell
107
 *
108
 * NOTE: This command is available everywhere commands are given.
109
 *
110
 * Pass the string given as argument to a shell. If you have multiple
111
 * commands to run, you can use curly brackets to describe a multi-lines
112
 * script, eg::
113
 *
114
 *         shell {
115
 *                 echo begin
116
 *                 cat /etc/fstab
117
 *                 echo end
118
 *         }
119
 *
120
 * By default a zero exit code is expected, otherwise the vtc will fail.
121
 *
122
 * Notice that the commandstring is prefixed with "exec 2>&1;" to combine
123
 * stderr and stdout back to the test process.
124
 *
125
 * Optional arguments:
126
 *
127
 * \-err
128
 *      Expect non-zero exit code.
129
 *
130
 * \-exit N
131
 *      Expect exit code N instead of zero.
132
 *
133
 * \-expect STRING
134
 *      Expect string to be found in stdout+err.
135
 *
136
 * \-match REGEXP
137
 *      Expect regexp to match the stdout+err output.
138
 */
139
/* SECTION: client-server.spec.shell
140
 *
141
 * shell
142
 *      Same as for the top-level shell.
143
 */
144
145
static void
146 3760
cmd_shell_engine(struct vtclog *vl, int ok, const char *cmd,
147
    const char *expect, const char *re)
148
{
149
        struct vsb *vsb, re_vsb[1];
150
        FILE *fp;
151 3760
        vre_t *vre = NULL;
152
        int r, c;
153
        int err, erroff;
154
        char errbuf[VRE_ERROR_LEN];
155
156 3760
        AN(vl);
157 3760
        AN(cmd);
158 3760
        vsb = VSB_new_auto();
159 3760
        AN(vsb);
160 3760
        if (re != NULL) {
161 568
                vre = VRE_compile(re, 0, &err, &erroff, 1);
162 568
                if (vre == NULL) {
163 0
                        AN(VSB_init(re_vsb, errbuf, sizeof errbuf));
164 0
                        AZ(VRE_error(re_vsb, err));
165 0
                        AZ(VSB_finish(re_vsb));
166 0
                        VSB_fini(re_vsb);
167 0
                        vtc_fatal(vl,
168
                            "shell_match invalid regexp (\"%s\" at %d)",
169 0
                            errbuf, erroff);
170
                }
171 568
        }
172 3760
        VSB_printf(vsb, "set -e ;");
173 3760
        VSB_printf(vsb, "exec 2>&1 ; %s", cmd);
174 3760
        AZ(VSB_finish(vsb));
175 3760
        vtc_dump(vl, 4, "shell_cmd", VSB_data(vsb), -1);
176 3760
        fp = popen(VSB_data(vsb), "r");
177 3760
        if (fp == NULL)
178 0
                vtc_fatal(vl, "popen fails: %s", strerror(errno));
179 3760
        VSB_clear(vsb);
180 3760
        do {
181 4814354
                c = getc(fp);
182 4814354
                if (c != EOF)
183 4810594
                        VSB_putc(vsb, c);
184 4814354
        } while (c != EOF);
185 3760
        r = pclose(fp);
186 3760
        AZ(VSB_finish(vsb));
187 3760
        vtc_dump(vl, 4, "shell_out", VSB_data(vsb), VSB_len(vsb));
188 3760
        vtc_log(vl, 4, "shell_status = 0x%04x", WEXITSTATUS(r));
189 3760
        if (WIFSIGNALED(r))
190 0
                vtc_log(vl, 4, "shell_signal = %d", WTERMSIG(r));
191
192 3760
        if (ok < 0 && !WEXITSTATUS(r) && !WIFSIGNALED(r))
193 0
                vtc_fatal(vl, "shell did not fail as expected");
194 3760
        else if (ok >= 0 && WEXITSTATUS(r) != ok)
195 32
                vtc_fatal(vl, "shell_exit not as expected: "
196 16
                    "got 0x%04x wanted 0x%04x", WEXITSTATUS(r), ok);
197
198 3744
        if (expect != NULL) {
199 1840
                if (strstr(VSB_data(vsb), expect) == NULL)
200 0
                        vtc_fatal(vl,
201 0
                            "shell_expect not found: (\"%s\")", expect);
202
                else
203 1840
                        vtc_log(vl, 4, "shell_expect found");
204 3744
        } else if (vre != NULL) {
205 568
                if (VRE_match(vre, VSB_data(vsb), VSB_len(vsb), 0, NULL) < 1)
206 0
                        vtc_fatal(vl, "shell_match failed: (\"%s\")", re);
207
                else
208 568
                        vtc_log(vl, 4, "shell_match succeeded");
209 568
                VRE_free(&vre);
210 568
        }
211 3744
        VSB_destroy(&vsb);
212 3744
}
213
214
215
void
216 11824
cmd_shell(CMD_ARGS)
217
{
218 11824
        const char *expect = NULL;
219 11824
        const char *re = NULL;
220
        int n;
221 11824
        int ok = 0;
222
223 11824
        (void)priv;
224
225 11824
        if (av == NULL)
226 8064
                return;
227 7936
        for (n = 1; av[n] != NULL; n++) {
228 7936
                if (!strcmp(av[n], "-err")) {
229 1640
                        ok = -1;
230 7936
                } else if (!strcmp(av[n], "-exit")) {
231 128
                        n += 1;
232 128
                        ok = atoi(av[n]);
233 6296
                } else if (!strcmp(av[n], "-expect")) {
234 1840
                        if (re != NULL)
235 0
                                vtc_fatal(vl,
236
                                    "Cannot use -expect with -match");
237 1840
                        n += 1;
238 1840
                        expect = av[n];
239 6168
                } else if (!strcmp(av[n], "-match")) {
240 568
                        if (expect != NULL)
241 0
                                vtc_fatal(vl,
242
                                    "Cannot use -match with -expect");
243 568
                        n += 1;
244 568
                        re = av[n];
245 568
                } else {
246 3760
                        break;
247
                }
248 4176
        }
249 3760
        AN(av[n]);
250 3760
        cmd_shell_engine(vl, ok, av[n], expect, re);
251 11824
}
252
253
/* SECTION: filewrite filewrite
254
 *
255
 * Write strings to file
256
 *
257
 *         filewrite [-a] /somefile "Hello" " " "World\n"
258
 *
259
 * The -a flag opens the file in append mode.
260
 *
261
 */
262
263
void v_matchproto_(cmd_f)
264 8312
cmd_filewrite(CMD_ARGS)
265
{
266
        FILE *fo;
267
        int n;
268 8312
        const char *mode = "w";
269
270 8312
        (void)priv;
271
272 8312
        if (av == NULL)
273 8064
                return;
274 248
        if (av[1] != NULL && !strcmp(av[1], "-a")) {
275 112
                av++;
276 112
                mode = "a";
277 112
        }
278 248
        if (av[1] == NULL)
279 0
                vtc_fatal(vl, "Need filename");
280 248
        fo = fopen(av[1], mode);
281 248
        if (fo == NULL)
282 0
                vtc_fatal(vl, "Cannot open %s: %s", av[1], strerror(errno));
283 592
        for (n = 2; av[n] != NULL; n++)
284 344
                (void)fputs(av[n], fo);
285 248
        AZ(fclose(fo));
286 8312
}
287
288
/* SECTION: setenv setenv
289
 *
290
 * Set or change an environment variable::
291
 *
292
 *         setenv FOO "bar baz"
293
 *
294
 * The above will set the environment variable $FOO to the value
295
 * provided. There is also an ``-ifunset`` argument which will only
296
 * set the value if the environment variable does not already
297
 * exist::
298
 *
299
 *        setenv -ifunset FOO quux
300
 */
301
302
void v_matchproto_(cmd_f)
303 8096
cmd_setenv(CMD_ARGS)
304
{
305
        int r;
306
        int force;
307
308 8096
        (void)priv;
309
310 8096
        if (av == NULL)
311 8064
                return;
312 32
        AN(av[1]);
313 32
        AN(av[2]);
314
315 32
        force = 1;
316 32
        if (strcmp("-ifunset", av[1]) == 0) {
317 8
                force = 0;
318 8
                av++;
319 8
                AN(av[2]);
320 8
        }
321 32
        if (av[3] != NULL)
322 0
                vtc_fatal(vl, "CMD setenv: Unexpected argument '%s'", av[3]);
323 32
        r = setenv(av[1], av[2], force);
324 32
        if (r != 0)
325 0
                vtc_log(vl, 0, "CMD setenv %s=\"%s\" failed: %s",
326 0
                    av[1], av[2], strerror(errno));
327 8096
}
328
329
/* SECTION: delay delay
330
 *
331
 * NOTE: This command is available everywhere commands are given.
332
 *
333
 * Sleep for the number of seconds specified in the argument. The number
334
 * can include a fractional part, e.g. 1.5.
335
 */
336
void
337 12855
cmd_delay(CMD_ARGS)
338
{
339
        double f;
340
341 12855
        (void)priv;
342 12855
        if (av == NULL)
343 8064
                return;
344 4791
        AN(av[1]);
345 4791
        AZ(av[2]);
346 4791
        f = VNUM(av[1]);
347 4791
        if (isnan(f))
348 0
                vtc_fatal(vl, "Syntax error in number (%s)", av[1]);
349 4791
        vtc_log(vl, 3, "delaying %g second(s)", f);
350 4791
        VTIM_sleep(f);
351 12855
}
352
353
/* SECTION: include include
354
 *
355
 * Executes a vtc fragment::
356
 *
357
 *         include FILE [...]
358
 *
359
 * Open a file and execute it as a VTC fragment. This command is available
360
 * everywhere commands are given.
361
 *
362
 */
363
void
364 8064
cmd_include(CMD_ARGS)
365
{
366
        char *spec;
367
        unsigned i;
368
369 8064
        if (av == NULL)
370 8064
                return;
371
372 0
        if (av[1] == NULL)
373 0
                vtc_fatal(vl, "CMD include: At least 1 argument required");
374
375 0
        for (i = 1; av[i] != NULL; i++) {
376 0
                spec = VFIL_readfile(NULL, av[i], NULL);
377 0
                if (spec == NULL)
378 0
                        vtc_fatal(vl, "CMD include: Unable to read file '%s' "
379 0
                            "(%s)", av[i], strerror(errno));
380 0
                vtc_log(vl, 2, "Begin include '%s'", av[i]);
381 0
                parse_string(vl, priv, spec);
382 0
                vtc_log(vl, 2, "End include '%s'", av[i]);
383 0
                free(spec);
384 0
        }
385 8064
}
386
387
/**********************************************************************
388
 * Most test-cases use only numeric IP#'s but a few requires non-demented
389
 * DNS services.  This is a basic sanity check for those.
390
 */
391
392
static int
393 8
dns_works(void)
394
{
395
        const struct suckaddr *sa;
396
        char abuf[VTCP_ADDRBUFSIZE];
397
        char pbuf[VTCP_PORTBUFSIZE];
398
399 8
        sa = VSS_ResolveOne(NULL, "dns-canary.varnish-cache.org", NULL,
400
            AF_INET, SOCK_STREAM, 0);
401 8
        if (sa == NULL)
402 0
                return (0);
403 8
        VTCP_name(sa, abuf, sizeof abuf, pbuf, sizeof pbuf);
404 8
        VSA_free(&sa);
405 8
        if (strcmp(abuf, "192.0.2.255"))
406 0
                return (0);
407
408 8
        sa = VSS_ResolveOne(NULL, "dns-canary.varnish-cache.org", NULL,
409
            AF_INET6, SOCK_STREAM, 0);
410 8
        if (sa == NULL)
411 8
                return (1); /* the canary is ipv4 only */
412 0
        VSA_free(&sa);
413 0
        return (0);
414 8
}
415
416
/**********************************************************************
417
 * Test if IPv4/IPv6 works
418
 */
419
420
static int
421 56
ipvx_works(const char *target)
422
{
423
        const struct suckaddr *sa;
424
        int fd;
425
426 56
        sa = VSS_ResolveOne(NULL, target, "0", 0, SOCK_STREAM, 0);
427 56
        if (sa == NULL)
428 0
                return (0);
429 56
        fd = VTCP_bind(sa, NULL);
430 56
        VSA_free(&sa);
431 56
        if (fd >= 0) {
432 56
                VTCP_close(&fd);
433 56
                return (1);
434
        }
435 0
        return (0);
436 56
}
437
438
/**********************************************************************/
439
440
static int
441 8
addr_no_randomize_works(void)
442
{
443 8
        int r = 0;
444
445
#ifdef HAVE_SYS_PERSONALITY_H
446
        r = personality(0xffffffff);
447
        r = personality(r | ADDR_NO_RANDOMIZE);
448
#endif
449 8
        return (r >= 0);
450
}
451
452
/**********************************************************************/
453
454
static int
455 8
uds_socket(void *priv, const struct sockaddr_un *uds)
456
{
457
458 8
        return (VUS_bind(uds, priv));
459
}
460
static int
461 8
abstract_uds_works(void)
462
{
463
        const char *err;
464
        int fd;
465
466 8
        fd = VUS_resolver("@vtc.feature.abstract_uds", uds_socket, NULL, &err);
467 8
        if (fd < 0)
468 8
                return (0);
469 0
        AZ(close(fd));
470 0
        return (1);
471 8
}
472
473
/* SECTION: feature feature
474
 *
475
 * Test that the required feature(s) for a test are available, and skip
476
 * the test otherwise; or change the interpretation of the test, as
477
 * documented below. feature takes any number of arguments from this list:
478
 *
479
 * 64bit
480
 *        The environment is 64 bits
481
 * ipv4
482
 *        127.0.0.1 works
483
 * ipv6
484
 *        [::1] works
485
 * dns
486
 *        DNS lookups are working
487
 * topbuild
488
 *        The test has been started with '-i'
489
 * root
490
 *        The test has been invoked by the root user
491
 * user_varnish
492
 *        The varnish user is present
493
 * user_vcache
494
 *        The vcache user is present
495
 * group_varnish
496
 *        The varnish group is present
497
 * cmd <command-line>
498
 *        A command line that should execute with a zero exit status
499
 * ignore_unknown_macro
500
 *        Do not fail the test if a string of the form ${...} is not
501
 *        recognized as a macro.
502
 * persistent_storage
503
 *        Varnish was built with the deprecated persistent storage.
504
 * coverage
505
 *        Varnish was built with code coverage enabled.
506
 * asan
507
 *        Varnish was built with the address sanitizer.
508
 * msan
509
 *        Varnish was built with the memory sanitizer.
510
 * tsan
511
 *        Varnish was built with the thread sanitizer.
512
 * ubsan
513
 *        Varnish was built with the undefined behavior sanitizer.
514
 * sanitizer
515
 *        Varnish was built with a sanitizer.
516
 * workspace_emulator
517
 *        Varnish was built with its workspace emulator.
518
 * abstract_uds
519
 *        Creation of an abstract unix domain socket succeeded.
520
 * disable_aslr
521
 *        ASLR can be disabled.
522
 *
523
 * A feature name can be prefixed with an exclamation mark (!) to skip a
524
 * test if the feature is present.
525
 *
526
 * Be careful with ignore_unknown_macro, because it may cause a test with a
527
 * misspelled macro to fail silently. You should only need it if you must
528
 * run a test with strings of the form "${...}".
529
 */
530
531
#if ENABLE_COVERAGE
532
static const unsigned coverage = 1;
533
#else
534
static const unsigned coverage = 0;
535
#endif
536
537
#if ENABLE_ASAN
538
static const unsigned asan = 1;
539
#else
540
static const unsigned asan = 0;
541
#endif
542
543
#if ENABLE_MSAN
544
static const unsigned msan = 1;
545
#else
546
static const unsigned msan = 0;
547
#endif
548
549
#if ENABLE_TSAN
550
static const unsigned tsan = 1;
551
#else
552
static const unsigned tsan = 0;
553
#endif
554
555
#if ENABLE_UBSAN
556
static const unsigned ubsan = 1;
557
#else
558
static const unsigned ubsan = 0;
559
#endif
560
561
#if ENABLE_SANITIZER
562
static const unsigned sanitizer = 1;
563
#else
564
static const unsigned sanitizer = 0;
565
#endif
566
567
#if ENABLE_WORKSPACE_EMULATOR
568
static const unsigned workspace_emulator = 1;
569
#else
570
static const unsigned workspace_emulator = 0;
571
#endif
572
573
#if WITH_PERSISTENT_STORAGE
574
static const unsigned with_persistent_storage = 1;
575
#else
576
static const unsigned with_persistent_storage = 0;
577
#endif
578
579
void v_matchproto_(cmd_f)
580 8976
cmd_feature(CMD_ARGS)
581
{
582
        const char *feat;
583
        int r, good, skip, neg;
584
585 8976
        (void)priv;
586
587 8976
        if (av == NULL)
588 8064
                return;
589
590
#define FEATURE(nm, tst)                                \
591
        do {                                            \
592
                if (!strcmp(feat, nm)) {                \
593
                        good = 1;                       \
594
                        if (tst) {                      \
595
                                skip = neg;             \
596
                        } else {                        \
597
                                skip = !neg;            \
598
                        }                               \
599
                }                                       \
600
        } while (0)
601
602 912
        skip = 0;
603
604 1712
        for (av++; *av != NULL; av++) {
605 920
                good = 0;
606 920
                neg = 0;
607 920
                feat = *av;
608
609 920
                if (feat[0] == '!') {
610 72
                        neg = 1;
611 72
                        feat++;
612 72
                }
613
614 920
                FEATURE("ipv4", ipvx_works("127.0.0.1"));
615 920
                FEATURE("ipv6", ipvx_works("[::1]"));
616 920
                FEATURE("64bit", sizeof(void*) == 8);
617 920
                FEATURE("disable_aslr", addr_no_randomize_works());
618 920
                FEATURE("dns", dns_works());
619 920
                FEATURE("topbuild", iflg);
620 920
                FEATURE("root", !geteuid());
621 920
                FEATURE("user_varnish", getpwnam("varnish") != NULL);
622 920
                FEATURE("user_vcache", getpwnam("vcache") != NULL);
623 920
                FEATURE("group_varnish", getgrnam("varnish") != NULL);
624 920
                FEATURE("persistent_storage", with_persistent_storage);
625 920
                FEATURE("coverage", coverage);
626 920
                FEATURE("asan", asan);
627 920
                FEATURE("msan", msan);
628 920
                FEATURE("tsan", tsan);
629 920
                FEATURE("ubsan", ubsan);
630 920
                FEATURE("sanitizer", sanitizer);
631 920
                FEATURE("workspace_emulator", workspace_emulator);
632 920
                FEATURE("abstract_uds", abstract_uds_works());
633
634 920
                if (!strcmp(feat, "cmd")) {
635 312
                        good = 1;
636 312
                        skip = neg;
637 312
                        av++;
638 312
                        if (*av == NULL)
639 0
                                vtc_fatal(vl, "Missing the command-line");
640 312
                        r = system(*av);
641 312
                        if (WEXITSTATUS(r) != 0)
642 64
                                skip = !neg;
643 920
                } else if (!strcmp(feat, "ignore_unknown_macro")) {
644 80
                        ign_unknown_macro = 1;
645 80
                        good = 1;
646 80
                }
647 920
                if (!good)
648 0
                        vtc_fatal(vl, "FAIL test, unknown feature: %s", feat);
649
650 920
                if (!skip)
651 800
                        continue;
652
653 120
                vtc_stop = 2;
654 120
                if (neg)
655 16
                        vtc_log(vl, 1,
656 8
                            "SKIPPING test, conflicting feature: %s", feat);
657
                else
658 224
                        vtc_log(vl, 1,
659 112
                            "SKIPPING test, lacking feature: %s", feat);
660 120
                return;
661
        }
662 8976
}