varnish-cache/bin/varnishd/cache/cache_vcl.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2016 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 */
31
32
#include "config.h"
33
34
#include <dlfcn.h>
35
#include <fnmatch.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
39
#include "cache_varnishd.h"
40
#include "common/heritage.h"
41
42
#include "vcl.h"
43
44
#include "cache_director.h"
45
#include "cache_vcl.h"
46
#include "vbm.h"
47
#include "vcli_serve.h"
48
#include "vte.h"
49
#include "vtim.h"
50
#include "vcc_interface.h"
51
52
const struct vcltemp VCL_TEMP_INIT[1] = {{ .name = "init", .is_cold = 1 }};
53
const struct vcltemp VCL_TEMP_COLD[1] = {{ .name = "cold", .is_cold = 1 }};
54
const struct vcltemp VCL_TEMP_WARM[1] = {{ .name = "warm", .is_warm = 1 }};
55
const struct vcltemp VCL_TEMP_BUSY[1] = {{ .name = "busy", .is_warm = 1 }};
56
const struct vcltemp VCL_TEMP_COOLING[1] = {{ .name = "cooling" }};
57
58
// not really a temperature
59
static const struct vcltemp VCL_TEMP_LABEL[1] = {{ .name = "label" }};
60
61
/*
62
 * XXX: Presently all modifications to this list happen from the
63
 * CLI event-engine, so no locking is necessary
64
 */
65
static VTAILQ_HEAD(, vcl)       vcl_head =
66
    VTAILQ_HEAD_INITIALIZER(vcl_head);
67
68
struct lock             vcl_mtx;
69
struct vcl              *vcl_active; /* protected by vcl_mtx */
70
71
static struct vrt_ctx ctx_cli;
72
static struct wrk_vpi wrk_vpi_cli;
73
static struct ws ws_cli;
74
static uintptr_t ws_snapshot_cli;
75
static struct vsl_log vsl_cli;
76
77
/*--------------------------------------------------------------------*/
78
79
void
80 619054
VCL_Bo2Ctx(struct vrt_ctx *ctx, struct busyobj *bo)
81
{
82
83 619054
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
84 619054
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
85 619054
        CHECK_OBJ_NOTNULL(bo->wrk, WORKER_MAGIC);
86 619054
        ctx->vcl = bo->vcl;
87 619054
        ctx->syntax = ctx->vcl->conf->syntax;
88 619054
        ctx->vsl = bo->vsl;
89 619054
        ctx->http_bereq = bo->bereq;
90 619054
        ctx->http_beresp = bo->beresp;
91 619054
        ctx->bo = bo;
92 619054
        ctx->sp = bo->sp;
93 619054
        ctx->now = bo->t_prev;
94 619054
        ctx->ws = bo->ws;
95 619054
        ctx->vpi = bo->wrk->vpi;
96 619054
        ctx->vpi->handling = 0;
97 619054
        ctx->vpi->trace = bo->trace;
98 619054
}
99
100
void
101 1000014
VCL_Req2Ctx(struct vrt_ctx *ctx, struct req *req)
102
{
103
104 1000014
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
105 1000014
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
106 1000014
        CHECK_OBJ_NOTNULL(req->doclose, STREAM_CLOSE_MAGIC);
107
108 1000014
        ctx->vcl = req->vcl;
109 1000014
        ctx->syntax = ctx->vcl->conf->syntax;
110 1000014
        ctx->vsl = req->vsl;
111 1000014
        ctx->http_req = req->http;
112 1000014
        CHECK_OBJ_NOTNULL(req->top, REQTOP_MAGIC);
113 1000014
        ctx->http_req_top = req->top->topreq->http;
114 1000014
        ctx->http_resp = req->resp;
115 1000014
        ctx->req = req;
116 1000014
        ctx->sp = req->sp;
117 1000014
        ctx->now = req->t_prev;
118 1000014
        ctx->ws = req->ws;
119 1000014
        ctx->vpi = req->wrk->vpi;
120 1000014
        ctx->vpi->handling = 0;
121 1000014
        ctx->vpi->trace = req->trace;
122 1000014
}
123
124
/*--------------------------------------------------------------------*/
125
126
struct vrt_ctx *
127 153212
VCL_Get_CliCtx(int msg)
128
{
129
130 153212
        ASSERT_CLI();
131 153212
        INIT_OBJ(&ctx_cli, VRT_CTX_MAGIC);
132 153212
        INIT_OBJ(&wrk_vpi_cli, WRK_VPI_MAGIC);
133 153212
        ctx_cli.vpi = &wrk_vpi_cli;
134 153212
        wrk_vpi_cli.trace = FEATURE(FEATURE_TRACE);
135 153212
        ctx_cli.now = VTIM_real();
136 153212
        if (msg) {
137 96960
                ctx_cli.msg = VSB_new_auto();
138 96960
                AN(ctx_cli.msg);
139 96960
        } else {
140 56252
                ctx_cli.vsl = &vsl_cli;
141
        }
142 153212
        ctx_cli.ws = &ws_cli;
143 153212
        WS_Assert(ctx_cli.ws);
144 153212
        return (&ctx_cli);
145
}
146
147
/*
148
 * releases CLI ctx
149
 *
150
 * returns finished error msg vsb if VCL_Get_CliCtx(1) was called
151
 *
152
 * caller needs to VSB_destroy a non-NULL return value
153
 *
154
 */
155
struct vsb *
156 153172
VCL_Rel_CliCtx(struct vrt_ctx **ctx)
157
{
158 153172
        struct vsb *r = NULL;
159
160 153172
        ASSERT_CLI();
161 153172
        assert(*ctx == &ctx_cli);
162 153172
        AN((*ctx)->vpi);
163 153172
        if (ctx_cli.msg) {
164 96960
                TAKE_OBJ_NOTNULL(r, &ctx_cli.msg, VSB_MAGIC);
165 96960
                AZ(VSB_finish(r));
166 96960
        }
167 153172
        if (ctx_cli.vsl)
168 56212
                VSL_Flush(ctx_cli.vsl, 0);
169 153172
        WS_Assert(ctx_cli.ws);
170 153172
        WS_Rollback(&ws_cli, ws_snapshot_cli);
171 153172
        INIT_OBJ(*ctx, VRT_CTX_MAGIC);
172 153172
        *ctx = NULL;
173
174 153172
        return (r);
175
}
176
177
/*--------------------------------------------------------------------*/
178
179
/* VRT_fail() can be called
180
 * - from the vcl sub via a vmod
181
 * - via a PRIV_TASK .fini callback
182
 *
183
 * if this happens during init, we fail it
184
 * if during fini, we ignore, because otherwise VMOD authors would be forced to
185
 * handle VCL_MET_FINI specifically everywhere.
186
 */
