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 13570
vcc_Extract_JSON(struct vmod_import *vim, const char *filename)
81
{
82 13570
        const char *magic = "VMOD_JSON_SPEC\x02", *p;
83
        int c;
84
        FILE *f;
85
86 13570
        CHECK_OBJ_NOTNULL(vim, VMOD_IMPORT_MAGIC);
87 13570
        AN(filename);
88
89 13570
        f = fopen(filename, "rb");
90 13570
        if (f == NULL) {
91 23
                vim->err = strerror(errno);
92 23
                return (-1);
93
        }
94
95 13547
        p = magic;
96 13547
        vim->err = "No VMOD JSON found";
97 1100067
        while (1) {
98 266025544
                c = getc(f);
99 266025544
                if (c == EOF) {
100 23
                        AZ(fclose(f));
101 23
                        vim->err = "No VMOD JSON found";
102 23
                        return (-1);
103
                }
104 266025521
                if (c != *p) {
105 264925477
                        p = magic;
106 264925477
                        continue;
107
                }
108 1100044
                p++;
109 1100044
                if (*p == '\0')
110 13524
                        break;
111
        }
112
113 13524
        vim->json = VSB_new_auto();
114 13524
        AN(vim->json);
115
116 267577768
        while (1) {
117 267577768
                c = getc(f);
118 267577768
                if (c == EOF) {
119 23
                        AZ(fclose(f));
120 23
                        vim->err = "Truncated VMOD JSON";
121 23
                        VSB_destroy(&vim->json);
122 23
                        return (-1);
123
                }
124 267577745
                if (c == '\x03')
125 13501
                        break;
126 267564244
                VSB_putc(vim->json, c);
127
        }
128 13501
        AZ(fclose(f));
129 13501
        AZ(VSB_finish(vim->json));
130 13501
        return (0);
131 13570
}
132
133
static const char *
134 13501
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 13501
        vim->vj = vjsn_parse(jsn, &err);
141 13501
        if (err != NULL)
142 23
                return (err);
143 13478
        AN(vim->vj);
144
145 13478
        vv = vim->vj->value;
146 13478
        if (!vjsn_is_array(vv))
147 23
                return ("Not array[0]");
148
149 13455
        vv2 = VTAILQ_FIRST(&vv->children);
150 13455
        AN(vv2);
151 13455
        if (!vjsn_is_array(vv2))
152 23
                return ("Not array[1]");
153 13432
        vv3 = VTAILQ_FIRST(&vv2->children);
154 13432
        AN(vv3);
155 13432
        if (!vjsn_is_string(vv3))
156 23
                return ("Not string[2]");
157 13409
        if (strcmp(vv3->value, "$VMOD"))
158 23
                return ("Not $VMOD[3]");
159
160 13386
        vv3 = VTAILQ_NEXT(vv3, list);
161 13386
        AN(vv3);
162 13386
        assert(vjsn_is_string(vv3));
163 13386
        vim->vmod_syntax = strtod(vv3->value, NULL);
164 13386
        if (vim->vmod_syntax != 2.0)
165 23
                return ("Syntax != 2.0");
166
167 13363
        vv3 = VTAILQ_NEXT(vv3, list);
168 13363
        AN(vv3);
169 13363
        assert(vjsn_is_string(vv3));
170 13363
        vim->name = vv3->value;
171
172 13363
        vv3 = VTAILQ_NEXT(vv3, list);
173 13363
        AN(vv3);
174 13363
        assert(vjsn_is_string(vv3));
175 13363
        vim->func_name = vv3->value;
176
177 13363
        vv3 = VTAILQ_NEXT(vv3, list);
178 13363
        AN(vv3);
179 13363
        assert(vjsn_is_string(vv3));
180 13363
        vim->file_id = vv3->value;
181
182 13363
        vv3 = VTAILQ_NEXT(vv3, list);
183 13363
        AN(vv3);
184 13363
        assert(vjsn_is_string(vv3));
185 13363
        vim->abi = vv3->value;
186
187 13363
        vv3 = VTAILQ_NEXT(vv3, list);
