varnish-cache/lib/libvarnishapi/vut.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Martin Blix Grydeland <martin@varnish-software.com>
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
 * Common functions for the utilities
31
 */
32
33
#include "config.h"
34
35 0
#include <ctype.h>
36 0
#include <math.h>
37 0
#include <stdint.h>
38 0
#include <stdarg.h>
39
#include <stdlib.h>
40
#include <unistd.h>
41
#include <stdio.h>
42
#include <string.h>
43
#include <sys/stat.h> /* for MUSL */
44
45
#include "compat/daemon.h"
46
#include "vdef.h"
47
#include "vpf.h"
48
#include "vapi/vsm.h"
49
#include "vapi/vsl.h"
50
#include "vtim.h"
51
#include "vas.h"
52
#include "miniobj.h"
53
#include "vcs.h"
54
#include "vsb.h"
55
#include "vfil.h"
56
57
#include "vapi/voptget.h"
58
#include "vapi/vsig.h"
59
60
#include "vut.h"
61
62
63
static int vut_synopsis(const struct vopt_spec *);
64
static int vut_options(const struct vopt_spec *);
65
66
static struct vpf_fh    *pfh;
67
static unsigned         daemonized;
68
69
static struct VUT pfh_vut;
70
71
static int
72 50
vut_daemon(struct VUT *vut)
73
{
74 50
        if (daemonized)
75 0
                VUT_Error(vut, 1, "Already running as a daemon");
76 50
        daemonized = 1;
77 50
        return (varnish_daemon(0, 0));
78
}
79
80
static void
81 100
vut_vpf_remove(void)
82
{
83
84 100
        CHECK_OBJ(&pfh_vut, VUT_MAGIC);
85 100
        AN(pfh);
86 100
        AN(pfh_vut.P_arg);
87
88 100
        VPF_Remove(pfh);
89 100
        free(pfh_vut.P_arg);
90 100
        ZERO_OBJ(&pfh_vut, sizeof pfh_vut);
91 100
        pfh = NULL;
92 100
}
93
94
static int v_matchproto_(VSLQ_dispatch_f)
95 23584
vut_dispatch(struct VSL_data *vsl, struct VSL_transaction * const trans[],
96
    void *priv)
