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 26424
mgt_vcl_symtab_val(const struct vjsn_val *vv, const char *val)
50
{
51
        const struct vjsn_val *jv;
52
53 26424
        jv = vjsn_child(vv, val);
54 26424
        AN(jv);
55 26424
        assert(jv->type == VJSN_STRING);
56 26424
        AN(jv->value);
57 26424
        return (jv->value);
58
}
59
60
static void
61 324
mgt_vcl_import_vcl(struct vclprog *vp1, const struct vjsn_val *vv)
62
{
63
        struct vclprog *vp2;
64
65 324
        CHECK_OBJ_NOTNULL(vp1, VCLPROG_MAGIC);
66 324
        AN(vv);
67
68 324
        vp2 = mcf_vcl_byname(mgt_vcl_symtab_val(vv, "name"));
69 324
        CHECK_OBJ_NOTNULL(vp2, VCLPROG_MAGIC);
70 324
        mgt_vcl_dep_add(vp1, vp2)->vj = vv;
71 324
}
72
73
static int
74 4500
mgt_vcl_cache_vmod(const char *nm, const char *fm, const char *to)
75
{
76
        int fi, fo;
77 4500
        int ret = 0;
78
        ssize_t sz;
79
        char buf[BUFSIZ];
80
81 4500
        fo = open(to, O_WRONLY | O_CREAT | O_EXCL, 0744);
82 4500
        if (fo < 0 && errno == EEXIST)
83 0
                return (0);
84 4500
        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 4500
        fi = open(fm, O_RDONLY);
90 4500
        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 902412
        while (1) {
98 902412
                sz = read(fi, buf, sizeof buf);
99 902412
                if (sz == 0)
100 4500
                        break;
101 897912
                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 4500
        closefd(&fi);
110 4500
        AZ(fchmod(fo, 0444));
111 4500
        closefd(&fo);
112 4500
        return (ret);
113 4500
}
114
115
static void
116 6444
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 6444
        CHECK_OBJ_NOTNULL(vp, VCLPROG_MAGIC);
125 6444
        AN(vv);
126
127 6444
        v_name = mgt_vcl_symtab_val(vv, "name");
128 6444
        v_file = mgt_vcl_symtab_val(vv, "file");
129 6444
        v_dst = mgt_vcl_symtab_val(vv, "dst");
130
131 8064
        VTAILQ_FOREACH(vf, &vmodhead, list)
132 3564
                if (!strcmp(vf->fname, v_dst))
133 1944
                        break;
134 6444
        if (vf == NULL) {
135 4500
                ALLOC_OBJ(vf, VMODFILE_MAGIC);
136 4500
                AN(vf);
137 4500
                REPLACE(vf->fname, v_dst);
138 4500
                AN(vf->fname);
139 4500
                VTAILQ_INIT(&vf->vcls);
140 4500
                AZ(mgt_vcl_cache_vmod(v_name, v_file, v_dst));
141 4500
                VTAILQ_INSERT_TAIL(&vmodhead, vf, list);
142 4500
        }
143 6444
        ALLOC_OBJ(vd, VMODDEP_MAGIC);
144 6444
        AN(vd);
145 6444
        vd->to = vf;
146 6444
        VTAILQ_INSERT_TAIL(&vp->vmods, vd, lfrom);
147 6444
        VTAILQ_INSERT_TAIL(&vf->vcls, vd, lto);
148 6444
}
149
150
void
151 16848
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 16848
        CHECK_OBJ_NOTNULL(vp, VCLPROG_MAGIC);
158 16848
        AN(input);
159 16848
        vj = vjsn_parse(input, &err);
160 16848
        if (err != NULL) {
161 0
                fprintf(stderr, "FATAL: Symtab parse error: %s\n%s\n",
162 0
                    err, input);
163 0
        }
164 16848
        AZ(err);
165 16848
        AN(vj);
166 16848
        vp->symtab = vj;
