varnish-cache/lib/libvcc/vcc_vmod.c
1
/*-
2
 * Copyright (c) 2010-2015 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 <dlfcn.h>
32
#include <stdlib.h>
33
#include <string.h>
34
35
#include "vcc_compile.h"
36
37
#include "libvcc.h"
38
#include "vfil.h"
39
#include "vmod_abi.h"
40
41
static int
42 250
vcc_path_dlopen(void *priv, const char *fn)
43
{
44
        void *hdl, **pp;
45
46 250
        AN(priv);
47 250
        AN(fn);
48
49 250
        hdl = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
50 250
        if (hdl == NULL)
51 0
                return (-1);
52 250
        pp = priv;
53 250
        *pp = hdl;
54 250
        return (0);
55
}
56
57
void
58 255
vcc_ParseImport(struct vcc *tl)
59
{
60
        void *hdl;
61
        char fn[1024], *fnp, *fnpx;
62
        char buf[256];
63
        struct token *mod, *t1;
64
        struct inifin *ifp;
65
        const char * const *spec;
66
        struct symbol *sym;
67
        struct symbol *msym;
68
        const struct symbol *osym;
69
        const char *p;
70
        // int *modlen;
71
        const struct vmod_data *vmd;
72
73 255
        t1 = tl->t;
74 261
        SkipToken(tl, ID);              /* "import" */
75
76 255
        ExpectErr(tl, ID);
77 255
        mod = tl->t;
78 255
        vcc_NextToken(tl);
79
80 255
        osym = VCC_SymbolTok(tl, NULL, mod, SYM_NONE, 0);
81 255
        if (osym != NULL && osym->kind != SYM_VMOD) {
82 2
                VSB_printf(tl->sb, "Module %.*s conflicts with other symbol.\n",
83 1
                    PF(mod));
84 1
                vcc_ErrWhere2(tl, t1, tl->t);
85 1
                return;
86
        }
87 254
        if (osym != NULL) {
88 2
                VSB_printf(tl->sb, "Module %.*s already imported.\n",
89 1
                    PF(mod));
90 1
                vcc_ErrWhere2(tl, t1, tl->t);
91 1
                VSB_printf(tl->sb, "Previous import was here:\n");
92 1
                vcc_ErrWhere2(tl, osym->def_b, osym->def_e);
93 1
                return;
94
        }
95
96 253
        bprintf(fn, "%.*s", PF(mod));
97 253
        msym = VCC_Symbol(tl, NULL, fn, NULL, SYM_VMOD, 1);
98 253
        ERRCHK(tl);
99 253
        AN(msym);
100 253
        msym->def_b = t1;
101 253
        msym->def_e = tl->t;
102
103 253
        if (tl->t->tok == ID) {
104 4
                if (!vcc_IdIs(tl->t, "from")) {
105 1
                        VSB_printf(tl->sb, "Expected 'from path ...'\n");
106 1
                        vcc_ErrWhere(tl, tl->t);
107 1
                        return;
108
                }
109 3
                vcc_NextToken(tl);
110 3
                if (!tl->unsafe_path && strchr(tl->t->dec, '/')) {
111 1
                        VSB_printf(tl->sb,
112
                            "'import ... from path ...' is unsafe.\nAt:");
113 1
                        vcc_ErrToken(tl, tl->t);
114 1
                        vcc_ErrWhere(tl, tl->t);
115 1
                        return;
116
                }
117 2
                ExpectErr(tl, CSTR);
118 2
                p = strrchr(tl->t->dec, '/');
119 2
                if (p != NULL && p[1] == '\0')
120 1
                        bprintf(fn, "%slibvmod_%.*s.so", tl->t->dec, PF(mod));
121
                else
122 1
                        bprintf(fn, "%s", tl->t->dec);
123 2
                vcc_NextToken(tl);
124
        } else {
125 249
                bprintf(fn, "libvmod_%.*s.so", PF(mod));
126
        }
127
128 251
        SkipToken(tl, ';');
