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 3027
cmd_vtest(CMD_ARGS)
72
{
73
74 3027
        (void)priv;
75 3027
        (void)vl;
76
77 3027
        if (av == NULL)
78 3021
                return;
79 6
        AZ(strcmp(av[0], "vtest"));
80
81 6
        vtc_log(vl, 1, "VTEST %s", av[1]);
82 6
        AZ(av[2]);
83 3027
}
84
85
/* SECTION: varnishtest varnishtest
86
 *
87
 * Alternate name for 'vtest', see above.
88
 *
89
 */
90
91
void v_matchproto_(cmd_f)
92 6036
cmd_varnishtest(CMD_ARGS)
93
{
94
95 6036
        (void)priv;
96 6036
        (void)vl;
97
98 6036
        if (av == NULL)
99 3021
                return;
100 3015
        AZ(strcmp(av[0], "varnishtest"));
101
102 3015
        vtc_log(vl, 1, "VTEST %s", av[1]);
103 3015
        AZ(av[2]);
104 6036
}
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 1410
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 1410
        vre_t *vre = NULL;
152
        int r, c;
153
        int err, erroff;
154
        char errbuf[VRE_ERROR_LEN];
155
156 1410
        AN(vl);
157 1410
        AN(cmd);
158 1410
        vsb = VSB_new_auto();
159 1410
        AN(vsb);
160 1410
        if (re != NULL) {
161 213
                vre = VRE_compile(re, 0, &err, &erroff, 1);
162 213
                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 213
        }
172 1410
        VSB_printf(vsb, "exec 2>&1 ; %s", cmd);
173 1410
        AZ(VSB_finish(vsb));
174 1410
        vtc_dump(vl, 4, "shell_cmd", VSB_data(vsb), -1);
175 1410
        fp = popen(VSB_data(vsb), "r");
176 1410
        if (fp == NULL)
177 0
                vtc_fatal(vl, "popen fails: %s", strerror(errno));
178 1410
        VSB_clear(vsb);
179 1410
        do {
180 1805445
                c = getc(fp);
181 1805445
                if (c != EOF)
182 1804035
                        VSB_putc(vsb, c);
183 1805445
        } while (c != EOF);
184 1410
        r = pclose(fp);
185 1410
        AZ(VSB_finish(vsb));
186 1410
        vtc_dump(vl, 4, "shell_out", VSB_data(vsb), VSB_len(vsb));
187 1410
        vtc_log(vl, 4, "shell_status = 0x%04x", WEXITSTATUS(r));
188 1410
        if (WIFSIGNALED(r))
189 0
                vtc_log(vl, 4, "shell_signal = %d", WTERMSIG(r));
190
191 1410
        if (ok < 0 && !WEXITSTATUS(r) && !WIFSIGNALED(r))
192 0
                vtc_fatal(vl, "shell did not fail as expected");
193 1410
        else if (ok >= 0 && WEXITSTATUS(r) != ok)
194 12
                vtc_fatal(vl, "shell_exit not as expected: "
195 6
                    "got 0x%04x wanted 0x%04x", WEXITSTATUS(r), ok);
196
197 1404
        if (expect != NULL) {
198 690
                if (strstr(VSB_data(vsb), expect) == NULL)
199 0
                        vtc_fatal(vl,
200 0
                            "shell_expect not found: (\"%s\")", expect);
201
                else
202 690
                        vtc_log(vl, 4, "shell_expect found");
203 1404
        } else if (vre != NULL) {
204 213
                if (VRE_match(vre, VSB_data(vsb), VSB_len(vsb), 0, NULL) < 1)
205 0
                        vtc_fatal(vl, "shell_match failed: (\"%s\")", re);
206
                else
207 213
                        vtc_log(vl, 4, "shell_match succeeded");
208 213
                VRE_free(&vre);
209 213
        }
210 1404
        VSB_destroy(&vsb);
