varnish-cache/lib/libvarnishapi/vsc.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 * Author: Martin Blix Grydeland <martin@varnish-software.com>
7
 *
8
 * SPDX-License-Identifier: BSD-2-Clause
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 *
19
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29
 * SUCH DAMAGE.
30
 */
31
32
#include "config.h"
33
34
#include <sys/stat.h>
35
36
#include <fnmatch.h>
37
#include <stdint.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <unistd.h>
42
43
#include "vdef.h"
44
#include "vas.h"
45
#include "miniobj.h"
46
#include "vqueue.h"
47
#include "vjsn.h"
48
#include "vsb.h"
49
#include "vsc_priv.h"
50
#include "vmb.h"
51
52
#include "vapi/vsc.h"
53
#include "vapi/vsm.h"
54
55
struct vsc_sf_mode {
56
        const char              *name;
57
        unsigned                include;
58
        unsigned                fail;
59
        unsigned                append;
60
};
61
62
static const struct vsc_sf_mode VSC_SF_INCLUDE[1] = {{"include", 1, 1, 1}};
63
static const struct vsc_sf_mode VSC_SF_EXCLUDE[1] = {{"exclude", 0, 0, 1}};
64
static const struct vsc_sf_mode VSC_SF_REQUIRE[1] = {{"require", 1, 0, 0}};
65
66
struct vsc_sf {
67
        unsigned                        magic;
68
#define VSC_SF_MAGIC                    0x558478dd
69
        VTAILQ_ENTRY(vsc_sf)            list;
70
        char                            *pattern;
71
        const struct vsc_sf_mode        *mode;
72
};
73
74
VTAILQ_HEAD(vsc_sf_head, vsc_sf);
75
76
struct vsc_pt {
77
        struct VSC_point        point;
78
        char                    *name;
79
};
80
81
struct vsc_seg {
82
        unsigned                magic;
83
#define VSC_SEG_MAGIC           0x801177d4
84
        VTAILQ_ENTRY(vsc_seg)   list;
85
        struct vsm_fantom       fantom[1];
86
        struct vsc_head         *head;
87
        char                    *body;
88
89
        struct vjsn             *vj;
90
91
        unsigned                npoints;
92
        struct vsc_pt           *points;
93
        int                     exposed;
94
};
95
96
struct vsc {
97
        unsigned                magic;
98
#define VSC_MAGIC               0x3373554a
99
100
        unsigned                raw;
101
        struct vsc_sf_head      sf_list;
102
        VTAILQ_HEAD(,vsc_seg)   segs;
103
104
        VSC_new_f               *fnew;
105
        VSC_destroy_f           *fdestroy;
106
        void                    *priv;
107
};
108
109
/*--------------------------------------------------------------------
110
 * Build the static level, type and point descriptions
111
 */
