varnish-cache/lib/libvarnish/vsub.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2011 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
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
 * Run stuff in a child process
30
 */
31
32
#include "config.h"
33
34
#include <sys/wait.h>
35
36
#include <errno.h>
37
#include <stdint.h>
38
#include <stdlib.h>             // Solaris closefrom(3c)
39
#include <string.h>
40
#include <unistd.h>
41
42
#include "vdef.h"
43
44
#include "vas.h"
45
#include "vfil.h"
46
#include "vlu.h"
47
#include "vsb.h"
48
#include "vsub.h"
49
50
struct vsub_priv {
51
        const char      *name;
52
        struct vsb      *sb;
53
        int             lines;
54
        int             maxlines;
55
};
56
57
void
58 8768
VSUB_closefrom(int fd)
59
{
60
61 8768
        assert(fd >= 0);
62
63
#ifdef HAVE_CLOSEFROM
64 8768
        closefrom(fd);
65
#else
66
        int i = sysconf(_SC_OPEN_MAX);
67
        assert(i > 0);
68
        for (; i > fd; i--)
69
                (void)close(i);
70
#endif
71 8768
}
72
73
static int
74 1962
vsub_vlu(void *priv, const char *str)
75
{
76
        struct vsub_priv *sp;
77
78 1962
        sp = priv;
79 1962
        if (!sp->lines++)
80 336
                VSB_printf(sp->sb, "Message from %s:\n", sp->name);
81 1962
        if (sp->maxlines < 0 || sp->lines <= sp->maxlines)
82 1962
                VSB_printf(sp->sb, "%s\n", str);
83 1962
        return (0);
84
}
85
86
/* returns an exit code */
87
unsigned
88 4832
VSUB_run(struct vsb *sb, vsub_func_f *func, void *priv, const char *name,
89
    int maxlines)
90
{
91
        int rv, p[2], status;
92
        pid_t pid;
93
        struct vsub_priv sp;
94
95 4832
        sp.sb = sb;
96 4832
        sp.name = name;
97 4832
        sp.lines = 0;
98 4832
        sp.maxlines = maxlines;
99
100 4832
        if (pipe(p) < 0) {
101 0
                VSB_printf(sb, "Starting %s: pipe() failed: %s",
102 0
                    name, strerror(errno));
103 0
                return (1);
104
        }
105 4832
        assert(p[0] > STDERR_FILENO);
106 4832
        assert(p[1] > STDERR_FILENO);
107 4832
        if ((pid = fork()) < 0) {
108 0
                VSB_printf(sb, "Starting %s: fork() failed: %s",
109 0
                    name, strerror(errno));
110 0
                closefd(&p[0]);
111 0
                closefd(&p[1]);
112 0
                return (1);
113
        }
114 9664
        if (pid == 0) {
115 4832
                VFIL_null_fd(STDIN_FILENO);
116 4832
                assert(dup2(p[1], STDOUT_FILENO) == STDOUT_FILENO);
117 4832
                assert(dup2(p[1], STDERR_FILENO) == STDERR_FILENO);
118
                /* Close all other fds */
119 4832
                VSUB_closefrom(STDERR_FILENO + 1);
120 4832
                func(priv);
121
                /*
122
                 * func should either exec or exit, so getting here should be
123
                 * treated like an assertion failure - except that we don't know
124
                 * if it's safe to trigger an actual assertion
125
                 */
126 0
                _exit(4);
127
        }
128 4832
        closefd(&p[1]);
129 4832
        (void)VLU_File(p[0], vsub_vlu, &sp, 0);
130 4832
        if (sp.maxlines >= 0 && sp.lines > sp.maxlines)
131 0
                VSB_printf(sb, "[%d lines truncated]\n",
132 0
                    sp.lines - sp.maxlines);
133
        do {
134 4832
                rv = waitpid(pid, &status, 0);
135 4832
                if (rv < 0 && errno != EINTR) {
136 0
                        VSB_printf(sb, "Running %s: waitpid() failed: %s\n",
137 0
                            name, strerror(errno));
138 0
                        return (1);
139
                }
140 4832
        } while (rv < 0);
141 4832
        if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
142 302
                rv = -1;
143 302
                VSB_printf(sb, "Running %s failed", name);
144 302
                if (WIFEXITED(status)) {
145 302
                        rv = WEXITSTATUS(status);
146 302
                        VSB_printf(sb, ", exited with %d", rv);
147
                }
148 302
                if (WIFSIGNALED(status)) {
149 0
                        rv = 2;
150 0
                        VSB_printf(sb, ", signal %d", WTERMSIG(status));
151
                }
152 302
                if (WCOREDUMP(status))
153 0
                        VSB_printf(sb, ", core dumped");
154 302
                VSB_printf(sb, "\n");
155 302
                assert(rv != -1);
156 302
                return (rv);
157
        }
158 4530
        return (0);
159
}