211 1404
}
212
213
214
void
215 4431
cmd_shell(CMD_ARGS)
216
{
217 4431
        const char *expect = NULL;
218 4431
        const char *re = NULL;
219
        int n;
220 4431
        int ok = 0;
221
222 4431
        (void)priv;
223
224 4431
        if (av == NULL)
225 3021
                return;
226 2976
        for (n = 1; av[n] != NULL; n++) {
227 2976
                if (!strcmp(av[n], "-err")) {
228 615
                        ok = -1;
229 2976
                } else if (!strcmp(av[n], "-exit")) {
230 48
                        n += 1;
231 48
                        ok = atoi(av[n]);
232 2361
                } else if (!strcmp(av[n], "-expect")) {
233 690
                        if (re != NULL)
234 0
                                vtc_fatal(vl,
235
                                    "Cannot use -expect with -match");
236 690
                        n += 1;
237 690
                        expect = av[n];
238 2313
                } else if (!strcmp(av[n], "-match")) {
239 213
                        if (expect != NULL)
240 0
                                vtc_fatal(vl,
241
                                    "Cannot use -match with -expect");
242 213
                        n += 1;
243 213
                        re = av[n];
244 213
                } else {
245 1410
                        break;
246
                }
247 1566
        }
248 1410
        AN(av[n]);
249 1410
        cmd_shell_engine(vl, ok, av[n], expect, re);
250 4431
}
251
252
/* SECTION: filewrite filewrite
253
 *
254
 * Write strings to file
255
 *
256
 *         filewrite [-a] /somefile "Hello" " " "World\n"
257
 *
258
 * The -a flag opens the file in append mode.
259
 *
260
 */
261
262
void v_matchproto_(cmd_f)
263 3114
cmd_filewrite(CMD_ARGS)
264
{
265
        FILE *fo;
266
        int n;
267 3114
        const char *mode = "w";
268
269 3114
        (void)priv;
270
271 3114
        if (av == NULL)
272 3021
                return;
273 93
        if (av[1] != NULL && !strcmp(av[1], "-a")) {
274 42
                av++;
275 42
                mode = "a";
276 42
        }
277 93
        if (av[1] == NULL)
278 0
                vtc_fatal(vl, "Need filename");
279 93
        fo = fopen(av[1], mode);
280 93
        if (fo == NULL)
281 0
                vtc_fatal(vl, "Cannot open %s: %s", av[1], strerror(errno));
282 222
        for (n = 2; av[n] != NULL; n++)
283 129
                (void)fputs(av[n], fo);
284 93
        AZ(fclose(fo));
285 3114
}
286
287
/* SECTION: setenv setenv
288
 *
289
 * Set or change an environment variable::
290
 *
291
 *         setenv FOO "bar baz"
292
 *
293
 * The above will set the environment variable $FOO to the value
294
 * provided. There is also an ``-ifunset`` argument which will only
295
 * set the value if the environment variable does not already
296
 * exist::
297
 *
298
 *        setenv -ifunset FOO quux
299
 */
300
301
void v_matchproto_(cmd_f)
302 3033
cmd_setenv(CMD_ARGS)
303
{
304
        int r;
305
        int force;
306
307 3033
        (void)priv;
308
309 3033
        if (av == NULL)
310 3021
                return;
311 12
        AN(av[1]);
312 12
        AN(av[2]);
313
314 12
        force = 1;
315 12
        if (strcmp("-ifunset", av[1]) == 0) {
316 3
                force = 0;
317 3
                av++;
318 3
                AN(av[2]);
319 3
        }
320 12
        if (av[3] != NULL)
321 0
                vtc_fatal(vl, "CMD setenv: Unexpected argument '%s'", av[3]);
322 12
        r = setenv(av[1], av[2], force);
323 12
        if (r != 0)
324 0
                vtc_log(vl, 0, "CMD setenv %s=\"%s\" failed: %s",
325 0
                    av[1], av[2], strerror(errno));
326 3033
}
327
328
/* SECTION: delay delay
329
 *
330
 * NOTE: This command is available everywhere commands are given.
331
 *
332
 * Sleep for the number of seconds specified in the argument. The number
333
 * can include a fractional part, e.g. 1.5.
334
 */