112
113
enum vsc_levels {
114
#define VSC_LEVEL_F(v,l,e,d) v,
115
#include "tbl/vsc_levels.h"
116
};
117
118
static const struct VSC_level_desc levels[] = {
119
#define VSC_LEVEL_F(v,l,e,d) [v] = {#v, l, e, d},
120
#include "tbl/vsc_levels.h"
121
};
122
123
static const ssize_t nlevels = sizeof(levels)/sizeof(*levels);
124
125
/*--------------------------------------------------------------------*/
126
127
struct vsc *
128 37400
VSC_New(void)
129
{
130
        struct vsc *vsc;
131
132 37400
        ALLOC_OBJ(vsc, VSC_MAGIC);
133 37400
        if (vsc == NULL)
134 0
                return (vsc);
135 37400
        VTAILQ_INIT(&vsc->sf_list);
136 37400
        VTAILQ_INIT(&vsc->segs);
137 37400
        return (vsc);
138 37400
}
139
140
/*--------------------------------------------------------------------*/
141
142
static int
143 1440
vsc_sf_arg(struct vsc *vsc, const char *glob, const struct vsc_sf_mode *mode)
144
{
145
        struct vsc_sf *sf;
146
147 1440
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
148 1440
        AN(glob);
149 1440
        AN(mode);
150
151 1440
        ALLOC_OBJ(sf, VSC_SF_MAGIC);
152 1440
        AN(sf);
153 1440
        REPLACE(sf->pattern, glob);
154 1440
        sf->mode = mode;
155 1440
        AN(mode->name);
156 1440
        if (mode->append)
157 1120
                VTAILQ_INSERT_TAIL(&vsc->sf_list, sf, list);
158
        else
159 320
                VTAILQ_INSERT_HEAD(&vsc->sf_list, sf, list);
160 1440
        return (1);
161
}
162
163
static int
164 800
vsc_f_arg(struct vsc *vsc, const char *opt)
165
{
166
167 800
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
168 800
        AN(opt);
169
170 800
        if (opt[0] == '^')
171 200
                return (vsc_sf_arg(vsc, opt + 1, VSC_SF_EXCLUDE));
172 600
        return (vsc_sf_arg(vsc, opt, VSC_SF_INCLUDE));
173 800
}
174
175
/*--------------------------------------------------------------------*/
176
177
int
178 1440
VSC_Arg(struct vsc *vsc, char arg, const char *opt)
179
{
180
181 1440
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
182
183 1440
        switch (arg) {
184 280
        case 'I': return (vsc_sf_arg(vsc, opt, VSC_SF_INCLUDE));
185 40
        case 'X': return (vsc_sf_arg(vsc, opt, VSC_SF_EXCLUDE));
186 320
        case 'R': return (vsc_sf_arg(vsc, opt, VSC_SF_REQUIRE));
187 800
        case 'f': return (vsc_f_arg(vsc, opt));
188 0
        case 'r': vsc->raw = !vsc->raw; return (1);
189 0
        default: return (0);
190
        }
191 1440
}
192
193
unsigned
194 240
VSC_IsRaw(const struct vsc *vsc)
195
{
196
197 240
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
198 240
        return (vsc->raw);
199
}
200
201
/*--------------------------------------------------------------------
202
 */
203
204
static int
205 2152272
vsc_filter(const struct vsc *vsc, const char *nm)
206
{
207
        struct vsc_sf *sf;
208 2152272
        unsigned res = 0;
209
210 2152272
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
211 2576392
        VTAILQ_FOREACH(sf, &vsc->sf_list, list) {
212 432040
                if (!fnmatch(sf->pattern, nm, 0))
213 7920
                        return (!sf->mode->include);
214 424120
                res |= sf->mode->fail;
215 424120
        }
216 2144352
        return (res);
217 2152272
}
218
219
/*--------------------------------------------------------------------
220
 */
221
222
static void
223 1860672
vsc_clean_point(struct vsc_pt *point)
224
{
225 1860672
        REPLACE(point->name, NULL);
226 1860672
}
227
228
static void
229 2152272
vsc_fill_point(const struct vsc *vsc, const struct vsc_seg *seg,
230
    const struct vjsn_val *vv, struct vsb *vsb, struct vsc_pt *point)
