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 24475
cmd_vtest(CMD_ARGS)
72
{
73
74 24475
        (void)priv;
75 24475
        (void)vl;
76
77 24475
        if (av == NULL)
78 24425
                return;
79 50
        AZ(strcmp(av[0], "vtest"));
80
81 50
        vtc_log(vl, 1, "VTEST %s", av[1]);
82 50
        AZ(av[2]);
83 24475
}
84
85
/* SECTION: varnishtest varnishtest
86
 *
87
 * Alternate name for 'vtest', see above.
88
 *
89
 */
90
91
void v_matchproto_(cmd_f)
92 48800
cmd_varnishtest(CMD_ARGS)
93
{
94
95 48800
        (void)priv;
96 48800
        (void)vl;
97
98 48800
        if (av == NULL)
99 24425
                return;
100 24375
        AZ(strcmp(av[0], "varnishtest"));
101
102 24375
        vtc_log(vl, 1, "VTEST %s", av[1]);
103 24375
        AZ(av[2]);
104 48800
}
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 11325
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 11325
        vre_t *vre = NULL;
152
        int r, c;
153
        int err, erroff;
154
        char errbuf[VRE_ERROR_LEN];
155
156 11325
        AN(vl);
157 11325
        AN(cmd);
158 11325
        vsb = VSB_new_auto();
159 11325
        AN(vsb);
160 11325
        if (re != NULL) {
161 1650
                vre = VRE_compile(re, 0, &err, &erroff, 1);
162 1650
                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 1650
        }
172 11325
        VSB_printf(vsb, "exec 2>&1 ; %s", cmd);
173 11325
        AZ(VSB_finish(vsb));
174 11325
        vtc_dump(vl, 4, "shell_cmd", VSB_data(vsb), -1);
175 11325
        fp = popen(VSB_data(vsb), "r");
176 11325
        if (fp == NULL)
177 0
                vtc_fatal(vl, "popen fails: %s", strerror(errno));
178 11325
        VSB_clear(vsb);
179 11325
        do {
180 13751659
                c = getc(fp);
181 13751659
                if (c != EOF)
182 13740334
                        VSB_putc(vsb, c);
183 13751659
        } while (c != EOF);
184 11325
        r = pclose(fp);
185 11325
        AZ(VSB_finish(vsb));
186 11325
        vtc_dump(vl, 4, "shell_out", VSB_data(vsb), VSB_len(vsb));
187 11325
        vtc_log(vl, 4, "shell_status = 0x%04x", WEXITSTATUS(r));
188 11325
        if (WIFSIGNALED(r))
189 0
                vtc_log(vl, 4, "shell_signal = %d", WTERMSIG(r));
190
191 11325
        if (ok < 0 && !WEXITSTATUS(r) && !WIFSIGNALED(r))
192 0
                vtc_fatal(vl, "shell did not fail as expected");
193 11325
        else if (ok >= 0 && WEXITSTATUS(r) != ok)
194 100
                vtc_fatal(vl, "shell_exit not as expected: "
195 50
                    "got 0x%04x wanted 0x%04x", WEXITSTATUS(r), ok);
196
197 11275
        if (expect != NULL) {
198 5650
                if (strstr(VSB_data(vsb), expect) == NULL)
199 0
                        vtc_fatal(vl,
200 0
                            "shell_expect not found: (\"%s\")", expect);
201
                else
202 5650
                        vtc_log(vl, 4, "shell_expect found");
203 11275
        } else if (vre != NULL) {
204 1650
                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 1650
                        vtc_log(vl, 4, "shell_match succeeded");
208 1650
                VRE_free(&vre);
209 1650
        }
210 11275
        VSB_destroy(&vsb);