187
188
static int
189 101932
vcl_event_handling(VRT_CTX)
190
{
191 101932
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
192
193 101932
        if (ctx->vpi->handling == 0)
194 100212
                return (0);
195
196 1720
        assert(ctx->vpi->handling == VCL_RET_FAIL);
197
198 1720
        if (ctx->method == VCL_MET_INIT)
199 1640
                return (1);
200
201
        /*
202
         * EVENT_WARM / EVENT_COLD: method == 0
203
         * must not set handling
204
         */
205 80
        assert(ctx->method == VCL_MET_FINI);
206
207 80
        ctx->vpi->handling = 0;
208 80
        VRT_fail(ctx, "VRT_fail() from vcl_fini{} has no effect");
209 80
        return (0);
210 101932
}
211
212
static int
213 101972
vcl_send_event(struct vcl *vcl, enum vcl_event_e ev, struct vsb **msg)
214
{
215
        int r, havemsg;
216 101972
        unsigned method = 0;
217
        struct vrt_ctx *ctx;
218 101972
        void *vbm_alloc = NULL;
219
        size_t sz;
220
221 101972
        ASSERT_CLI();
222 101972
        ASSERT_VCL_ACTIVE();
223
224 101972
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
225 101972
        CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);
226 101972
        AN(msg);
227 101972
        AZ(*msg);
228
229 101972
        switch (ev) {
230
        case VCL_EVENT_LOAD:
231 49280
                method = VCL_MET_INIT;
232
                /* FALLTHROUGH */
233
        case VCL_EVENT_WARM:
234 96960
                havemsg = 1;
235 96960
                break;
236
        case VCL_EVENT_DISCARD:
237 3107
                method = VCL_MET_FINI;
238
                /* FALLTHROUGH */
239
        case VCL_EVENT_COLD:
240 5012
                havemsg = 0;
241 5012
                break;
242
        default:
243 0
                WRONG("vcl_event");
244 0
        }
245
246 101972
        ctx = VCL_Get_CliCtx(havemsg);
247
248 101972
        AN(ctx->vpi);
249 101972
        AZ(ctx->vpi->handling);
250 101972
        AN(ctx->ws);
251
252 101972
        ctx->vcl = vcl;
253 101972
        ctx->syntax = ctx->vcl->conf->syntax;
254 101972
        ctx->method = method;
255
256 101972
        if (vcl->conf->nsub > 0) {
257 480
                sz = VBITMAP_SZ(vcl->conf->nsub);
258 480
                vbm_alloc = malloc(sz);
259 480
                AN(vbm_alloc);
260 480
                ctx->called = vbit_init(vbm_alloc, sz);
261 480
        }
262
263 101972
        VCL_TaskEnter(cli_task_privs);
264 101972
        r = ctx->vcl->conf->event_vcl(ctx, ev);
265 101972
        VCL_TaskLeave(ctx, cli_task_privs);
266 101972
        r |= vcl_event_handling(ctx);
267
268 101972
        *msg = VCL_Rel_CliCtx(&ctx);
269
270 101972
        if (r && (ev == VCL_EVENT_COLD || ev == VCL_EVENT_DISCARD))
271 0
                WRONG("A VMOD cannot fail COLD or DISCARD events");
272
273 101972
        free(vbm_alloc);
274
275 101972
        return (r);
276
}
277
278
/*--------------------------------------------------------------------*/
279
280
struct vcl *
281 102360
vcl_find(const char *name)
282
{
283
        struct vcl *vcl;
284
285 102360
        ASSERT_CLI();
286 155027
        VTAILQ_FOREACH(vcl, &vcl_head, list) {
287 104707
                if (vcl->discard)
288 27
                        continue;
289 104680
                if (!strcmp(vcl->loaded_name, name))
290 52040
                        return (vcl);
291 52640
        }
292 50320
        return (NULL);
293 102360
}
294
295
/*--------------------------------------------------------------------*/
296
297
static void
298 280
vcl_panic_conf(struct vsb *vsb, const struct VCL_conf *conf)
299
{
300
        unsigned u;
301
        const struct vpi_ii *ii;
302
303 280
        if (PAN_dump_struct(vsb, conf, VCL_CONF_MAGIC, "conf"))
304 0
                return;
305 280
        VSB_printf(vsb, "syntax = \"%u\",\n", conf->syntax);
306 280
        VSB_cat(vsb, "srcname = {\n");
307 280
        VSB_indent(vsb, 2);
308 840
        for (u = 0; u < conf->nsrc; ++u)
309 560
                VSB_printf(vsb, "[%u] = \"%s\",\n", u, conf->srcname[u]);
310 280
        VSB_indent(vsb, -2);
311 280
        VSB_cat(vsb, "},\n");
312 280
        VSB_cat(vsb, "instances = {\n");
313 280
        VSB_indent(vsb, 2);
314 280
        ii = conf->instance_info;
315 440
        while (ii != NULL && ii->p != NULL) {
316 320
                VSB_printf(vsb, "\"%s\" = %p,\n", ii->name,
317 160
                    (const void *)*(const uintptr_t *)ii->p);
318 160
                ii++;
319
        }
320 280
        VSB_indent(vsb, -2);
321 280
        VSB_cat(vsb, "},\n");
322 280
        VSB_indent(vsb, -2);
323 280
        VSB_cat(vsb, "},\n");
324 280
}
325
326
void
327 520
VCL_Panic(struct vsb *vsb, const char *nm, const struct vcl *vcl)
328
{
329
330 520
        AN(vsb);
331 520
        if (PAN_dump_struct(vsb, vcl, VCL_MAGIC, "vcl[%s]", nm))
332 240
                return;
333 280
        VSB_printf(vsb, "name = \"%s\",\n", vcl->loaded_name);
334 280
        VSB_printf(vsb, "busy = %u,\n", vcl->busy);
335 280
        VSB_printf(vsb, "discard = %u,\n", vcl->discard);
336 280
        VSB_printf(vsb, "state = %s,\n", vcl->state);
337 280
        VSB_printf(vsb, "temp = %s,\n", vcl->temp ? vcl->temp->name : "(null)");
338 280
        vcl_panic_conf(vsb, vcl->conf);
339 280
        VSB_indent(vsb, -2);
340 280
        VSB_cat(vsb, "},\n");
341 520
}
342
343
/*--------------------------------------------------------------------*/
344
345
void
346 57833
VCL_Update(struct vcl **vcc, struct vcl *vcl)
347
{
348
        struct vcl *old;
349
350 57833
        AN(vcc);
351
352 57833
        old = *vcc;
353 57833
        *vcc = NULL;
354
355 57833
        CHECK_OBJ_ORNULL(old, VCL_MAGIC);
356 57833
        ASSERT_VCL_ACTIVE();
357
358 57833
        Lck_Lock(&vcl_mtx);
359 57833
        if (old != NULL) {
360 2947
                assert(old->busy > 0);
361 2947
                old->busy--;
362 2947
        }
363
364 57833
        if (vcl == NULL)
365 57313
                vcl = vcl_active; /* Sample vcl_active under lock to avoid
366
                                   * race */
367 57833
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
368 57833
        if (vcl->label == NULL) {
369 57193
                AN(strcmp(vcl->state, VCL_TEMP_LABEL->name));
370 57193
                *vcc = vcl;
371 57193
        } else {
372 640
                AZ(strcmp(vcl->state, VCL_TEMP_LABEL->name));
373 640
                *vcc = vcl->label;
374
        }
375 57833
        CHECK_OBJ_NOTNULL(*vcc, VCL_MAGIC);
376 57833
        AZ((*vcc)->discard);
377 57833
        (*vcc)->busy++;
378 57833
        Lck_Unlock(&vcl_mtx);
379 57833
        assert((*vcc)->temp->is_warm);
380 57833
}
381
382
/*--------------------------------------------------------------------
383
 * vdire: Vcl DIrector REsignation Management (born out of a dire situation)
384
 * iterators over the director list need to register.
385
 * while iterating, directors can not retire immediately,
386
 * they get put on a list of resigning directors. The
387
 * last iterator executes the retirement.
388
 */