231
{
232
        struct vjsn_val *vt;
233
234 2152272
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
235 2152272
        memset(point, 0, sizeof *point);
236
237 2152272
        vt = vjsn_child(vv, "name");
238 2152272
        AN(vt);
239 2152272
        assert(vjsn_is_string(vt));
240
241 2152272
        VSB_clear(vsb);
242 2152272
        VSB_printf(vsb, "%s.%s", seg->fantom->ident, vt->value);
243 2152272
        AZ(VSB_finish(vsb));
244
245 2152272
        if (vsc_filter(vsc, VSB_data(vsb)))
246 144160
                return;
247
248 2008112
        point->name = strdup(VSB_data(vsb));
249 2008112
        AN(point->name);
250 2008112
        point->point.name = point->name;
251
252
#define DOF(n, k)                               \
253
        vt = vjsn_child(vv, k);                 \
254
        AN(vt);                                 \
255
        assert(vjsn_is_string(vt));             \
256
        point->point.n = vt->value;
257
258 2008112
        DOF(ctype, "ctype");
259 2008112
        DOF(sdesc, "oneliner");
260 2008112
        DOF(ldesc, "docs");
261
#undef DOF
262 2008112
        vt = vjsn_child(vv, "type");
263 2008112
        AN(vt);
264 2008112
        assert(vjsn_is_string(vt));
265
266 2008112
        if (!strcmp(vt->value, "counter")) {
267 1747092
                point->point.semantics = 'c';
268 2008112
        } else if (!strcmp(vt->value, "gauge")) {
269 254229
                point->point.semantics = 'g';
270 261020
        } else if (!strcmp(vt->value, "bitmap")) {
271 6791
                point->point.semantics = 'b';
272 6791
        } else {
273 0
                point->point.semantics = '?';
274
        }
275
276 2008112
        vt = vjsn_child(vv, "format");
277 2008112
        AN(vt);
278 2008112
        assert(vjsn_is_string(vt));
279
280 2008112
        if (!strcmp(vt->value, "integer")) {
281 1784870
                point->point.format = 'i';
282 2008112
        } else if (!strcmp(vt->value, "bytes")) {
283 199251
                point->point.format = 'B';
284 223242
        } else if (!strcmp(vt->value, "bitmap")) {
285 6791
                point->point.format = 'b';
286 23991
        } else if (!strcmp(vt->value, "duration")) {
287 17200
                point->point.format = 'd';
288 17200
        } else {
289 0
                point->point.format = '?';
290
        }
291
292 2008112
        vt = vjsn_child(vv, "level");
293 2008112
        AN(vt);
294 2008112
        assert(vjsn_is_string(vt));
295
296 2008112
        if (!strcmp(vt->value, "info"))  {
297 925917
                point->point.level = &levels[info];
298 2008112
        } else if (!strcmp(vt->value, "diag")) {
299 567577
                point->point.level = &levels[diag];
300 1082195
        } else if (!strcmp(vt->value, "debug")) {
301 514618
                point->point.level = &levels[debug];
302 514618
        } else {
303 0
                WRONG("Illegal level");
304
        }
305
306 2008112
        vt = vjsn_child(vv, "index");
307 2008112
        AN(vt);
308
309 2008112
        point->point.ptr = (volatile void*)(seg->body + atoi(vt->value));
310 2008112
        point->point.raw = vsc->raw;
311 2152272
}
312
313
static void
314 125399
vsc_del_seg(const struct vsc *vsc, struct vsm *vsm, struct vsc_seg **spp)
315
{
316
        unsigned u;
317
        struct vsc_pt *pp;
318
        struct vsc_seg *sp;
319
320 125399
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
321 125399
        TAKE_OBJ_NOTNULL(sp, spp, VSC_SEG_MAGIC);
322 125399
        AZ(VSM_Unmap(vsm, sp->fantom));
323 125399
        if (sp->vj != NULL) {
324 27982
                vjsn_delete(&sp->vj);
325 27982
        } else {
326 97417
                pp = sp->points;
327 1958089
                for (u = 0; u < sp->npoints; u++, pp++)
328 1860672
                        vsc_clean_point(pp);
329 97417
                free(sp->points);
330
        }
331 125399
        FREE_OBJ(sp);
332 125399
}
333
334
static struct vsc_seg *
335 152159
vsc_add_seg(const struct vsc *vsc, struct vsm *vsm, const struct vsm_fantom *fp)
336
{
337
        struct vsc_seg *sp, *spd;
338
        const char *e;
339
        struct vjsn_val *vv, *vve;
340
        struct vsb *vsb;
341
        struct vsc_pt *pp;
342
343 152159
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
344
345 152159
        ALLOC_OBJ(sp, VSC_SEG_MAGIC);
346 152159
        AN(sp);
347 152159
        *sp->fantom = *fp;
348 152159
        if (VSM_Map(vsm, sp->fantom)) {
349
                /*
350
                 * If the seg was removed between our call to VSM_Status()
351
                 * and now, we won't be able to map it.
352
                 */
353 0
                FREE_OBJ(sp);
354 0
                return (NULL);
355
        }
356 152159
        sp->head = sp->fantom->b;
357 152159
        if (sp->head->ready == 0) {
358 0
                VRMB();
359 0
                usleep(100000);
360 0
        }
361 152159
        assert(sp->head->ready > 0);
362 152159
        sp->body = (char*)sp->fantom->b + sp->head->body_offset;
363
364 152159
        if (!strcmp(fp->category, VSC_CLASS)) {
365 1368406
                VTAILQ_FOREACH(spd, &vsc->segs, list)
366 1368406
                        if (spd->head->doc_id == sp->head->doc_id)
367 120577
                                break;
368 120577
                AN(spd);
369
                // XXX: Refcount ?
370 120577
                vve = vjsn_child(spd->vj->value, "elements");
371 120577
                AN(vve);
372 120577
                sp->npoints = strtoul(vve->value, NULL, 0);
373 120577
                sp->points = calloc(sp->npoints, sizeof *sp->points);
374 120577
                AN(sp->points);
375 120577
                vsb = VSB_new_auto();
376 120577
                AN(vsb);
377 120577
                vve = vjsn_child(spd->vj->value, "elem");
378 120577
                AN(vve);
379 120577
                pp = sp->points;
380 2272849
                VTAILQ_FOREACH(vv, &vve->children, list) {
381 2152272
                        vsc_fill_point(vsc, sp, vv, vsb, pp);
382 2152272
                        pp++;
383 2152272
                }
384 120577
                VSB_destroy(&vsb);
385 120577
                return (sp);
386
        }
387 31582
        assert(!strcmp(fp->category, VSC_DOC_CLASS));
388 31582
        sp->vj = vjsn_parse(sp->body, &e);
389 31582
        XXXAZ(e);
390 31582
        AN(sp->vj);
391 31582
        return (sp);
392 152159
}
393
394
/*--------------------------------------------------------------------
395
 */
