varnish-cache/bin/varnishncsa/varnishncsa.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2016 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Anders Berg <andersb@vgnett.no>
6
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7
 * Author: Tollef Fog Heen <tfheen@varnish-software.com>
8
 * Author: Martin Blix Grydeland <mbgrydeland@varnish-software.com>
9
 *
10
 * SPDX-License-Identifier: BSD-2-Clause
11
 *
12
 * Redistribution and use in source and binary forms, with or without
13
 * modification, are permitted provided that the following conditions
14
 * are met:
15
 * 1. Redistributions of source code must retain the above copyright
16
 *    notice, this list of conditions and the following disclaimer.
17
 * 2. Redistributions in binary form must reproduce the above copyright
18
 *    notice, this list of conditions and the following disclaimer in the
19
 *    documentation and/or other materials provided with the distribution.
20
 *
21
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
25
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
 * SUCH DAMAGE.
32
 *
33
 * Obtain log data from the shared memory log, order it by session ID, and
34
 * display it in Apache / NCSA combined log format.
35
 *
36
 * See doc/sphinx/reference/varnishncsa.rst for the supported format
37
 * specifiers.
38
 *
39
 */
40
41
#include "config.h"
42
43
#include <stdlib.h>
44
#include <stdio.h>
45
#include <unistd.h>
46
#include <string.h>
47
#include <signal.h>
48
#include <stdarg.h>
49
#include <inttypes.h>
50
#include <limits.h>
51
#include <ctype.h>
52
#include <time.h>
53
#include <math.h>
54
55
#define VOPT_DEFINITION
56
#define VOPT_INC "varnishncsa_options.h"
57
58
#include "vdef.h"
59
60
#include "vapi/vsl.h"
61
#include "vapi/voptget.h"
62
#include "vas.h"
63
#include "venc.h"
64
#include "vsb.h"
65
#include "vut.h"
66
#include "vqueue.h"
67
#include "miniobj.h"
68
69
#define TIME_FMT "[%d/%b/%Y:%T %z]"
70
#define FORMAT "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\""
71
72
static struct VUT *vut;
73
74
struct format;
75
76
enum e_frag {
77
        F_H,                    /* %H Proto */
78
        F_U,                    /* %U URL path */
79
        F_q,                    /* %q Query string */
80
        F_b,                    /* %b Body bytes sent */
81
        F_h,                    /* %h Host name / IP Address */
82
        F_m,                    /* %m Method */
83
        F_s,                    /* %s Status */
84
        F_I,                    /* %I Bytes received */
85
        F_O,                    /* %O Bytes sent */
86
        F_tstart,               /* Time start */
87
        F_tend,                 /* Time end */
88
        F_ttfb,                 /* %{Varnish:time_firstbyte}x */
89
        F_host,                 /* Host header */
90
        F_auth,                 /* Authorization header */
91
        F__MAX,
92
};
93
94
enum format_policy {
95
        FMTPOL_INTERNAL = 1,
96
        FMTPOL_REQ,
97
        FMTPOL_RESP,
98
        FMTPOL_FIRST,
99
        FMTPOL_LAST
100
};
101
102
struct fragment {
103
        uint64_t                gen;
104
        const char              *b, *e;
105
};
106
107
typedef int format_f(const struct format *format);
108
109
struct format {
110
        unsigned                magic;
111
#define FORMAT_MAGIC            0xC3119CDA
112
113
        char                    time_type;
114
        VTAILQ_ENTRY(format)    list;
115
        format_f                *func;
116
        struct fragment         *frag;
117
        char                    *string;
118
        const char *const       *strptr;
119
        char                    *time_fmt;
120
        int64_t                 *int64;
121
};
122
123
struct watch {
124
        unsigned                magic;
125
#define WATCH_MAGIC             0xA7D4005C
126
127
        VTAILQ_ENTRY(watch)     list;
128
        char                    *key;
129
        int                     keylen;
130
        struct fragment         frag;
131
        enum format_policy      match;
132
};
133
VTAILQ_HEAD(watch_head, watch);
134
135
struct vsl_watch {
136
        unsigned                magic;
137
#define VSL_WATCH_MAGIC         0xE3E27D23
138
139
        VTAILQ_ENTRY(vsl_watch) list;
140
        enum VSL_tag_e          tag;
141
        int                     idx;
142
        char                    *prefix;
143
        int                     prefixlen;
144
        struct fragment         frag;
145
};
146
VTAILQ_HEAD(vsl_watch_head, vsl_watch);
147
148
static struct ctx {
149
        /* Options */
150
        int                     a_opt;
151
        char                    *w_arg;
152
153
        FILE                    *fo;
154
        struct vsb              *vsb;
155
        uint64_t                gen;
156
        VTAILQ_HEAD(,format)    format;
157
        int                     quote_how;
158
        char                    *missing_string;
159
        char                    *missing_int;
160
161
        /* State */
162
        struct watch_head       watch_vcl_log;
163
        struct watch_head       watch_reqhdr; /* also bereqhdr */
164
        struct watch_head       watch_resphdr; /* also beresphdr */
165
        struct vsl_watch_head   watch_vsl;
166
        struct fragment         frag[F__MAX];
167
        const char              *hitmiss;
168
        const char              *handling;
169
        const char              *side;
170
        int64_t                 vxid;
171
        int                     recv_compl;
172
} CTX;
173
174
static void parse_format(const char *format);
175
176
static unsigned
177 60040
frag_needed(const struct fragment *frag, enum format_policy fp)
178
{
179
        unsigned is_first, want_first, want_frag;
180
181 60040
        is_first = CTX.gen != frag->gen;
182
183 60040
        switch (fp) {
184
        case FMTPOL_LAST:
185 800
                want_frag = 1;
186 800
                want_first = 0;
187 800
                break;
188
        case FMTPOL_FIRST:
189
        case FMTPOL_INTERNAL:
190 30360
                want_first = 1;
191 30360
                want_frag = 1;
192 30360
                break;
193
        case FMTPOL_REQ:
194 24560
                want_first = *CTX.side == 'c';
195 24560
                want_frag = !CTX.recv_compl;
196 24560
                break;
197
        case FMTPOL_RESP:
198 4320
                want_first = *CTX.side == 'b';
199 4320
                want_frag = (*CTX.side == 'c') || !CTX.recv_compl;
200 4320
                break;
201
        default:
202 0
                WRONG("Invalid format policy");
203 0
        }
204
205 60040
        if (!want_frag)
206 2320
                return (0);
207 57720
        if (want_first && !is_first)
208 2000
                return (0);
209 55720
        return (1);
210 60040
}
211
212
static void
213 200
openout(int append)
214
{
215
216 200
        AN(CTX.w_arg);
217 200
        if (!strcmp(CTX.w_arg, "-"))
218 0
                CTX.fo = stdout;
219
        else
220 200
                CTX.fo = fopen(CTX.w_arg, append ? "a" : "w");
221 200
        if (CTX.fo == NULL)
222 80
                VUT_Error(vut, 1, "Can't open output file (%s)",
223 40
                    strerror(errno));
224 160
}
225
226
static int v_matchproto_(VUT_cb_f)
227 40
rotateout(struct VUT *v)
228
{
229
230 40
        assert(v == vut);
231 40
        AN(CTX.w_arg);
232 40
        AN(CTX.fo);
233 40
        (void)fclose(CTX.fo);
234 40
        openout(1);
235 40
        AN(CTX.fo);
236 40
        return (0);
237
}
238
239
static int v_matchproto_(VUT_cb_f)
240 34056
flushout(struct VUT *v)
241
{
242
243 34056
        assert(v == vut);
244 34056
        AN(CTX.fo);
245 34056
        if (fflush(CTX.fo))
246 0
                return (-5);
247 34056
        return (0);
248 34056
}
249
250
static inline int
251 10160
vsb_fcat(struct vsb *vsb, const struct fragment *f, const char *dflt)
252
{
253 10160
        if (f->gen == CTX.gen) {
254 10000
                assert(f->b <= f->e);
255 10000
                VSB_quote(vsb, f->b, f->e - f->b, CTX.quote_how);
256 10160
        } else if (dflt)
257 160
                VSB_quote(vsb, dflt, -1, CTX.quote_how);
258
        else
259 0
                return (-1);
260 10160
        return (0);
261 10160
}
262
263
static int v_matchproto_(format_f)
264 12680
format_string(const struct format *format)
265
{
266
267 12680
        CHECK_OBJ_NOTNULL(format, FORMAT_MAGIC);
268 12680
        AN(format->string);
269 12680
        AZ(VSB_cat(CTX.vsb, format->string));
270 12680
        return (1);
271
}
272
273
static int v_matchproto_(format_f)
274 1480
format_strptr(const struct format *format)
275
{
276
277 1480
        CHECK_OBJ_NOTNULL(format, FORMAT_MAGIC);
278 1480
        AN(format->strptr);
279 1480
        AN(*format->strptr);
280 1480
        AZ(VSB_cat(CTX.vsb, *format->strptr));
281 1480
        return (1);
282
}
283
284
static int v_matchproto_(format_f)
285 840
format_int64(const struct format *format)
286
{
287
288 840
        CHECK_OBJ_NOTNULL(format, FORMAT_MAGIC);
289 840
        VSB_printf(CTX.vsb, "%jd", (intmax_t)*format->int64);
290 840
        return (1);
291
}
292
293
static int v_matchproto_(format_f)
294 9160
format_fragment(const struct format *format)
295
{
296
297 9160
        CHECK_OBJ_NOTNULL(format, FORMAT_MAGIC);
298 9160
        AN(format->frag);
299
300 9160
        if (format->frag->gen != CTX.gen) {
301 1920
                if (format->string == NULL)
302 0
                        return (-1);
303 1920
                VSB_quote(CTX.vsb, format->string, -1, CTX.quote_how);
304 1920
                return (0);
305
        }
306 7240
        AZ(vsb_fcat(CTX.vsb, format->frag, NULL));
307 7240
        return (1);
308 9160
}
309
310
static int v_matchproto_(format_f)
311 2400
format_time(const struct format *format)
312
{
313
        double t_start, t_end, d;
314
        char *p;
315
        char buf[64];
316
        time_t t;
317
        intmax_t l;
318
        struct tm tm;
319
320 2400
        CHECK_OBJ_NOTNULL(format, FORMAT_MAGIC);
321 2400
        if (CTX.frag[F_tstart].gen == CTX.gen) {
322 2400
                t_start = strtod(CTX.frag[F_tstart].b, &p);
323 2400
                if (p != CTX.frag[F_tstart].e)
324 0
                        t_start = NAN;
325 2400
        } else
326 0
                t_start = NAN;
327 2400
        if (isnan(t_start)) {
328
                /* Missing t_start is a no go */
329 0
                if (format->string == NULL)
330 0
                        return (-1);
331 0
                AZ(VSB_cat(CTX.vsb, format->string));
332 0
                return (0);
333
        }
334
335
        /* Missing t_end defaults to t_start */
336 2400
        if (CTX.frag[F_tend].gen == CTX.gen) {
337 2360
                t_end = strtod(CTX.frag[F_tend].b, &p);
338 2360
                if (p != CTX.frag[F_tend].e)
339 0
                        t_end = t_start;
340 2360
        } else
341 40
                t_end = t_start;
342
343 2400
        AN(format->time_fmt);
344
345 2400
        switch (format->time_type) {
346
        case 't':
347 1200
                t = (intmax_t)floor(t_start);
348 1200
                (void)localtime_r(&t, &tm);
349 1200
                AN(strftime(buf, sizeof buf, format->time_fmt, &tm));
350 1200
                AZ(VSB_cat(CTX.vsb, buf));
351 1200
                return (1);
352
        case '3':
353 120
                l = (intmax_t)(modf(t_start, &d) * 1e3);
354 120
                break;
355
        case '6':
356 120
                l = (intmax_t)(modf(t_start, &d) * 1e6);
357 120
                break;
358
        case 'S':
359 120
                l = (intmax_t)t_start;
360 120
                break;
361
        case 'M':
362 120
                l = (intmax_t)(t_start * 1e3);
363 120
                break;
364
        case 'U':
365 120
                l = (intmax_t)(t_start * 1e6);
366 120
                break;
367
        case 's':
368 240
                l = (intmax_t)(t_end - t_start);
369 240
                break;
370
        case 'm':
371 120
                l = (intmax_t)((t_end - t_start) * 1e3);
372 120
                break;
373
        case 'u':
374 240
                l = (intmax_t)((t_end - t_start) * 1e6);
375 240
                break;
376
        default:
377 0
                WRONG("Time format specifier");
378 0
        }
379
380
#ifdef __FreeBSD__
381 1200
        assert(fmtcheck(format->time_fmt, "%jd") == format->time_fmt);
382
#endif
383 1200
        AZ(VSB_printf(CTX.vsb, format->time_fmt, l));
384
385 1200
        return (1);
386 2400
}
387
388
static int v_matchproto_(format_f)
389 600
format_requestline(const struct format *format)
390
{
391
392 600
        (void)format;
393 600
        AZ(vsb_fcat(CTX.vsb, &CTX.frag[F_m], "-"));
394 600
        AZ(VSB_putc(CTX.vsb, ' '));
395 600
        if (CTX.frag[F_host].gen == CTX.gen) {
396 520
                if (strncmp(CTX.frag[F_host].b, "http://", 7))
397 520
                        AZ(VSB_cat(CTX.vsb, "http://"));
398 520
                AZ(vsb_fcat(CTX.vsb, &CTX.frag[F_host], NULL));
399 520
        } else
400 80
                AZ(VSB_cat(CTX.vsb, "http://localhost"));
401 600
        AZ(vsb_fcat(CTX.vsb, &CTX.frag[F_U], ""));
402 600
        AZ(vsb_fcat(CTX.vsb, &CTX.frag[F_q], ""));
403 600
        AZ(VSB_putc(CTX.vsb, ' '));
404 600
        AZ(vsb_fcat(CTX.vsb, &CTX.frag[F_H], "HTTP/1.0"));
405 600
        return (1);
406
}
407
408
static int v_matchproto_(format_f)
409 720
format_auth(const struct format *format)
410
{
411 720
        struct vsb *vsb = VSB_new_auto();
412 720
        AN(vsb);
413
        char *q;
414
415 720
        if (CTX.frag[F_auth].gen != CTX.gen ||
416 320
            VENC_Decode_Base64(vsb, CTX.frag[F_auth].b, CTX.frag[F_auth].e)) {
417 400
                VSB_destroy(&vsb);
418 400
                if (format->string == NULL)
419 0
                        return (-1);
420 400
                VSB_quote(CTX.vsb, format->string, -1, CTX.quote_how);
421 400
                return (0);
422
        }
423 320
        AZ(VSB_finish(vsb));
424 320
        q = strchr(VSB_data(vsb), ':');
425 320
        if (q != NULL)
426 320
                *q = '\0';
427 320
        VSB_quote(CTX.vsb, VSB_data(vsb), -1, CTX.quote_how);
428 320
        VSB_destroy(&vsb);
429 320
        return (1);
430 720
}
431
432
static int
433 4000
print(void)
434
{
435
        const struct format *f;
436 4000
        int i, r = 1;
437
438 4000
        VSB_clear(CTX.vsb);
439 31880
        VTAILQ_FOREACH(f, &CTX.format, list) {
440 27880
                CHECK_OBJ_NOTNULL(f, FORMAT_MAGIC);
441 27880
                i = (f->func)(f);
442 27880
                AZ(VSB_error(CTX.vsb));
443 27880
                if (r > i)
444 1040
                        r = i;
445 27880
        }
446 4000
        AZ(VSB_putc(CTX.vsb, '\n'));
447 4000
        AZ(VSB_finish(CTX.vsb));
448 4000
        if (r >= 0) {
449 4000
                i = fwrite(VSB_data(CTX.vsb), 1, VSB_len(CTX.vsb), CTX.fo);
450 4000
                if (i != VSB_len(CTX.vsb))
451 0
                        return (-5);
452 4000
        }
453 4000
        return (0);
454 4000
}
455
456
static void
457 9520
addf_string(const char *str)
458
{
459
        struct format *f;
460
461 9520
        AN(str);
462 9520
        ALLOC_OBJ(f, FORMAT_MAGIC);
463 9520
        AN(f);
464 9520
        f->func = format_string;
465 9520
        f->string = strdup(str);
466 9520
        AN(f->string);
467 9520
        VTAILQ_INSERT_TAIL(&CTX.format, f, list);
468 9520
}
469
470
static void
471 320
addf_strptr(const char *const *strptr)
472
{
473
        struct format *f;
474
475 320
        AN(strptr);
476 320
        ALLOC_OBJ(f, FORMAT_MAGIC);
477 320
        AN(f);
478 320
        f->func = format_strptr;
479 320
        f->strptr = strptr;
480 320
        VTAILQ_INSERT_TAIL(&CTX.format, f, list);
481 320
}
482
483
static void
484 3960
addf_fragment(struct fragment *frag, const char *str)
485
{
486
        struct format *f;
487
488 3960
        AN(frag);
489 3960
        ALLOC_OBJ(f, FORMAT_MAGIC);
490 3960
        AN(f);
491 3960
        f->func = format_fragment;
492 3960
        f->frag = frag;
493 3960
        if (str != NULL) {
494 3960
                f->string = strdup(str);
495 3960
                AN(f->string);
496 3960
        }
497 3960
        VTAILQ_INSERT_TAIL(&CTX.format, f, list);
498 3960
}
499
500
static void
501 200
addf_int64(int64_t *i)
502
{
503
        struct format *f;
504
505 200
        AN(i);
506 200
        ALLOC_OBJ(f, FORMAT_MAGIC);
507 200
        AN(f);
508 200
        f->func = format_int64;
509 200
        f->int64 = i;
510 200
        VTAILQ_INSERT_TAIL(&CTX.format, f, list);
511 200
}
512
513
static void
514 1280
addf_time(char type, const char *fmt)
515
{
516
        struct format *f;
517
518 1280
        ALLOC_OBJ(f, FORMAT_MAGIC);
519 1280
        AN(f);
520 1280
        AN(fmt);
521 1280
        f->func = format_time;
522 1280
        f->time_type = type;
523 1280
        f->time_fmt = strdup(fmt);
524
525 1280
        if (f->time_type == 'T') {
526 200
                if (!strcmp(fmt, "s"))
527 80
                        f->time_type = 's';
528 120
                else if (!strcmp(fmt, "ms"))
529 40
                        f->time_type = 'm';
530 80
                else if (!strcmp(fmt, "us"))
531 80
                        f->time_type = 'u';
532
                else
533 0
                        VUT_Error(vut, 1, "Unknown specifier: %%{%s}T",
534 0
                            fmt);
535 200
                REPLACE(f->time_fmt, "%jd");
536 1280
        } else if (f->time_type == 't') {
537 1080
                if (!strcmp(fmt, "sec")) {
538 40
                        f->time_type = 'S';
539 40
                        REPLACE(f->time_fmt, "%jd");
540 1080
                } else if (!strncmp(fmt, "msec", 4)) {
541 120
                        fmt += 4;
542 120
                        if (!strcmp(fmt, "_frac")) {
543 40
                                f->time_type = '3';
544 40
                                REPLACE(f->time_fmt, "%03jd");
545 120
                        } else if (*fmt == '\0') {
546 40
                                f->time_type = 'M';
547 40
                                REPLACE(f->time_fmt, "%jd");
548 40
                        }
549 1040
                } else if (!strncmp(fmt, "usec", 4)) {
550 120
                        fmt += 4;
551 120
                        if (!strcmp(fmt, "_frac")) {
552 40
                                f->time_type = '6';
553 40
                                REPLACE(f->time_fmt, "%06jd");
554 120
                        } else if (*fmt == '\0') {
555 40
                                f->time_type = 'U';
556 40
                                REPLACE(f->time_fmt, "%jd");
557 40
                        }
558 120
                }
559 1080
        }
560
561 1280
        AN(f->time_fmt);
562 1280
        VTAILQ_INSERT_TAIL(&CTX.format, f, list);
563 1280
}
564
565
static void
566 760
addf_requestline(void)
567
{
568
        struct format *f;
569
570 760
        ALLOC_OBJ(f, FORMAT_MAGIC);
571 760
        AN(f);
572 760
        f->func = format_requestline;
573 760
        VTAILQ_INSERT_TAIL(&CTX.format, f, list);
574 760
}
575
576
static void
577 80
addf_vcl_log(const char *key)
578
{
579
        struct watch *w;
580
        struct format *f;
581
582 80
        AN(key);
583 80
        ALLOC_OBJ(w, WATCH_MAGIC);
584 80
        AN(w);
585 80
        w->keylen = asprintf(&w->key, "%s:", key);
586 80
        assert(w->keylen > 0);
587 80
        VTAILQ_INSERT_TAIL(&CTX.watch_vcl_log, w, list);
588
589 80
        ALLOC_OBJ(f, FORMAT_MAGIC);
590 80
        AN(f);
591 80
        f->func = format_fragment;
592 80
        f->frag = &w->frag;
593 80
        f->string = strdup("");
594 80
        AN(f->string);
595 80
        VTAILQ_INSERT_TAIL(&CTX.format, f, list);
596 80
}
597
598
static void
599 2840
addf_hdr(struct watch_head *head, const char *key)
600
{
601
        struct watch *w;
602
        struct format *f;
603
        char *match;
604
605 2840
        AN(head);
606 2840
        AN(key);
607 2840
        ALLOC_OBJ(w, WATCH_MAGIC);
608 2840
        AN(w);
609
610 2840
        match = strchr(key, ':');
611 2840
        if (match != NULL) {
612 640
                match++;
613 640
                if (!strncmp(match, "first", 5))
614 320
                        w->match = FMTPOL_FIRST;
615 320
                else if (!strncmp(match, "last", 4))
616 320
                        w->match = FMTPOL_LAST;
617
                else
618 0
                        VUT_Error(vut, 1, "Unknown match rule :%s", match);
619 640
                match[-1] = '\0';
620 640
        }
621
622 2840
        w->keylen = asprintf(&w->key, "%s:", key);
623 2840
        assert(w->keylen > 0);
624 2840
        VTAILQ_INSERT_TAIL(head, w, list);
625
626 2840
        ALLOC_OBJ(f, FORMAT_MAGIC);
627 2840
        AN(f);
628 2840
        f->func = format_fragment;
629 2840
        f->frag = &w->frag;
630 2840
        f->string = strdup(CTX.missing_string);
631 2840
        AN(f->string);
632 2840
        VTAILQ_INSERT_TAIL(&CTX.format, f, list);
633 2840
}
634
635
static void
636 520
addf_vsl(enum VSL_tag_e tag, long i, const char *prefix)
637
{
638
        struct vsl_watch *w;
639
640 520
        ALLOC_OBJ(w, VSL_WATCH_MAGIC);
641 520
        AN(w);
642 520
        if (VSL_tagflags[tag] && CTX.quote_how != VSB_QUOTE_JSON)
643 80
                VUT_Error(vut, 1, "Tag %s can contain control characters",
644 40
                    VSL_tags[tag]);
645 480
        w->tag = tag;
646 480
        assert(i <= INT_MAX);
647 480
        w->idx = i;
648 480
        if (prefix != NULL) {
649 120
                w->prefixlen = asprintf(&w->prefix, "%s:", prefix);
650 120
                assert(w->prefixlen > 0);
651 120
        }
652 480
        VTAILQ_INSERT_TAIL(&CTX.watch_vsl, w, list);
653 480
        addf_fragment(&w->frag, CTX.missing_string);
654 480
}
655
656
static void
657 800
addf_auth(void)
658
{
659
        struct format *f;
660
661 800
        ALLOC_OBJ(f, FORMAT_MAGIC);
662 800
        AN(f);
663 800
        f->func = format_auth;
664 800
        f->string = strdup("-");
665 800
        AN(f->string);
666 800
        VTAILQ_INSERT_TAIL(&CTX.format, f, list);
667 800
}
668
669
static void
670 1600
parse_x_format(char *buf)
671
{
672
        char *e, *r, *s;
673
        long lval;
674
        int slt;
675
676 1600
        if (!strcmp(buf, "Varnish:time_firstbyte")) {
677 40
                addf_fragment(&CTX.frag[F_ttfb], CTX.missing_int);
678 40
                return;
679
        }
680 1560
        if (!strcmp(buf, "Varnish:hitmiss")) {
681 40
                addf_strptr(&CTX.hitmiss);
682 40
                return;
683
        }
684 1520
        if (!strcmp(buf, "Varnish:handling")) {
685 80
                addf_strptr(&CTX.handling);
686 80
                return;
687
        }
688 1440
        if (!strcmp(buf, "Varnish:side")) {
689 200
                addf_strptr(&CTX.side);
690 200
                return;
691
        }
692 1240
        if (!strcmp(buf, "Varnish:vxid")) {
693 200
                addf_int64(&CTX.vxid);
694 200
                return;
695
        }
696 1040
        if (!strncmp(buf, "VCL_Log:", 8)) {
697 80
                addf_vcl_log(buf + 8);
698 80
                return;
699
        }
700 960
        if (!strncmp(buf, "VSL:", 4)) {
701 880
                buf += 4;
702 880
                e = buf;
703 8240
                while (*e != '\0')
704 7360
                        e++;
705 880
                if (e == buf)
706 40
                        VUT_Error(vut, 1, "Missing tag in VSL:");
707 840
                if (e[-1] == ']') {
708 480
                        r = e - 1;
709 2000
                        while (r > buf && *r != '[')
710 1520
                                r--;
711 480
                        if (r == buf || r[1] == ']')
712 40
                                VUT_Error(vut, 1, "Syntax error: VSL:%s", buf);
713 440
                        e[-1] = '\0';
714 440
                        lval = strtol(r + 1, &s, 10);
715 440
                        if (s != e - 1)
716 40
                                VUT_Error(vut, 1, "Syntax error: VSL:%s]", buf);
717 400
                        if (lval <= 0 || lval > 255) {
718 160
                                VUT_Error(vut, 1,
719
                                    "Syntax error. Field specifier must be"
720
                                    " between 1 and 255: %s]",
721 80
                                    buf);
722
                        }
723 320
                        *r = '\0';
724 320
                } else
725 360
                        lval = 0;
726 680
                r = buf;
727 5720
                while (r < e && *r != ':')
728 5040
                        r++;
729 680
                if (r != e) {
730 120
                        slt = VSL_Name2Tag(buf, r - buf);
731 120
                        r++;
732 120
                } else {
733 560
                        slt = VSL_Name2Tag(buf, -1);
734 560
                        r = NULL;
735
                }
736 680
                if (slt == -2)
737 40
                        VUT_Error(vut, 1, "Tag not unique: %s", buf);
738 640
                if (slt == -1)
739 120
                        VUT_Error(vut, 1, "Unknown log tag: %s", buf);
740 520
                assert(slt >= 0);
741
742 520
                addf_vsl((enum VSL_tag_e)slt, lval, r);
743 520
                return;
744
        }
745 80
        if (!strcmp(buf, "Varnish:default_format")) {
746 40
                parse_format(FORMAT);
747 40
                return;
748
        }
749 40
        VUT_Error(vut, 1, "Unknown formatting extension: %s", buf);
750 1200
}
751
752
static void
753 3040
parse_format(const char *format)
754
{
755
        const char *p, *q;
756
        struct vsb *vsb;
757
        char buf[256];
758
        int b;
759
760 3040
        if (format == NULL)
761 600
                format = FORMAT;
762
763 3040
        vsb = VSB_new_auto();
764 3040
        AN(vsb);
765
766 29160
        for (p = format; *p != '\0'; p++) {
767
768
                /* Allow the most essential escape sequences in format */
769 26240
                if (*p == '\\' && p[1] != '\0') {
770 40
                        if (*++p == 't')
771 0
                                AZ(VSB_putc(vsb, '\t'));
772 40
                        else if (*p == 'n')
773 40
                                AZ(VSB_putc(vsb, '\n'));
774
                        else
775 0
                                AZ(VSB_putc(vsb, *p));
776 40
                        continue;
777
                }
778
779 26200
                if (*p != '%') {
780 14680
                        AZ(VSB_putc(vsb, *p));
781 14680
                        continue;
782
                }
783
784 11520
                if (VSB_len(vsb) > 0) {
785 8680
                        AZ(VSB_finish(vsb));
786 8680
                        addf_string(VSB_data(vsb));
787 8680
                        VSB_clear(vsb);
788 8680
                }
789
790 11520
                p++;
791 11520
                switch (*p) {
792
                case 'b':       /* Body bytes sent */
793 800
                        addf_fragment(&CTX.frag[F_b], CTX.missing_int);
794 800
                        break;
795
                case 'D':       /* Float request time */
796 40
                        addf_time('T', "us");
797 40
                        break;
798
                case 'h':       /* Client host name / IP Address */
799 800
                        addf_fragment(&CTX.frag[F_h], CTX.missing_string);
800 800
                        break;
801
                case 'H':       /* Protocol */
802 120
                        addf_fragment(&CTX.frag[F_H], "HTTP/1.0");
803 120
                        break;
804
                case 'I':       /* Bytes received */
805 40
                        addf_fragment(&CTX.frag[F_I], CTX.missing_int);
806 40
                        break;
807
                case 'l':       /* Client user ID (identd) always '-' */
808 680
                        AZ(VSB_putc(vsb, '-'));
809 680
                        break;
810
                case 'm':       /* Method */
811 120
                        addf_fragment(&CTX.frag[F_m], CTX.missing_string);
812 120
                        break;
813
                case 'O':       /* Bytes sent */
814 40
                        addf_fragment(&CTX.frag[F_O], CTX.missing_int);
815 40
                        break;
816
                case 'q':       /* Query string */
817 120
                        addf_fragment(&CTX.frag[F_q], "");
818 120
                        break;
819
                case 'r':       /* Request line */
820 760
                        addf_requestline();
821 760
                        break;
822
                case 's':       /* Status code */
823 1240
                        addf_fragment(&CTX.frag[F_s], CTX.missing_int);
824 1240
                        break;
825
                case 't':       /* strftime */
826 680
                        addf_time(*p, TIME_FMT);
827 680
                        break;
828
                case 'T':       /* Int request time */
829 40
                        addf_time(*p, "s");
830 40
                        break;
831
                case 'u':       /* Remote user from auth */
832 800
                        addf_auth();
833 800
                        break;
834
                case 'U':       /* URL */
835 160
                        addf_fragment(&CTX.frag[F_U], CTX.missing_string);
836 160
                        break;
837
                case '{':
838 5040
                        p++;
839 5040
                        q = p;
840 5040
                        b = 1;
841 53040
                        while (*q) {
842 53000
                                if (*q == '{')
843 160
                                        b++;
844 52840
                                else if (*q == '}')
845 5160
                                        if (--b == 0)
846 5000
                                                break;
847 48000
                                q++;
848
                        }
849 5040
                        if (b > 0)
850 80
                                VUT_Error(vut, 1, "Unmatched bracket at: %s",
851 40
                                    p - 2);
852 5000
                        assert((unsigned)(q - p) < sizeof buf - 1);
853 5000
                        strncpy(buf, p, q - p);
854 5000
                        buf[q - p] = '\0';
855 5000
                        q++;
856 5000
                        switch (*q) {
857
                        case 'i':
858 2280
                                addf_hdr(&CTX.watch_reqhdr, buf);
859 2280
                                break;
860
                        case 'o':
861 560
                                addf_hdr(&CTX.watch_resphdr, buf);
862 560
                                break;
863
                        case 't':
864 400
                                addf_time(*q, buf);
865 400
                                break;
866
                        case 'T':
867 120
                                addf_time(*q, buf);
868 120
                                break;
869
                        case 'x':
870 1600
                                parse_x_format(buf);
871 1600
                                break;
872
                        default:
873 80
                                VUT_Error(vut, 1,
874
                                    "Unknown format specifier at: %s",
875 40
                                    p - 2);
876
                        }
877 4960
                        p = q;
878 4960
                        break;
879
                default:
880 80
                        VUT_Error(vut, 1, "Unknown format specifier at: %s",
881 40
                            p - 1);
882
                }
883 11400
        }
884
885 2920
        if (VSB_len(vsb) > 0) {
886
                /* Add any remaining static */
887 840
                AZ(VSB_finish(vsb));
888 840
                addf_string(VSB_data(vsb));
889 840
                VSB_clear(vsb);
890 840
        }
891
892 2920
        VSB_destroy(&vsb);
893 2920
}
894
895
static int
896 149760
isprefix(const char *prefix, size_t len, const char *b,
897
    const char *e, const char **next)