211 11275
}
212
213
214
void
215 35750
cmd_shell(CMD_ARGS)
216
{
217 35750
        const char *expect = NULL;
218 35750
        const char *re = NULL;
219
        int n;
220 35750
        int ok = 0;
221
222 35750
        (void)priv;
223
224 35750
        if (av == NULL)
225 24425
                return;
226 24100
        for (n = 1; av[n] != NULL; n++) {
227 24100
                if (!strcmp(av[n], "-err")) {
228 5075
                        ok = -1;
229 24100
                } else if (!strcmp(av[n], "-exit")) {
230 400
                        n += 1;
231 400
                        ok = atoi(av[n]);
232 19025
                } else if (!strcmp(av[n], "-expect")) {
233 5650
                        if (re != NULL)
234 0
                                vtc_fatal(vl,
235
                                    "Cannot use -expect with -match");
236 5650
                        n += 1;
237 5650
                        expect = av[n];
238 18625
                } else if (!strcmp(av[n], "-match")) {
239 1650
                        if (expect != NULL)
240 0
                                vtc_fatal(vl,
241
                                    "Cannot use -match with -expect");
242 1650
                        n += 1;
243 1650
                        re = av[n];
244 1650
                } else {
245 11325
                        break;
246
                }
247 12775
        }
248 11325
        AN(av[n]);
249 11325
        cmd_shell_engine(vl, ok, av[n], expect, re);
250 35750
}
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 25200
cmd_filewrite(CMD_ARGS)
264
{
265
        FILE *fo;
266
        int n;
267 25200
        const char *mode = "w";
268
269 25200
        (void)priv;
270
271 25200
        if (av == NULL)
272 24425
                return;
273 775
        if (av[1] != NULL && !strcmp(av[1], "-a")) {
274 350
                av++;
275 350
                mode = "a";
276 350
        }
277 775
        if (av[1] == NULL)
278 0
                vtc_fatal(vl, "Need filename");
279 775
        fo = fopen(av[1], mode);
280 775
        if (fo == NULL)
281 0
                vtc_fatal(vl, "Cannot open %s: %s", av[1], strerror(errno));
282 1850
        for (n = 2; av[n] != NULL; n++)
283 1075
                (void)fputs(av[n], fo);
284 775
        AZ(fclose(fo));
285 25200
}
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 the environment variable does not already
296
 * exist::
297
 *
298
 *        setenv -ifunset FOO quux
299
 */
300
301
void v_matchproto_(cmd_f)
302 24525
cmd_setenv(CMD_ARGS)
303
{
304
        int r;
305
        int force;
306
307 24525
        (void)priv;
308
309 24525
        if (av == NULL)
310 24425
                return;
311 100
        AN(av[1]);
312 100
        AN(av[2]);
313
314 100
        force = 1;
315 100
        if (strcmp("-ifunset", av[1]) == 0) {
316 25
                force = 0;
317 25
                av++;
318 25
                AN(av[2]);
319 25
        }
320 100
        if (av[3] != NULL)
321 0
                vtc_fatal(vl, "CMD setenv: Unexpected argument '%s'", av[3]);
322 100
        r = setenv(av[1], av[2], force);
323 100
        if (r != 0)
324 0
                vtc_log(vl, 0, "CMD setenv %s=\"%s\" failed: %s",
325 0
                    av[1], av[2], strerror(errno));
326 24525
}
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 38944
cmd_delay(CMD_ARGS)
337
{
338
        double f;
339
340 38944
        (void)priv;
341 38944
        if (av == NULL)
342 24425
                return;
343 14519
        AN(av[1]);
344 14519
        AZ(av[2]);
345 14519
        f = VNUM(av[1]);
346 14519
        if (isnan(f))
347 0
                vtc_fatal(vl, "Syntax error in number (%s)", av[1]);
348 14519
        vtc_log(vl, 3, "delaying %g second(s)", f);
349 14519
        VTIM_sleep(f);
350 38944
}
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 24425
cmd_include(CMD_ARGS)
364
{
365
        char *spec;
366
        unsigned i;
367
368 24425
        if (av == NULL)
369 24425
                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 24425
}
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 25
dns_works(void)
393
{
394
        const struct suckaddr *sa;
395
        char abuf[VTCP_ADDRBUFSIZE];
396
        char pbuf[VTCP_PORTBUFSIZE];
397
398 25
        sa = VSS_ResolveOne(NULL, "dns-canary.varnish-cache.org", NULL,
399
            AF_INET, SOCK_STREAM, 0);
400 25
        if (sa == NULL)
401 0
                return (0);
402 25
        VTCP_name(sa, abuf, sizeof abuf, pbuf, sizeof pbuf);
403 25
        VSA_free(&sa);
404 25
        if (strcmp(abuf, "192.0.2.255"))
405 0
                return (0);
406
407 25
        sa = VSS_ResolveOne(NULL, "dns-canary.varnish-cache.org", NULL,
408
            AF_INET6, SOCK_STREAM, 0);
409 25
        if (sa == NULL)
410 25
                return (1); /* the canary is ipv4 only */
411 0
        VSA_free(&sa);
412 0
        return (0);
413 25
}
414
415
/**********************************************************************
416
 * Test if IPv4/IPv6 works
417
 */