389
390
static struct vdire *
391 98720
vdire_new(struct lock *mtx, const struct vcltemp **tempp)
392
{
393
        struct vdire *vdire;
394
395 98720
        ALLOC_OBJ(vdire, VDIRE_MAGIC);
396 98720
        AN(vdire);
397 98720
        AN(mtx);
398 98720
        VTAILQ_INIT(&vdire->directors);
399 98720
        VTAILQ_INIT(&vdire->resigning);
400 98720
        vdire->mtx = mtx;
401 98720
        PTOK(pthread_cond_init(&vdire->cond, NULL));
402 98720
        vdire->tempp = tempp;
403 98720
        return (vdire);
404
}
405
406
/* starting an interation prevents removals from the directors list */
407
void
408 41827
vdire_start_iter(struct vdire *vdire)
409
{
410
411 41827
        CHECK_OBJ_NOTNULL(vdire, VDIRE_MAGIC);
412
413
        // https://github.com/varnishcache/varnish-cache/pull/4142#issuecomment-2593091097
414 41827
        ASSERT_CLI();
415
416 41827
        Lck_Lock(vdire->mtx);
417 41827
        while (! VTAILQ_EMPTY(&vdire->resigning))
418 0
                (void)Lck_CondWait(&vdire->cond, vdire->mtx);
419 41827
        vdire->iterating++;
420 41827
        Lck_Unlock(vdire->mtx);
421 41827
}
422
423
void
424 91292
vdire_end_iter(struct vdire *vdire)
425
{
426 91292
        struct vcldir_head resigning = VTAILQ_HEAD_INITIALIZER(resigning);
427 91292
        const struct vcltemp *temp = NULL;
428
        struct vcldir *vdir, *next;
429
        unsigned n;
430
431 91292
        CHECK_OBJ_NOTNULL(vdire, VDIRE_MAGIC);
432
433 91292
        Lck_Lock(vdire->mtx);
434 91292
        AN(vdire->iterating);
435 91292
        n = --vdire->iterating;
436
437 91292
        if (n == 0) {
438 91292
                VTAILQ_SWAP(&vdire->resigning, &resigning, vcldir, resigning_list);
439 91292
                VTAILQ_FOREACH(vdir, &resigning, resigning_list)
440 0
                        VTAILQ_REMOVE(&vdire->directors, vdir, directors_list);
441 91292
                temp = *vdire->tempp;
442 91292
                PTOK(pthread_cond_broadcast(&vdire->cond));
443 91292
        }
444 91292
        Lck_Unlock(vdire->mtx);
445
446 91292
        VTAILQ_FOREACH_SAFE(vdir, &resigning, resigning_list, next)
447 0
                vcldir_retire(vdir, temp);
448 91292
}
449
450
/*
451
 * like vdire_start_iter, but also prepare for backend_event_*()
452
 * by setting the checkpoint
453
 */
454
static void
455 49465
vdire_start_event(struct vdire *vdire, const struct vcltemp *temp)
456
{
457
458 49465
        CHECK_OBJ_NOTNULL(vdire, VDIRE_MAGIC);
459 49465
        AN(temp);
460
461 49465
        Lck_AssertHeld(vdire->mtx);
462
463
        // https://github.com/varnishcache/varnish-cache/pull/4142#issuecomment-2593091097
464 49465
        ASSERT_CLI();
465
466 49465
        AZ(vdire->checkpoint);
467 49465
        vdire->checkpoint = VTAILQ_LAST(&vdire->directors, vcldir_head);
468 49465
        AN(vdire->tempp);
469 49465
        *vdire->tempp = temp;
470 49465
        vdire->iterating++;
471 49465
}
472
473
static void
474 49465
vdire_end_event(struct vdire *vdire)
475
{
476 49465
        vdire->checkpoint = NULL;
477 49465
        vdire_end_iter(vdire);
478 49465
}
479
480
// if there are no iterators, remove from directors and retire
481
// otherwise put on resigning list to work when iterators end
482
void
483 4345
vdire_resign(struct vdire *vdire, struct vcldir *vdir)
484
{
485 4345
        const struct vcltemp *temp = NULL;
486
487 4345
        CHECK_OBJ_NOTNULL(vdire, VDIRE_MAGIC);
488 4345
        AN(vdir);
489
490 4345
        Lck_Lock(vdire->mtx);
491 4345
        if (vdire->iterating != 0) {
492 0
                VTAILQ_INSERT_TAIL(&vdire->resigning, vdir, resigning_list);
493 0
                vdir = NULL;
494 0
        } else {
495 4345
                VTAILQ_REMOVE(&vdire->directors, vdir, directors_list);
496 4345
                temp = *vdire->tempp;
497
        }
498 4345
        Lck_Unlock(vdire->mtx);
499
500 4345
        if (vdir != NULL)
501 4345
                vcldir_retire(vdir, temp);
502 4345
}
503
504
// unlocked version of vcl_iterdir
505
// pat can also be NULL (to iterate all)
506
static int
507 38680
vdire_iter(struct cli *cli, const char *pat, const struct vcl *vcl,
508
    vcl_be_func *func, void *priv)
509
{
510 38680
        int i, found = 0;
511
        struct vcldir *vdir;
512 38680
        struct vdire *vdire = vcl->vdire;
513
514 38680
        vdire_start_iter(vdire);
515 94800
        VTAILQ_FOREACH(vdir, &vdire->directors, directors_list) {
516 56120
                CHECK_OBJ(vdir, VCLDIR_MAGIC);
517 56120
                if (vdir->refcnt == 0)
518 0
                        continue;
519 56120
                if (pat != NULL && fnmatch(pat, vdir->cli_name, 0))
520 3720
                        continue;
521 52400
                found++;
522 52400
                i = func(cli, vdir->dir, priv);
523 52400
                if (i < 0) {
524 0
                        found = i;
525 0
                        break;
526
                }
527 52400
                found += i;
528 52400
        }
529 38680
        vdire_end_iter(vdire);
530 38680
        return (found);
531
}
532
533
534
/*--------------------------------------------------------------------*/
535
536
// XXX locked case across VCLs - should do without
537
static int
538 280
vcl_iterdir(struct cli *cli, const char *pat, const struct vcl *vcl,
539
    vcl_be_func *func, void *priv)