898
{
899 149760
        assert(len > 0);
900 149760
        if (e < b + len || strncasecmp(b, prefix, len))
901 127600
                return (0);
902 22160
        b += len;
903 22160
        if (next) {
904 42920
                while (b < e && *b == ' ')
905 20760
                        b++;
906 22160
                *next = b;
907 22160
        }
908 22160
        return (1);
909 149760
}
910
911
static void
912 21680
frag_fields(enum format_policy fp, const char *b, const char *e, ...)
913
{
914
        va_list ap;
915
        const char *p, *q;
916
        int n, field;
917
        struct fragment *frag;
918
919 21680
        AN(b);
920 21680
        AN(e);
921 21680
        va_start(ap, e);
922
923 21680
        n = 0;
924 50960
        while (1) {
925 51080
                field = va_arg(ap, int);
926 51080
                frag = va_arg(ap, struct fragment *);
927 51080
                if (field == 0) {
928 21680
                        AZ(frag);
929 21680
                        break;
930
                }
931 29400
                p = q = NULL;
932 78160
                while (n < field) {
933 75720
                        while (b < e && isspace(*b))
934 26960
                                b++;
935 48760
                        p = b;
936 417640
                        while (b < e && !isspace(*b))
937 368880
                                b++;
938 48760
                        q = b;
939 48760
                        n++;
940
                }
941 29400
                assert(p != NULL && q != NULL);
942 29400
                if (p >= e || q <= p)
943 120
                        continue;
944 29280
                if (frag_needed(frag, fp)) {
945
                        /* We only grab the same matching field once */
946 28520
                        frag->gen = CTX.gen;
947 28520
                        frag->b = p;
948 28520
                        frag->e = q;
949 28520
                }
950
        }
951 21680
        va_end(ap);
952 21680
}
953
954
static void
955 30760
frag_line(enum format_policy fp, const char *b, const char *e,
956
    struct fragment *f)
