varnish-cache/bin/varnishtest/vtc_misc.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/wait.h>
32
#include <sys/socket.h>
33
34
#include <grp.h>
35
#include <math.h>
36
#include <pwd.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <unistd.h>
41
42
#ifdef HAVE_SYS_PERSONALITY_H
43
#  include <sys/personality.h>
44
#endif
45
46
#include "vtc.h"
47
48
#include "vnum.h"
49
#include "vre.h"
50
#include "vtcp.h"
51
#include "vss.h"
52
#include "vtim.h"
53
54
/* SECTION: vtest vtest
55
 *
56
 * This should be the first command in your vtc as it will identify the test
57
 * case with a short yet descriptive sentence. It takes exactly one argument, a
58
 * string, eg::
59
 *
60
 *         vtest "Check that vtest is actually a valid command"
61
 *
62
 * It will also print that string in the log.
63
 */
64
65
void v_matchproto_(cmd_f)
66 3192
cmd_vtest(CMD_ARGS)
67
{
68
69 3192
        (void)priv;
70 3192
        (void)cmd;
71 3192
        (void)vl;
72
73 3192
        if (av == NULL)
74 3184
                return;
75 8
        AZ(strcmp(av[0], "vtest"));
76
77 8
        vtc_log(vl, 1, "VTEST %s", av[1]);
78 8
        AZ(av[2]);
79 3192
}
80
81
/* SECTION: varnishtest varnishtest
82
 *
83
 * Alternate name for 'vtest', see above.
84
 *
85
 */
86
87
void v_matchproto_(cmd_f)
88 6360
cmd_varnishtest(CMD_ARGS)
89
{
90
91 6360
        (void)priv;
92 6360
        (void)cmd;
93 6360
        (void)vl;
94
95 6360
        if (av == NULL)
96 3184
                return;
97 3176
        AZ(strcmp(av[0], "varnishtest"));
98
99 3176
        vtc_log(vl, 1, "VTEST %s", av[1]);
100 3176
        AZ(av[2]);
101 6360
}
102
103
/* SECTION: shell shell
104
 *
105
 * NOTE: This command is available everywhere commands are given.
106
 *
107
 * Pass the string given as argument to a shell. If you have multiple
108
 * commands to run, you can use curly brackets to describe a multi-lines
109
 * script, eg::
110
 *
111
 *         shell {
112
 *                 echo begin
113
 *                 cat /etc/fstab
114
 *                 echo end
115
 *         }
116
 *
117
 * By default a zero exit code is expected, otherwise the vtc will fail.
118
 *
119
 * Notice that the commandstring is prefixed with "exec 2>&1;" to combine
120
 * stderr and stdout back to the test process.
121
 *
122
 * Optional arguments:
123
 *
124
 * \-err
125
 *      Expect non-zero exit code.
126
 *
127
 * \-exit N
128
 *      Expect exit code N instead of zero.
129
 *
130
 * \-expect STRING
131
 *      Expect string to be found in stdout+err.
132
 *
133
 * \-match REGEXP
134
 *      Expect regexp to match the stdout+err output.
135
 */
136
/* SECTION: client-server.spec.shell
137
 *
138
 * shell
139
 *      Same as for the top-level shell.
140
 */
141
142
static void
143 1476
cmd_shell_engine(struct vtclog *vl, int ok, const char *cmd,
144
    const char *expect, const char *re)
