varnish-cache/bin/varnishtest/vtc_process.c
1
/*-
2
 * Copyright (c) 2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Dridi Boukelmoune <dridi@varnish-software.com>
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/resource.h>
32
#include <sys/wait.h>
33
34
#include <errno.h>
35
#include <fcntl.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <unistd.h>
40
41
#include "vtc.h"
42
#include "vlu.h"
43
#include "vsub.h"
44
45
struct process {
46
        unsigned                magic;
47
#define PROCESS_MAGIC           0x1617b43e
48
        char                    *name;
49
        struct vtclog           *vl;
50
        VTAILQ_ENTRY(process)   list;
51
52
        char                    *spec;
53
        char                    *dir;
54
        char                    *out;
55
        char                    *err;
56
        int                     fd_to;
57
        int                     log;
58
        int                     fd_from;
59
        pid_t                   pid;
60
61
        pthread_mutex_t         mtx;
62
        pthread_t               tp;
63
        unsigned                hasthread;
64
        int                     status;
65
};
66
67
static VTAILQ_HEAD(, process)   processes =
68
    VTAILQ_HEAD_INITIALIZER(processes);
69
70
/**********************************************************************
71
 * Allocate and initialize a process
72
 */
73
74
#define PROCESS_EXPAND(field, format, ...)              \
75
        do {                                            \
76
                bprintf(buf, format, __VA_ARGS__);      \
77
                vsb = macro_expand(p->vl, buf);         \
78
                AN(vsb);                                \
79
                p->field = strdup(VSB_data(vsb));       \
80
                AN(p->field);                           \
81
                VSB_destroy(&vsb);                      \
82
        } while (0)
83
84
static struct process *
85 14
process_new(const char *name)
86
{
87
        struct process *p;
88
        struct vsb *vsb;
89
        char buf[1024];
90
91 14
        ALLOC_OBJ(p, PROCESS_MAGIC);
92 14
        AN(p);
93 14
        REPLACE(p->name, name);
94 14
        AZ(pthread_mutex_init(&p->mtx, NULL));
95
96 14
        p->vl = vtc_logopen(name);
97 14
        AN(p->vl);
98
99 14
        PROCESS_EXPAND(dir, "${tmpdir}/%s", name);
100 14
        PROCESS_EXPAND(out, "${tmpdir}/%s/stdout", name);
101 14
        PROCESS_EXPAND(err, "${tmpdir}/%s/stderr", name);
102
103 14
        bprintf(buf, "rm -rf %s ; mkdir -p %s ; touch %s %s",
104
            p->dir, p->dir, p->out, p->err);
105 14
        AZ(system(buf));
106
107 14
        p->fd_to = -1;
108 14
        p->fd_from = -1;
109
110 14
        VTAILQ_INSERT_TAIL(&processes, p, list);
111 14
        return (p);
112
}
113
114
#undef PROCESS_EXPAND
115
116
/**********************************************************************
117
 * Clean up process
118
 */
119
120
static void
121 14
process_delete(struct process *p)
122
{
123
124 14
        CHECK_OBJ_NOTNULL(p, PROCESS_MAGIC);
125 14
        AZ(pthread_mutex_destroy(&p->mtx));
126 14
        vtc_logclose(p->vl);
127 14
        free(p->name);
128 14
        free(p->dir);
129 14
        free(p->out);
130 14
        free(p->err);
131
132
        /*
133
         * We do not delete the directory, it may contain useful stdout
134
         * and stderr files. They will be deleted on account of belonging
135
         * to the test's tmpdir.
136
         */
137
138
        /* XXX: MEMLEAK (?) */
139 14
        FREE_OBJ(p);
140 14
}
141
142
static void
143 14
process_undef(const struct process *p)
144
{
145 14
        CHECK_OBJ_NOTNULL(p, PROCESS_MAGIC);
146
147 14
        macro_undef(p->vl, p->name, "dir");
148 14
        macro_undef(p->vl, p->name, "out");
149 14
        macro_undef(p->vl, p->name, "err");
150 14
}
151
152
/**********************************************************************
153
 * Start the process thread
154
 */