396
397
static void
398 1067063
vsc_expose(const struct vsc *vsc, struct vsc_seg *sp, int del)
399
{
400
        struct vsc_pt *pp;
401
        unsigned u;
402
        int expose;
403
404 1076023
        if (vsc->fnew != NULL && !sp->exposed &&
405 8960
            !del && sp->head->ready == 1)
406 8960
                expose = 1;
407 1125609
        else if (vsc->fdestroy != NULL && sp->exposed &&
408 76466
            (del || sp->head->ready == 2))
409 8960
                expose = 0;
410
        else
411 1049143
                return;
412
413 17920
        pp = sp->points;
414 184640
        for (u = 0; u < sp->npoints; u++, pp++) {
415 166720
                if (pp->name == NULL)
416 26320
                        continue;
417 140400
                if (expose)
418 70200
                        pp->point.priv = vsc->fnew(vsc->priv, &pp->point);
419
                else
420 70200
                        vsc->fdestroy(vsc->priv, &pp->point);
421 140400
        }
422 17920
        sp->exposed = expose;
423 1067063
}
424
425
/*--------------------------------------------------------------------
426
 */
427
428
static int
429 857158
vsc_iter_seg(const struct vsc *vsc, const struct vsc_seg *sp,
430
    VSC_iter_f *fiter, void *priv)
431
{
432
        unsigned u;
433 857158
        int i = 0;
434
        struct vsc_pt *pp;
435
436 857158
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
437 857158
        CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC);
438 857158
        AN(fiter);
439 857158
        pp = sp->points;
440 10046846
        for (u = 0; u < sp->npoints && i == 0; u++, pp++) {
441 9189688
                if (pp->name != NULL)
442 9111248
                        i = fiter(priv, &pp->point);
443 9189688
        }
444 857158
        return (i);