540
{
541 280
        int i, found = 0;
542
        struct vcldir *vdir;
543
544 280
        AN(vcl->vdire); // no labels
545
546 280
        Lck_AssertHeld(&vcl_mtx);
547 680
        VTAILQ_FOREACH(vdir, &vcl->vdire->directors, directors_list) {
548 400
                CHECK_OBJ(vdir, VCLDIR_MAGIC);
549 400
                if (fnmatch(pat, vdir->cli_name, 0))
550 160
                        continue;
551 240
                found++;
552 240
                i = func(cli, vdir->dir, priv);
553 240
                if (i < 0)
554 0
                        return (i);
555 240
                found += i;
556 240
        }
557 280
        return (found);
558 280
}
559
560
int
561 38960
VCL_IterDirector(struct cli *cli, const char *pat,
562
    vcl_be_func *func, void *priv)
563
{
564 38960
        int i, found = 0;
565
        struct vsb *vsb;
566
        struct vcl *vcl;
567
568 38960
        ASSERT_CLI();
569 38960
        ASSERT_VCL_ACTIVE();
570 38960
        vsb = VSB_new_auto();
571 38960
        AN(vsb);
572 38960
        if (pat == NULL || *pat == '\0' || !strcmp(pat, "*")) {
573
                // all backends in active VCL
574 37160
                VSB_printf(vsb, "%s.*", VCL_Name(vcl_active));
575 37160
                vcl = vcl_active;
576 38960
        } else if (strchr(pat, '.') == NULL) {
577
                // pattern applies to active vcl
578 1520
                VSB_printf(vsb, "%s.%s", VCL_Name(vcl_active), pat);
579 1520
                vcl = vcl_active;
580 1520
        } else {
581
                // use pattern as is
582 280
                VSB_cat(vsb, pat);
583 280
                vcl = NULL;
584
        }
585 38960
        AZ(VSB_finish(vsb));
586 38960
        if (vcl != NULL) {
587 38680
                found = vdire_iter(cli, VSB_data(vsb), vcl, func, priv);
588 38680
        } else {
589 280
                Lck_Lock(&vcl_mtx);
590 600
                VTAILQ_FOREACH(vcl, &vcl_head, list) {
591
                        // skip labels
592 320
                        if (! vcl->vdire)
593 40
                                continue;
594 280
                        i = vcl_iterdir(cli, VSB_data(vsb), vcl, func, priv);
595 280
                        if (i < 0) {
596 0
                                found = i;
597 0
                                break;
598
                        } else {
599 280
                                found += i;
600
                        }
601 280
                }
602 280
                Lck_Unlock(&vcl_mtx);
603
        }
604 38960
        VSB_destroy(&vsb);
605 38960
        return (found);
606
}
607
608
/*
609
 * vdire_start_event() must have been called before
610
 *
611
 * send event to directors pre checkpoint
612
 */
613
static void
614 49345
backend_event_base(const struct vcl *vcl, enum vcl_event_e e)
615
{
616
        struct vcldir *vdir;
617
        struct vdire *vdire;
618
619 49345
        ASSERT_CLI();
620 49345
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
621 49345
        AZ(vcl->busy);
622 49345
        vdire = vcl->vdire;
623 49345
        AN(vdire->iterating);
624
625 49345
        vdir = vdire->checkpoint;
626 49345
        if (vdir == NULL)
627 5440
                return;
628
629 43905
        CHECK_OBJ(vdir, VCLDIR_MAGIC);
630 102248
        VTAILQ_FOREACH_REVERSE_FROM(vdir, &vdire->directors,
631
            vcldir_head, directors_list) {
632 58343
                CHECK_OBJ(vdir, VCLDIR_MAGIC);
633 58343
                VDI_Event(vdir->dir, e);
634 58343
        }
635 49345
}
636
637
/*
638
 * vdire_start_event() must have been called before
639
 *
640
 * set a new temperature.
641
 * send event to directors added post checkpoint, but before
642
 * the new temperature
643
 */