155
156
static int
157 20
process_vlu_func(void *priv, const char *l)
158
{
159
        struct process *p;
160
161 20
        CAST_OBJ_NOTNULL(p, priv, PROCESS_MAGIC);
162 20
        vtc_dump(p->vl, 4, "output", l, -1);
163 20
        return (0);
164
}
165
166
static void *
167 14
process_thread(void *priv)
168
{
169
        struct process *p;
170
        struct rusage ru;
171
        int r;
172
173 14
        CAST_OBJ_NOTNULL(p, priv, PROCESS_MAGIC);
174 14
        if (p->fd_from > 0)
175 2
                (void)VLU_File(p->fd_from, process_vlu_func, p, 1024);
176 14
        r = wait4(p->pid, &p->status, 0, &ru);
177
178 14
        AZ(pthread_mutex_lock(&p->mtx));
179
180 14
        if (p->fd_to >= 0)
181 12
                closefd(&p->fd_to);
182
183
        /* NB: We keep the other macros around */
184 14
        macro_undef(p->vl, p->name, "pid");
185 14
        p->pid = -1;
186
187 56
        vtc_log(p->vl, 2, "R 0x%04x Status: %04x (u %.6f s %.6f)",
188
            r, p->status,
189 28
            ru.ru_utime.tv_sec + 1e-6 * ru.ru_utime.tv_usec,
190 28
            ru.ru_stime.tv_sec + 1e-6 * ru.ru_stime.tv_usec
191
        );
192
193 14
        AZ(pthread_mutex_unlock(&p->mtx));
194
195 14
        if (WIFEXITED(p->status) && WEXITSTATUS(p->status) == 0)
196 8
                return (NULL);
197
#ifdef WCOREDUMP
198 18
        vtc_log(p->vl, 2, "Bad exit code: %04x sig %d exit %d core %d",
199 12
            p->status, WTERMSIG(p->status), WEXITSTATUS(p->status),
200 6
            WCOREDUMP(p->status));
201
#else
202
        vtc_log(p->vl, 2, "Bad exit code: %04x sig %d exit %d",
203
            p->status, WTERMSIG(p->status), WEXITSTATUS(p->status));
204
#endif
205
206 6
        return (NULL);
207
}
208
209
static void
210 14
process_start(struct process *p)
211
{
212
        struct vsb *cl;
213
        int out_fd, err_fd;
214
        int fds[2];
215 14
        int fdt[2] = { -1, -1 };
216
217 14
        CHECK_OBJ_NOTNULL(p, PROCESS_MAGIC);
218 14
        if (p->hasthread)
219 0
                vtc_fatal(p->vl, "Already running, -wait first");
220
221 14
        vtc_log(p->vl, 4, "CMD: %s", p->spec);
222
223 14
        cl = macro_expand(p->vl, p->spec);
224 14
        AN(cl);
225 14
        AZ(pipe(fds));
226 14
        if (p->log) {
227 2
                AZ(pipe(fdt));
228 2
                out_fd = fdt[1];
229 2
                err_fd = fdt[1];
230
        } else {
231 12
                out_fd = open(p->out, O_WRONLY|O_APPEND);
232 12
                assert(out_fd >= 0);
233 12
                err_fd = open(p->err, O_WRONLY|O_APPEND);
234 12
                assert(err_fd >= 0);
235
        }
236 14
        p->pid = fork();
237 28
        assert(p->pid >= 0);
238 28
        if (p->pid == 0) {
239 14
                assert(dup2(fds[0], 0) == 0);
240 14
                assert(dup2(out_fd, 1) == 1);
241 14
                assert(dup2(err_fd, 2) == 2);
242 14
                VSUB_closefrom(STDERR_FILENO + 1);
243 14
                AZ(setpgid(0, 0));
244 14
                AZ(execl("/bin/sh", "/bin/sh", "-c", VSB_data(cl),
245
                    (char *)NULL));
246 0
                exit(1);
247
        }
248 14
        vtc_log(p->vl, 3, "PID: %ld", (long)p->pid);
249 14
        macro_def(p->vl, p->name, "pid", "%ld", (long)p->pid);
250 14
        macro_def(p->vl, p->name, "dir", "%s", p->dir);
251 14
        macro_def(p->vl, p->name, "out", "%s", p->out);
252 14
        macro_def(p->vl, p->name, "err", "%s", p->err);
253 14
        closefd(&fds[0]);
254 14
        p->fd_to = fds[1];
255 14
        if (p->log) {
256 2
                closefd(&fdt[1]);
257 2
                p->fd_from = fdt[0];
258
        } else {
259 12
                closefd(&out_fd);
260 12
                closefd(&err_fd);
261
        }
262 14
        VSB_destroy(&cl);
263 14
        p->hasthread = 1;
264 14
        AZ(pthread_create(&p->tp, NULL, process_thread, p));
265 14
}
266
267
/**********************************************************************
268
 * Wait for process thread to stop
269
 */