418
419
static int
420 175
ipvx_works(const char *target)
421
{
422
        const struct suckaddr *sa;
423
        int fd;
424
425 175
        sa = VSS_ResolveOne(NULL, target, "0", 0, SOCK_STREAM, 0);
426 175
        if (sa == NULL)
427 0
                return (0);
428 175
        fd = VTCP_bind(sa, NULL);
429 175
        VSA_free(&sa);
430 175
        if (fd >= 0) {
431 175
                VTCP_close(&fd);
432 175
                return (1);
433
        }
434 0
        return (0);
435 175
}
436
437
/**********************************************************************/
438
439
static int
440 0
addr_no_randomize_works(void)
441
{
442 0
        int r = 0;
443
444
#ifdef HAVE_SYS_PERSONALITY_H
445
        r = personality(0xffffffff);
446
        r = personality(r | ADDR_NO_RANDOMIZE);
447
#endif
448 0
        return (r >= 0);
449
}
450
451
/**********************************************************************/
452
453
static int
454 25
uds_socket(void *priv, const struct sockaddr_un *uds)
455
{
456
457 25
        return (VUS_bind(uds, priv));
458
}
459
static int
460 25
abstract_uds_works(void)
461
{
462
        const char *err;
463
        int fd;
464
465 25
        fd = VUS_resolver("@vtc.feature.abstract_uds", uds_socket, NULL, &err);
466 25
        if (fd < 0)
467 25
                return (0);
468 0
        AZ(close(fd));
469 0
        return (1);
470 25
}
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
 *
520
 * A feature name can be prefixed with an exclamation mark (!) to skip a
521
 * test if the feature is present.
522
 *
523
 * Be careful with ignore_unknown_macro, because it may cause a test with a
524
 * misspelled macro to fail silently. You should only need it if you must
525
 * run a test with strings of the form "${...}".
526
 */