644
static void
645 120
backend_event_delta(const struct vcl *vcl, enum vcl_event_e e, const struct vcltemp *temp)
646
{
647
        struct vcldir *vdir, *end;
648
        struct vdire *vdire;
649
650 120
        ASSERT_CLI();
651 120
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
652 120
        AZ(vcl->busy);
653 120
        vdire = vcl->vdire;
654 120
        AN(temp);
655 120
        AN(vdire->iterating);
656
657 120
        Lck_Lock(vdire->mtx);
658 120
        if (vdire->checkpoint == NULL)
659 0
                vdir = VTAILQ_FIRST(&vdire->directors);
660
        else
661 120
                vdir = VTAILQ_NEXT(vdire->checkpoint, directors_list);
662 120
        AN(vdire->tempp);
663 120
        *vdire->tempp = temp;
664 120
        end = VTAILQ_LAST(&vdire->directors, vcldir_head);
665 120
        Lck_Unlock(vdire->mtx);
666
667 120
        while (vdir != NULL) {
668 0
                CHECK_OBJ(vdir, VCLDIR_MAGIC);
669 0
                VDI_Event(vdir->dir, e);
670 0
                if (vdir == end)
671 0
                        break;
672 0
                vdir = VTAILQ_NEXT(vdir, directors_list);
673
        }
674 120
}
675
676
static void
677 3107
vcl_KillBackends(const struct vcl *vcl)
678
{
679
        struct vcldir *vdir, *vdir2;
680
        struct vdire *vdire;
681
682 3107
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
683 3107
        assert(vcl->temp == VCL_TEMP_COLD || vcl->temp == VCL_TEMP_INIT);
684 3107
        vdire = vcl->vdire;
685 3107
        CHECK_OBJ_NOTNULL(vdire, VDIRE_MAGIC);
686
687
        /*
688
         * ensure all retirement has finished (vdire_start_iter waits for it)
689
         */
690 3107
        vdire_start_iter(vdire);
691 3107
        vdire_end_iter(vdire);
692 3107
        AZ(vdire->iterating);
693 3107
        assert(VTAILQ_EMPTY(&vdire->resigning));
694
695
        /*
696
         * Unlocked and sidelining vdire because no further directors can be added, and the
697
         * remaining ones need to be able to remove themselves.
698
         */
699 5774
        VTAILQ_FOREACH_SAFE(vdir, &vdire->directors, directors_list, vdir2) {
700 2667
                CHECK_OBJ(vdir, VCLDIR_MAGIC);
701 2667
                VDI_Event(vdir->dir, VCL_EVENT_DISCARD);
702 2667
        }
703 3107
        assert(VTAILQ_EMPTY(&vdire->directors));
704 3107
}
705
706
/*--------------------------------------------------------------------*/
707
708
static struct vcl *
709 98800
VCL_Open(const char *fn, struct vsb *msg)
710
{
711
        struct vcl *vcl;
712
        void *dlh;
713
        struct VCL_conf const *cnf;
714
        const char *dlerr;
715
        int err;
716
717 98800
        AN(fn);
718 98800
        AN(msg);
719
720
#ifdef RTLD_NOLOAD
721
        /* Detect bogus caching by dlopen(3) */
722 98800
        dlh = dlopen(fn, RTLD_NOW | RTLD_NOLOAD);
723 98800
        AZ(dlh);
724
#endif
725 98800
        dlh = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
726 98800
        if (dlh == NULL) {
727 40
                err = errno;
728 40
                dlerr = dlerror();
729 40
                VSB_cat(msg, "Could not load compiled VCL.\n");
730 40
                if (dlerr != NULL)
731 40
                        VSB_printf(msg, "\tdlopen() = %s\n", dlerr);
732 40
                if (err) {
733 0
                        VSB_printf(msg, "\terror = %s (%d)\n",
734 0
                            strerror(err), err);
735 0
                }
736 40
                VSB_cat(msg, "\thint: check for \"noexec\" mount\n");
737 40
                VSB_cat(msg, "\thint: check \"vmod_path\" parameter\n");
738 40
                return (NULL);
739
        }
740 98760
        cnf = dlsym(dlh, "VCL_conf");
741 98760
        if (cnf == NULL) {
742 0
                VSB_cat(msg, "Compiled VCL lacks metadata.\n");
743 0
                (void)dlclose(dlh);
744 0
                return (NULL);
745
        }
746 98760
        if (cnf->magic != VCL_CONF_MAGIC) {
747 0
                VSB_cat(msg, "Compiled VCL has mangled metadata.\n");
748 0
                (void)dlclose(dlh);
749 0
                return (NULL);
750
        }
751 98760
        if (cnf->syntax < heritage.min_vcl_version ||
752 98720
            cnf->syntax > heritage.max_vcl_version) {
753 80
                VSB_printf(msg, "Compiled VCL version (%.1f) not supported.\n",
754 40
                    .1 * cnf->syntax);
755 40
                (void)dlclose(dlh);
756 40
                return (NULL);
757
        }
758 98720
        ALLOC_OBJ(vcl, VCL_MAGIC);
759 98720
        AN(vcl);
760 98720
        vcl->dlh = dlh;
761 98720
        vcl->conf = cnf;
762 98720
        vcl->vdire = vdire_new(&vcl_mtx, &vcl->temp);
763 98720
        return (vcl);
764 98800
}
765
766
static void
767 52547
VCL_Close(struct vcl **vclp)
768
{
769
        struct vcl *vcl;
770
771 52547
        TAKE_OBJ_NOTNULL(vcl, vclp, VCL_MAGIC);
772 52547
        assert(VTAILQ_EMPTY(&vcl->filters));
773 52547
        AZ(dlclose(vcl->dlh));
774 52547
        PTOK(pthread_cond_destroy(&vcl->vdire->cond));
775 52547
        FREE_OBJ(vcl->vdire);
776 52547
        FREE_OBJ(vcl);
777 52547
}
778
779
/*--------------------------------------------------------------------
780
 * NB: This function is called in/from the test-load subprocess.
781
 */
782
783
int
784 49520
VCL_TestLoad(const char *fn)
785
{
786
        struct vsb *vsb;
787
        struct vcl *vcl;
788 49520
        int retval = 0;
789
790 49520
        AN(fn);
791 49520
        vsb = VSB_new_auto();
792 49520
        AN(vsb);
793 49520
        vcl = VCL_Open(fn, vsb);
794 49520
        if (vcl == NULL) {
795 80
                AZ(VSB_finish(vsb));
796 80
                fprintf(stderr, "%s", VSB_data(vsb));
797 80
                retval = -1;
798 80
        } else
799 49440
                VCL_Close(&vcl);
800 49520
        VSB_destroy(&vsb);
801 49520
        return (retval);
802
}
803
804
/*--------------------------------------------------------------------*/
805
806
static struct vsb *
807 40
vcl_print_refs(const struct vcl *vcl)
808
{
809
        struct vsb *msg;
810
        struct vclref *ref;
811
812 40
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
813 40
        msg = VSB_new_auto();
814 40
        AN(msg);
815
816 40
        VSB_printf(msg, "VCL %s is waiting for:", vcl->loaded_name);
817 40
        Lck_Lock(&vcl_mtx);
818 80
        VTAILQ_FOREACH(ref, &vcl->ref_list, list)
819 40
                VSB_printf(msg, "\n\t- %s", ref->desc);
820 40
        Lck_Unlock(&vcl_mtx);
821 40
        AZ(VSB_finish(msg));
822 40
        return (msg);
823
}
824
825
static int
826 51560
vcl_set_state(struct vcl *vcl, const char *state, struct vsb **msg)
827
{
828 51560
        struct vsb *nomsg = NULL;
829 51560
        int i = 0;
830
831 51560
        ASSERT_CLI();
832
833 51560
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
834 51560
        AN(state);
835 51560
        AN(msg);
836 51560
        AZ(*msg);
837
838 51560
        AN(vcl->temp);
839
840 51560
        switch (state[0]) {
841
        case '0':
842 3760
                if (vcl->temp == VCL_TEMP_COLD)
843 80
                        break;
844 3680
                if (vcl->busy == 0 && vcl->temp->is_warm) {
845 1745
                        Lck_Lock(&vcl_mtx);
846 1745
                        vdire_start_event(vcl->vdire, VTAILQ_EMPTY(&vcl->ref_list) ?
847
                            VCL_TEMP_COLD : VCL_TEMP_COOLING);
848 1745
                        Lck_Unlock(&vcl_mtx);
849 1745
                        backend_event_base(vcl, VCL_EVENT_COLD);
850 1745
                        vdire_end_event(vcl->vdire);
851
                        // delta directors at VCL_TEMP_COLD do not need an event
852 1745
                        AZ(vcl_send_event(vcl, VCL_EVENT_COLD, msg));
853 1745
                        AZ(*msg);
854 1745
                }
855 1935
                else if (vcl->busy)
856 1057
                        vcl->temp = VCL_TEMP_BUSY;
857 878
                else if (VTAILQ_EMPTY(&vcl->ref_list))
858 718
                        vcl->temp = VCL_TEMP_COLD;
859
                else
860 160
                        vcl->temp = VCL_TEMP_COOLING;
861 3680
                break;
862
        case '1':
863 47800
                if (vcl->temp == VCL_TEMP_WARM)
864 40
                        break;
865
                /* The warm VCL hasn't seen a cold event yet */
866 47760
                if (vcl->temp == VCL_TEMP_BUSY)
867 40
                        vcl->temp = VCL_TEMP_WARM;
868
                /* The VCL must first reach a stable cold state */
869 47720
                else if (vcl->temp == VCL_TEMP_COOLING) {
870 40
                        *msg = vcl_print_refs(vcl);
871 40
                        i = -1;
872 40
                }
873
                else {
874 47680
                        Lck_Lock(&vcl_mtx);
875 47680
                        vdire_start_event(vcl->vdire, VCL_TEMP_WARM);
876 47680
                        Lck_Unlock(&vcl_mtx);
877 47680
                        i = vcl_send_event(vcl, VCL_EVENT_WARM, msg);
878 47680
                        if (i == 0) {
879 47560
                                backend_event_base(vcl, VCL_EVENT_WARM);
880
                                // delta directors are already warm
881 47560
                                vdire_end_event(vcl->vdire);
882 47560
                                break;
883
                        }
884 120
                        AZ(vcl_send_event(vcl, VCL_EVENT_COLD, &nomsg));
885 120
                        AZ(nomsg);
886 120
                        backend_event_delta(vcl, VCL_EVENT_COLD, VCL_TEMP_COLD);
887 120
                        vdire_end_event(vcl->vdire);
888
                }
889 200
                break;
890
        default:
891 0
                WRONG("Wrong enum state");
892 0
        }
893 51560
        if (i == 0 && state[1])
894 49720
                bprintf(vcl->state, "%s", state + 1);
895
896 51560
        return (i);
897
}
898
899
static void
900 1720
vcl_cancel_load(struct vcl *vcl, struct cli *cli, struct vsb *msg,
901
    const char *name, const char *step)
