varnish-cache/bin/varnishd/mgt/mgt_symtab.c
1
/*-
2
 * Copyright (c) 2019 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
 * VCL/VMOD symbol table
29
 */
30
31
#include "config.h"
32
33
#include <fcntl.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <unistd.h>
38
#include <sys/stat.h>
39
40
#include "mgt/mgt.h"
41
#include "mgt/mgt_vcl.h"
42
43
#include "vcli_serve.h"
44
#include "vjsn.h"
45
46
/*--------------------------------------------------------------------*/
47
48
static const char *
49 1574
mgt_vcl_symtab_val(const struct vjsn_val *vv, const char *val)
50
{
51
        const struct vjsn_val *jv;
52
53 1574
        jv = vjsn_child(vv, val);
54 1574
        AN(jv);
55 1574
        assert(jv->type == VJSN_STRING);
56 1574
        AN(jv->value);
57 1574
        return (jv->value);
58
}
59
60
static void
61 19
mgt_vcl_import_vcl(struct vclprog *vp1, const struct vjsn_val *vv)
62
{
63
        struct vclprog *vp2;
64
65 19
        CHECK_OBJ_NOTNULL(vp1, VCLPROG_MAGIC);
66 19
        AN(vv);
67
68 19
        vp2 = mcf_vcl_byname(mgt_vcl_symtab_val(vv, "name"));
69 19
        CHECK_OBJ_NOTNULL(vp2, VCLPROG_MAGIC);
70 19
        mgt_vcl_dep_add(vp1, vp2)->vj = vv;
71 19
}
72
73
static int
74 258
mgt_vcl_cache_vmod(const char *nm, const char *fm, const char *to)
75
{
76
        int fi, fo;
77 258
        int ret = 0;
78
        ssize_t sz;
79
        char buf[BUFSIZ];
80
81 258
        fo = open(to, O_WRONLY | O_CREAT | O_EXCL, 0744);
82 258
        if (fo < 0 && errno == EEXIST)
83 0
                return (0);
84 258
        if (fo < 0) {
85 0
                fprintf(stderr, "While creating copy of vmod %s:\n\t%s: %s\n",
86 0
                    nm, to, vstrerror(errno));
87 0
                return (1);
88
        }
89 258
        fi = open(fm, O_RDONLY);
90 258
        if (fi < 0) {
91 0
                fprintf(stderr, "Opening vmod %s from %s: %s\n",
92 0
                    nm, fm, vstrerror(errno));
93 0
                AZ(unlink(to));
94 0
                closefd(&fo);
95 0
                return (1);
96
        }
97 55537
        while (1) {
98 55537
                sz = read(fi, buf, sizeof buf);
99 55537
                if (sz == 0)
100 258
                        break;
101 55279
                if (sz < 0 || sz != write(fo, buf, sz)) {
102 0
                        fprintf(stderr, "Copying vmod %s: %s\n",
103 0
                            nm, vstrerror(errno));
104 0
                        AZ(unlink(to));
105 0
                        ret = 1;
106 0
                        break;
107
                }
108
        }
109 258
        closefd(&fi);
110 258
        AZ(fchmod(fo, 0444));
111 258
        closefd(&fo);
112 258
        return (ret);
113 258
}
114
115
static void
116 384
mgt_vcl_import_vmod(struct vclprog *vp, const struct vjsn_val *vv)
117
{
118
        struct vmodfile *vf;
119
        struct vmoddep *vd;
120
        const char *v_name;
121
        const char *v_file;
122
        const char *v_dst;
123
124 384
        CHECK_OBJ_NOTNULL(vp, VCLPROG_MAGIC);
125 384
        AN(vv);
126
127 384
        v_name = mgt_vcl_symtab_val(vv, "name");
128 384
        v_file = mgt_vcl_symtab_val(vv, "file");
129 384
        v_dst = mgt_vcl_symtab_val(vv, "dst");
130
131 495
        VTAILQ_FOREACH(vf, &vmodhead, list)
132 237
                if (!strcmp(vf->fname, v_dst))
133 126
                        break;
134 384
        if (vf == NULL) {
135 258
                ALLOC_OBJ(vf, VMODFILE_MAGIC);
136 258
                AN(vf);
137 258
                REPLACE(vf->fname, v_dst);
138 258
                AN(vf->fname);
139 258
                VTAILQ_INIT(&vf->vcls);
140 258
                AZ(mgt_vcl_cache_vmod(v_name, v_file, v_dst));
141 258
                VTAILQ_INSERT_TAIL(&vmodhead, vf, list);
142 258
        }
143 384
        ALLOC_OBJ(vd, VMODDEP_MAGIC);
144 384
        AN(vd);
145 384
        vd->to = vf;
146 384
        VTAILQ_INSERT_TAIL(&vp->vmods, vd, lfrom);
147 384
        VTAILQ_INSERT_TAIL(&vf->vcls, vd, lto);
148 384
}
149
150
void
151 961
mgt_vcl_symtab(struct vclprog *vp, const char *input)
152
{
153
        struct vjsn *vj;
154
        struct vjsn_val *v1, *v2;
155
        const char *typ, *err;
156
157 961
        CHECK_OBJ_NOTNULL(vp, VCLPROG_MAGIC);
158 961
        AN(input);
159 961
        vj = vjsn_parse(input, &err);
160 961
        if (err != NULL) {
161 0
                fprintf(stderr, "FATAL: Symtab parse error: %s\n%s\n",
162 0
                    err, input);
163 0
        }
164 961
        AZ(err);
165 961
        AN(vj);
166 961
        vp->symtab = vj;
167 961
        assert(vj->value->type == VJSN_ARRAY);
168 2325
        VTAILQ_FOREACH(v1, &vj->value->children, list) {
169 1364
                assert(v1->type == VJSN_OBJECT);
170 1364
                v2 = vjsn_child(v1, "dir");
171 1364
                if (v2 == NULL)
172 961
                        continue;
173 403
                assert(v2->type == VJSN_STRING);
174 403
                if (strcmp(v2->value, "import"))
175 0
                        continue;
176 403
                typ = mgt_vcl_symtab_val(v1, "type");
177 403
                if (!strcmp(typ, "$VMOD"))
178 384
                        mgt_vcl_import_vmod(vp, v1);
179 19
                else if (!strcmp(typ, "$VCL"))
180 19
                        mgt_vcl_import_vcl(vp, v1);
181
                else
182 0
                        WRONG("Bad symtab import entry");
183 403
        }
184 961
}
185
186
void
187 1181
mgt_vcl_symtab_clean(struct vclprog *vp)
188
{
189
190 1181
        if (vp->symtab)
191 961
                vjsn_delete(&vp->symtab);
192 1181
}
193
194
/*--------------------------------------------------------------------*/
195
196
static void
197 108
mcf_vcl_vjsn_dump(struct cli *cli, const struct vjsn_val *vj, int indent)
198
{
199
        struct vjsn_val *vj1;
200 108
        AN(cli);
201 108
        AN(vj);
202
203 108
        VCLI_Out(cli, "%*s", indent, "");
204 108
        if (vj->name != NULL)
205 72
                VCLI_Out(cli, "[\"%s\"]: ", vj->name);
206 108
        VCLI_Out(cli, "{%s}", vj->type);
207 108
        if (vj->value != NULL)
208 72
                VCLI_Out(cli, " <%s>", vj->value);
209 108
        VCLI_Out(cli, "\n");
210 196
        VTAILQ_FOREACH(vj1, &vj->children, list)
211 88
                mcf_vcl_vjsn_dump(cli, vj1, indent + 2);
212 108
}
213
214
void v_matchproto_(cli_func_t)
215 1
mcf_vcl_symtab(struct cli *cli, const char * const *av, void *priv)
216
{
217
        struct vclprog *vp;
218
        struct vcldep *vd;
219
220 1
        (void)av;
221 1
        (void)priv;
222 11
        VTAILQ_FOREACH(vp, &vclhead, list) {
223 10
                if (mcf_is_label(vp))
224 2
                        VCLI_Out(cli, "Label: %s\n", vp->name);
225
                else
226 8
                        VCLI_Out(cli, "Vcl: %s\n", vp->name);
227 10
                if (!VTAILQ_EMPTY(&vp->dfrom)) {
228 8
                        VCLI_Out(cli, "  imports from:\n");
229 16
                        VTAILQ_FOREACH(vd, &vp->dfrom, lfrom) {
230 8
                                VCLI_Out(cli, "    %s\n", vd->to->name);
231 8
                                if (vd->vj)
232 6
                                        mcf_vcl_vjsn_dump(cli, vd->vj, 6);
233 8
                        }
234 8
                }
235 10
                if (!VTAILQ_EMPTY(&vp->dto)) {
236 4
                        VCLI_Out(cli, "  exports to:\n");
237 12
                        VTAILQ_FOREACH(vd, &vp->dto, lto) {
238 8
                                VCLI_Out(cli, "    %s\n", vd->from->name);
239 8
                                if (vd->vj)
240 6
                                        mcf_vcl_vjsn_dump(cli, vd->vj, 6);
241 8
                        }
242 4
                }
243 10
                if (vp->symtab != NULL) {
244 8
                        VCLI_Out(cli, "  symtab:\n");
245 8
                        mcf_vcl_vjsn_dump(cli, vp->symtab->value, 4);
246 8
                }
247 10
        }
248 1
}