129
130 251
        if (VFIL_searchpath(tl->vmod_path,
131
            vcc_path_dlopen, &hdl, fn, &fnpx)) {
132 1
                VSB_printf(tl->sb, "Could not load VMOD %.*s\n", PF(mod));
133 1
                VSB_printf(tl->sb, "\tFile name: %s\n",
134 1
                    fnpx != NULL ? fnpx : fn);
135 1
                VSB_printf(tl->sb, "\tdlerror: %s\n", dlerror());
136 1
                vcc_ErrWhere(tl, mod);
137 1
                free(fnpx);
138 1
                return;
139
        }
140
141 250
        AN(fnpx);
142 250
        fnp = TlDup(tl, fnpx);
143 250
        free(fnpx);
144
145 250
        bprintf(buf, "Vmod_%.*s_Data", PF(mod));
146 250
        vmd = dlsym(hdl, buf);
147 250
        if (vmd == NULL) {
148 1
                VSB_printf(tl->sb, "Malformed VMOD %.*s\n", PF(mod));
149 1
                VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
150 1
                VSB_printf(tl->sb, "\t(no Vmod_Data symbol)\n");
151 1
                vcc_ErrWhere(tl, mod);
152 1
                return;
153
        }
154 498
        if (vmd->vrt_major == 0 && vmd->vrt_minor == 0 &&
155 249
            strcmp(vmd->abi, VMOD_ABI_Version) != 0) {
156 0
                VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(mod));
157 0
                VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
158 0
                VSB_printf(tl->sb, "\tABI mismatch, expected <%s>, got <%s>\n",
159
                           VMOD_ABI_Version, vmd->abi);
160 0
                vcc_ErrWhere(tl, mod);
161 0
                return;
162
        }
163 249
        if (vmd->vrt_major != 0 && (vmd->vrt_major != VRT_MAJOR_VERSION ||
164 0
            vmd->vrt_minor > VRT_MINOR_VERSION)) {
165 0
                VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(mod));
166 0
                VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
167 0
                VSB_printf(tl->sb, "\tVMOD version %u.%u\n",
168
                    vmd->vrt_major, vmd->vrt_minor);
169 0
                VSB_printf(tl->sb, "\tvarnishd version %u.%u\n",
170
                    VRT_MAJOR_VERSION, VRT_MINOR_VERSION);
171 0
                vcc_ErrWhere(tl, mod);
172 0
                return;
173
        }
174 498
        if (vmd->name == NULL ||
175 498
            vmd->func == NULL ||
176 498
            vmd->func_len <= 0 ||
177 498
            vmd->proto == NULL ||
178 249
            vmd->abi == NULL) {
179 0
                VSB_printf(tl->sb, "Mangled VMOD %.*s\n", PF(mod));
180 0
                VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
181 0
                VSB_printf(tl->sb, "\tInconsistent metadata\n");
182 0
                vcc_ErrWhere(tl, mod);
183 0
                return;
184
        }
185
186 249
        if (!vcc_IdIs(mod, vmd->name)) {
187 0
                VSB_printf(tl->sb, "Wrong VMOD file %.*s\n", PF(mod));
188 0
                VSB_printf(tl->sb, "\tFile name: %s\n", fnp);
189 0
                VSB_printf(tl->sb, "\tContains vmod \"%s\"\n", vmd->name);
190 0
                vcc_ErrWhere(tl, mod);
191 0
                return;
192
        }
193
194 249
        ifp = New_IniFin(tl);
195
196 249
        VSB_printf(ifp->ini, "\tif (VRT_Vmod_Init(ctx,\n");
197 249
        VSB_printf(ifp->ini, "\t    &VGC_vmod_%.*s,\n", PF(mod));
198 249
        VSB_printf(ifp->ini, "\t    &Vmod_%.*s_Func,\n", PF(mod));
199 249
        VSB_printf(ifp->ini, "\t    sizeof(Vmod_%.*s_Func),\n", PF(mod));