957
{
958
959 30760
        if (!frag_needed(f, fp)) {
960
                /* We only grab the same matching record once */
961 3560
                return;
962
        }
963
964 27200
        if (e == NULL)
965 160
                e = b + strlen(b);
966
967
        /* Skip leading space */
968 27200
        while (b < e && isspace(*b))
969 0
                ++b;
970
971
        /* Skip trailing space */
972 27200
        while (e > b && isspace(e[-1]))
973 0
                --e;
974
975 27200
        f->gen = CTX.gen;
976 27200
        f->b = b;
977 27200
        f->e = e;
978 30760
}
979
980
static void
981 45840
process_hdr(enum format_policy fp, const struct watch_head *head, const char *b,
982
    const char *e, int unset)
983
{
984
        struct watch *w;
985
        const char *p;
986
987 69920
        VTAILQ_FOREACH(w, head, list) {
988 24080
                CHECK_OBJ_NOTNULL(w, WATCH_MAGIC);
989 24080
                if (!isprefix(w->key, w->keylen, b, e, &p))
990 20600
                        continue;
991
992 3480
                if (w->match) {
993 1600
                        assert(w->match == FMTPOL_FIRST ||
994
                            w->match == FMTPOL_LAST);
995 1600
                        fp = w->match;
996 1600
                }
997
998 3480
                if (unset && !w->match) {
999 880
                        frag_line(fp, CTX.missing_string,
1000
                            NULL,
1001 440
                            &w->frag);
1002 440
                } else
1003 3040
                        frag_line(fp, p, e, &w->frag);
1004 3480
        }
1005 45840
}
1006
1007
static void
1008 148840
process_vsl(const struct vsl_watch_head *head, enum VSL_tag_e tag,
1009
    const char *b, const char *e)