97
{
98
        struct VUT *vut;
99
        int i;
100
101 23584
        CAST_OBJ_NOTNULL(vut, priv, VUT_MAGIC);
102
103 23584
        if (vut->k_arg == 0)
104 0
                return (-1);    /* End of file */
105 23584
        AN(vut->dispatch_f);
106 23584
        i = vut->dispatch_f(vsl, trans, vut->dispatch_priv);
107 23584
        if (vut->k_arg > 0)
108 75
                vut->k_arg--;
109 23584
        if (i >= 0 && vut->k_arg == 0)
110 75
                return (-1);    /* End of file */
111 23509
        return (i);
112 23584
}
113
114
void
115 2400
VUT_Error(struct VUT *vut, int status, const char *fmt, ...)
116
{
117
        va_list ap;
118
119 2400
        CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
120 2400
        AN(status);
121
122 2400
        va_start(ap, fmt);
123 2400
        if (vut->error_f != NULL) {
124 0
                vut->error_f(vut, status, fmt, ap);
125 0
        } else {
126 2400
                vfprintf(stderr, fmt, ap);
127 2400
                fprintf(stderr, "\n");
128
        }
129 2400
        va_end(ap);
130 2400
        exit(status);
131
}
132
133
static void
134 1475
vut_arg_q(struct VUT *vut, const char *arg)
135
{
136
        struct vsb *vsb;
137
138 1475
        AN(arg);
139 1475
        if (vut->q_arg == NULL) {
140 1400
                REPLACE(vut->q_arg, arg);
141 1400
                return;
142
        }
143
144 75
        vsb = VSB_new_auto();
145 75
        AN(vsb);
146 75
        AZ(VSB_printf(vsb, "%s\n%s", vut->q_arg, arg));
147 75
        AZ(VSB_finish(vsb));
148
149 75
        REPLACE(vut->q_arg, VSB_data(vsb));
150
151 75
        VSB_destroy(&vsb);
152 1475
}
153
154
int
155 9925
VUT_Arg(struct VUT *vut, int opt, const char *arg)
156
{
157
        int i;
158
        char *p;
159
160 9925
        CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
161 9925
        AN(opt);
162
163 9925
        switch (opt) {
164
        case 'd':
165
                /* Head */
166 1800
                vut->d_opt = 1;
167 1800
                return (1);
168
        case 'D':
169
                /* Daemon mode */
170 150
                vut->D_opt = 1;
171 150
                return (1);
172
        case 'g':
173
                /* Grouping */
174 325
                AN(arg);
175 325
                vut->g_arg = VSLQ_Name2Grouping(arg, -1);
176 325
                if (vut->g_arg == -2)
177 25
                        VUT_Error(vut, 1, "Ambiguous grouping type: %s", arg);
178 300
                else if (vut->g_arg < 0)
179 25
                        VUT_Error(vut, 1, "Unknown grouping type: %s", arg);
180 275
                return (1);
181
        case 'k':
182
                /* Log transaction limit */
183 100
                AN(arg);
184 100
                vut->k_arg = (int)strtol(arg, &p, 10);
185 100
                if (*p != '\0' || vut->k_arg <= 0)
186 25
                        VUT_Error(vut, 1, "-k: Invalid number '%s'", arg);
187 75
                return (1);
188
        case 'n':
189
                /* Varnish instance name */
190 2200
                AN(arg);
191 2200
                REPLACE(vut->n_arg, arg);
192 2200
                return (1);
193
        case 'P':
194
                /* PID file */
195 100
                AN(arg);
196 100
                REPLACE(vut->P_arg, arg);
197 100
                return (1);
198
        case 'Q':
199 200
                AN(arg);
200 200
                p = VFIL_readfile(NULL, arg, NULL);
201 200
                if (p == NULL)
202 25
                        VUT_Error(vut, 1, "-Q %s: %s", arg, strerror(errno));
203 175
                vut_arg_q(vut, p);
204 175
                free(p);
205 175
                return (1);
206
        case 'q':
207
                /* Query to use */
208 1300
                AN(arg);
209 1300
                vut_arg_q(vut, arg);
210 1300
                return (1);
211
        case 'r':
212
                /* Binary file input */
213 200
                AN(arg);
214 200
                REPLACE(vut->r_arg, arg);
215 200
                return (1);
216
        case 't':
217
                /* VSM connect timeout */
218 100
                REPLACE(vut->t_arg, arg);
219 100
                return (1);
220
        case 'V':
221
                /* Print version number and exit */
222 125
                VCS_Message(vut->progname);
223 125
                exit(0);
224
        default:
225 3325
                AN(vut->vsl);
226 3325
                i = VSL_Arg(vut->vsl, opt, arg);
227 3325
                if (i < 0)
228 450
                        VUT_Error(vut, 1, "%s", VSL_Error(vut->vsl));
229 2875
                return (i);
230
        }
231 9250
}
232
233
struct VUT *
234 5650
VUT_Init(const char *progname, int argc, char * const *argv,
235
    const struct vopt_spec *voc)