200 249
        VSB_printf(ifp->ini, "\t    \"%.*s\",\n", PF(mod));
201 249
        VSB_printf(ifp->ini, "\t    ");
202 249
        VSB_quote(ifp->ini, fnp, -1, VSB_QUOTE_CSTR);
203 249
        VSB_printf(ifp->ini, ",\n");
204 249
        AN(vmd);
205 249
        AN(vmd->file_id);
206 249
        VSB_printf(ifp->ini, "\t    \"%s\",\n", vmd->file_id);
207 498
        VSB_printf(ifp->ini, "\t    \"./vmod_cache/_vmod_%.*s.%s\"\n",
208 249
            PF(mod), vmd->file_id);
209 249
        VSB_printf(ifp->ini, "\t    ))\n");
210 249
        VSB_printf(ifp->ini, "\t\treturn(1);");
211
212 498
        VSB_printf(tl->fi, "%s VMOD %s ./vmod_cache/_vmod_%.*s.%s */\n",
213 249
            VCC_INFO_PREFIX, fnp, PF(mod), vmd->file_id);
214
215
        /* XXX: zero the function pointer structure ?*/
216 249
        VSB_printf(ifp->fin, "\t\tVRT_priv_fini(&vmod_priv_%.*s);\n", PF(mod));
217 249
        VSB_printf(ifp->fin, "\t\t\tVRT_Vmod_Fini(&VGC_vmod_%.*s);", PF(mod));
218
219 249
        ifp = NULL;
220
221 249
        spec = vmd->spec;
222 4984
        for (; *spec != NULL; spec++) {
223 4735
                p = *spec;
224 4735
                if (!strcmp(p, "$OBJ")) {
225 321
                        p += strlen(p) + 1;
226 321
                        sym = VCC_Symbol(tl, NULL, p, NULL, SYM_OBJECT, 1);
227 321
                        XXXAN(sym);
228 321
                        sym->extra = p;
229 321
                        sym->vmod = msym->name;
230 4414
                } else if (!strcmp(p, "$EVENT")) {
231 49
                        p += strlen(p) + 1;
232 49
                        if (ifp == NULL)
233 49
                                ifp = New_IniFin(tl);
234 98
                        VSB_printf(ifp->ini,
235
                            "\tif (%s(ctx, &vmod_priv_%.*s, VCL_EVENT_LOAD))\n"
236
                            "\t\treturn(1);",
237 49
                            p, PF(mod));
238 98
                        VSB_printf(ifp->fin,
239
                            "\t\t(void)%s(ctx, &vmod_priv_%.*s,\n"
240 49
                            "\t\t\t    VCL_EVENT_DISCARD);\n", p, PF(mod));
241 98
                        VSB_printf(ifp->event, "%s(ctx, &vmod_priv_%.*s, ev)",
242 49
                            p, PF(mod));
243 4365
                } else if (!strcmp(p, "$FUNC")) {
244 4365
                        p += strlen(p) + 1;
245 4365
                        sym = VCC_Symbol(tl, NULL, p, NULL, SYM_FUNC, 1);
246 4365
                        ERRCHK(tl);
247 4365
                        AN(sym);
248 4365
                        sym->vmod = msym->name;
249 4365
                        sym->eval = vcc_Eval_SymFunc;
250 4365
                        p += strlen(p) + 1;
251 4365
                        sym->eval_priv = p;
252 4365
                        sym->fmt = VCC_Type(p);
253 4365
                        AN(sym->fmt);
254
                } else {
255 0
                        VSB_printf(tl->sb, "Internal spec error (%s)\n", p);
256 0
                        vcc_ErrWhere(tl, mod);
257 0
                        return;
258
                }
259
        }
260
261 249
        Fh(tl, 0, "\n/* --- BEGIN VMOD %.*s --- */\n\n", PF(mod));
262 249
        Fh(tl, 0, "static struct vmod *VGC_vmod_%.*s;\n", PF(mod));