445
}
446
447
int
448 46379
VSC_Iter(struct vsc *vsc, struct vsm *vsm, VSC_iter_f *fiter, void *priv)
449
{
450
        struct vsm_fantom ifantom;
451
        struct vsc_seg *sp, *sp2;
452 46379
        int i = 0;
453
454 46379
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
455 46379
        AN(vsm);
456 46379
        sp = VTAILQ_FIRST(&vsc->segs);
457 1208964
        VSM_FOREACH(&ifantom, vsm) {
458 1195937
                AN(ifantom.category);
459 1195937
                if (strcmp(ifantom.category, VSC_CLASS) &&
460 429345
                    strcmp(ifantom.category, VSC_DOC_CLASS))
461 254273
                        continue;
462 1740215
                while (sp != NULL &&
463 794028
                    (strcmp(ifantom.ident, sp->fantom->ident) ||
464 790025
                    VSM_StillValid(vsm, sp->fantom) != VSM_valid)) {
465 4523
                        sp2 = sp;
466 4523
                        sp = VTAILQ_NEXT(sp, list);
467 4523
                        VTAILQ_REMOVE(&vsc->segs, sp2, list);
468 4523
                        vsc_expose(vsc, sp2, 1);
469 4523
                        vsc_del_seg(vsc, vsm, &sp2);
470
                }
471 941664
                if (sp == NULL) {
472 152159
                        sp = vsc_add_seg(vsc, vsm, &ifantom);
473 152159
                        if (sp != NULL) {
474 152159
                                VTAILQ_INSERT_TAIL(&vsc->segs, sp, list);
475 152159
                                vsc_expose(vsc, sp, 0);
476 152159
                        }
477 152159
                } else {
478 789505
                        vsc_expose(vsc, sp, 0);
479
                }
480 941664
                if (sp != NULL) {
481 941664
                        if (fiter != NULL && sp->head->ready < 2)
482 857158
                                i = vsc_iter_seg(vsc, sp, fiter, priv);
483 941664
                        sp = VTAILQ_NEXT(sp, list);
484 941664
                }
485
486 941664
                if (i)
487 33352
                        break;
488
        }
489 84895
        while (sp != NULL) {
490 38516
                sp2 = sp;
491 38516
                sp = VTAILQ_NEXT(sp, list);
492 38516
                VTAILQ_REMOVE(&vsc->segs, sp2, list);
493 38516
                vsc_expose(vsc, sp2, 1);
494 38516
                vsc_del_seg(vsc, vsm, &sp2);
495
        }
496 46379
        return (i);
497
}
498
499
/*--------------------------------------------------------------------
500
 */
501
502
void
503 240
VSC_State(struct vsc *vsc, VSC_new_f *fn, VSC_destroy_f *fd, void *priv)
504
{
505
        struct vsc_seg *sp;
506
507 240
        CHECK_OBJ_NOTNULL(vsc, VSC_MAGIC);
508 240
        assert((fn == NULL && fd == NULL) || (fn != NULL && fd != NULL));
509 240
        if (fd == NULL) {
510 0
                VTAILQ_FOREACH(sp, &vsc->segs, list)
511 0
                        vsc_expose(vsc, sp, 1);
512 0
        }
513 240
        vsc->fnew = fn;
514 240
        vsc->fdestroy = fd;
515 240
        vsc->priv = priv;
516 240
}
517
518
/*--------------------------------------------------------------------
519
 */
520
521
const struct VSC_level_desc *
522 400
VSC_ChangeLevel(const struct VSC_level_desc *old, int chg)
523
{
524
        int i;
525
526 400
        if (old == NULL)
527 240
                old = &levels[0];
528 440
        for (i = 0; i < nlevels; i++)
529 440
                if (old == &levels[i])
530 400
                        break;
531 400
        if (i == nlevels)
532 0
                i = 0;
533
534 400
        i += chg;
535 400
        if (i >= nlevels)
536 0
                i = nlevels - 1;
537 400
        if (i < 0)
538 0
                i = 0;
539 400
        return (&levels[i]);
540
}
541
542
/*--------------------------------------------------------------------*/
543
544
void
545 36520
VSC_Destroy(struct vsc **vscp, struct vsm *vsm)
546
{
547
        struct vsc *vsc;
548
        struct vsc_sf *sf, *sf2;
549
        struct vsc_seg *sp, *sp2;
550
551 36520
        TAKE_OBJ_NOTNULL(vsc, vscp, VSC_MAGIC);
552
553 37280
        VTAILQ_FOREACH_SAFE(sf, &vsc->sf_list, list, sf2) {
554 760
                CHECK_OBJ_NOTNULL(sf, VSC_SF_MAGIC);
555 760
                VTAILQ_REMOVE(&vsc->sf_list, sf, list);
556 760
                free(sf->pattern);
557 760
                FREE_OBJ(sf);
558 760
        }
559 118880
        VTAILQ_FOREACH_SAFE(sp, &vsc->segs, list, sp2) {
560 82360
                VTAILQ_REMOVE(&vsc->segs, sp, list);
561 82360
                vsc_expose(vsc, sp, 1);
562 82360
                vsc_del_seg(vsc, vsm, &sp);
563 82360
        }
564 36520
        FREE_OBJ(vsc);
565 36520
}
566