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