236
{
237
        struct VUT *vut;
238
239 5650
        AN(progname);
240 5650
        AN(argv);
241 5650
        AN(voc);
242
243 5650
        VSIG_Arm_hup();
244 5650
        VSIG_Arm_int();
245 5650
        VSIG_Arm_term();
246 5650
        VSIG_Arm_usr1();
247
248 5650
        if (argc == 2 && !strcmp(argv[1], "--synopsis"))
249 125
                exit(vut_synopsis(voc));
250 5525
        if (argc == 2 && !strcmp(argv[1], "--options"))
251 125
                exit(vut_options(voc));
252 5400
        if (argc == 2 && !strcmp(argv[1], "--optstring")) {
253 0
                (void)printf("%s\n", voc->vopt_optstring);
254 0
                exit(0);
255
        }
256
257 5400
        ALLOC_OBJ(vut, VUT_MAGIC);
258 5400
        AN(vut);
259 5400
        vut->progname = progname;
260 5400
        vut->g_arg = VSL_g_vxid;
261 5400
        vut->k_arg = -1;
262 5400
        AZ(vut->vsl);
263 5400
        vut->vsl = VSL_New();
264 5400
        AN(vut->vsl);
265 5400
        return (vut);
266
}
267
268
void
269 0
VUT_Signal(VUT_sighandler_f sig_cb)
270
{
271
272 0
        AN(sig_cb);
273 0
        (void)signal(SIGHUP, sig_cb);
274 0
        (void)signal(SIGINT, sig_cb);
275 0
        (void)signal(SIGTERM, sig_cb);
276 0
        (void)signal(SIGUSR1, sig_cb);
277 0
}
278
279
void
280 0
VUT_Signaled(struct VUT *vut, int sig)
281
{
282
283 0
        CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
284
#define VSIG_SIGNAL(UPPER, lower) \
285
        VSIG_##lower += (int)(sig == SIG##UPPER);
286
#include "tbl/vsig_list.h"
287 0
}
288
289
void
290 2875
VUT_Setup(struct VUT *vut)
291
{
292
        struct VSL_cursor *c;
293
294 2875
        CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
295 2875
        AN(vut->vsl);
296 2875
        AZ(vut->vsm);
297 2875
        AZ(vut->vslq);
298
299
        /* Check input arguments (2 used for bug in FlexeLint) */
300 8625
        if ((vut->n_arg == NULL ? 0 : 2) +
301 5750
            (vut->r_arg == NULL ? 0 : 2) > 2)
302 25
                VUT_Error(vut, 1, "Only one of -n and -r options may be used");
303
304 2850
        if (vut->r_arg != NULL && !strcmp(vut->r_arg, "-") && vut->D_opt)
305 0
                VUT_Error(vut, 1, "Daemon cannot read from stdin");
306
307
        /* Create and validate the query expression */
308 5700
        vut->vslq = VSLQ_New(vut->vsl, NULL,
309 2850
            (enum VSL_grouping_e)vut->g_arg, vut->q_arg);
310 2850
        if (vut->vslq == NULL)
311 1600
                VUT_Error(vut, 1, "Query expression error:\n%s",
312 800
                    VSL_Error(vut->vsl));
313
314
        /* Setup input */
315 2050
        if (vut->r_arg) {
316 175
                c = VSL_CursorFile(vut->vsl, vut->r_arg, 0);
317 175
                if (c == NULL)
318 50
                        VUT_Error(vut, 1, "%s", VSL_Error(vut->vsl));
319 125
                VSLQ_SetCursor(vut->vslq, &c);
320 125
                AZ(c);
321 125
        } else {
322 1875
                vut->vsm = VSM_New();
323 1875
                AN(vut->vsm);
324 1875
                if (vut->n_arg && VSM_Arg(vut->vsm, 'n', vut->n_arg) <= 0)
325 0
                        VUT_Error(vut, 1, "%s", VSM_Error(vut->vsm));
326 1875
                if (vut->t_arg && VSM_Arg(vut->vsm, 't', vut->t_arg) <= 0)
327 75
                        VUT_Error(vut, 1, "%s", VSM_Error(vut->vsm));
328 1800
                if (VSM_Attach(vut->vsm, STDERR_FILENO))
329 25
                        VUT_Error(vut, 1, "VSM: %s", VSM_Error(vut->vsm));
330
                // Cursor is handled in VUT_Main()
331
        }
332
333
        /* Open PID file */
334 1900
        if (vut->P_arg) {
335 100
                if (pfh != NULL)
336 0
                        VUT_Error(vut, 1, "PID file already created");
337 100
                pfh = VPF_Open(vut->P_arg, 0644, NULL);
338 100
                if (pfh == NULL)
339 0
                        VUT_Error(vut, 1,
340 0
                            "%s: %s", vut->P_arg, strerror(errno));
341 100
        }
342
343
        /* Daemon mode */
344 1900
        if (vut->D_opt && vut_daemon(vut) == -1)
345 0
                VUT_Error(vut, 1, "Daemon mode: %s", strerror(errno));
346
347
        /* Write PID and setup exit handler */
348 1900
        if (vut->P_arg) {
349 100
                AN(pfh);
350 100
                VPF_Write(pfh);
351
352
                /* NB: move ownership to a global pseudo-VUT. */
353 100
                INIT_OBJ(&pfh_vut, VUT_MAGIC);
354 100
                pfh_vut.P_arg = vut->P_arg;
355 100
                pfh_vut.error_f = vut->error_f;
356 100
                vut->P_arg = NULL;
357
358 100
                AZ(atexit(vut_vpf_remove));
359 100
        }
360 1900
}
361
362
void
363 1900
VUT_Fini(struct VUT **vutp)
364
{
365
        struct VUT *vut;
366
367 1900
        TAKE_OBJ_NOTNULL(vut, vutp, VUT_MAGIC);
368 1900
        AN(vut->progname);
369
370 1900
        free(vut->n_arg);
371 1900
        free(vut->q_arg);
372 1900
        free(vut->r_arg);
373 1900
        free(vut->t_arg);
374 1900
        AZ(vut->P_arg);
375
376 1900
        if (vut->vslq)
377 1900
                VSLQ_Delete(&vut->vslq);
378 1900
        if (vut->vsl)
379 1900
                VSL_Delete(vut->vsl);
380 1900
        if (vut->vsm)
381 1775
                VSM_Destroy(&vut->vsm);
382
383 1900
        FREE_OBJ(vut);
384 1900
}
385
386
static void
387 0
vut_CursorError(struct VUT *vut, vtim_mono *last)
388
{
389
        const char *diag;
390
        vtim_mono now;
391
392 0
        CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
393 0
        AN(vut->vsl);
394 0
        AN(last);
395
396 0
        diag = VSL_Error(vut->vsl);
397 0
        if (diag == NULL)
398 0
                diag = "Missing diagnostic";
399
400 0
        now = VTIM_mono();
401 0
        if (isnan(*last) || *last + 1 < now) {
402 0
                fprintf(stderr, "Failed to acquire log: %s\n", diag);
403 0
                *last = now;
404 0
        }
405 0
}
406
407
int
408 1900
VUT_Main(struct VUT *vut)
409
{
410
        struct VSL_cursor *c;
411 1900
        int i = -1;
412 1900
        int hascursor = -1;
413 1900
        vtim_mono t_failcursor = NAN;
414
415 1900
        CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
416 1900
        AN(vut->vslq);
417
418 176142
        while (!VSIG_int && !VSIG_term) {
419 175842
                if (VSIG_hup != vut->last_sighup) {
420
                        /* sighup callback */
421 100
                        vut->last_sighup = VSIG_hup;
422 100
                        if (vut->sighup_f != NULL)
423 50
                                i = vut->sighup_f(vut);
424
                        else
425 50
                                i = 1;
426 100
                        if (i)
427 50
                                break;
428 50
                }
429
430 175792
                if (VSIG_usr1 != vut->last_sigusr1) {
431
                        /* Flush and report any incomplete records */
432 0
                        vut->last_sigusr1 = VSIG_usr1;
433 0
                        (void)VSLQ_Flush(vut->vslq, vut_dispatch, vut);
434 0
                }
435
436
                /* We must repeatedly call VSM_Status() when !hascursor
437
                 * to make VSM discover our segment.
438
                 *
439
                 * XXX consider moving the error handling to VSLQ_Dispatch.
440
                 * or some other VSL utility function
441
                 * Reasons:
442
                 *
443
                 * - it does not seem to make much sense to call VSM_StillValid
444
                 *   in vsl if that can only detect invalid segments after
445
                 *   VSM_Status has run, so it appears both should be
446
                 *   consolidated
447
                 *
448
                 * - not all VSL Clients will use VUT, yet the log abandoned/
449
                 *   overrun situation will be occur for all of them.
450
                 */
451
452 175792
                if (vut->vsm != NULL &&
453 175667
                    (VSM_Status(vut->vsm) & VSM_WRK_RESTARTED)) {
454 0
                        if (hascursor < 1) {
455 0
                                fprintf(stderr, "Log abandoned (vsm)\n");
456 0
                                VSLQ_SetCursor(vut->vslq, NULL);
457 0
                                hascursor = 0;
458 0
                        }
459 0
                }
460 175792
                if (vut->vsm != NULL && hascursor < 1) {
461
                        /* Reconnect VSM */
462 1775
                        AZ(vut->r_arg);
463 1775
                        VTIM_sleep(0.1);
464 3550
                        c = VSL_CursorVSM(vut->vsl, vut->vsm,
465 1775
                            (vut->d_opt ? VSL_COPT_TAILSTOP : VSL_COPT_TAIL)
466 1775
                            | VSL_COPT_BATCH);
467 1775
                        if (c == NULL) {
468 0
                                vut_CursorError(vut, &t_failcursor);
469 0
                                VSL_ResetError(vut->vsl);
470 0
                                continue;
471
                        }
472 1775
                        if (hascursor >= 0)
473 0
                                fprintf(stderr, "Log reacquired\n");
474 1775
                        hascursor = 1;
475 1775
                        VSLQ_SetCursor(vut->vslq, &c);
476 1775
                        AZ(c);
477 1775
                }
478
479 175792
                do
480 444120
                        i = VSLQ_Dispatch(vut->vslq, vut_dispatch, vut);
481 268328
                while (i == vsl_more &&
482 92536
                    VSIG_usr1 == vut->last_sigusr1 &&
483 92536
                    VSIG_hup == vut->last_sighup);
484
485 175792
                if (i == vsl_more)
486 0
                        continue;
487 175792
                else if (i == vsl_end) {
488 174242
                        if (vut->idle_f) {
489 76820
                                i = vut->idle_f(vut);
490 76820
                                if (i)
491 0
                                        break;
492 76820
                        }
493 174242
                        VTIM_sleep(0.01);
494 174242
                        continue;
495 1550
                } else if (i == vsl_e_eof)
496 1550
                        break;
497
498 0
                if (vut->vsm == NULL)
499 0
                        break;
500
501
                /* XXX: Make continuation optional */
502
503 0
                (void)VSLQ_Flush(vut->vslq, vut_dispatch, vut);
504
505 0
                if (i == vsl_e_abandon) {
506 0
                        fprintf(stderr, "Log abandoned (vsl)\n");
507 0
                        VSLQ_SetCursor(vut->vslq, NULL);
508 0
                        hascursor = 0;
509 0
                } else if (i == vsl_e_overrun) {
510 0
                        fprintf(stderr, "Log overrun\n");
511 0
                        VSLQ_SetCursor(vut->vslq, NULL);
512 0
                        hascursor = 0;
513 0
                } else
514 0
                        fprintf(stderr, "Error %d from VSLQ_Dispatch()", i);
515
        }
516
517 1900
        return (i);
518
}
519
520
/**********************************************************************/
521
522
void v_noreturn_
523 250
VUT_Usage(const struct VUT *vut, const struct vopt_spec *voc, int status)
524
{
525
        const char **opt;
526
527 250
        fprintf(stderr, "Usage: %s <options>\n\n", vut->progname);
528 250
        fprintf(stderr, "Options:\n");
529 6100
        for (opt = voc->vopt_usage; *opt != NULL; opt += 2)
530 5850
                fprintf(stderr, " %-25s %s\n", *opt, *(opt + 1));
531 250
        exit(status);
532
}
533
534
/**********************************************************************/
535
536
537
static void
538 2675
print_nobrackets(const char *s)
539
{
540
        const char *e;
541
542
        /* Remove whitespace */
543 2675
        while (isspace(*s))
544 0
                s++;
545 2675
        e = s + strlen(s);
546 2675
        while (e > s && isspace(e[-1]))
547 0
                e--;
548
549
        /* Remove outer layer brackets if present */
550 2675
        if (e > s && *s == '[' && e[-1] == ']') {
551 2675
                s++;
552 2675
                e--;
553 2675
        }
554
555 2675
        printf("%.*s", (int)(e - s), s);
556 2675
}
557
558
static void
559 2675
print_tabbed(const char *string, int tabs)
560
{
561
        int i;
562
        const char *c;
563
564 415175
        for (c = string; *c; c++) {
565 412500
                if (c == string || *(c - 1) == '\n')
566 5750
                        for (i = 0; i < tabs; i++)
567 5750
                                printf("\t");
568 412500
                printf("%c", *c);
569 412500
        }
570 2675
}
571
572
static void
573 2675
print_opt(const struct vopt_list *opt)
574
{
575 2675
        print_nobrackets(opt->synopsis);
576 2675
        printf("\n\n");
577 2675
        print_tabbed(opt->ldesc, 1);
578 2675
        printf("\n\n");
579 2675
}
580
581
static int
582 125
vut_synopsis(const struct vopt_spec *voc)
583
{
584 125
        printf(".. |synopsis| replace:: %s\n", voc->vopt_synopsis);
585 125
        return (0);
586
}
587
588
static int
589 125
vut_options(const struct vopt_spec *voc)
590
{
591
        int i;
592
593 2800
        for (i = 0; i < voc->vopt_list_n; i++)
594 2675
                print_opt(&voc->vopt_list[i]);
595 125
        printf("--optstring\n"
596
            "\tPrint the optstring parameter to ``getopt(3)`` to help"
597
            " writing wrapper scripts.\n\n");
598 125
        return (0);
599
}