335
void
336 4821
cmd_delay(CMD_ARGS)
337
{
338
        double f;
339
340 4821
        (void)priv;
341 4821
        if (av == NULL)
342 3021
                return;
343 1800
        AN(av[1]);
344 1800
        AZ(av[2]);
345 1800
        f = VNUM(av[1]);
346 1800
        if (isnan(f))
347 0
                vtc_fatal(vl, "Syntax error in number (%s)", av[1]);
348 1800
        vtc_log(vl, 3, "delaying %g second(s)", f);
349 1800
        VTIM_sleep(f);
350 4821
}
351
352
/* SECTION: include include
353
 *
354
 * Executes a vtc fragment::
355
 *
356
 *         include FILE [...]
357
 *
358
 * Open a file and execute it as a VTC fragment. This command is available
359
 * everywhere commands are given.
360
 *
361
 */
362
void
363 3021
cmd_include(CMD_ARGS)
364
{
365
        char *spec;
366
        unsigned i;
367
368 3021
        if (av == NULL)
369 3021
                return;
370
371 0
        if (av[1] == NULL)
372 0
                vtc_fatal(vl, "CMD include: At least 1 argument required");
373
374 0
        for (i = 1; av[i] != NULL; i++) {
375 0
                spec = VFIL_readfile(NULL, av[i], NULL);
376 0
                if (spec == NULL)
377 0
                        vtc_fatal(vl, "CMD include: Unable to read file '%s' "
378 0
                            "(%s)", av[i], strerror(errno));
379 0
                vtc_log(vl, 2, "Begin include '%s'", av[i]);
380 0
                parse_string(vl, priv, spec);
381 0
                vtc_log(vl, 2, "End include '%s'", av[i]);
382 0
                free(spec);
383 0
        }
384 3021
}
385
386
/**********************************************************************
387
 * Most test-cases use only numeric IP#'s but a few requires non-demented
388
 * DNS services.  This is a basic sanity check for those.
389
 */
390
391
static int
392 3
dns_works(void)
393
{
394
        const struct suckaddr *sa;
395
        char abuf[VTCP_ADDRBUFSIZE];
396
        char pbuf[VTCP_PORTBUFSIZE];
397
398 3
        sa = VSS_ResolveOne(NULL, "dns-canary.varnish-cache.org", NULL,
399
            AF_INET, SOCK_STREAM, 0);
400 3
        if (sa == NULL)
401 0
                return (0);
402 3
        VTCP_name(sa, abuf, sizeof abuf, pbuf, sizeof pbuf);
403 3
        VSA_free(&sa);
404 3
        if (strcmp(abuf, "192.0.2.255"))
405 0
                return (0);
406
407 3
        sa = VSS_ResolveOne(NULL, "dns-canary.varnish-cache.org", NULL,
408
            AF_INET6, SOCK_STREAM, 0);
409 3
        if (sa == NULL)
410 3
                return (1); /* the canary is ipv4 only */
411 0
        VSA_free(&sa);
412 0
        return (0);
413 3
}
414
415
/**********************************************************************
416
 * Test if IPv4/IPv6 works
417
 */