167 16848
        assert(vj->value->type == VJSN_ARRAY);
168 40464
        VTAILQ_FOREACH(v1, &vj->value->children, list) {
169 23616
                assert(v1->type == VJSN_OBJECT);
170 23616
                v2 = vjsn_child(v1, "dir");
171 23616
                if (v2 == NULL)
172 16848
                        continue;
173 6768
                assert(v2->type == VJSN_STRING);
174 6768
                if (strcmp(v2->value, "import"))
175 0
                        continue;
176 6768
                typ = mgt_vcl_symtab_val(v1, "type");
177 6768
                if (!strcmp(typ, "$VMOD"))
178 6444
                        mgt_vcl_import_vmod(vp, v1);
179 324
                else if (!strcmp(typ, "$VCL"))
180 324
                        mgt_vcl_import_vcl(vp, v1);
181
                else
182 0
                        WRONG("Bad symtab import entry");
183 6768
        }
184 16848
}
185
186
void
187 20736
mgt_vcl_symtab_clean(struct vclprog *vp)
188
{
189
190 20736
        if (vp->symtab)
191 16848
                vjsn_delete(&vp->symtab);
192 20736
}
193
194
/*--------------------------------------------------------------------*/
195
196
static void
197 1944
mcf_vcl_vjsn_dump(struct cli *cli, const struct vjsn_val *vj, int indent)
198
{
199
        struct vjsn_val *vj1;
200 1944
        AN(cli);
201 1944
        AN(vj);
202
203 1944
        VCLI_Out(cli, "%*s", indent, "");
204 1944
        if (vj->name != NULL)
205 1296
                VCLI_Out(cli, "[\"%s\"]: ", vj->name);
206 1944
        VCLI_Out(cli, "{%s}", vj->type);
207 1944
        if (vj->value != NULL)
208 1296
                VCLI_Out(cli, " <%s>", vj->value);
209 1944
        VCLI_Out(cli, "\n");
210 3528
        VTAILQ_FOREACH(vj1, &vj->children, list)
211 1584
                mcf_vcl_vjsn_dump(cli, vj1, indent + 2);
212 1944
}
213
214
void v_matchproto_(cli_func_t)
215 18
mcf_vcl_symtab(struct cli *cli, const char * const *av, void *priv)
216
{
217
        struct vclprog *vp;
218
        struct vcldep *vd;
219
220 18
        (void)av;
221 18
        (void)priv;
222 198
        VTAILQ_FOREACH(vp, &vclhead, list) {
223 180
                if (mcf_is_label(vp))
224 36
                        VCLI_Out(cli, "Label: %s\n", vp->name);
225
                else
226 144
                        VCLI_Out(cli, "Vcl: %s\n", vp->name);
227 180
                if (!VTAILQ_EMPTY(&vp->dfrom)) {
228 144
                        VCLI_Out(cli, "  imports from:\n");
229 288
                        VTAILQ_FOREACH(vd, &vp->dfrom, lfrom) {
230 144
                                VCLI_Out(cli, "    %s\n", vd->to->name);
231 144
                                if (vd->vj)
232 108
                                        mcf_vcl_vjsn_dump(cli, vd->vj, 6);
233 144
                        }
234 144
                }
235 180
                if (!VTAILQ_EMPTY(&vp->dto)) {
236 72
                        VCLI_Out(cli, "  exports to:\n");
237 216
                        VTAILQ_FOREACH(vd, &vp->dto, lto) {
238 144
                                VCLI_Out(cli, "    %s\n", vd->from->name);
239 144
                                if (vd->vj)
240 108
                                        mcf_vcl_vjsn_dump(cli, vd->vj, 6);
241 144
                        }
242 72
                }
243 180
                if (vp->symtab != NULL) {
244 144
                        VCLI_Out(cli, "  symtab:\n");
245 144
                        mcf_vcl_vjsn_dump(cli, vp->symtab->value, 4);
246 144
                }
247 180
        }
248 18
}