1010
{
1011
        struct vsl_watch *w;
1012
        const char *p;
1013 203080
        VTAILQ_FOREACH(w, head, list) {
1014 54240
                CHECK_OBJ_NOTNULL(w, VSL_WATCH_MAGIC);
1015 54240
                if (tag != w->tag)
1016 51400
                        continue;
1017 2840
                p = b;
1018 2840
                if (w->prefixlen > 0 &&
1019 1680
                    !isprefix(w->prefix, w->prefixlen, b, e, &p))
1020 1520
                        continue;
1021 1320
                if (w->idx == 0)
1022 240
                        frag_line(FMTPOL_INTERNAL, p, e, &w->frag);
1023
                else
1024 1080
                        frag_fields(FMTPOL_INTERNAL, p, e, w->idx, &w->frag, 0, NULL);
1025 1320
        }
1026 148840
}
1027
1028
static int v_matchproto_(VSLQ_dispatch_f)
1029 5120
dispatch_f(struct VSL_data *vsl, struct VSL_transaction * const pt[],
1030
    void *priv)
1031
{
1032
        struct VSL_transaction *t;
1033
        enum VSL_tag_e tag;
1034
        const char *b, *e, *p;
1035
        struct watch *w;
1036
        int i, skip;
1037
1038 5120
        (void)vsl;
1039 5120
        (void)priv;
1040
1041 10240
        for (t = pt[0]; t != NULL; t = *++pt) {
1042 5120
                CTX.gen++;
1043
1044 5120
                if (t->type == VSL_t_req) {
1045 3440
                        CTX.side = "c";
1046 5120
                } else if (t->type == VSL_t_bereq) {
1047 560
                        CTX.side = "b";
1048 560
                } else
1049 1120
                        continue;
1050
1051 4000
                CTX.recv_compl = 0;
1052 4000
                CTX.hitmiss = "-";
1053 4000
                CTX.handling = "-";
1054 4000
                CTX.vxid = t->vxid;
1055 4000
                skip = 0;
1056 153440
                while (skip == 0 && 1 == VSL_Next(t->c)) {
1057 149440
                        tag = VSL_TAG(t->c->rec.ptr);
1058 149440
                        if (VSL_tagflags[tag] &&
1059 640
                            CTX.quote_how != VSB_QUOTE_JSON)
1060 600
                                continue;
1061
1062 148840
                        b = VSL_CDATA(t->c->rec.ptr);
1063 148840
                        e = b + VSL_LEN(t->c->rec.ptr);
1064 148840
                        if (!VSL_tagflags[tag]) {
1065 297600
                                while (e > b && e[-1] == '\0')
1066 148800
                                        e--;
1067 148800
                        }
1068
1069 148840
                        switch (tag) {
1070
                        case SLT_HttpGarbage:
1071 0
                                skip = 1;
1072 0
                                break;
1073
                        case SLT_PipeAcct:
1074 280
                                frag_fields(FMTPOL_INTERNAL, b, e,
1075
                                    3, &CTX.frag[F_I],
1076
                                    4, &CTX.frag[F_O],
1077
                                    0, NULL);
1078 280
                                break;
1079
                        case SLT_BackendOpen:
1080 560
                                frag_fields(FMTPOL_INTERNAL, b, e,
1081
                                    3, &CTX.frag[F_h],
1082
                                    0, NULL);
1083 560
                                break;
1084
                        case SLT_ReqStart:
1085 3440
                                frag_fields(FMTPOL_INTERNAL, b, e,
1086
                                    1, &CTX.frag[F_h],
1087
                                    0, NULL);
1088 3440
                                break;
1089
                        case SLT_BereqMethod:
1090
                        case SLT_ReqMethod:
1091 4280
                                frag_line(FMTPOL_REQ, b, e, &CTX.frag[F_m]);
1092 4280
                                break;
1093
                        case SLT_BereqURL:
1094
                        case SLT_ReqURL:
1095 4960
                                p = memchr(b, '?', e - b);
1096 4960
                                if (p == NULL)
1097 3720
                                        p = e;
1098 4960
                                frag_line(FMTPOL_REQ, b, p, &CTX.frag[F_U]);
1099 4960
                                frag_line(FMTPOL_REQ, p, e, &CTX.frag[F_q]);
1100 4960
                                break;
1101
                        case SLT_BereqProtocol:
1102
                        case SLT_ReqProtocol:
1103 4080
                                frag_line(FMTPOL_REQ, b, e, &CTX.frag[F_H]);
1104 4080
                                break;
1105
                        case SLT_BerespStatus:
1106
                        case SLT_RespStatus:
1107 3840
                                frag_line(FMTPOL_RESP, b, e, &CTX.frag[F_s]);
1108 3840
                                break;
1109
                        case SLT_BereqAcct:
1110
                        case SLT_ReqAcct:
1111 3720
                                frag_fields(FMTPOL_INTERNAL, b, e,
1112
                                    3, &CTX.frag[F_I],
1113
                                    5, &CTX.frag[F_b],
1114
                                    6, &CTX.frag[F_O],
1115
                                    0, NULL);
1116 3720
                                break;
1117
                        case SLT_Timestamp:
1118
#define ISPREFIX(a, b, c, d)    isprefix(a, strlen(a), b, c, d)
1119 19560
                                if (ISPREFIX("Start:", b, e, &p)) {
1120 4000
                                        frag_fields(FMTPOL_INTERNAL, p, e, 1,
1121
                                            &CTX.frag[F_tstart], 0, NULL);
1122
1123 31720
                                } else if (ISPREFIX("Resp:", b, e, &p) ||
1124 12440
                                    ISPREFIX("PipeSess:", b, e, &p) ||
1125 12160
                                    ISPREFIX("BerespBody:", b, e, &p)) {
1126 3880
                                        frag_fields(FMTPOL_INTERNAL, p, e, 1,
1127
                                            &CTX.frag[F_tend], 0, NULL);
1128
1129 23000
                                } else if (ISPREFIX("Process:", b, e, &p) ||
1130 7720
                                    ISPREFIX("Pipe:", b, e, &p) ||
1131 7440
                                    ISPREFIX("Beresp:", b, e, &p)) {
1132 4720
                                        frag_fields(FMTPOL_INTERNAL, p, e, 2,
1133
                                            &CTX.frag[F_ttfb], 0, NULL);
1134 4720
                                }
1135 19560
                                break;
1136
                        case SLT_BereqHeader:
1137
                        case SLT_ReqHeader:
1138 18720
                                process_hdr(FMTPOL_REQ, &CTX.watch_reqhdr, b, e, 0);
1139 18720
                                if (ISPREFIX("Authorization:", b, e, &p) &&
1140 1040
                                    ISPREFIX("basic ", p, e, &p))
1141 1040
                                        frag_line(FMTPOL_REQ, p, e,
1142
                                            &CTX.frag[F_auth]);
1143 17680
                                else if (ISPREFIX("Host:", b, e, &p))
1144 3840
                                        frag_line(FMTPOL_REQ, p, e,
1145
                                            &CTX.frag[F_host]);
1146
#undef ISPREFIX
1147 18720
                                break;
1148
                        case SLT_BerespHeader:
1149
                        case SLT_RespHeader:
1150 25240
                                process_hdr(FMTPOL_RESP, &CTX.watch_resphdr, b, e, 0);
1151 25240
                                break;
1152
                        case SLT_BereqUnset:
1153
                        case SLT_ReqUnset:
1154 880
                                process_hdr(FMTPOL_REQ, &CTX.watch_reqhdr, b, e, 1);
1155 880
                                break;
1156
                        case SLT_BerespUnset:
1157
                        case SLT_RespUnset:
1158 1000
                                process_hdr(FMTPOL_RESP, &CTX.watch_resphdr, b, e, 1);
1159 1000
                                break;
1160
                        case SLT_HitMiss:
1161 440
                                CTX.hitmiss = "miss";
1162 440
                                CTX.handling = "hitmiss";
1163 440
                                break;
1164
                        case SLT_HitPass:
1165 40
                                CTX.hitmiss = "miss";
1166 40
                                CTX.handling = "hitpass";
1167 40
                                break;
1168
                        case SLT_VCL_call:
1169 14000
                                if (!strcasecmp(b, "recv")) {
1170 3400
                                        CTX.recv_compl = 1;
1171 3400
                                        CTX.hitmiss = "-";
1172 3400
                                        CTX.handling = "-";
1173 14000
                                } else if (!strcasecmp(b, "hit")) {
1174 680
                                        CTX.hitmiss = "hit";
1175 680
                                        CTX.handling = "hit";
1176 10600
                                } else if (!strcasecmp(b, "miss") && strcmp(CTX.handling, "hitmiss")) {
1177 1480
                                        CTX.hitmiss = "miss";
1178 1480
                                        CTX.handling = "miss";
1179 9920
                                } else if (!strcasecmp(b, "pass") && strcmp(CTX.handling, "hitpass")) {
1180 280
                                        CTX.hitmiss = "miss";
1181 280
                                        CTX.handling = "pass";
1182 8440
                                } else if (!strcasecmp(b, "synth")) {
1183
                                        /* Arguably, synth isn't a hit or
1184
                                           a miss, but miss is less
1185
                                           wrong */
1186 480
                                        CTX.hitmiss = "miss";
1187 480
                                        CTX.handling = "synth";
1188 8160
                                } else if (!strcasecmp(b, "backend_response")) {
1189 480
                                        CTX.recv_compl = 1;
1190 480
                                }
1191 14000
                                break;
1192
                        case SLT_VCL_return:
1193 14000
                                if (!strcasecmp(b, "pipe")) {
1194 560
                                        CTX.hitmiss = "miss";
1195 560
                                        CTX.handling = "pipe";
1196 14000
                                } else if (!strcasecmp(b, "restart"))
1197 0
                                        skip = 1;
1198 14000
                                break;
1199
                        case SLT_VCL_Log:
1200 440
                                VTAILQ_FOREACH(w, &CTX.watch_vcl_log, list) {
1201 40
                                        CHECK_OBJ_NOTNULL(w, WATCH_MAGIC);
1202 40
                                        if (e - b < w->keylen ||
1203 40
                                            strncmp(b, w->key, w->keylen))
1204 0
                                                continue;
1205 40
                                        p = b + w->keylen;
1206 40
                                        frag_line(FMTPOL_INTERNAL, p, e, &w->frag);
1207 40
                                }
1208 400
                                break;
1209
                        default:
1210 29400
                                break;
1211
                        }
1212
1213 148840
                        process_vsl(&CTX.watch_vsl, tag, b, e);
1214
                }
1215 4000
                if (skip)
1216 0
                        continue;
1217 4000
                i = print();
1218 4000
                if (i)
1219 0
                        return (i);
1220 4000
        }
1221
1222 5120
        return (0);
1223 5120
}
1224
1225
static char *
1226 120
read_format(const char *formatfile)
1227
{
1228
        FILE *fmtfile;
1229 120
        size_t len = 0;
1230
        int fmtlen;
1231 120
        char *fmt = NULL;
1232
1233 120
        fmtfile = fopen(formatfile, "r");
1234 120
        if (fmtfile == NULL)
1235 80
                VUT_Error(vut, 1, "Can't open format file (%s)",
1236 40
                    strerror(errno));
1237 80
        AN(fmtfile);
1238 80
        fmtlen = getline(&fmt, &len, fmtfile);
1239 80
        if (fmtlen == -1) {
1240 40
                free(fmt);
1241 40
                if (feof(fmtfile))
1242 40
                        VUT_Error(vut, 1, "Empty format file");
1243 0
                VUT_Error(vut, 1, "Can't read format from file (%s)",
1244 0
                    strerror(errno));
1245
        }
1246 40
        AZ(fclose(fmtfile));
1247 40
        if (fmt[fmtlen - 1] == '\n')
1248 40
                fmt[fmtlen - 1] = '\0';
1249 40
        return (fmt);
1250
}
1251
1252
int
1253 4080
main(int argc, char * const *argv)
1254
{
1255
        signed char opt;
1256 4080
        char *format = NULL;
1257 4080
        int mode_opt = 0;
1258
1259 4080
        vut = VUT_InitProg(argc, argv, &vopt_spec);
1260 4080
        AN(vut);
1261 4080
        memset(&CTX, 0, sizeof CTX);
1262 4080
        VTAILQ_INIT(&CTX.format);
1263 4080
        VTAILQ_INIT(&CTX.watch_vcl_log);
1264 4080
        VTAILQ_INIT(&CTX.watch_reqhdr);
1265 4080
        VTAILQ_INIT(&CTX.watch_resphdr);
1266 4080
        VTAILQ_INIT(&CTX.watch_vsl);
1267 4080
        CTX.vsb = VSB_new_auto();
1268 4080
        AN(CTX.vsb);
1269 4080
        CTX.quote_how = VSB_QUOTE_ESCHEX;
1270 4080
        REPLACE(CTX.missing_string, "-");
1271 4080
        REPLACE(CTX.missing_int, "-");
1272
1273 2560
        tzset();                // We use localtime_r(3)
1274
1275 12360
        while ((opt = getopt(argc, argv, vopt_spec.vopt_optstring)) != -1) {
1276 9840
                switch (opt) {
1277
                case 'a':
1278
                        /* Append to file */
1279 0
                        CTX.a_opt = 1;
1280 0
                        break;
1281
                case 'b': /* backend mode */
1282
                case 'c': /* client mode */
1283
                case 'E': /* show ESI */
1284 800
                        AN(VUT_Arg(vut, opt, NULL));
1285 800
                        mode_opt = 1;
1286 800
                        break;
1287
                case 'F':
1288 2360
                        if (format != NULL)
1289 0
                                VUT_Error(vut, 1, "Format already set");
1290 2360
                        REPLACE(format, optarg);
1291 2360
                        break;
1292
                case 'f':
1293 40
                        if (format != NULL)
1294 0
                                VUT_Error(vut, 1, "Format already set");
1295
                        /* Format string from file */
1296 40
                        format = read_format(optarg);
1297 40
                        AN(format);
1298 40
                        break;
1299
                case 'h':
1300
                        /* Usage help */
1301 40
                        VUT_Usage(vut, &vopt_spec, 0);
1302
                        break;
1303
                case 'j':
1304 200
                        REPLACE(CTX.missing_string, "");
1305 200
                        REPLACE(CTX.missing_int, "0");
1306 200
                        CTX.quote_how = VSB_QUOTE_JSON;
1307 200
                        break;
1308
                case 'w':
1309
                        /* Write to file */
1310 160
                        REPLACE(CTX.w_arg, optarg);
1311 160
                        break;
1312
                default:
1313 6240
                        if (!VUT_Arg(vut, opt, optarg))
1314 0
                                VUT_Usage(vut, &vopt_spec, 1);
1315 6240
                }
1316
        }
1317
1318
        /* default is client mode: */
1319 2520
        if (!mode_opt)
1320 2360
                AN(VUT_Arg(vut, 'c', NULL));
1321
1322 2520
        if (optind != argc)
1323 40
                VUT_Usage(vut, &vopt_spec, 1);
1324
1325 2480
        if (vut->D_opt && !CTX.w_arg)
1326 40
                VUT_Error(vut, 1, "Missing -w option");
1327
1328 2440
        if (vut->D_opt && !strcmp(CTX.w_arg, "-"))
1329 0
                VUT_Error(vut, 1, "Daemon cannot write to stdout");
1330
1331
        /* Check for valid grouping mode */
1332 2440
        assert(vut->g_arg < VSL_g__MAX);
1333 2440
        if (vut->g_arg != VSL_g_vxid && vut->g_arg != VSL_g_request)
1334 80
                VUT_Error(vut, 1, "Invalid grouping mode: %s",
1335 40
                    VSLQ_grouping[vut->g_arg]);
1336
1337
        /* Prepare output format */
1338 2400
        parse_format(format);
1339 2400
        REPLACE(format, NULL);
1340
1341
        /* Setup output */
1342 2400
        vut->dispatch_f = dispatch_f;
1343 2400
        vut->dispatch_priv = NULL;
1344 2400
        if (CTX.w_arg) {
1345 120
                openout(CTX.a_opt);
1346 120
                AN(CTX.fo);
1347 120
                if (vut->D_opt)
1348 40
                        vut->sighup_f = rotateout;
1349 120
        } else
1350 2280
                CTX.fo = stdout;
1351 2400
        vut->idle_f = flushout;
1352
1353 2400
        VUT_Setup(vut);
1354 2400
        (void)VUT_Main(vut);
1355 2400
        VUT_Fini(&vut);
1356
1357 2400
        exit(0);
1358
}