418
419
static int
420 21
ipvx_works(const char *target)
421
{
422
        const struct suckaddr *sa;
423
        int fd;
424
425 21
        sa = VSS_ResolveOne(NULL, target, "0", 0, SOCK_STREAM, 0);
426 21
        if (sa == NULL)
427 0
                return (0);
428 21
        fd = VTCP_bind(sa, NULL);
429 21
        VSA_free(&sa);
430 21
        if (fd >= 0) {
431 21
                VTCP_close(&fd);
432 21
                return (1);
433
        }
434 0
        return (0);
435 21
}
436
437
/**********************************************************************/
438
439
static int
440 3
addr_no_randomize_works(void)
441
{
442 3
        int r = 0;
443
444
#ifdef HAVE_SYS_PERSONALITY_H
445
        r = personality(0xffffffff);
446
        r = personality(r | ADDR_NO_RANDOMIZE);
447
#endif
448 3
        return (r >= 0);
449
}
450
451
/**********************************************************************/
452
453
static int
454 3
uds_socket(void *priv, const struct sockaddr_un *uds)
455
{
456
457 3
        return (VUS_bind(uds, priv));
458
}
459
static int
460 3
abstract_uds_works(void)
461
{
462
        const char *err;
463
        int fd;
464
465 3
        fd = VUS_resolver("@vtc.feature.abstract_uds", uds_socket, NULL, &err);
466 3
        if (fd < 0)
467 3
                return (0);
468 0
        AZ(close(fd));
469 0
        return (1);
470 3
}
471
472
/* SECTION: feature feature
473
 *
474
 * Test that the required feature(s) for a test are available, and skip
475
 * the test otherwise; or change the interpretation of the test, as
476
 * documented below. feature takes any number of arguments from this list:
477
 *
478
 * 64bit
479
 *        The environment is 64 bits
480
 * ipv4
481
 *        127.0.0.1 works
482
 * ipv6
483
 *        [::1] works
484
 * dns
485
 *        DNS lookups are working
486
 * topbuild
487
 *        The test has been started with '-i'
488
 * root
489
 *        The test has been invoked by the root user
490
 * user_varnish
491
 *        The varnish user is present
492
 * user_vcache
493
 *        The vcache user is present
494
 * group_varnish
495
 *        The varnish group is present
496
 * cmd <command-line>
497
 *        A command line that should execute with a zero exit status
498
 * ignore_unknown_macro
499
 *        Do not fail the test if a string of the form ${...} is not
500
 *        recognized as a macro.
501
 * persistent_storage
502
 *        Varnish was built with the deprecated persistent storage.
503
 * coverage
504
 *        Varnish was built with code coverage enabled.
505
 * asan
506
 *        Varnish was built with the address sanitizer.
507
 * msan
508
 *        Varnish was built with the memory sanitizer.
509
 * tsan
510
 *        Varnish was built with the thread sanitizer.
511
 * ubsan
512
 *        Varnish was built with the undefined behavior sanitizer.
513
 * sanitizer
514
 *        Varnish was built with a sanitizer.
515
 * workspace_emulator
516
 *        Varnish was built with its workspace emulator.
517
 * abstract_uds
518
 *        Creation of an abstract unix domain socket succeeded.
519
 * disable_aslr
520
 *        ASLR can be disabled.
521
 *
522
 * A feature name can be prefixed with an exclamation mark (!) to skip a
523
 * test if the feature is present.
524
 *
525
 * Be careful with ignore_unknown_macro, because it may cause a test with a
526
 * misspelled macro to fail silently. You should only need it if you must
527
 * run a test with strings of the form "${...}".
528
 */