145
{
146
        struct vsb *vsb;
147
        FILE *fp;
148 1476
        vre_t *vre = NULL;
149
        const char *errptr;
150
        int r, c;
151
        int err;
152
153 1476
        AN(vl);
154 1476
        AN(cmd);
155 1476
        vsb = VSB_new_auto();
156 1476
        AN(vsb);
157 1476
        if (re != NULL) {
158 220
                vre = VRE_compile(re, 0, &errptr, &err);
159 220
                if (vre == NULL)
160 0
                        vtc_fatal(vl, "shell_match invalid regexp (\"%s\")",
161 0
                            re);
162 220
        }
163 1476
        VSB_printf(vsb, "exec 2>&1 ; %s", cmd);
164 1476
        AZ(VSB_finish(vsb));
165 1476
        vtc_dump(vl, 4, "shell_cmd", VSB_data(vsb), -1);
166 1476
        fp = popen(VSB_data(vsb), "r");
167 1476
        if (fp == NULL)
168 0
                vtc_fatal(vl, "popen fails: %s", strerror(errno));
169 1476
        VSB_clear(vsb);
170 1476
        do {
171 1779074
                c = getc(fp);
172 1779074
                if (c != EOF)
173 1777598
                        VSB_putc(vsb, c);
174 1779074
        } while (c != EOF);
175 1476
        r = pclose(fp);
176 1476
        AZ(VSB_finish(vsb));
177 1476
        vtc_dump(vl, 4, "shell_out", VSB_data(vsb), VSB_len(vsb));
178 1476
        vtc_log(vl, 4, "shell_status = 0x%04x", WEXITSTATUS(r));
179 1476
        if (WIFSIGNALED(r))
180 0
                vtc_log(vl, 4, "shell_signal = %d", WTERMSIG(r));
181
182 1476
        if (ok < 0 && !WEXITSTATUS(r) && !WIFSIGNALED(r))
183 0
                vtc_fatal(vl, "shell did not fail as expected");
184 1476
        else if (ok >= 0 && WEXITSTATUS(r) != ok)
185 16
                vtc_fatal(vl, "shell_exit not as expected: "
186 8
                    "got 0x%04x wanted 0x%04x", WEXITSTATUS(r), ok);
187
188 1468
        if (expect != NULL) {
189 816
                if (strstr(VSB_data(vsb), expect) == NULL)
190 0
                        vtc_fatal(vl,
191 0
                            "shell_expect not found: (\"%s\")", expect);
192
                else
193 816
                        vtc_log(vl, 4, "shell_expect found");
194 1468
        } else if (vre != NULL) {
195 440
                if (VRE_exec(vre, VSB_data(vsb), VSB_len(vsb), 0, 0,
196 220
                    NULL, 0, NULL) < 1)
197 0
                        vtc_fatal(vl,
198 0
                            "shell_match failed: (\"%s\")", re);
199
                else
200 220
                        vtc_log(vl, 4, "shell_match succeeded");
201 220
                VRE_free(&vre);
202 220
        }
203 1468
        VSB_destroy(&vsb);
204 1468
}
205
206
207
void
208 4660
cmd_shell(CMD_ARGS)
209
{
210 4660
        const char *expect = NULL;
211 4660
        const char *re = NULL;
212
        int n;
213 4660
        int ok = 0;
214
215 4660
        (void)priv;
216 4660
        (void)cmd;
217
218 4660
        if (av == NULL)
219 3184
                return;
220 3320
        for (n = 1; av[n] != NULL; n++) {
221 3320
                if (!strcmp(av[n], "-err")) {
222 748
                        ok = -1;
223 3320
                } else if (!strcmp(av[n], "-exit")) {
224 60
                        n += 1;
225 60
                        ok = atoi(av[n]);
226 2572
                } else if (!strcmp(av[n], "-expect")) {
227 816
                        if (re != NULL)
228 0
                                vtc_fatal(vl,
229
                                    "Cannot use -expect with -match");
230 816
                        n += 1;
231 816
                        expect = av[n];
232 2512
                } else if (!strcmp(av[n], "-match")) {
233 220
                        if (expect != NULL)
234 0
                                vtc_fatal(vl,
235
                                    "Cannot use -match with -expect");
236 220
                        n += 1;
237 220
                        re = av[n];
238 220
                } else {
239 1476
                        break;
240
                }
241 1844
        }
242 1476
        AN(av[n]);
243 1476
        cmd_shell_engine(vl, ok, av[n], expect, re);
244 4660
}
245
246
/* SECTION: err_shell err_shell
247
 *
248
 * NOTICE: err_shell is deprecated, use `shell -err -expect` instead.
249
 *
250
 * This is very similar to the the ``shell`` command, except it takes a first
251
 * string as argument before the command::
252
 *
253
 *         err_shell "foo" "echo foo"
254
 *
255
 * err_shell expect the shell command to fail AND stdout to match the string,
256
 * failing the test case otherwise.
257
 */