188 13363
        AN(vv3);
189 13363
        assert(vjsn_is_string(vv3));
190 13363
        vim->major = strtoul(vv3->value, &p, 10);
191 13363
        assert(p == NULL || *p == '\0' || *p == 'U');
192
193 13363
        vv3 = VTAILQ_NEXT(vv3, list);
194 13363
        AN(vv3);
195 13363
        assert(vjsn_is_string(vv3));
196 13363
        vim->minor = strtoul(vv3->value, &p, 10);
197 13363
        assert(p == NULL || *p == '\0' || *p == 'U');
198
199
200 13363
        if (vim->major == 0 && vim->minor == 0 &&
201 10281
            strcmp(vim->abi, VMOD_ABI_Version)) {
202 23
                VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(vim->t_mod));
203 23
                VSB_printf(tl->sb, "\tFile name: %s\n", vim->path);
204 46
                VSB_printf(tl->sb, "\tABI mismatch, expected <%s>, got <%s>\n",
205 23
                           VMOD_ABI_Version, vim->abi);
206 23
                return ("");
207
        }
208 16399
        if (vim->major != 0 &&
209 3082
            (vim->major != VRT_MAJOR_VERSION ||
210 3059
            vim->minor > VRT_MINOR_VERSION)) {
211 23
                VSB_printf(tl->sb, "Incompatible VMOD %.*s\n", PF(vim->t_mod));
212 23
                VSB_printf(tl->sb, "\tFile name: %s\n", vim->path);
213 46
                VSB_printf(tl->sb, "\tVMOD wants ABI version %u.%u\n",
214 23
                    vim->major, vim->minor);
215 23
                VSB_printf(tl->sb, "\tvarnishd provides ABI version %u.%u\n",
216
                    VRT_MAJOR_VERSION, VRT_MINOR_VERSION);
217 23
                return ("");
218
        }