527
528
#if ENABLE_COVERAGE
529
static const unsigned coverage = 1;
530
#else
531
static const unsigned coverage = 0;
532
#endif
533
534
#if ENABLE_ASAN
535
static const unsigned asan = 1;
536
#else
537
static const unsigned asan = 0;
538
#endif
539
540
#if ENABLE_MSAN
541
static const unsigned msan = 1;
542
#else
543
static const unsigned msan = 0;
544
#endif
545
546
#if ENABLE_TSAN
547
static const unsigned tsan = 1;
548
#else
549
static const unsigned tsan = 0;
550
#endif
551
552
#if ENABLE_UBSAN
553
static const unsigned ubsan = 1;
554
#else
555
static const unsigned ubsan = 0;
556
#endif
557
558
#if ENABLE_SANITIZER
559
static const unsigned sanitizer = 1;
560
#else
561
static const unsigned sanitizer = 0;
562
#endif
563
564
#if ENABLE_WORKSPACE_EMULATOR
565
static const unsigned workspace_emulator = 1;
566
#else
567
static const unsigned workspace_emulator = 0;
568
#endif
569
570
#if WITH_PERSISTENT_STORAGE
571
static const unsigned with_persistent_storage = 1;
572
#else
573
static const unsigned with_persistent_storage = 0;
574
#endif
575
576
void v_matchproto_(cmd_f)
577 27075
cmd_feature(CMD_ARGS)
578
{
579
        const char *feat;
580
        int r, good, skip, neg;
581
582 27075
        (void)priv;
583
584 27075
        if (av == NULL)
585 24425
                return;
586
587
#define FEATURE(nm, tst)                                \
588
        do {                                            \
589
                if (!strcmp(feat, nm)) {                \
590
                        good = 1;                       \
591
                        if (tst) {                      \
592
                                skip = neg;             \
593
                        } else {                        \
594
                                skip = !neg;            \
595
                        }                               \
596
                }                                       \
597
        } while (0)
598
599 2650
        skip = 0;
600
601 5025
        for (av++; *av != NULL; av++) {
602 2675
                good = 0;
603 2675
                neg = 0;
604 2675
                feat = *av;
605
606 2675
                if (feat[0] == '!') {
607 175
                        neg = 1;
608 175
                        feat++;
609 175
                }
610
611 2675
                FEATURE("ipv4", ipvx_works("127.0.0.1"));
612 2675
                FEATURE("ipv6", ipvx_works("[::1]"));
613 2675
                FEATURE("64bit", sizeof(void*) == 8);
614 2675
                FEATURE("disable_aslr", addr_no_randomize_works());
615 2675
                FEATURE("dns", dns_works());
616 2675
                FEATURE("topbuild", iflg);
617 2675
                FEATURE("root", !geteuid());
618 2675
                FEATURE("user_varnish", getpwnam("varnish") != NULL);
619 2675
                FEATURE("user_vcache", getpwnam("vcache") != NULL);
620 2675
                FEATURE("group_varnish", getgrnam("varnish") != NULL);
621 2675
                FEATURE("persistent_storage", with_persistent_storage);
622 2675
                FEATURE("coverage", coverage);
623 2675
                FEATURE("asan", asan);
624 2675
                FEATURE("msan", msan);
625 2675
                FEATURE("tsan", tsan);
626 2675
                FEATURE("ubsan", ubsan);
627 2675
                FEATURE("sanitizer", sanitizer);
628 2675
                FEATURE("workspace_emulator", workspace_emulator);
629 2675
                FEATURE("abstract_uds", abstract_uds_works());
630
631 2675
                if (!strcmp(feat, "cmd")) {
632 850
                        good = 1;
633 850
                        skip = neg;
634 850
                        av++;
635 850
                        if (*av == NULL)
636 0
                                vtc_fatal(vl, "Missing the command-line");
637 850
                        r = system(*av);
638 850
                        if (WEXITSTATUS(r) != 0)
639 125
                                skip = !neg;
640 2675
                } else if (!strcmp(feat, "ignore_unknown_macro")) {
641 250
                        ign_unknown_macro = 1;
642 250
                        good = 1;
643 250
                }
644 2675
                if (!good)
645 0
                        vtc_fatal(vl, "FAIL test, unknown feature: %s", feat);
646
647 2675
                if (!skip)
648 2375
                        continue;
649
650 300
                vtc_stop = 2;
651 300
                if (neg)
652 50
                        vtc_log(vl, 1,
653 25
                            "SKIPPING test, conflicting feature: %s", feat);
654
                else
655 550
                        vtc_log(vl, 1,
656 275
                            "SKIPPING test, lacking feature: %s", feat);
657 300
                return;
658
        }
659 27075
}