529
530
#if ENABLE_COVERAGE
531
static const unsigned coverage = 1;
532
#else
533
static const unsigned coverage = 0;
534
#endif
535
536
#if ENABLE_ASAN
537
static const unsigned asan = 1;
538
#else
539
static const unsigned asan = 0;
540
#endif
541
542
#if ENABLE_MSAN
543
static const unsigned msan = 1;
544
#else
545
static const unsigned msan = 0;
546
#endif
547
548
#if ENABLE_TSAN
549
static const unsigned tsan = 1;
550
#else
551
static const unsigned tsan = 0;
552
#endif
553
554
#if ENABLE_UBSAN
555
static const unsigned ubsan = 1;
556
#else
557
static const unsigned ubsan = 0;
558
#endif
559
560
#if ENABLE_SANITIZER
561
static const unsigned sanitizer = 1;
562
#else
563
static const unsigned sanitizer = 0;
564
#endif
565
566
#if ENABLE_WORKSPACE_EMULATOR
567
static const unsigned workspace_emulator = 1;
568
#else
569
static const unsigned workspace_emulator = 0;
570
#endif
571
572
#if WITH_PERSISTENT_STORAGE
573
static const unsigned with_persistent_storage = 1;
574
#else
575
static const unsigned with_persistent_storage = 0;
576
#endif
577
578
void v_matchproto_(cmd_f)
579 3360
cmd_feature(CMD_ARGS)
580
{
581
        const char *feat;
582
        int r, good, skip, neg;
583
584 3360
        (void)priv;
585
586 3360
        if (av == NULL)
587 3021
                return;
588
589
#define FEATURE(nm, tst)                                \
590
        do {                                            \
591
                if (!strcmp(feat, nm)) {                \
592
                        good = 1;                       \
593
                        if (tst) {                      \
594
                                skip = neg;             \
595
                        } else {                        \
596
                                skip = !neg;            \
597
                        }                               \
598
                }                                       \
599
        } while (0)
600
601 339
        skip = 0;
602
603 636
        for (av++; *av != NULL; av++) {
604 342
                good = 0;
605 342
                neg = 0;
606 342
                feat = *av;
607
608 342
                if (feat[0] == '!') {
609 24
                        neg = 1;
610 24
                        feat++;
611 24
                }
612
613 342
                FEATURE("ipv4", ipvx_works("127.0.0.1"));
614 342
                FEATURE("ipv6", ipvx_works("[::1]"));
615 342
                FEATURE("64bit", sizeof(void*) == 8);
616 342
                FEATURE("disable_aslr", addr_no_randomize_works());
617 342
                FEATURE("dns", dns_works());
618 342
                FEATURE("topbuild", iflg);
619 342
                FEATURE("root", !geteuid());
620 342
                FEATURE("user_varnish", getpwnam("varnish") != NULL);
621 342
                FEATURE("user_vcache", getpwnam("vcache") != NULL);
622 342
                FEATURE("group_varnish", getgrnam("varnish") != NULL);
623 342
                FEATURE("persistent_storage", with_persistent_storage);
624 342
                FEATURE("coverage", coverage);
625 342
                FEATURE("asan", asan);
626 342
                FEATURE("msan", msan);
627 342
                FEATURE("tsan", tsan);
628 342
                FEATURE("ubsan", ubsan);
629 342
                FEATURE("sanitizer", sanitizer);
630 342
                FEATURE("workspace_emulator", workspace_emulator);
631 342
                FEATURE("abstract_uds", abstract_uds_works());
632
633 342
                if (!strcmp(feat, "cmd")) {
634 117
                        good = 1;
635 117
                        skip = neg;
636 117
                        av++;
637 117
                        if (*av == NULL)
638 0
                                vtc_fatal(vl, "Missing the command-line");
639 117
                        r = system(*av);
640 117
                        if (WEXITSTATUS(r) != 0)
641 24
                                skip = !neg;
642 342
                } else if (!strcmp(feat, "ignore_unknown_macro")) {
643 30
                        ign_unknown_macro = 1;
644 30
                        good = 1;
645 30
                }
646 342
                if (!good)
647 0
                        vtc_fatal(vl, "FAIL test, unknown feature: %s", feat);
648
649 342
                if (!skip)
650 297
                        continue;
651
652 45
                vtc_stop = 2;
653 45
                if (neg)
654 6
                        vtc_log(vl, 1,
655 3
                            "SKIPPING test, conflicting feature: %s", feat);
656
                else
657 84
                        vtc_log(vl, 1,
658 42
                            "SKIPPING test, lacking feature: %s", feat);
659 45
                return;
660
        }
661 3360
}