219
220
221 499813
        VTAILQ_FOREACH(vv2, &vv->children, list) {
222 486519
                assert (vjsn_is_array(vv2));
223 486519
                vv3 = VTAILQ_FIRST(&vv2->children);
224 486519
                assert(vjsn_is_string(vv3));
225 486519
                assert(vv3->value[0] == '$');
226
#define STANZA(UU, ll, ss) \
227
    if (!strcmp(vv3->value, "$" #UU)) {vim->n_##ll++; continue;}
228 486519
                STANZA_TBL
229
#undef STANZA
230 23
                return ("Unknown metadata stanza.");
231
        }
232 13294
        if (vim->n_cproto != 1)
233 23
                return ("Bad cproto stanza(s)");
234 13271
        if (vim->n_vmod != 1)
235 23
                return ("Bad vmod stanza(s)");
236 13248
        return (NULL);
237 13501
}
238
239
/*
240
 * Load and check the metadata from the objectfile containing the vmod
241
 */
242
243
static int
244 13501
vcc_VmodLoad(struct vcc *tl, struct vmod_import *vim)
245
{
246
        static const char *err;
247
        struct vmod_import *vim2;
248
249 13501
        CHECK_OBJ_NOTNULL(vim, VMOD_IMPORT_MAGIC);
250
251 13501
        err = vcc_ParseJSON(tl, VSB_data(vim->json), vim);
252 13501
        if (err != NULL && *err != '\0') {
253 414
                VSB_printf(tl->sb,
254 207
                    "VMOD %.*s: bad metadata\n", PF(vim->t_mod));
255 207
                VSB_printf(tl->sb, "\t(%s)\n", err);
256 207
                VSB_printf(tl->sb, "\tFile name: %s\n", vim->path);
257 207
        }
258
259 13501
        if (err != NULL)
260 253
                return (-1);
261
262 16583
        VTAILQ_FOREACH(vim2, &imports, list) {
263 3427
                if (strcmp(vim->name, vim2->name))
264 3335
                        continue;
265 92
                if (!strcmp(vim->file_id, vim2->file_id)) {
266
                        // (Truly) duplicate imports are OK
267 69
                        return (0);
268
                }
269 46
                VSB_printf(tl->sb,
270
                    "Different version of VMOD %.*s already loaded\n",
271 23
                    PF(vim->t_mod));
272 23
                vcc_ErrWhere(tl, vim->t_mod);
273 23
                VSB_cat(tl->sb, "Previous import at:\n");
274 23
                vcc_ErrWhere(tl, vim2->t_mod);
275 23
                vcc_Warn(tl);
276 23
                break;
277
        }
278 13179
        VTAILQ_INSERT_TAIL(&imports, vim, list);
279
280 13179
        return (0);
281 13501
}
282
283
static void v_matchproto_(vcc_do_stanza_f)
284 2829
vcc_do_event(struct vcc *tl, const struct vmod_import *vim,
285
    const struct vjsn_val *vv)
286
{
287
        struct inifin *ifp;
288
289 2829
        ifp = New_IniFin(tl);
290 5658
        VSB_printf(ifp->ini,
291
            "\tif (%s(ctx, &vmod_priv_%s, VCL_EVENT_LOAD))\n"
292
            "\t\treturn(1);",
293 2829
            vv->value, vim->sym->vmod_name);
294 5658
        VSB_printf(ifp->fin,
295
            "\t\t(void)%s(ctx, &vmod_priv_%s,\n"
296
            "\t\t\t    VCL_EVENT_DISCARD);",
297 2829
            vv->value, vim->sym->vmod_name);
298 5658
        VSB_printf(ifp->event, "%s(ctx, &vmod_priv_%s, ev)",
299 2829
            vv->value, vim->sym->vmod_name);
300 2829
}
301
302
static void v_matchproto_(vcc_do_stanza_f)
303 13087
vcc_do_cproto(struct vcc *tl, const struct vmod_import *vim,
304
    const struct vjsn_val *vv)
305
{
306 13087
        (void)vim;
307 13087
        do {
308 2501319
                assert (vjsn_is_string(vv));
309 2501319
                Fh(tl, 0, "%s\n", vv->value);
310 2501319
                vv = VTAILQ_NEXT(vv, list);
311 2501319
        } while(vv != NULL);
312 13087
}
313
314
static void
315 26174
vcc_vj_foreach(struct vcc *tl, const struct vmod_import *vim,
316
    const char *stanza, vcc_do_stanza_f *func)
317
{
318
        const struct vjsn_val *vv, *vv2, *vv3;
319
320 26174
        vv = vim->vj->value;
321 26174
        assert (vjsn_is_array(vv));
322 980812
        VTAILQ_FOREACH(vv2, &vv->children, list) {
323 954638
                assert (vjsn_is_array(vv2));
324 954638
                vv3 = VTAILQ_FIRST(&vv2->children);
325 954638
                assert (vjsn_is_string(vv3));
326 954638
                if (!strcmp(vv3->value, stanza))
327 15916
                        func(tl, vim, VTAILQ_NEXT(vv3, list));
328 954638
        }
329 26174
}
330
331
static void
332 13087
vcc_emit_setup(struct vcc *tl, const struct vmod_import *vim)
333
{
334
        struct inifin *ifp;
335 13087
        const struct token *mod = vim->t_mod;
336
337 13087
        ifp = New_IniFin(tl);
338
339 13087
        VSB_cat(ifp->ini, "\tif (VPI_Vmod_Init(ctx,\n");
340 13087
        VSB_printf(ifp->ini, "\t    &VGC_vmod_%.*s,\n", PF(mod));
341 13087
        VSB_printf(ifp->ini, "\t    %u,\n", tl->vmod_count++);
342 13087
        VSB_printf(ifp->ini, "\t    &%s,\n", vim->func_name);
343 13087
        VSB_printf(ifp->ini, "\t    sizeof(%s),\n", vim->func_name);
344 13087
        VSB_printf(ifp->ini, "\t    \"%.*s\",\n", PF(mod));
345 13087
        VSB_cat(ifp->ini, "\t    ");
346 13087
        VSB_quote(ifp->ini, vim->path, -1, VSB_QUOTE_CSTR);
347 13087
        VSB_cat(ifp->ini, ",\n");
348 13087
        AN(vim->file_id);
349 13087
        VSB_printf(ifp->ini, "\t    \"%s\",\n", vim->file_id);
350 13087
        if (vim->from_vext) {
351 23
                VSB_cat(ifp->ini, "\t    ");
352 23
                VSB_quote(ifp->ini, vim->path, -1, VSB_QUOTE_CSTR);
353 23
                VSB_cat(ifp->ini, "\n");
354 23
        } else {
355 26128
                VSB_printf(ifp->ini, "\t    \"./vmod_cache/_vmod_%.*s.%s\"\n",
356 13064
                    PF(mod), vim->file_id);
357
        }
358 13087
        VSB_cat(ifp->ini, "\t    ))\n");
359 13087
        VSB_cat(ifp->ini, "\t\treturn(1);");
360
361 13087
        VSB_cat(tl->symtab, ",\n    {\n");
362 13087
        VSB_cat(tl->symtab, "\t\"dir\": \"import\",\n");
363 13087
        VSB_cat(tl->symtab, "\t\"type\": \"$VMOD\",\n");
364 13087
        VSB_printf(tl->symtab, "\t\"name\": \"%.*s\",\n", PF(mod));
365 13087
        if (vim->from_vext)
366 23
                VSB_cat(tl->symtab, "\t\"vext\": true,\n");
367
        else
368 13064
                VSB_cat(tl->symtab, "\t\"vext\": false,\n");
369 13087
        VSB_printf(tl->symtab, "\t\"file\": \"%s\",\n", vim->path);
370 26174
        VSB_printf(tl->symtab, "\t\"dst\": \"./vmod_cache/_vmod_%.*s.%s\"\n",
371 13087
            PF(mod), vim->file_id);
372 13087
        VSB_cat(tl->symtab, "    }");
373
374
        /* XXX: zero the function pointer structure ?*/
375 26174
        VSB_printf(ifp->fin, "\t\tVRT_priv_fini(ctx, &vmod_priv_%.*s);",
376 13087
            PF(mod));
377 26174
        VSB_printf(ifp->final, "\t\tVPI_Vmod_Unload(ctx, &VGC_vmod_%.*s);",
378 13087
            PF(mod));
379
380 13087
        vcc_vj_foreach(tl, vim, "$EVENT", vcc_do_event);
381
382 13087
        Fh(tl, 0, "\n/* --- BEGIN VMOD %.*s --- */\n\n", PF(mod));
383 13087
        Fh(tl, 0, "static struct vmod *VGC_vmod_%.*s;\n", PF(mod));
384 13087
        Fh(tl, 0, "static struct vmod_priv vmod_priv_%.*s;\n", PF(mod));
385
386 13087
        vcc_vj_foreach(tl, vim, "$CPROTO", vcc_do_cproto);
387
388 13087
        Fh(tl, 0, "\n/* --- END VMOD %.*s --- */\n\n", PF(mod));
389 13087
}
390
391
static void
392 483
vcc_vim_destroy(struct vmod_import **vimp)
393
{
394
        struct vmod_import *vim;
395
396 483
        TAKE_OBJ_NOTNULL(vim, vimp, VMOD_IMPORT_MAGIC);
397 483
        if (vim->path)
398 460
                free(vim->path);
399 483
        if (vim->vj)
400 368
                vjsn_delete(&vim->vj);
401 483
        if (vim->json)
402 391
                VSB_destroy(&vim->json);
403 483
        FREE_OBJ(vim);
404 483
}
405
406
static int
407 13547
vcc_path_open(void *priv, const char *fn)
408
{
409
        struct vmod_import *vim;
410
411 13547
        CAST_OBJ_NOTNULL(vim, priv, VMOD_IMPORT_MAGIC);
412 13547
        AN(fn);
413
414 13547
        return (vcc_Extract_JSON(vim, fn));
415
}
416
417
void
418 13662
vcc_ParseImport(struct vcc *tl)
419
{
420
        char fn[1024];
421
        const char *p;
422
        struct token *mod, *tmod, *t1;
423
        struct symbol *msym, *vsym;
424 13662
        struct vmod_import *vim = NULL;
425
        const struct vmod_import *vimold;
426
427 13662
        t1 = tl->t;
428 13662
        SkipToken(tl, ID);              /* "import" */
429
430 13662
        ExpectErr(tl, ID);              /* "vmod_name" */
431 13662
        mod = tl->t;
432 13662
        tmod = vcc_PeekTokenFrom(tl, mod);
433 13662
        AN(tmod);
434 13662
        if (tmod->tok == ID && vcc_IdIs(tmod, "as")) {
435 115
                vcc_NextToken(tl);              /* "vmod_name" */
436 115
                vcc_NextToken(tl);              /* "as" */
437 115
                ExpectErr(tl, ID);              /* "vcl_name" */
438 115
        }
439 13662
        tmod = tl->t;
440
441 13662
        msym = VCC_SymbolGet(tl, SYM_MAIN, SYM_VMOD, SYMTAB_CREATE, XREF_NONE);
442 13662
        ERRCHK(tl);
443 13639
        AN(msym);
444
445 13639
        bprintf(fn, "libvmod_%.*s.so", PF(mod));
446 13639
        if (tl->t->tok == ID) {
447 115
                if (!vcc_IdIs(tl->t, "from")) {
448 23
                        VSB_cat(tl->sb, "Expected 'from path ...'\n");
449 23
                        vcc_ErrWhere(tl, tl->t);
450 23
                        return;
451
                }
452 92
                vcc_NextToken(tl);
453 92
                if (!tl->unsafe_path && strchr(tl->t->dec, '/')) {
454 23
                        VSB_cat(tl->sb,
455
                            "'import ... from path ...' is unsafe.\nAt:");
456 23
                        vcc_ErrToken(tl, tl->t);
457 23
                        vcc_ErrWhere(tl, tl->t);
458 23
                        return;
459
                }
460 69
                ExpectErr(tl, CSTR);
461 69
                p = strrchr(tl->t->dec, '/');
462 69
                if (p != NULL && p[1] == '\0')
463 23
                        bprintf(fn, "%slibvmod_%.*s.so", tl->t->dec, PF(mod));
464
                else
465 46
                        bprintf(fn, "%s", tl->t->dec);
466 69
                vcc_NextToken(tl);
467 69
        } else {
468 16997
                VTAILQ_FOREACH(vim, &imports, list) {
469 3496
                        if (!vcc_IdIs(mod, vim->name))
470 3404
                                continue;
471 92
                        if (!vim->unimported_vext)
472 69
                                continue;
473 23
                        fprintf(stderr, "IMPORT %s from VEXT\n", vim->name);
474 23
                        vim->unimported_vext = 0;
475 23
                        vim->t_mod = mod;
476 23
                        vim->sym = msym;
477 23
                        break;
478
                }
479
        }
480
481 13593
        SkipToken(tl, ';');
482
483 13593
        if (vim == NULL) {
484 13570
                ALLOC_OBJ(vim, VMOD_IMPORT_MAGIC);
485 13570
                AN(vim);
486 13570
                vim->t_mod = mod;
487 13570
                vim->sym = msym;
488
489 13570
                if (VFIL_searchpath(tl->vmod_path, vcc_path_open, vim, fn, &vim->path)) {
490 92
                        if (vim->err == NULL) {
491 46
                                VSB_printf(tl->sb,
492 23
                                    "Could not find VMOD %.*s\n", PF(mod));
493 23
                        } else {
494 138
                                VSB_printf(tl->sb,
495 69
                                    "Could not open VMOD %.*s\n", PF(mod));
496 138
                                VSB_printf(tl->sb, "\tFile name: %s\n",
497 69
                                    vim->path != NULL ? vim->path : fn);
498 69
                                VSB_printf(tl->sb, "\tError: %s\n", vim->err);
499
                        }
500 92
                        vcc_ErrWhere(tl, mod);
501 92
                        vcc_vim_destroy(&vim);
502 92
                        return;
503
                }
504
505 13478
                if (vcc_VmodLoad(tl, vim) < 0 || tl->err) {
506 253
                        vcc_ErrWhere(tl, vim->t_mod);
507 253
                        vcc_vim_destroy(&vim);
508 253
                        return;
509
                }
510 13225
        }
511
512 13248
        if (!vcc_IdIs(vim->t_mod, vim->name)) {
513 46
                vcc_ErrWhere(tl, vim->t_mod);
514 92
                VSB_printf(tl->sb, "Wrong file for VMOD %.*s\n",
515 46
                    PF(vim->t_mod));
516 46
                VSB_printf(tl->sb, "\tFile name: %s\n", vim->path);
517 46
                VSB_printf(tl->sb, "\tContains vmod \"%s\"\n", vim->name);
518 46
                vcc_vim_destroy(&vim);
519 46
                return;
520
        }
521
522 13202
        vimold = msym->import;
523 13202
        if (vimold != NULL) {
524 69
                CHECK_OBJ(vimold, VMOD_IMPORT_MAGIC);
525 69
                if (!strcmp(vimold->file_id, vim->file_id)) {
526
                        /* Identical import is OK */
527 46
                } else {
528 46
                        VSB_printf(tl->sb,
529
                            "Another module already imported as %.*s.\n",
530 23
                            PF(tmod));
531 23
                        vcc_ErrWhere2(tl, t1, tl->t);
532
                }
533 69
                vcc_vim_destroy(&vim);
534 69
                return;
535
        }
536 13133
        msym->def_b = t1;
537 13133
        msym->def_e = tl->t;
538
539 16422
        VTAILQ_FOREACH(vsym, &tl->sym_vmods, sideways) {
540 3312
                assert(vsym->kind == SYM_VMOD);
541 3312
                vimold = vsym->import;
542 3312
                CHECK_OBJ_NOTNULL(vimold, VMOD_IMPORT_MAGIC);
543 3312
                if (!strcmp(vimold->file_id, vim->file_id)) {
544
                        /* Already loaded under different name */
545 23
                        msym->eval_priv = vsym->eval_priv;
546 23
                        msym->import = vsym->import;
547 23
                        msym->vmod_name = vsym->vmod_name;
548 23
                        vcc_VmodSymbols(tl, msym);
549 23
                        AZ(tl->err);
550
                        // XXX: insert msym in sideways ?
551 23
                        vcc_vim_destroy(&vim);
552 23
                        return;
553
                }
554 3289
        }
555
556 13110
        VTAILQ_INSERT_TAIL(&tl->sym_vmods, msym, sideways);
557
558 13110
        msym->eval_priv = vim->vj;
559 13110
        msym->import = vim;
560 13110
        msym->vmod_name = TlDup(tl, vim->name);
561 13110
        vcc_VmodSymbols(tl, msym);
562 13110
        ERRCHK(tl);
563
564 13087
        vcc_emit_setup(tl, vim);
565 13662
}
566
567
void
568 23
vcc_ImportVext(struct vcc *tl, const char *filename)
569
{
570
        struct vmod_import *vim;
571
572 23
        ALLOC_OBJ(vim, VMOD_IMPORT_MAGIC);
573 23
        AN(vim);
574
575 23
        if (vcc_Extract_JSON(vim, filename)) {
576 0
                FREE_OBJ(vim);
577 0
                return;
578
        }
579 23
        fprintf(stderr, "FOUND VMOD in VEXT %s\n", filename);
580 23
        if (vcc_VmodLoad(tl, vim) < 0 || tl->err) {
581
                // vcc_ErrWhere(tl, vim->t_mod);
582 0
                vcc_vim_destroy(&vim);
583 0
                return;
584
        }
585 23
        vim->from_vext = 1;
586 23
        vim->unimported_vext = 1;
587 23
        vim->path = strdup(filename);
588 23
        vim->path += 1;
589 23
        AN(vim->path);
590 23
        fprintf(stderr, "GOOD VMOD %s in VEXT %s\n", vim->name, filename);
591 23
}