varnish-cache/lib/libvarnishapi/vut.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2015 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Martin Blix Grydeland <martin@varnish-software.com>
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 *
29
 * Common functions for the utilities
30
 */
31
32
#include "config.h"
33
34
#include <ctype.h>
35
#include <stdint.h>
36
#include <stdarg.h>
37
#include <stdlib.h>
38
#include <unistd.h>
39
#include <stdio.h>
40
#include <errno.h>
41
#include <string.h>
42
#include <signal.h>
43
#include <math.h>
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
55
#include "vut.h"
56
57
#include "vapi/voptget.h"
58
59
static int vut_synopsis(const struct vopt_spec *);
60
static int vut_options(const struct vopt_spec *);
61
62
static struct vpf_fh    *pfh;
63
static unsigned         daemonized;
64
65
static int
66 2
vut_daemon(struct VUT *vut)
67
{
68 2
        if (daemonized)
69 0
                VUT_Error(vut, 1, "Already running as a daemon");
70 2
        daemonized = 1;
71 2
        return (varnish_daemon(0, 0));
72
}
73
74
static void
75 19
vut_vpf_remove(void)
76
{
77 19
        if (pfh != NULL) {
78 2
                AZ(VPF_Remove(pfh));
79 2
                pfh = NULL;
80
        }
81 19
}
82
83
static int v_matchproto_(VSLQ_dispatch_f)
84 120
vut_dispatch(struct VSL_data *vsl, struct VSL_transaction * const trans[],
85
    void *priv)
86
{
87
        struct VUT *vut;
88
        int i;
89
90 120
        CAST_OBJ_NOTNULL(vut, priv, VUT_MAGIC);
91
92 120
        if (vut->k_arg == 0)
93 0
                return (-1);    /* End of file */
94 120
        AN(vut->dispatch_f);
95 120
        i = vut->dispatch_f(vsl, trans, vut->dispatch_priv);
96 120
        if (vut->k_arg > 0)
97 3
                vut->k_arg--;
98 120
        if (i >= 0 && vut->k_arg == 0)
99 1
                return (-1);    /* End of file */
100 119
        return (i);
101
}
102
103
//lint -sem(vut_error, r_no)
104
static void v_noreturn_ v_matchproto_(VUT_error_f)
105 55
vut_error(struct VUT *vut, int status, const char *fmt, va_list ap)
106
{
107
108 55
        CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
109 55
        AN(fmt);
110 55
        vfprintf(stderr, fmt, ap);
111 55
        fprintf(stderr, "\n");
112
113 55
        exit(status);
114
}
115
116
void
117 55
VUT_Error(struct VUT *vut, int status, const char *fmt, ...)
118
{
119
        va_list ap;
120
121 55
        CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
122 55
        AN(vut->error_f);
123 55
        AN(status);
124
125 55
        va_start(ap, fmt);
126 55
        vut->error_f(vut, status, fmt, ap);
127 0
        va_end(ap);
128 0
}
129
130
int
131 101
VUT_Arg(struct VUT *vut, int opt, const char *arg)
132
{
133
        int i;
134
        char *p;
135
136 101
        switch (opt) {
137
        case 'd':
138
                /* Head */
139 21
                vut->d_opt = 1;
140 21
                return (1);
141
        case 'D':
142
                /* Daemon mode */
143 4
                vut->D_opt = 1;
144 4
                return (1);
145
        case 'g':
146
                /* Grouping */
147 8
                AN(arg);
148 8
                vut->g_arg = VSLQ_Name2Grouping(arg, -1);
149 8
                if (vut->g_arg == -2)
150 1
                        VUT_Error(vut, 1, "Ambiguous grouping type: %s", arg);
151 7
                else if (vut->g_arg < 0)
152 1
                        VUT_Error(vut, 1, "Unknown grouping type: %s", arg);
153 6
                return (1);
154
        case 'k':
155
                /* Log transaction limit */
156 2
                AN(arg);
157 2
                vut->k_arg = (int)strtol(arg, &p, 10);
158 2
                if (*p != '\0' || vut->k_arg <= 0)
159 1
                        VUT_Error(vut, 1, "-k: Invalid number '%s'", arg);
160 1
                return (1);
161
        case 'n':
162
                /* Varnish instance name */
163 24
                AN(arg);
164 24
                REPLACE(vut->n_arg, arg);
165 24
                return (1);
166
        case 'P':
167
                /* PID file */
168 2
                AN(arg);
169 2
                REPLACE(vut->P_arg, arg);
170 2
                return (1);
171
        case 'q':
172
                /* Query to use */
173 10
                AN(arg);
174 10
                REPLACE(vut->q_arg, arg);
175 10
                return (1);
176
        case 'r':
177
                /* Binary file input */
178 4
                AN(arg);
179 4
                REPLACE(vut->r_arg, arg);
180 4
                return (1);
181
        case 't':
182
                /* VSM connect timeout */
183 3
                REPLACE(vut->t_arg, arg);
184 3
                return (1);
185
        case 'V':
186
                /* Print version number and exit */
187 5
                VCS_Message(vut->progname);
188 5
                exit(0);
189
        default:
190 18
                AN(vut->vsl);
191 18
                i = VSL_Arg(vut->vsl, opt, arg);
192 18
                if (i < 0)
193 9
                        VUT_Error(vut, 1, "%s", VSL_Error(vut->vsl));
194 9
                return (i);
195
        }
196
}
197
198
struct VUT *
199 106
VUT_Init(const char *progname, int argc, char * const *argv,
200
    const struct vopt_spec *voc)