263 249
        Fh(tl, 0, "static struct vmod_priv vmod_priv_%.*s;\n", PF(mod));
264 249
        Fh(tl, 0, "\n%s\n", vmd->proto);
265 249
        Fh(tl, 0, "\n/* --- END VMOD %.*s --- */\n\n", PF(mod));
266
}
267
268
void
269 120
vcc_ParseNew(struct vcc *tl)
270
{
271
        struct symbol *sy1, *sy2, *sy3;
272
        struct inifin *ifp;
273
        const char *p, *s_obj;
274
        char buf1[128];
275
        char buf2[128];
276
277 120
        vcc_NextToken(tl);
278 125
        ExpectErr(tl, ID);
279 120
        vcc_ExpectVid(tl, "VCL object");
280 120
        ERRCHK(tl);
281 119
        sy1 = VCC_HandleSymbol(tl, tl->t, INSTANCE, "vo");
282 119
        ERRCHK(tl);
283
284
        /* We allow implicit use of VMOD objects:  Pretend it's ref'ed */
285 117
        sy1->nref++;
286
287 117
        vcc_NextToken(tl);
288
289 117
        ExpectErr(tl, '=');
290 117
        vcc_NextToken(tl);
291
292 117
        ExpectErr(tl, ID);
293 117
        sy2 = VCC_SymbolTok(tl, NULL, tl->t, SYM_OBJECT, 0);
294 117
        if (sy2 == NULL || sy2->extra == NULL) {
295 2
                if (sy2 == NULL)
296 2
                        p = "Symbol";
297
                else
298 0
                        p = "Constructor";
299 2
                VSB_printf(tl->sb, "%s not found: ", p);
300 2
                vcc_ErrToken(tl, tl->t);
301 2
                VSB_printf(tl->sb, " at ");
302 2
                vcc_ErrWhere(tl, tl->t);
303 2
                return;
304
        }
305 115
        vcc_NextToken(tl);
306
307 115
        p = sy2->extra;
308 115
        AN(p);
309
310 115
        s_obj = p;
311 115
        p += strlen(p) + 1;
312
313 115
        Fh(tl, 0, "static %s *%s;\n\n", p, sy1->rname);
314 115
        p += strlen(p) + 1;
315
316 115
        bprintf(buf1, ", &%s, \"%s\"", sy1->rname, sy1->name);
317 115
        vcc_Eval_Func(tl, p, buf1, sy2);
318 115
        ERRCHK(tl);
319 115
        ExpectErr(tl, ';');
320
321 10278
        while (p[0] != '\0' || p[1] != '\0' || p[2] != '\0')
322 10048
                p++;
323 115
        p += 3;
324
325 115
        ifp = New_IniFin(tl);
326 115
        p += strlen(p) + 1;
327 115
        VSB_printf(ifp->fin, "\t\t%s(&%s);", p, sy1->rname);
328
329 3418
        while (p[0] != '\0' || p[1] != '\0' || p[2] != '\0')
330 3188
                p++;
331 115
        p += 3;
332
333
        /* Instantiate symbols for the methods */
334 115
        bprintf(buf1, ", %s", sy1->rname);
335 687
        while (*p != '\0') {
336 457
                p += strlen(s_obj);
337 457
                bprintf(buf2, "%s%s", sy1->name, p);
338 457
                sy3 = VCC_Symbol(tl, NULL, buf2, NULL, SYM_FUNC, 1);
339 457
                AN(sy3);
340 457
                sy3->eval = vcc_Eval_SymFunc;
341 457
                p += strlen(p) + 1;
342 457
                sy3->eval_priv = p;
343 457
                sy3->fmt = VCC_Type(p);
344 457
                sy3->extra = TlDup(tl, buf1);
345 457
                sy3->vmod = sy2->vmod;
346 33532
                while (p[0] != '\0' || p[1] != '\0' || p[2] != '\0')
347 32618
                        p++;
348 457
                p += 3;
349
        }
350 115
        sy1->def_e = tl->t;
351
}