902
{
903
904 1720
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
905 1720
        CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);
906
907 1720
        VCLI_SetResult(cli, CLIS_CANT);
908 1720
        VCLI_Out(cli, "VCL \"%s\" Failed %s", name, step);
909 1720
        if (VSB_len(msg))
910 1720
                VCLI_Out(cli, "\nMessage:\n\t%s", VSB_data(msg));
911 1720
        VSB_destroy(&msg);
912
913 1720
        AZ(vcl_send_event(vcl, VCL_EVENT_DISCARD, &msg));
914 1720
        AZ(msg);
915
916 1720
        vcl_KillBackends(vcl);
917 1720
        free(vcl->loaded_name);
918 1720
        VCL_Close(&vcl);
919 1720
}
920
921
static void
922 49280
vcl_load(struct cli *cli,
923
    const char *name, const char *fn, const char *state)
924
{
925
        struct vcl *vcl;
926
        struct vsb *msg;
927
928 49280
        ASSERT_CLI();
929 49280
        ASSERT_VCL_ACTIVE();
930
931 49280
        vcl = vcl_find(name);
932 49280
        AZ(vcl);
933
934 49280
        msg = VSB_new_auto();
935 49280
        AN(msg);
936 49280
        vcl = VCL_Open(fn, msg);
937 49280
        AZ(VSB_finish(msg));
938 49280
        if (vcl == NULL) {
939 0
                VCLI_SetResult(cli, CLIS_PARAM);
940 0
                VCLI_Out(cli, "%s", VSB_data(msg));
941 0
                VSB_destroy(&msg);
942 0
                return;
943
        }
944
945 49280
        VSB_destroy(&msg);
946
947 49280
        vcl->loaded_name = strdup(name);
948 49280
        XXXAN(vcl->loaded_name);
949 49280
        VTAILQ_INIT(&vcl->ref_list);
950 49280
        VTAILQ_INIT(&vcl->filters);
951
952 49280
        vcl->temp = VCL_TEMP_INIT;
953
954 49280
        if (vcl_send_event(vcl, VCL_EVENT_LOAD, &msg)) {
955 1680
                vcl_cancel_load(vcl, cli, msg, name, "initialization");
956 1680
                return;
957
        }
958 47600
        VSB_destroy(&msg);
959
960 47600
        if (vcl_set_state(vcl, state, &msg)) {
961 40
                assert(*state == '1');
962 40
                vcl_cancel_load(vcl, cli, msg, name, "warmup");
963 40
                return;
964
        }
965 47560
        if (msg)
966 47400
                VSB_destroy(&msg);
967
968 47560
        VCLI_Out(cli, "Loaded \"%s\" as \"%s\"", fn , name);
969 47560
        VTAILQ_INSERT_TAIL(&vcl_head, vcl, list);
970 47560
        VSC_C_main->n_vcl++;
971 47560
        VSC_C_main->n_vcl_avail++;
972 49280
}
973
974
/*--------------------------------------------------------------------*/
975
976
void
977 310291
VCL_Poll(void)
978
{
979 310291
        struct vsb *nomsg = NULL;
980
        struct vcl *vcl, *vcl2;
981
982 310291
        ASSERT_CLI();
983 310291
        ASSERT_VCL_ACTIVE();
984 653515
        VTAILQ_FOREACH_SAFE(vcl, &vcl_head, list, vcl2) {
985 343224
                if (vcl->temp == VCL_TEMP_BUSY ||
986 342262
                    vcl->temp == VCL_TEMP_COOLING)
987 1680
                        AZ(vcl_set_state(vcl, "0", &nomsg));
988 343224
                AZ(nomsg);
989 343224
                if (vcl->discard && vcl->temp == VCL_TEMP_COLD) {
990 1387
                        AZ(vcl->busy);
991 1387
                        assert(vcl != vcl_active);
992 1387
                        assert(VTAILQ_EMPTY(&vcl->ref_list));
993 1387
                        VTAILQ_REMOVE(&vcl_head, vcl, list);
994 1387
                        AZ(vcl_send_event(vcl, VCL_EVENT_DISCARD, &nomsg));
995 1387
                        AZ(nomsg);
996 1387
                        vcl_KillBackends(vcl);
997 1387
                        free(vcl->loaded_name);
998 1387
                        VCL_Close(&vcl);
999 1387
                        VSC_C_main->n_vcl--;
1000 1387
                        VSC_C_main->n_vcl_discard--;
1001 1387
                }
1002 343224
        }
1003 310291
}
1004
1005
/*--------------------------------------------------------------------*/
1006
1007
static void v_matchproto_(cli_func_t)
1008 3000
vcl_cli_list(struct cli *cli, const char * const *av, void *priv)
1009
{
1010
        struct vcl *vcl;
1011
        const char *flg;
1012
        struct vte *vte;
1013
1014
        /* NB: Shall generate same output as mcf_vcl_list() */
1015
1016 3000
        (void)av;
1017 3000
        (void)priv;
1018 3000
        ASSERT_CLI();
1019 3000
        ASSERT_VCL_ACTIVE();
1020 3000
        vte = VTE_new(7, 80);
1021 3000
        AN(vte);
1022 9579
        VTAILQ_FOREACH(vcl, &vcl_head, list) {
1023 6579
                if (vcl == vcl_active) {
1024 3000
                        flg = "active";
1025 6579
                } else if (vcl->discard) {
1026 139
                        flg = "discarded";
1027 139
                } else
1028 3440
                        flg = "available";
1029 13158
                VTE_printf(vte, "%s\t%s\t%s\t\v%u\t%s", flg, vcl->state,
1030 6579
                    vcl->temp->name, vcl->busy, vcl->loaded_name);
1031 6579
                if (vcl->label != NULL) {
1032 760
                        VTE_printf(vte, "\t->\t%s", vcl->label->loaded_name);
1033 760
                        if (vcl->nrefs)
1034 320
                                VTE_printf(vte, " (%d return(vcl)%s)",
1035 160
                                    vcl->nrefs, vcl->nrefs > 1 ? "'s" : "");
1036 6579
                } else if (vcl->nlabels > 0) {
1037 1040
                        VTE_printf(vte, "\t<-\t(%d label%s)",
1038 520
                            vcl->nlabels, vcl->nlabels > 1 ? "s" : "");
1039 520
                }
1040 6579
                VTE_cat(vte, "\n");
1041 6579
        }
1042 3000
        AZ(VTE_finish(vte));
1043 3000
        AZ(VTE_format(vte, VCLI_VTE_format, cli));
1044 3000
        VTE_destroy(&vte);
1045 3000
}
1046
1047
static void v_matchproto_(cli_func_t)
1048 200
vcl_cli_list_json(struct cli *cli, const char * const *av, void *priv)
1049
{
1050
        struct vcl *vcl;
1051
1052 200
        (void)priv;
1053 200
        ASSERT_CLI();
1054 200
        ASSERT_VCL_ACTIVE();
1055 200
        VCLI_JSON_begin(cli, 2, av);
1056 200
        VCLI_Out(cli, ",\n");
1057 840
        VTAILQ_FOREACH(vcl, &vcl_head, list) {
1058 640
                VCLI_Out(cli, "{\n");
1059 640
                VSB_indent(cli->sb, 2);
1060 640
                VCLI_Out(cli, "\"status\": ");
1061 640
                if (vcl == vcl_active) {
1062 200
                        VCLI_Out(cli, "\"active\",\n");
1063 640
                } else if (vcl->discard) {
1064 0
                        VCLI_Out(cli, "\"discarded\",\n");
1065 0
                } else
1066 440
                        VCLI_Out(cli, "\"available\",\n");
1067 640
                VCLI_Out(cli, "\"state\": \"%s\",\n", vcl->state);
1068 640
                VCLI_Out(cli, "\"temperature\": \"%s\",\n", vcl->temp->name);
1069 640
                VCLI_Out(cli, "\"busy\": %u,\n", vcl->busy);
1070 640
                VCLI_Out(cli, "\"name\": \"%s\"", vcl->loaded_name);
1071 640
                if (vcl->label != NULL) {
1072 240
                        VCLI_Out(cli, ",\n");
1073 240
                        VCLI_Out(cli, "\"label\": {\n");
1074 240
                        VSB_indent(cli->sb, 2);
1075 480
                                VCLI_Out(cli, "\"name\": \"%s\"",
1076 240
                                         vcl->label->loaded_name);
1077 240
                        if (vcl->nrefs)
1078 0
                                VCLI_Out(cli, ",\n\"refs\": %d", vcl->nrefs);
1079 240
                        VCLI_Out(cli, "\n");
1080 240
                        VCLI_Out(cli, "}");
1081 240
                        VSB_indent(cli->sb, -2);
1082 640
                } else if (vcl->nlabels > 0) {
1083 80
                        VCLI_Out(cli, ",\n");
1084 80
                        VCLI_Out(cli, "\"labels\": %d", vcl->nlabels);
1085 80
                }
1086 640
                VSB_indent(cli->sb, -2);
1087 640
                VCLI_Out(cli, "\n}");
1088 640
                if (VTAILQ_NEXT(vcl, list) != NULL)
1089 440
                        VCLI_Out(cli, ",\n");
1090 640
        }
1091 200
        VCLI_JSON_end(cli);
1092 200
}
1093
1094
static void v_matchproto_(cli_func_t)
1095 49280
vcl_cli_load(struct cli *cli, const char * const *av, void *priv)
1096
{
1097
1098 49280
        AZ(priv);
1099 49280
        ASSERT_CLI();
1100
        // XXX move back code from vcl_load?
1101 49280
        vcl_load(cli, av[2], av[3], av[4]);
1102 49280
}
1103
1104
static void v_matchproto_(cli_func_t)
1105 2320
vcl_cli_state(struct cli *cli, const char * const *av, void *priv)
1106
{
1107
        struct vcl *vcl;
1108 2320
        struct vsb *msg = NULL;
1109
1110 2320
        AZ(priv);
1111 2320
        ASSERT_CLI();
1112 2320
        ASSERT_VCL_ACTIVE();
1113 2320
        AN(av[2]);
1114 2320
        AN(av[3]);
1115
1116 2320
        vcl = vcl_find(av[2]);
1117 2320
        AN(vcl);
1118
1119 2320
        if (vcl_set_state(vcl, av[3], &msg)) {
1120 120
                CHECK_OBJ_NOTNULL(msg, VSB_MAGIC);
1121
1122 120
                VCLI_SetResult(cli, CLIS_CANT);
1123 240
                VCLI_Out(cli, "Failed <vcl.state %s %s>", vcl->loaded_name,
1124 120
                    av[3] + 1);
1125 120
                if (VSB_len(msg))
1126 120
                        VCLI_Out(cli, "\nMessage:\n\t%s", VSB_data(msg));
1127 120
        }
1128 2320
        if (msg)
1129 280
                VSB_destroy(&msg);
1130 2320
}
1131
1132
static void v_matchproto_(cli_func_t)
1133 1560
vcl_cli_discard(struct cli *cli, const char * const *av, void *priv)
1134
{
1135
        struct vcl *vcl;
1136
1137 1560
        ASSERT_CLI();
1138 1560
        ASSERT_VCL_ACTIVE();
1139 1560
        (void)cli;
1140 1560
        AZ(priv);
1141 1560
        vcl = vcl_find(av[2]);
1142 1560
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);              // MGT ensures this
1143 1560
        Lck_Lock(&vcl_mtx);