270
271
static void
272 14
process_wait(struct process *p)
273
{
274
        void *v;
275
276 14
        if (p->hasthread) {
277 14
                AZ(pthread_join(p->tp, &v));
278 14
                p->hasthread = 0;
279
        }
280 14
}
281
282
/**********************************************************************
283
 * Send a signal to a process
284
 */
285
286
static void
287 6
process_kill(struct process *p, const char *sig)
288
{
289 6
        int j = 0;
290
        pid_t pid;
291
292 6
        CHECK_OBJ_NOTNULL(p, PROCESS_MAGIC);
293 6
        AN(sig);
294
295 6
        AZ(pthread_mutex_lock(&p->mtx));
296 6
        pid = p->pid;
297 6
        AZ(pthread_mutex_unlock(&p->mtx));
298
299 6
        if (pid <= 0)
300 0
                vtc_fatal(p->vl, "Cannot signal a non-running process");
301
302 6
        if (!strcmp(sig, "TERM"))
303 4
                j = SIGTERM;
304 2
        else if (!strcmp(sig, "INT"))
305 0
                j = SIGINT;
306 2
        else if (!strcmp(sig, "KILL"))
307 2
                j = SIGKILL;
308 0
        else if (*sig == '-')
309 0
                j = strtoul(sig + 1, NULL, 10);
310
        else
311 0
                vtc_fatal(p->vl, "Could not grok signal (%s)", sig);
312
313 6
        if (kill(-pid, j) < 0)
314 0
                vtc_fatal(p->vl, "Failed to send signal %d (%s)",
315 0
                    j, strerror(errno));
316
        else
317 6
                vtc_log(p->vl, 4, "Sent signal %d", j);
318 6
}
319
320
/**********************************************************************
321
 * Write to a process' stdin
322
 */
323
324
static void
325 12
process_write(const struct process *p, const char *text)
326
{
327
        int r, len;
328
329 12
        if (!p->hasthread)
330 0
                vtc_fatal(p->vl, "Cannot write to a non-running process");
331
332 12
        len = strlen(text);
333 12
        vtc_log(p->vl, 4, "Writing %d bytes", len);
334 12
        r = write(p->fd_to, text, len);
335 12
        if (r < 0)
336 0
                vtc_fatal(p->vl, "Failed to write: %s (%d)",
337 0
                    strerror(errno), errno);
338 12
}
339
340
static void
341 2
process_close(struct process *p)
342
{
343
344 2
        if (!p->hasthread)
345 0
                vtc_fatal(p->vl, "Cannot close a non-running process");
346
347 2
        AZ(pthread_mutex_lock(&p->mtx));
348 2
        if (p->fd_to >= 0)
349 2
                closefd(&p->fd_to);
350 2
        AZ(pthread_mutex_unlock(&p->mtx));
351 2
}
352
353
/* SECTION: process process
354
 *
355
 * Run a process in the background with stdout and stderr redirected to
356
 * ${pNAME_out} and ${pNAME_err}, both located in ${pNAME_dir}::
357
 *
358
 *      process pNAME SPEC [-log] [-start] [-wait] [-run] [-kill STRING] \
359
 *              [-stop] [-write STRING] [-writeln STRING] [-close]
360
 *
361
 * pNAME
362
 *      Name of the process. It must start with 'p'.
363
 *
364
 * SPEC
365
 *      The command(s) to run in this process.
366
 *
367
 * \-log
368
 *      Log stdout/stderr with vtc_dump(). Must be before -start/-run.
369
 *
370
 * \-start
371
 *      Start the process.
372
 *
373
 * \-wait
374
 *      Wait for the process to finish.
375
 *
376
 * \-run
377
 *      Shorthand for -start -wait.
378
 *
379
 *      In most cases, if you just want to start a process and wait for it
380
 *      to finish, you can use the varnishtest ``shell`` command instead.
381
 *      The following commands are equivalent::
382
 *
383
 *          shell "do --something"
384
 *
385
 *          process p1 "do --something" -run
386
 *
387
 *      However, you may use the the ``process`` variant to conveniently
388
 *      collect the standard input and output without dealing with shell
389
 *      redirections yourself. The ``shell`` command can also expect an
390
 *      expression from either output, consider using it if you only need
391
 *      to match one.
392
 *
393
 * \-kill STRING
394
 *      Send a signal to the process. The argument can be either
395
 *      the string "TERM", "INT", or "KILL" for SIGTERM, SIGINT or SIGKILL
396
 *      signals, respectively, or a hyphen (-) followed by the signal
397
 *      number.
398
 *
399
 *      If you need to use other signal names, you can use the ``kill``\(1)
400
 *      command directly::
401
 *
402
 *          shell "kill -USR1 ${pNAME_pid}"
403
 *
404
 *      Note that SIGHUP usage is discouraged in test cases.
405
 *
406
 * \-stop
407
 *      Shorthand for -kill TERM.
408
 *
409
 * \-write STRING
410
 *      Write a string to the process' stdin.
411
 *
412
 * \-writeln STRING
413
 *      Same as -write followed by a newline (\\n).
414
 *
415
 * \-close
416
 *      Close the process' stdin.
417
 *
418
 */