258
259
void v_matchproto_(cmd_f)
260 3184
cmd_err_shell(CMD_ARGS)
261
{
262 3184
        (void)priv;
263 3184
        (void)cmd;
264
265 3184
        if (av == NULL)
266 3184
                return;
267 0
        AN(av[1]);
268 0
        AN(av[2]);
269 0
        AZ(av[3]);
270 0
        vtc_log(vl, 1,
271
            "NOTICE: err_shell is deprecated, use 'shell -err -expect'");
272 0
        cmd_shell_engine(vl, -1, av[2], av[1], NULL);
273 3184
}
274
275
/* SECTION: setenv setenv
276
 *
277
 * Set or change an environment variable::
278
 *
279
 *         setenv FOO "bar baz"
280
 *
281
 * The above will set the environment variable $FOO to the value
282
 * provided. There is also an ``-ifunset`` argument which will only
283
 * set the value if the the environment variable does not already
284
 * exist::
285
 *
286
 *        setenv -ifunset FOO quux
287
 */
288
289
void v_matchproto_(cmd_f)
290 3196
cmd_setenv(CMD_ARGS)
291
{
292
        int r;
293
        int force;
294
295 3196
        (void)priv;
296 3196
        (void)cmd;
297
298 3196
        if (av == NULL)
299 3184
                return;
300 12
        AN(av[1]);
301 12
        AN(av[2]);
302
303 12
        force = 1;
304 12
        if (strcmp("-ifunset", av[1]) == 0) {
305 4
                force = 0;
306 4
                av++;
307 4
                AN(av[2]);
308 4
        }
309 12
        if (av[3] != NULL)
310 0
                vtc_fatal(vl, "CMD setenv: Unexpected argument '%s'", av[3]);
311 12
        r = setenv(av[1], av[2], force);
312 12
        if (r != 0)
313 0
                vtc_log(vl, 0, "CMD setenv %s=\"%s\" failed: %s",
314 0
                    av[1], av[2], strerror(errno));
315 3196
}
316
317
/* SECTION: delay delay
318
 *
319
 * NOTE: This command is available everywhere commands are given.
320
 *
321
 * Sleep for the number of seconds specified in the argument. The number
322
 * can include a fractional part, e.g. 1.5.
323
 *
324
 */
325
void
326 5220
cmd_delay(CMD_ARGS)
327
{
328
        double f;
329
330 5220
        (void)priv;
331 5220
        (void)cmd;
332 5220
        if (av == NULL)
333 3184
                return;
334 2040
        AN(av[1]);
335 2040
        AZ(av[2]);
336 2040
        f = VNUM(av[1]);
337 2040
        if (isnan(f))
338 0
                vtc_fatal(vl, "Syntax error in number (%s)", av[1]);
339 2040
        vtc_log(vl, 3, "delaying %g second(s)", f);
340 2040
        VTIM_sleep(f);
341 5224
}
342
343
/**********************************************************************
344
 * Most test-cases use only numeric IP#'s but a few requires non-demented
345
 * DNS services.  This is a basic sanity check for those.
346
 */
347
348
static int
349 4
dns_works(void)
350
{
351
        struct suckaddr *sa;
352
        char abuf[VTCP_ADDRBUFSIZE];
353
        char pbuf[VTCP_PORTBUFSIZE];
354
355 4
        sa = VSS_ResolveOne(NULL, "dns-canary.freebsd.dk", NULL, AF_UNSPEC, SOCK_STREAM, 0);
356 4
        if (sa == NULL)
357 0
                return (0);
358 4
        VTCP_name(sa, abuf, sizeof abuf, pbuf, sizeof pbuf);
359 4
        free(sa);
360 4
        if (strcmp(abuf, "192.0.2.255"))
361 0
                return (0);
362 4
        return (1);
363 4
}
364
365
/* SECTION: feature feature
366
 *
367
 * Test that the required feature(s) for a test are available, and skip
368
 * the test otherwise; or change the interpretation of the test, as
369
 * documented below. feature takes any number of arguments from this list:
370
 *
371
 * SO_RCVTIMEO_WORKS
372
 *        The SO_RCVTIMEO socket option is working
373
 * 64bit
374
 *        The environment is 64 bits
375
 * dns
376
 *        DNS lookups are working
377
 * topbuild
378
 *        The test has been started with '-i'
379
 * root
380
 *        The test has been invoked by the root user
381
 * user_varnish
382
 *        The varnish user is present
383
 * user_vcache
384
 *        The vcache user is present
385
 * group_varnish
386
 *        The varnish group is present
387
 * cmd <command-line>
388
 *        A command line that should execute with a zero exit status
389
 * ignore_unknown_macro
390
 *        Do not fail the test if a string of the form ${...} is not
391
 *        recognized as a macro.
392
 *
393
 * persistent_storage
394
 *        Varnish was built with the deprecated persistent storage.
395
 *
396
 * Be careful with ignore_unknown_macro, because it may cause a test with a
397
 * misspelled macro to fail silently. You should only need it if you must
398
 * run a test with strings of the form "${...}".
399
 */
