varnish-cache/lib/libvcc/vcc_vmod.c
0
/*-
1
 * Copyright (c) 2010-2015 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
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
 * Parse `import`, check metadata and versioning.
30
 *
31
 */
32
33
#include "config.h"
34
35
#include <stdlib.h>
36
#include <string.h>
37
38
#include "vcc_compile.h"
39
40
#include "libvcc.h"
41
#include "vfil.h"
42
#include "vjsn.h"
43
#include "vmod_abi.h"
44
45
#include "vcc_vmod.h"
46
47
struct vmod_import {
48
        unsigned                        magic;
49
#define VMOD_IMPORT_MAGIC               0x31803a5d
50
        const char                      *err;
51
        struct vsb                      *json;
52
        char                            *path;
53
        VTAILQ_ENTRY(vmod_import)       list;
54
        int                             from_vext;
55
        int                             unimported_vext;
56
57
        // From $VMOD
58
        double                          vmod_syntax;
59
        char                            *name;
60
        char                            *func_name;
61
        char                            *file_id;
62
        char                            *abi;
63
        unsigned                        major;
64
        unsigned                        minor;
65
66
        struct symbol                   *sym;
67
        const struct token              *t_mod;
68
        struct vjsn                     *vj;
69
#define STANZA(UU, ll, ss)              int n_##ll;
70
        STANZA_TBL
71
#undef STANZA
72
};
73
74
static VTAILQ_HEAD(,vmod_import) imports = VTAILQ_HEAD_INITIALIZER(imports);
75
76
typedef void vcc_do_stanza_f(struct vcc *tl, const struct vmod_import *vim,
77
    const struct vjsn_val *vv);
78
79
static int
80 19338
vcc_Extract_JSON(struct vmod_import *vim, const char *filename)
81
{
82 19338
        const char *magic = "VMOD_JSON_SPEC\x02", *p;
83
        int c;
84
        FILE *f;
85
86 19338
        CHECK_OBJ_NOTNULL(vim, VMOD_IMPORT_MAGIC);
87 19338
        AN(filename);
88
89 19338
        f = fopen(filename, "rb");
90 19338
        if (f == NULL) {
91 33
                vim->err = strerror(errno);
92 33
                return (-1);
93
        }
94
95 19305
        p = magic;
96 19305
        vim->err = "No VMOD JSON found";
97 1501962
        while (1) {
98 375332364
                c = getc(f);
99 375332364
                if (c == EOF) {
100 33
                        AZ(fclose(f));
101 33
                        vim->err = "No VMOD JSON found";
102 33
                        return (-1);
103
                }
104 375332331
                if (c != *p) {
105 373830402
                        p = magic;
106 373830402
                        continue;
107
                }
108 1501929
                p++;
109 1501929
                if (*p == '\0')
110 19272
                        break;
111
        }
112
113 19272
        vim->json = VSB_new_auto();
114 19272
        AN(vim->json);
115
116 355901535
        while (1) {
117 355901535
                c = getc(f);
118 355901535
                if (c == EOF) {
119 33
                        AZ(fclose(f));
120 33
                        vim->err = "Truncated VMOD JSON";
121 33
                        VSB_destroy(&vim->json);
122 33
                        return (-1);
123
                }
124 355901502
                if (c == '\x03')
125 19239
                        break;
126 355882263
                VSB_putc(vim->json, c);
127
        }
128 19239
        AZ(fclose(f));
129 19239
        AZ(VSB_finish(vim->json));
130 19239
        return (0);
131 19338
}
132
133
static const char *
134 19239
vcc_ParseJSON(const struct vcc *tl, const char *jsn, struct vmod_import *vim)
135
{
136
        const struct vjsn_val *vv, *vv2, *vv3;
137
        const char *err;
138
        char *p;
139
140 19239
        vim->vj = vjsn_parse(jsn, &err);
141 19239
        if (err != NULL)
142 33
                return (err);
143 19206
        AN(vim->vj);
144
145 19206
        vv = vim->vj->value;
146 19206
        if (!vjsn_is_array(vv))
147 33
                return ("Not array[0]");
148
149 19173
        vv2 = VTAILQ_FIRST(&vv->children);
150 19173
        AN(vv2);
151 19173
        if (!vjsn_is_array(vv2))
152 33
                return ("Not array[1]");
153 19140
        vv3 = VTAILQ_FIRST(&vv2->children);
154 19140
        AN(vv3);
155 19140
        if (!vjsn_is_string(vv3))
156 33
                return ("Not string[2]");
157 19107
        if (strcmp(vv3->value, "$VMOD"))
158 33
                return ("Not $VMOD[3]");
159
160 19074
        vv3 = VTAILQ_NEXT(vv3, list);
161 19074
        AN(vv3);
162 19074
        assert(vjsn_is_string(vv3));
163 19074
        vim->vmod_syntax = strtod(vv3->value, NULL);
164 19074
        assert (vim->vmod_syntax == 1.0);
165
166 19074
        vv3 = VTAILQ_NEXT(vv3, list);
167 19074
        AN(vv3);
168 19074
        assert(vjsn_is_string(vv3));
169 19074
        vim->name = vv3->value;
170
171 19074
        vv3 = VTAILQ_NEXT(vv3, list);
172 19074
        AN(vv3);
173 19074
        assert(vjsn_is_string(vv3));
174 19074
        vim->func_name = vv3->value;
175
176 19074
        vv3 = VTAILQ_NEXT(vv3, list);
177 19074
        AN(vv3);
178 19074
        assert(vjsn_is_string(vv3));
179 19074
        vim->file_id = vv3->value;
180
181 19074
        vv3 = VTAILQ_NEXT(vv3, list);
182 19074
        AN(vv3);
183 19074
        assert(vjsn_is_string(vv3));
184 19074
        vim->abi = vv3->value;
185
186 19074
        vv3 = VTAILQ_NEXT(vv3, list);
187 19074
        AN(vv3);
188 19074
        assert(vjsn_is_string(vv3));
189 19074
        vim->major = strtoul(vv3->value, &p, 10);
190 19074
        assert(p == NULL || *p == '\0' || *p == 'U');
191
192 19074
        vv3 = VTAILQ_NEXT(vv3, list);
193 19074
        AN(vv3);
194 19074
        assert(vjsn_is_string(vv3));
195 19074
        vim->minor = strtoul(vv3->value, &p, 10);
196 19074
        assert(p == NULL || *p == '\0' || *p == 'U');
197
198
199 19074
        if (vim->major == 0 && vim->minor == 0 &&
200 14685
            strcmp(vim->abi, VMOD_ABI_Version)) {
201 33
                VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(vim->t_mod));
202 33
                VSB_printf(tl->sb, "\tFile name: %s\n", vim->path);
203 66
                VSB_printf(tl->sb, "\tABI mismatch, expected <%s>, got <%s>\n",
204 33
                           VMOD_ABI_Version, vim->abi);
205 33
                return ("");
206
        }