201
{
202
        struct VUT *vut;
203
204 106
        AN(progname);
205 106
        AN(argv);
206 106
        AN(voc);
207
208 106
        ALLOC_OBJ(vut, VUT_MAGIC);
209 106
        AN(vut);
210
211 106
        if (argc == 2 && !strcmp(argv[1], "--synopsis"))
212 5
                exit(vut_synopsis(voc));
213 101
        if (argc == 2 && !strcmp(argv[1], "--options"))
214 5
                exit(vut_options(voc));
215 96
        if (argc == 2 && !strcmp(argv[1], "--optstring")) {
216 0
                (void)printf("%s\n", voc->vopt_optstring);
217 0
                exit(0);
218
        }
219
220 96
        vut->progname = progname;
221 96
        vut->g_arg = VSL_g_vxid;
222 96
        vut->k_arg = -1;
223 96
        vut->error_f = vut_error;
224 96
        AZ(vut->vsl);
225 96
        vut->vsl = VSL_New();
226 96
        AN(vut->vsl);
227 96
        return (vut);
228
}
229
230
void
231 30
VUT_Signal(VUT_sighandler_f sig_cb)
232
{
233
234 30
        AN(sig_cb);
235 30
        (void)signal(SIGHUP, sig_cb);
236 30
        (void)signal(SIGINT, sig_cb);
237 30
        (void)signal(SIGTERM, sig_cb);
238 30
        (void)signal(SIGUSR1, sig_cb);
239 30
}
240
241
void
242 4
VUT_Signaled(struct VUT *vut, int sig)
243
{
244
245 4
        CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
246 4
        vut->sighup |= (sig == SIGHUP);
247 4
        vut->sigint |= (sig == SIGINT || sig == SIGTERM);
248 4
        vut->sigusr1 |= (sig == SIGUSR1);
249 4
}
250
251
void
252 30
VUT_Setup(struct VUT *vut)
253
{
254
        struct VSL_cursor *c;
255
256 30
        CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
257 30
        AN(vut->vsl);
258 30
        AZ(vut->vsm);
259 30
        AZ(vut->vslq);
260
261
        /* Check input arguments (2 used for bug in FlexeLint) */
262 60
        if ((vut->n_arg == NULL ? 0 : 2) +
263 30
            (vut->r_arg == NULL ? 0 : 2) > 2)
264 1
                VUT_Error(vut, 1, "Only one of -n and -r options may be used");
265
266
        /* Create and validate the query expression */
267 29
        vut->vslq = VSLQ_New(vut->vsl, NULL, vut->g_arg, vut->q_arg);
268 29
        if (vut->vslq == NULL)
269 9
                VUT_Error(vut, 1, "Query expression error:\n%s",
270 9
                    VSL_Error(vut->vsl));
271
272
        /* Setup input */
273 20
        if (vut->r_arg) {
274 3
                c = VSL_CursorFile(vut->vsl, vut->r_arg, 0);
275 3
                if (c == NULL)
276 0
                        VUT_Error(vut, 1, "%s", VSL_Error(vut->vsl));
277 3
                VSLQ_SetCursor(vut->vslq, &c);
278 3
                AZ(c);
279
        } else {
280 17
                vut->vsm = VSM_New();
281 17
                AN(vut->vsm);
282 17
                if (vut->n_arg && VSM_Arg(vut->vsm, 'n', vut->n_arg) <= 0)
283 0
                        VUT_Error(vut, 1, "%s", VSM_Error(vut->vsm));
284 17
                if (vut->t_arg && VSM_Arg(vut->vsm, 't', vut->t_arg) <= 0)
285 3
                        VUT_Error(vut, 1, "%s", VSM_Error(vut->vsm));
286 14
                if (VSM_Attach(vut->vsm, STDERR_FILENO))
287 0
                        VUT_Error(vut, 1, "VSM: %s", VSM_Error(vut->vsm));
288
                // Cursor is handled in VUT_Main()
289
        }
290
291
        /* Open PID file */
292 17
        if (vut->P_arg) {
293 2
                if (pfh != NULL)
294 0
                        VUT_Error(vut, 1, "PID file already created");
295 2
                pfh = VPF_Open(vut->P_arg, 0644, NULL);
296 2
                if (pfh == NULL)
297 0
                        VUT_Error(vut, 1, "%s: %s", vut->P_arg, strerror(errno));
298
        }
299
300
        /* Daemon mode */
301 17
        if (vut->D_opt && vut_daemon(vut) == -1)
302 0
                VUT_Error(vut, 1, "Daemon mode: %s", strerror(errno));
303
304
        /* Write PID and setup exit handler */
305 17
        if (vut->P_arg) {
306 2
                AN(pfh);
307 2
                AZ(VPF_Write(pfh));
308 2
                AZ(atexit(vut_vpf_remove));
309
        }
310 17
}
311
312
void
313 17
VUT_Fini(struct VUT **vutp)
314
{
315
        struct VUT *vut;
316
317 17
        TAKE_OBJ_NOTNULL(vut, vutp, VUT_MAGIC);
318 17
        AN(vut->progname);
319
320 17
        free(vut->n_arg);
321 17
        free(vut->P_arg);
322 17
        free(vut->q_arg);
323 17
        free(vut->r_arg);
324 17
        free(vut->t_arg);
325
326 17
        vut_vpf_remove();
327 17
        AZ(pfh);
328
329 17
        if (vut->vslq)
330 17
                VSLQ_Delete(&vut->vslq);
331 17
        if (vut->vsl)
332 17
                VSL_Delete(vut->vsl);
333 17
        if (vut->vsm)
334 14
                VSM_Destroy(&vut->vsm);
335
336 17
        memset(vut, 0, sizeof *vut);
337 17
        FREE_OBJ(vut);
338 17
}
339
340
int
341 17
VUT_Main(struct VUT *vut)
342
{
343
        struct VSL_cursor *c;
344 17
        int i = -1;
345 17
        int hascursor = -1;
346
347 17
        CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
348 17
        AN(vut->vslq);
349
350 1967
        while (!vut->sigint) {
351 1948
                if (vut->sighup && vut->sighup_f) {
352
                        /* sighup callback */
353 2
                        vut->sighup = 0;
354 2
                        i = vut->sighup_f(vut);
355 2
                        if (i)
356 0
                                break;
357
                }
358
359 1948
                if (vut->sigusr1) {
360
                        /* Flush and report any incomplete records */
361 0
                        vut->sigusr1 = 0;
362 0
                        (void)VSLQ_Flush(vut->vslq, vut_dispatch, vut);
363
                }
364
365
                // We must repeatedly call VSM_Status() when !hascursor
366
                // to make VSM discover our segment.
367 3677
                if (vut->vsm != NULL &&
368 1729
                    (VSM_Status(vut->vsm) & VSM_WRK_RESTARTED)) {
369 0
                        if (hascursor < 1) {
370 0
                                fprintf(stderr, "Log abandoned (vsm)\n");
371 0
                                VSLQ_SetCursor(vut->vslq, NULL);
372 0
                                hascursor = 0;
373
                        }
374
                }
375 1948
                if (vut->vsm != NULL && hascursor < 1) {
376
                        /* Reconnect VSM */
377 14
                        AZ(vut->r_arg);
378 14
                        VTIM_sleep(0.1);
379 14
                        c = VSL_CursorVSM(vut->vsl, vut->vsm,
380 14
                            (vut->d_opt ? VSL_COPT_TAILSTOP : VSL_COPT_TAIL)
381
                            | VSL_COPT_BATCH);
382 14
                        if (c == NULL) {
383 0
                                VSL_ResetError(vut->vsl);
384 0
                                continue;
385
                        }
386 14
                        if (hascursor >= 0)
387 0
                                fprintf(stderr, "Log reacquired\n");
388 14
                        hascursor = 1;
389 14
                        VSLQ_SetCursor(vut->vslq, &c);
390 14
                        AZ(c);
391
                }
392
393 1948
                i = VSLQ_Dispatch(vut->vslq, vut_dispatch, vut);
394 1948
                if (i == 1)
395
                        /* Call again */
396 537
                        continue;
397 1411
                else if (i == 0) {
398
                        /* Nothing to do but wait */
399 1396
                        if (vut->idle_f) {
400 1396
                                i = vut->idle_f(vut);
401 1396
                                if (i)
402 0
                                        break;
403
                        }
404 1396
                        VTIM_sleep(0.01);
405 1396
                        continue;
406 15
                } else if (i == -1) {
407
                        /* EOF */
408 15
                        break;
409
                }
410
411 0
                if (vut->vsm == NULL)
412 0
                        break;
413
414
                /* XXX: Make continuation optional */
415
416 0
                (void)VSLQ_Flush(vut->vslq, vut_dispatch, vut);
417
418 0
                if (i == -2) {
419
                        /* Abandoned */
420 0
                        fprintf(stderr, "Log abandoned (vsl)\n");
421 0
                        VSLQ_SetCursor(vut->vslq, NULL);
422 0
                        hascursor = 0;
423 0
                } else if (i < -2)
424
                        /* Overrun */
425 0
                        fprintf(stderr, "Log overrun\n");
426
        }
427
428 17
        return (i);
429
}
430
431
/**********************************************************************/
432
433
434
static void
435 91
print_nobrackets(const char *s)
436
{
437
        const char *e;
438
439
        /* Remove whitespace */
440 182
        while (isspace(*s))
441 0
                s++;
442 91
        e = s + strlen(s);
443 182
        while (e > s && isspace(e[-1]))
444 0
                e--;
445
446
        /* Remove outer layer brackets if present */
447 91
        if (e > s && *s == '[' && e[-1] == ']') {
448 91
                s++;
449 91
                e--;
450
        }
451
452 91
        printf("%.*s", (int)(e - s), s);
453 91
}
454
455
static void
456 91
print_tabbed(const char *string, int tabs)
457
{
458
        int i;
459
        const char *c;
460
461 11746
        for (c = string; *c; c++) {
462 11655
                if (c == string || *(c - 1) == '\n')
463 198
                        for (i = 0; i < tabs; i++)
464 99
                                printf("\t");
465 11655
                printf("%c", *c);
466
        }
467 91
}
468
469
static void
470 91
print_opt(const struct vopt_list *opt)
471
{
472 91
        print_nobrackets(opt->synopsis);
473 91
        printf("\n\n");
474 91
        print_tabbed(opt->ldesc, 1);
475 91
        printf("\n\n");
476 91
}
477
478
static int
479 5
vut_synopsis(const struct vopt_spec *voc)
480
{
481 5
        printf(".. |synopsis| replace:: %s\n", voc->vopt_synopsis);
482 5
        return (0);
483
}
484
485
static int
486 5
vut_options(const struct vopt_spec *voc)
487
{
488
        int i;
489
490 96
        for (i = 0; i < voc->vopt_list_n; i++)
491 91
                print_opt(&voc->vopt_list[i]);
492 5
        printf("--optstring\n"
493
            "\tPrint the optstring parameter to ``getopt(3)`` to help"
494
            " writing wrapper scripts.\n\n");
495 5
        return (0);
496
}