400
401
#if WITH_PERSISTENT_STORAGE
402
static const unsigned with_persistent_storage = 1;
403
#else
404
static const unsigned with_persistent_storage = 0;
405
#endif
406
407
void v_matchproto_(cmd_f)
408 3484
cmd_feature(CMD_ARGS)
409
{
410
        int r;
411
        int good;
412
413 3484
        (void)priv;
414 3484
        (void)cmd;
415
416 3484
        if (av == NULL)
417 3184
                return;
418
419
#define FEATURE(nm, tst)                                \
420
        do {                                            \
421
                if (!strcmp(*av, nm)) {                 \
422
                        if (tst) {                      \
423
                                good = 1;               \
424
                        } else {                        \
425
                                vtc_stop = 2;           \
426
                        }                               \
427
                }                                       \
428
        } while (0)
429
430 564
        for (av++; *av != NULL; av++) {
431 300
                good = 0;
432 300
                if (!strcmp(*av, "SO_RCVTIMEO_WORKS")) {
433
#ifdef SO_RCVTIMEO_WORKS
434 28
                        good = 1;
435
#else
436
                        vtc_stop = 2;
437
#endif
438 28
                }
439
440 300
                FEATURE("pcre_jit", VRE_has_jit);
441 300
                FEATURE("64bit", sizeof(void*) == 8);
442 300
                FEATURE("dns", dns_works());
443 300
                FEATURE("topbuild", iflg);
444 300
                FEATURE("root", !geteuid());
445 300
                FEATURE("user_varnish", getpwnam("varnish") != NULL);
446 300
                FEATURE("user_vcache", getpwnam("vcache") != NULL);
447 300
                FEATURE("group_varnish", getgrnam("varnish") != NULL);
448 300
                FEATURE("persistent_storage", with_persistent_storage);
449
450 300
                if (!strcmp(*av, "disable_aslr")) {
451 4
                        good = 1;
452
#ifdef HAVE_SYS_PERSONALITY_H
453
                        r = personality(0xffffffff);
454
                        r = personality(r | ADDR_NO_RANDOMIZE);
455
                        if (r < 0) {
456
                                good = 0;
457
                                vtc_stop = 2;
458
                        }
459
#endif
460 300
                } else if (!strcmp(*av, "cmd")) {
461 72
                        av++;
462 72
                        if (*av == NULL)
463 0
                                vtc_fatal(vl, "Missing the command-line");
464 72
                        r = system(*av);
465 72
                        if (WEXITSTATUS(r) == 0)
466 56
                                good = 1;
467
                        else
468 16
                                vtc_stop = 2;
469 296
                } else if (!strcmp(*av, "ignore_unknown_macro")) {
470 24
                        ign_unknown_macro = 1;
471 24
                        good = 1;
472 24
                }
473 300
                if (good)
474 264
                        continue;
475
476 36
                if (!vtc_stop)
477 0
                        vtc_fatal(vl, "FAIL test, unknown feature: %s", *av);
478
                else
479 72
                        vtc_log(vl, 1,
480 36
                            "SKIPPING test, lacking feature: %s", *av);
481 36
                return;
482
        }
483 3484
}