207 23397
        if (vim->major != 0 &&
208 4389
            (vim->major != VRT_MAJOR_VERSION ||
209 4356
            vim->minor > VRT_MINOR_VERSION)) {
210 33
                VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(vim->t_mod));
211 33
                VSB_printf(tl->sb, "\tFile name: %s\n", vim->path);
212 66
                VSB_printf(tl->sb, "\tVMOD wants ABI version %u.%u\n",
213 33
                    vim->major, vim->minor);
214 33
                VSB_printf(tl->sb, "\tvarnishd provides ABI version %u.%u\n",
215
                    VRT_MAJOR_VERSION, VRT_MINOR_VERSION);
216 33
                return ("");
217
        }
218
219
220 703923
        VTAILQ_FOREACH(vv2, &vv->children, list) {
221 684948
                assert (vjsn_is_array(vv2));
222 684948
                vv3 = VTAILQ_FIRST(&vv2->children);
223 684948
                assert(vjsn_is_string(vv3));
224 684948
                assert(vv3->value[0] == '$');
225
#define STANZA(UU, ll, ss) \
226
    if (!strcmp(vv3->value, "$" #UU)) {vim->n_##ll++; continue;}
227 684948
                STANZA_TBL
228
#undef STANZA
229 33
                return ("Unknown metadata stanza.");
230
        }
231 18975
        if (vim->n_cproto != 1)
232 33
                return ("Bad cproto stanza(s)");
233 18942
        if (vim->n_vmod != 1)
234 33
                return ("Bad vmod stanza(s)");
235 18909
        return (NULL);
236 19239
}
237
238
/*
239
 * Load and check the metadata from the objectfile containing the vmod
240
 */
241
242
static int
243 19239
vcc_VmodLoad(struct vcc *tl, struct vmod_import *vim)
244
{
245
        static const char *err;
246
        struct vmod_import *vim2;
247
248 19239
        CHECK_OBJ_NOTNULL(vim, VMOD_IMPORT_MAGIC);
249
250 19239
        err = vcc_ParseJSON(tl, VSB_data(vim->json), vim);
251 19239
        if (err != NULL && *err != '\0') {
252 528
                VSB_printf(tl->sb,
253 264
                    "VMOD %.*s: bad metadata\n", PF(vim->t_mod));
254 264
                VSB_printf(tl->sb, "\t(%s)\n", err);
255 264
                VSB_printf(tl->sb, "\tFile name: %s\n", vim->path);
256 264
        }
257
258 19239
        if (err != NULL)
259 330
                return (-1);
260
261 23661
        VTAILQ_FOREACH(vim2, &imports, list) {
262 4884
                if (strcmp(vim->name, vim2->name))
263 4752
                        continue;
264 132
                if (!strcmp(vim->file_id, vim2->file_id)) {
265
                        // (Truly) duplicate imports are OK
266 99
                        return (0);
267
                }
268 66
                VSB_printf(tl->sb,
269
                    "Different version of VMOD %.*s already loaded\n",
270 33
                    PF(vim->t_mod));
271 33
                vcc_ErrWhere(tl, vim->t_mod);
272 33
                VSB_cat(tl->sb, "Previous import at:\n");
273 33
                vcc_ErrWhere(tl, vim2->t_mod);
274 33
                vcc_Warn(tl);
275 33
                break;
276
        }
277 18810
        VTAILQ_INSERT_TAIL(&imports, vim, list);
278
279 18810
        return (0);
280 19239
}
281
282
static void v_matchproto_(vcc_do_stanza_f)
283 4026
vcc_do_event(struct vcc *tl, const struct vmod_import *vim,
284
    const struct vjsn_val *vv)
285
{
286
        struct inifin *ifp;
287
288 4026
        ifp = New_IniFin(tl);
289 8052
        VSB_printf(ifp->ini,
290
            "\tif (%s(ctx, &vmod_priv_%s, VCL_EVENT_LOAD))\n"
291
            "\t\treturn(1);",
292 4026
            vv->value, vim->sym->vmod_name);
293 8052
        VSB_printf(ifp->fin,
294
            "\t\t(void)%s(ctx, &vmod_priv_%s,\n"
295
            "\t\t\t    VCL_EVENT_DISCARD);",
296 4026
            vv->value, vim->sym->vmod_name);
297 8052
        VSB_printf(ifp->event, "%s(ctx, &vmod_priv_%s, ev)",
298 4026
            vv->value, vim->sym->vmod_name);
299 4026
}
300
301
static void v_matchproto_(vcc_do_stanza_f)
302 18678
vcc_do_cproto(struct vcc *tl, const struct vmod_import *vim,
303
    const struct vjsn_val *vv)
304
{
305 18678
        (void)vim;
306 18678
        do {
307 3544992
                assert (vjsn_is_string(vv));
308 3544992
                Fh(tl, 0, "%s\n", vv->value);
309 3544992
                vv = VTAILQ_NEXT(vv, list);
310 3544992
        } while(vv != NULL);
311 18678
}
312
313
static void
314 37356
vcc_vj_foreach(struct vcc *tl, const struct vmod_import *vim,
315
    const char *stanza, vcc_do_stanza_f *func)
316
{
317
        const struct vjsn_val *vv, *vv2, *vv3;
318
319 37356
        vv = vim->vj->value;
320 37356
        assert (vjsn_is_array(vv));
321 1381512
        VTAILQ_FOREACH(vv2, &vv->children, list) {
322 1344156
                assert (vjsn_is_array(vv2));
323 1344156
                vv3 = VTAILQ_FIRST(&vv2->children);
324 1344156
                assert (vjsn_is_string(vv3));
325 1344156
                if (!strcmp(vv3->value, stanza))
326 22704
                        func(tl, vim, VTAILQ_NEXT(vv3, list));
327 1344156
        }
328 37356
}
329
330
static void
331 18678
vcc_emit_setup(struct vcc *tl, const struct vmod_import *vim)
332
{
333
        struct inifin *ifp;
334 18678
        const struct token *mod = vim->t_mod;
335
336 18678
        ifp = New_IniFin(tl);
337
338 18678
        VSB_cat(ifp->ini, "\tif (VPI_Vmod_Init(ctx,\n");
339 18678
        VSB_printf(ifp->ini, "\t    &VGC_vmod_%.*s,\n", PF(mod));
340 18678
        VSB_printf(ifp->ini, "\t    %u,\n", tl->vmod_count++);
341 18678
        VSB_printf(ifp->ini, "\t    &%s,\n", vim->func_name);
342 18678
        VSB_printf(ifp->ini, "\t    sizeof(%s),\n", vim->func_name);
343 18678
        VSB_printf(ifp->ini, "\t    \"%.*s\",\n", PF(mod));
344 18678
        VSB_cat(ifp->ini, "\t    ");
345 18678
        VSB_quote(ifp->ini, vim->path, -1, VSB_QUOTE_CSTR);
346 18678
        VSB_cat(ifp->ini, ",\n");
347 18678
        AN(vim->file_id);
348 18678
        VSB_printf(ifp->ini, "\t    \"%s\",\n", vim->file_id);
349 18678
        if (vim->from_vext) {
350 33
                VSB_cat(ifp->ini, "\t    ");
351 33
                VSB_quote(ifp->ini, vim->path, -1, VSB_QUOTE_CSTR);
352 33
                VSB_cat(ifp->ini, "\n");
353 33
        } else {
354 37290
                VSB_printf(ifp->ini, "\t    \"./vmod_cache/_vmod_%.*s.%s\"\n",
355 18645
                    PF(mod), vim->file_id);
356
        }
357 18678
        VSB_cat(ifp->ini, "\t    ))\n");
358 18678
        VSB_cat(ifp->ini, "\t\treturn(1);");
359
360 18678
        VSB_cat(tl->symtab, ",\n    {\n");
361 18678
        VSB_cat(tl->symtab, "\t\"dir\": \"import\",\n");
362 18678
        VSB_cat(tl->symtab, "\t\"type\": \"$VMOD\",\n");
363 18678
        VSB_printf(tl->symtab, "\t\"name\": \"%.*s\",\n", PF(mod));
364 18678
        if (vim->from_vext)
365 33
                VSB_cat(tl->symtab, "\t\"vext\": true,\n");
366
        else
367 18645
                VSB_cat(tl->symtab, "\t\"vext\": false,\n");
368 18678
        VSB_printf(tl->symtab, "\t\"file\": \"%s\",\n", vim->path);
369 37356
        VSB_printf(tl->symtab, "\t\"dst\": \"./vmod_cache/_vmod_%.*s.%s\"\n",
370 18678
            PF(mod), vim->file_id);
371 18678
        VSB_cat(tl->symtab, "    }");
372
373
        /* XXX: zero the function pointer structure ?*/
374 37356
        VSB_printf(ifp->fin, "\t\tVRT_priv_fini(ctx, &vmod_priv_%.*s);",
375 18678
            PF(mod));
376 37356
        VSB_printf(ifp->final, "\t\tVPI_Vmod_Unload(ctx, &VGC_vmod_%.*s);",
377 18678
            PF(mod));
378
379 18678
        vcc_vj_foreach(tl, vim, "$EVENT", vcc_do_event);
380
381 18678
        Fh(tl, 0, "\n/* --- BEGIN VMOD %.*s --- */\n\n", PF(mod));
382 18678
        Fh(tl, 0, "static struct vmod *VGC_vmod_%.*s;\n", PF(mod));
383 18678
        Fh(tl, 0, "static struct vmod_priv vmod_priv_%.*s;\n", PF(mod));
384
385 18678
        vcc_vj_foreach(tl, vim, "$CPROTO", vcc_do_cproto);
386
387 18678
        Fh(tl, 0, "\n/* --- END VMOD %.*s --- */\n\n", PF(mod));
388 18678
}
389
390
static void
391 660
vcc_vim_destroy(struct vmod_import **vimp)
392
{
393
        struct vmod_import *vim;
394
395 660
        TAKE_OBJ_NOTNULL(vim, vimp, VMOD_IMPORT_MAGIC);
396 660
        if (vim->path)
397 627
                free(vim->path);
398 660
        if (vim->vj)
399 495
                vjsn_delete(&vim->vj);
400 660
        if (vim->json)
401 528
                VSB_destroy(&vim->json);
402 660
        FREE_OBJ(vim);
403 660
}
404
405
static int
406 19305
vcc_path_open(void *priv, const char *fn)
407
{
408
        struct vmod_import *vim;
409
410 19305
        CAST_OBJ_NOTNULL(vim, priv, VMOD_IMPORT_MAGIC);
411 19305
        AN(fn);
412
413 19305
        return (vcc_Extract_JSON(vim, fn));
414
}
415
416
void
417 19470
vcc_ParseImport(struct vcc *tl)
418
{
419
        char fn[1024];
420
        const char *p;
421
        struct token *mod, *tmod, *t1;
422
        struct symbol *msym, *vsym;
423 19470
        struct vmod_import *vim = NULL;
424
        const struct vmod_import *vimold;
425
426 19470
        t1 = tl->t;
427 19470
        SkipToken(tl, ID);              /* "import" */
428
429 19470
        ExpectErr(tl, ID);              /* "vmod_name" */
430 19470
        mod = tl->t;
431 19470
        tmod = vcc_PeekTokenFrom(tl, mod);
432 19470
        AN(tmod);
433 19470
        if (tmod->tok == ID && vcc_IdIs(tmod, "as")) {
434 165
                vcc_NextToken(tl);              /* "vmod_name" */
435 165
                vcc_NextToken(tl);              /* "as" */
436 165
                ExpectErr(tl, ID);              /* "vcl_name" */
437 165
        }
438 19470
        tmod = tl->t;
439
440 19470
        msym = VCC_SymbolGet(tl, SYM_MAIN, SYM_VMOD, SYMTAB_CREATE, XREF_NONE);
441 19470
        ERRCHK(tl);
442 19437
        AN(msym);
443
444 19437
        bprintf(fn, "libvmod_%.*s.so", PF(mod));
445 19437
        if (tl->t->tok == ID) {
446 165
                if (!vcc_IdIs(tl->t, "from")) {
447 33
                        VSB_cat(tl->sb, "Expected 'from path ...'\n");
448 33
                        vcc_ErrWhere(tl, tl->t);
449 33
                        return;
450
                }
451 132
                vcc_NextToken(tl);
452 132
                if (!tl->unsafe_path && strchr(tl->t->dec, '/')) {
453 33
                        VSB_cat(tl->sb,
454
                            "'import ... from path ...' is unsafe.\nAt:");
455 33
                        vcc_ErrToken(tl, tl->t);
456 33
                        vcc_ErrWhere(tl, tl->t);
457 33
                        return;
458
                }
459 99
                ExpectErr(tl, CSTR);
460 99
                p = strrchr(tl->t->dec, '/');
461 99
                if (p != NULL && p[1] == '\0')
462 33
                        bprintf(fn, "%slibvmod_%.*s.so", tl->t->dec, PF(mod));
463
                else
464 66
                        bprintf(fn, "%s", tl->t->dec);
465 99
                vcc_NextToken(tl);
466 99
        } else {
467 24222
                VTAILQ_FOREACH(vim, &imports, list) {
468 4983
                        if (!vcc_IdIs(mod, vim->name))
469 4851
                                continue;
470 132
                        if (!vim->unimported_vext)
471 99
                                continue;
472 33
                        fprintf(stderr, "IMPORT %s from VEXT\n", vim->name);
473 33
                        vim->unimported_vext = 0;
474 33
                        vim->t_mod = mod;
475 33
                        vim->sym = msym;
476 33
                        break;
477
                }
478
        }
479
480 19371
        SkipToken(tl, ';');
481
482 19371
        if (vim == NULL) {
483 19338
                ALLOC_OBJ(vim, VMOD_IMPORT_MAGIC);
484 19338
                AN(vim);
485 19338
                vim->t_mod = mod;
486 19338
                vim->sym = msym;
487
488 19338
                if (VFIL_searchpath(tl->vmod_path, vcc_path_open, vim, fn, &vim->path)) {
489 132
                        if (vim->err == NULL) {
490 66
                                VSB_printf(tl->sb,
491 33
                                    "Could not find VMOD %.*s\n", PF(mod));
492 33
                        } else {
493 198
                                VSB_printf(tl->sb,
494 99
                                    "Could not open VMOD %.*s\n", PF(mod));
495 198
                                VSB_printf(tl->sb, "\tFile name: %s\n",
496 99
                                    vim->path != NULL ? vim->path : fn);
497 99
                                VSB_printf(tl->sb, "\tError: %s\n", vim->err);
498
                        }
499 132
                        vcc_ErrWhere(tl, mod);
500 132
                        vcc_vim_destroy(&vim);
501 132
                        return;
502
                }
503
504 19206
                if (vcc_VmodLoad(tl, vim) < 0 || tl->err) {
505 330
                        vcc_ErrWhere(tl, vim->t_mod);
506 330
                        vcc_vim_destroy(&vim);
507 330
                        return;
508
                }
509 18876
        }
510
511 18909
        if (!vcc_IdIs(vim->t_mod, vim->name)) {
512 66
                vcc_ErrWhere(tl, vim->t_mod);
513 132
                VSB_printf(tl->sb, "Wrong file for VMOD %.*s\n",
514 66
                    PF(vim->t_mod));
515 66
                VSB_printf(tl->sb, "\tFile name: %s\n", vim->path);
516 66
                VSB_printf(tl->sb, "\tContains vmod \"%s\"\n", vim->name);
517 66
                vcc_vim_destroy(&vim);
518 66
                return;
519
        }
520
521 18843
        vimold = msym->import;
522 18843
        if (vimold != NULL) {
523 99
                CHECK_OBJ(vimold, VMOD_IMPORT_MAGIC);
524 99
                if (!strcmp(vimold->file_id, vim->file_id)) {
525
                        /* Identical import is OK */
526 66
                } else {
527 66
                        VSB_printf(tl->sb,
528
                            "Another module already imported as %.*s.\n",
529 33
                            PF(tmod));
530 33
                        vcc_ErrWhere2(tl, t1, tl->t);
531
                }
532 99
                vcc_vim_destroy(&vim);
533 99
                return;
534
        }
535 18744
        msym->def_b = t1;
536 18744
        msym->def_e = tl->t;
537
538 23430
        VTAILQ_FOREACH(vsym, &tl->sym_vmods, sideways) {
539 4719
                assert(vsym->kind == SYM_VMOD);
540 4719
                vimold = vsym->import;
541 4719
                CHECK_OBJ_NOTNULL(vimold, VMOD_IMPORT_MAGIC);
542 4719
                if (!strcmp(vimold->file_id, vim->file_id)) {
543
                        /* Already loaded under different name */
544 33
                        msym->eval_priv = vsym->eval_priv;
545 33
                        msym->import = vsym->import;
546 33
                        msym->vmod_name = vsym->vmod_name;
547 33
                        vcc_VmodSymbols(tl, msym);
548 33
                        AZ(tl->err);
549
                        // XXX: insert msym in sideways ?
550 33
                        vcc_vim_destroy(&vim);
551 33
                        return;
552
                }
553 4686
        }
554
555 18711
        VTAILQ_INSERT_TAIL(&tl->sym_vmods, msym, sideways);
556
557 18711
        msym->eval_priv = vim->vj;
558 18711
        msym->import = vim;
559 18711
        msym->vmod_name = TlDup(tl, vim->name);
560 18711
        vcc_VmodSymbols(tl, msym);
561 18711
        ERRCHK(tl);
562
563 18678
        vcc_emit_setup(tl, vim);
564 19470
}
565
566
void
567 33
vcc_ImportVext(struct vcc *tl, const char *filename)
568
{
569
        struct vmod_import *vim;
570
571 33
        ALLOC_OBJ(vim, VMOD_IMPORT_MAGIC);
572 33
        AN(vim);
573
574 33
        if (vcc_Extract_JSON(vim, filename)) {
575 0
                FREE_OBJ(vim);
576 0
                return;
577
        }
578 33
        fprintf(stderr, "FOUND VMOD in VEXT %s\n", filename);
579 33
        if (vcc_VmodLoad(tl, vim) < 0 || tl->err) {
580
                // vcc_ErrWhere(tl, vim->t_mod);
581 0
                vcc_vim_destroy(&vim);
582 0
                return;
583
        }
584 33
        vim->from_vext = 1;
585 33
        vim->unimported_vext = 1;
586 33
        vim->path = strdup(filename);
587 33
        vim->path += 1;
588 33
        AN(vim->path);
589 33
        fprintf(stderr, "GOOD VMOD %s in VEXT %s\n", vim->name, filename);
590 33
}