419
420
void
421 1392
cmd_process(CMD_ARGS)
422
{
423
        struct process *p, *p2;
424
425
        (void)priv;
426
        (void)cmd;
427
428 1392
        if (av == NULL) {
429
                /* Reset and free */
430 1370
                VTAILQ_FOREACH_SAFE(p, &processes, list, p2) {
431 14
                        if (p->pid > 0) {
432 0
                                process_kill(p, "TERM");
433 0
                                sleep(1);
434 0
                                if (p->pid > 0)
435 0
                                        process_kill(p, "KILL");
436
                        }
437 14
                        if (p->hasthread)
438 0
                                process_wait(p);
439 14
                        VTAILQ_REMOVE(&processes, p, list);
440 14
                        process_undef(p);
441 14
                        process_delete(p);
442
                }
443 2748
                return;
444
        }
445
446 36
        AZ(strcmp(av[0], "process"));
447 36
        av++;
448
449 36
        VTC_CHECK_NAME(vl, av[0], "Process", 'p');
450 62
        VTAILQ_FOREACH(p, &processes, list)
451 48
                if (!strcmp(p->name, av[0]))
452 22
                        break;
453 36
        if (p == NULL)
454 14
                p = process_new(av[0]);
455 36
        av++;
456
457 90
        for (; *av != NULL; av++) {
458 54
                if (vtc_error)
459 0
                        break;
460
461 54
                if (!strcmp(*av, "-start")) {
462 10
                        process_start(p);
463 10
                        continue;
464
                }
465 44
                if (!strcmp(*av, "-log")) {
466 2
                        if (p->hasthread)
467 0
                                vtc_fatal(p->vl,
468
                                    "Cannot log a running process");
469 2
                        p->log = 1;
470 2
                        continue;
471
                }
472 42
                if (!strcmp(*av, "-wait")) {
473 10
                        process_wait(p);
474 10
                        continue;
475
                }
476 32
                if (!strcmp(*av, "-run")) {
477 4
                        process_start(p);
478 4
                        process_wait(p);
479 4
                        continue;
480
                }
481 28
                if (!strcmp(*av, "-kill")) {
482 2
                        process_kill(p, av[1]);
483 2
                        av++;
484 2
                        continue;
485
                }
486 26
                if (!strcmp(*av, "-stop")) {
487 4
                        process_kill(p, "TERM");
488 4
                        continue;
489
                }
490 22
                if (!strcmp(*av, "-write")) {
491 0
                        process_write(p, av[1]);
492 0
                        av++;
493 0
                        continue;
494
                }
495 22
                if (!strcmp(*av, "-writeln")) {
496 6
                        process_write(p, av[1]);
497 6
                        process_write(p, "\n");
498 6
                        av++;
499 6
                        continue;
500
                }
501 16
                if (!strcmp(*av, "-close")) {
502 2
                        process_close(p);
503 2
                        continue;
504
                }
505 14
                if (**av == '-')
506 0
                        vtc_fatal(p->vl, "Unknown process argument: %s",
507
                            *av);
508 14
                REPLACE(p->spec, *av);
509
        }
510
}