1144 1560
        assert (vcl != vcl_active);     // MGT ensures this
1145 1560
        AZ(vcl->nlabels);               // MGT ensures this
1146 1560
        VSC_C_main->n_vcl_discard++;
1147 1560
        VSC_C_main->n_vcl_avail--;
1148 1560
        vcl->discard = 1;
1149 1560
        if (vcl->label != NULL) {
1150 160
                AZ(strcmp(vcl->state, VCL_TEMP_LABEL->name));
1151 160
                vcl->label->nlabels--;
1152 160
                vcl->label= NULL;
1153 160
        }
1154 1560
        Lck_Unlock(&vcl_mtx);
1155
1156 1560
        if (!strcmp(vcl->state, VCL_TEMP_LABEL->name)) {
1157 160
                VTAILQ_REMOVE(&vcl_head, vcl, list);
1158 160
                free(vcl->loaded_name);
1159 160
                AZ(vcl->vdire);
1160 160
                FREE_OBJ(vcl);
1161 1560
        } else if (vcl->temp == VCL_TEMP_COLD) {
1162 1072
                VCL_Poll();
1163 1072
        }
1164 1560
}
1165
1166
static void v_matchproto_(cli_func_t)
1167 1080
vcl_cli_label(struct cli *cli, const char * const *av, void *priv)
1168
{
1169
        struct vcl *lbl;
1170
        struct vcl *vcl;
1171
1172 1080
        ASSERT_CLI();
1173 1080
        ASSERT_VCL_ACTIVE();
1174 1080
        (void)cli;
1175 1080
        (void)priv;
1176 1080
        vcl = vcl_find(av[3]);
1177 1080
        AN(vcl);                                // MGT ensures this
1178 1080
        lbl = vcl_find(av[2]);
1179 1080
        if (lbl == NULL) {
1180 960
                ALLOC_OBJ(lbl, VCL_MAGIC);
1181 960
                AN(lbl);
1182 960
                bprintf(lbl->state, "%s", VCL_TEMP_LABEL->name);
1183 960
                lbl->temp = VCL_TEMP_WARM;
1184 960
                REPLACE(lbl->loaded_name, av[2]);
1185 960
                VTAILQ_INSERT_TAIL(&vcl_head, lbl, list);
1186 960
        }
1187 1080
        if (lbl->label != NULL)
1188 120
                lbl->label->nlabels--;
1189 1080
        lbl->label = vcl;
1190 1080
        vcl->nlabels++;
1191 1080
}
1192
1193
static void v_matchproto_(cli_func_t)
1194 45800
vcl_cli_use(struct cli *cli, const char * const *av, void *priv)
1195
{
1196
        struct vcl *vcl;
1197
1198 45800
        ASSERT_CLI();
1199 45800
        ASSERT_VCL_ACTIVE();
1200 45800
        AN(cli);
1201 45800
        AZ(priv);
1202 45800
        vcl = vcl_find(av[2]);
1203 45800
        AN(vcl);                                // MGT ensures this
1204 45800
        assert(vcl->temp == VCL_TEMP_WARM);     // MGT ensures this
1205 45800
        Lck_Lock(&vcl_mtx);
1206 45800
        vcl_active = vcl;
1207 45800
        Lck_Unlock(&vcl_mtx);
1208 45800
}
1209
1210
static void v_matchproto_(cli_func_t)
1211 480
vcl_cli_show(struct cli *cli, const char * const *av, void *priv)
1212
{
1213
        struct vcl *vcl;
1214 480
        int verbose = 0;
1215 480
        int i = 2;
1216
        unsigned u;
1217
1218 480
        ASSERT_CLI();
1219 480
        ASSERT_VCL_ACTIVE();
1220 480
        AZ(priv);
1221
1222 480
        if (av[i] != NULL && !strcmp(av[i], "-v")) {
1223 160
                verbose = 1;
1224 160
                i++;
1225 160
        }
1226
1227 480
        if (av[i] == NULL) {
1228 80
                vcl = vcl_active;
1229 80
                AN(vcl);
1230 80
        } else {
1231 400
                vcl = vcl_find(av[i]);
1232 400
                i++;
1233
        }
1234
1235 480
        if (av[i] != NULL) {
1236 40
                VCLI_Out(cli, "Too many parameters: '%s'", av[i]);
1237 40
                VCLI_SetResult(cli, CLIS_PARAM);
1238 40
                return;
1239
        }
1240
1241 440
        if (vcl == NULL) {
1242 40
                VCLI_Out(cli, "No VCL named '%s'", av[i - 1]);
1243 40
                VCLI_SetResult(cli, CLIS_PARAM);
1244 40
                return;
1245
        }
1246 400
        CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
1247 400
        if (vcl->label) {
1248 80
                vcl = vcl->label;
1249 80
                CHECK_OBJ_NOTNULL(vcl, VCL_MAGIC);
1250 80
                AZ(vcl->label);
1251 80
        }
1252 400
        CHECK_OBJ_NOTNULL(vcl->conf, VCL_CONF_MAGIC);
1253 400
        if (verbose) {
1254 480
                for (u = 0; u < vcl->conf->nsrc; u++)
1255 640
                        VCLI_Out(cli, "// VCL.SHOW %u %zd %s\n%s\n",
1256 320
                            u, strlen(vcl->conf->srcbody[u]),
1257 320
                            vcl->conf->srcname[u],
1258 320
                            vcl->conf->srcbody[u]);
1259 160
        } else {
1260 240
                VCLI_Out(cli, "%s", vcl->conf->srcbody[0]);
1261
        }
1262 480
}
1263
1264
/*--------------------------------------------------------------------*/
1265
1266
static struct cli_proto vcl_cmds[] = {
1267
        { CLICMD_VCL_LOAD,              "", vcl_cli_load },
1268
        { CLICMD_VCL_LIST,              "", vcl_cli_list, vcl_cli_list_json },
1269
        { CLICMD_VCL_STATE,             "", vcl_cli_state },
1270
        { CLICMD_VCL_DISCARD,           "", vcl_cli_discard },
1271
        { CLICMD_VCL_USE,               "", vcl_cli_use },
1272
        { CLICMD_VCL_SHOW,              "", vcl_cli_show },
1273
        { CLICMD_VCL_LABEL,             "", vcl_cli_label },
1274
        { NULL }
1275
};
1276
1277
void
1278 37949
VCL_Init(void)
1279
{
1280
1281 37949
        assert(cache_param->workspace_client > 0);
1282 75898
        WS_Init(&ws_cli, "cli", malloc(cache_param->workspace_client),
1283 37949
            cache_param->workspace_client);
1284 37949
        ws_snapshot_cli = WS_Snapshot(&ws_cli);
1285 37949
        CLI_AddFuncs(vcl_cmds);
1286 37949
        Lck_New(&vcl_mtx, lck_vcl);
1287 37949
        VSL_Setup(&vsl_cli, NULL, 0);
1288 37949
}
1289
1290
void
1291 37440
VCL_Shutdown(void)
1292
{
1293
        struct vcl *vcl;
1294 37440
        unsigned c = 0;
1295
1296 292828
        while (1) {
1297 292828
                Lck_Lock(&vcl_mtx);
1298 385160
                VTAILQ_FOREACH(vcl, &vcl_head, list)
1299 347720
                        if (vcl->busy)
1300 255388
                                break;
1301 292828
                Lck_Unlock(&vcl_mtx);
1302 292828
                if (vcl == NULL)
1303 37440
                        return;
1304 255388
                if (++c % 10 == 0) {
1305 766
                        fprintf(stderr, "shutdown waiting for %u reference%s "
1306 383
                            "on %s\n", vcl->busy, vcl->busy > 1 ? "s" : "",
1307 383
                            vcl->loaded_name);
1308 383
                }
1309 255388
                usleep(100 * 1000);
1310
        }
1311
}