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 * SPDX-License-Identifier: BSD-2-Clause
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * Common functions for the utilities
32 */
33
34 #include "config.h"
35
36 #include <ctype.h>
37 #include <math.h>
38 #include <stdint.h>
39 #include <stdarg.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <sys/stat.h> /* for MUSL */
45
46 #include "compat/daemon.h"
47 #include "vdef.h"
48 #include "vpf.h"
49 #include "vapi/vsm.h"
50 #include "vapi/vsl.h"
51 #include "vtim.h"
52 #include "vas.h"
53 #include "miniobj.h"
54 #include "vcs.h"
55 #include "vsb.h"
56 #include "vfil.h"
57
58 #include "vapi/voptget.h"
59 #include "vapi/vsig.h"
60
61 #include "vut.h"
62
63
64 static int vut_synopsis(const struct vopt_spec *);
65 static int vut_options(const struct vopt_spec *);
66
67 static struct vpf_fh *pfh;
68 static unsigned daemonized;
69
70 static struct VUT pfh_vut;
71
72 static int
vut_daemon(struct VUT * vut)73 vut_daemon(struct VUT *vut)
74 {
75 if (daemonized)
76 VUT_Error(vut, 1, "Already running as a daemon");
77 daemonized = 1;
78 return (varnish_daemon(0, 0));
79 }
80
81 static void
vut_vpf_remove(void)82 vut_vpf_remove(void)
83 {
84
85 CHECK_OBJ(&pfh_vut, VUT_MAGIC);
86 AN(pfh);
87 AN(pfh_vut.P_arg);
88
89 VPF_Remove(pfh);
90 free(pfh_vut.P_arg);
91 ZERO_OBJ(&pfh_vut, sizeof pfh_vut);
92 pfh = NULL;
93 }
94
v_matchproto_(VSLQ_dispatch_f)95 static int v_matchproto_(VSLQ_dispatch_f)
96 vut_dispatch(struct VSL_data *vsl, struct VSL_transaction * const trans[],
97 void *priv)
98 {
99 struct VUT *vut;
100 int i;
101
102 CAST_OBJ_NOTNULL(vut, priv, VUT_MAGIC);
103
104 if (vut->k_arg == 0)
105 return (-1); /* End of file */
106 AN(vut->dispatch_f);
107 i = vut->dispatch_f(vsl, trans, vut->dispatch_priv);
108 if (vut->k_arg > 0)
109 vut->k_arg--;
110 if (i >= 0 && vut->k_arg == 0)
111 return (-1); /* End of file */
112 return (i);
113 }
114
115 void
VUT_Error(struct VUT * vut,int status,const char * fmt,...)116 VUT_Error(struct VUT *vut, int status, const char *fmt, ...)
117 {
118 va_list ap;
119
120 CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
121 AN(status);
122
123 va_start(ap, fmt);
124 if (vut->error_f != NULL) {
125 vut->error_f(vut, status, fmt, ap);
126 } else {
127 vfprintf(stderr, fmt, ap);
128 fprintf(stderr, "\n");
129 }
130 va_end(ap);
131 exit(status);
132 }
133
134 static void
vut_arg_q(struct VUT * vut,const char * arg)135 vut_arg_q(struct VUT *vut, const char *arg)
136 {
137 struct vsb *vsb;
138
139 AN(arg);
140 if (vut->q_arg == NULL) {
141 REPLACE(vut->q_arg, arg);
142 return;
143 }
144
145 vsb = VSB_new_auto();
146 AN(vsb);
147 AZ(VSB_printf(vsb, "%s\n%s", vut->q_arg, arg));
148 AZ(VSB_finish(vsb));
149
150 REPLACE(vut->q_arg, VSB_data(vsb));
151
152 VSB_destroy(&vsb);
153 }
154
155 int
VUT_Arg(struct VUT * vut,int opt,const char * arg)156 VUT_Arg(struct VUT *vut, int opt, const char *arg)
157 {
158 int i;
159 char *p;
160
161 CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
162 AN(opt);
163
164 switch (opt) {
165 case 'd':
166 /* Head */
167 vut->d_opt = 1;
168 return (1);
169 case 'D':
170 /* Daemon mode */
171 vut->D_opt = 1;
172 return (1);
173 case 'g':
174 /* Grouping */
175 AN(arg);
176 vut->g_arg = VSLQ_Name2Grouping(arg, -1);
177 if (vut->g_arg == -2)
178 VUT_Error(vut, 1, "Ambiguous grouping type: %s", arg);
179 else if (vut->g_arg < 0)
180 VUT_Error(vut, 1, "Unknown grouping type: %s", arg);
181 return (1);
182 case 'k':
183 /* Log transaction limit */
184 AN(arg);
185 vut->k_arg = (int)strtol(arg, &p, 10);
186 if (*p != '\0' || vut->k_arg <= 0)
187 VUT_Error(vut, 1, "-k: Invalid number '%s'", arg);
188 return (1);
189 case 'n':
190 /* Varnish instance name */
191 AN(arg);
192 REPLACE(vut->n_arg, arg);
193 return (1);
194 case 'P':
195 /* PID file */
196 AN(arg);
197 REPLACE(vut->P_arg, arg);
198 return (1);
199 case 'Q':
200 AN(arg);
201 p = VFIL_readfile(NULL, arg, NULL);
202 if (p == NULL)
203 VUT_Error(vut, 1, "-Q %s: %s", arg, strerror(errno));
204 vut_arg_q(vut, p);
205 free(p);
206 return (1);
207 case 'q':
208 /* Query to use */
209 AN(arg);
210 vut_arg_q(vut, arg);
211 return (1);
212 case 'r':
213 /* Binary file input */
214 AN(arg);
215 REPLACE(vut->r_arg, arg);
216 return (1);
217 case 't':
218 /* VSM connect timeout */
219 REPLACE(vut->t_arg, arg);
220 return (1);
221 case 'V':
222 /* Print version number and exit */
223 VCS_Message(vut->progname);
224 exit(0);
225 default:
226 AN(vut->vsl);
227 i = VSL_Arg(vut->vsl, opt, arg);
228 if (i < 0)
229 VUT_Error(vut, 1, "%s", VSL_Error(vut->vsl));
230 return (i);
231 }
232 }
233
234 struct VUT *
VUT_Init(const char * progname,int argc,char * const * argv,const struct vopt_spec * voc)235 VUT_Init(const char *progname, int argc, char * const *argv,
236 const struct vopt_spec *voc)
237 {
238 struct VUT *vut;
239
240 AN(progname);
241 AN(argv);
242 AN(voc);
243
244 VSIG_Arm_hup();
245 VSIG_Arm_int();
246 VSIG_Arm_term();
247 VSIG_Arm_usr1();
248
249 ALLOC_OBJ(vut, VUT_MAGIC);
250 AN(vut);
251
252 if (argc == 2 && !strcmp(argv[1], "--synopsis"))
253 exit(vut_synopsis(voc));
254 if (argc == 2 && !strcmp(argv[1], "--options"))
255 exit(vut_options(voc));
256 if (argc == 2 && !strcmp(argv[1], "--optstring")) {
257 (void)printf("%s\n", voc->vopt_optstring);
258 exit(0);
259 }
260
261 vut->progname = progname;
262 vut->g_arg = VSL_g_vxid;
263 vut->k_arg = -1;
264 AZ(vut->vsl);
265 vut->vsl = VSL_New();
266 AN(vut->vsl);
267 return (vut);
268 }
269
270 void
VUT_Signal(VUT_sighandler_f sig_cb)271 VUT_Signal(VUT_sighandler_f sig_cb)
272 {
273
274 AN(sig_cb);
275 (void)signal(SIGHUP, sig_cb);
276 (void)signal(SIGINT, sig_cb);
277 (void)signal(SIGTERM, sig_cb);
278 (void)signal(SIGUSR1, sig_cb);
279 }
280
281 void
VUT_Signaled(struct VUT * vut,int sig)282 VUT_Signaled(struct VUT *vut, int sig)
283 {
284
285 CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
286 #define VSIG_SIGNAL(UPPER, lower) \
287 VSIG_##lower += (int)(sig == SIG##UPPER);
288 #include "tbl/vsig_list.h"
289 }
290
291 void
VUT_Setup(struct VUT * vut)292 VUT_Setup(struct VUT *vut)
293 {
294 struct VSL_cursor *c;
295
296 CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
297 AN(vut->vsl);
298 AZ(vut->vsm);
299 AZ(vut->vslq);
300
301 /* Check input arguments (2 used for bug in FlexeLint) */
302 if ((vut->n_arg == NULL ? 0 : 2) +
303 (vut->r_arg == NULL ? 0 : 2) > 2)
304 VUT_Error(vut, 1, "Only one of -n and -r options may be used");
305
306 /* Create and validate the query expression */
307 vut->vslq = VSLQ_New(vut->vsl, NULL,
308 (enum VSL_grouping_e)vut->g_arg, vut->q_arg);
309 if (vut->vslq == NULL)
310 VUT_Error(vut, 1, "Query expression error:\n%s",
311 VSL_Error(vut->vsl));
312
313 /* Setup input */
314 if (vut->r_arg) {
315 c = VSL_CursorFile(vut->vsl, vut->r_arg, 0);
316 if (c == NULL)
317 VUT_Error(vut, 1, "%s", VSL_Error(vut->vsl));
318 VSLQ_SetCursor(vut->vslq, &c);
319 AZ(c);
320 } else {
321 vut->vsm = VSM_New();
322 AN(vut->vsm);
323 if (vut->n_arg && VSM_Arg(vut->vsm, 'n', vut->n_arg) <= 0)
324 VUT_Error(vut, 1, "%s", VSM_Error(vut->vsm));
325 if (vut->t_arg && VSM_Arg(vut->vsm, 't', vut->t_arg) <= 0)
326 VUT_Error(vut, 1, "%s", VSM_Error(vut->vsm));
327 if (VSM_Attach(vut->vsm, STDERR_FILENO))
328 VUT_Error(vut, 1, "VSM: %s", VSM_Error(vut->vsm));
329 // Cursor is handled in VUT_Main()
330 }
331
332 /* Open PID file */
333 if (vut->P_arg) {
334 if (pfh != NULL)
335 VUT_Error(vut, 1, "PID file already created");
336 pfh = VPF_Open(vut->P_arg, 0644, NULL);
337 if (pfh == NULL)
338 VUT_Error(vut, 1,
339 "%s: %s", vut->P_arg, strerror(errno));
340 }
341
342 /* Daemon mode */
343 if (vut->D_opt && vut_daemon(vut) == -1)
344 VUT_Error(vut, 1, "Daemon mode: %s", strerror(errno));
345
346 /* Write PID and setup exit handler */
347 if (vut->P_arg) {
348 AN(pfh);
349 VPF_Write(pfh);
350
351 /* NB: move ownership to a global pseudo-VUT. */
352 INIT_OBJ(&pfh_vut, VUT_MAGIC);
353 pfh_vut.P_arg = vut->P_arg;
354 pfh_vut.error_f = vut->error_f;
355 vut->P_arg = NULL;
356
357 AZ(atexit(vut_vpf_remove));
358 }
359 }
360
361 void
VUT_Fini(struct VUT ** vutp)362 VUT_Fini(struct VUT **vutp)
363 {
364 struct VUT *vut;
365
366 TAKE_OBJ_NOTNULL(vut, vutp, VUT_MAGIC);
367 AN(vut->progname);
368
369 free(vut->n_arg);
370 free(vut->q_arg);
371 free(vut->r_arg);
372 free(vut->t_arg);
373 AZ(vut->P_arg);
374
375 if (vut->vslq)
376 VSLQ_Delete(&vut->vslq);
377 if (vut->vsl)
378 VSL_Delete(vut->vsl);
379 if (vut->vsm)
380 VSM_Destroy(&vut->vsm);
381
382 memset(vut, 0, sizeof *vut);
383 FREE_OBJ(vut);
384 }
385
386 static void
vut_CursorError(struct VUT * vut,vtim_mono * last)387 vut_CursorError(struct VUT *vut, vtim_mono *last)
388 {
389 const char *diag;
390 vtim_mono now;
391
392 CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
393 AN(vut->vsl);
394 AN(last);
395
396 diag = VSL_Error(vut->vsl);
397 if (diag == NULL)
398 diag = "Missing diagnostic";
399
400 now = VTIM_mono();
401 if (isnan(*last) || *last + 1 < now) {
402 fprintf(stderr, "Failed to acquire log: %s\n", diag);
403 *last = now;
404 }
405 }
406
407 int
VUT_Main(struct VUT * vut)408 VUT_Main(struct VUT *vut)
409 {
410 struct VSL_cursor *c;
411 int i = -1;
412 int hascursor = -1;
413 vtim_mono t_failcursor = NAN;
414
415 CHECK_OBJ_NOTNULL(vut, VUT_MAGIC);
416 AN(vut->vslq);
417
418 while (!VSIG_int && !VSIG_term) {
419 if (VSIG_hup != vut->last_sighup) {
420 /* sighup callback */
421 vut->last_sighup = VSIG_hup;
422 if (vut->sighup_f != NULL)
423 i = vut->sighup_f(vut);
424 else
425 i = 1;
426 if (i)
427 break;
428 }
429
430 if (VSIG_usr1 != vut->last_sigusr1) {
431 /* Flush and report any incomplete records */
432 vut->last_sigusr1 = VSIG_usr1;
433 (void)VSLQ_Flush(vut->vslq, vut_dispatch, vut);
434 }
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 if (vut->vsm != NULL &&
453 (VSM_Status(vut->vsm) & VSM_WRK_RESTARTED)) {
454 if (hascursor < 1) {
455 fprintf(stderr, "Log abandoned (vsm)\n");
456 VSLQ_SetCursor(vut->vslq, NULL);
457 hascursor = 0;
458 }
459 }
460 if (vut->vsm != NULL && hascursor < 1) {
461 /* Reconnect VSM */
462 AZ(vut->r_arg);
463 VTIM_sleep(0.1);
464 c = VSL_CursorVSM(vut->vsl, vut->vsm,
465 (vut->d_opt ? VSL_COPT_TAILSTOP : VSL_COPT_TAIL)
466 | VSL_COPT_BATCH);
467 if (c == NULL) {
468 vut_CursorError(vut, &t_failcursor);
469 VSL_ResetError(vut->vsl);
470 continue;
471 }
472 if (hascursor >= 0)
473 fprintf(stderr, "Log reacquired\n");
474 hascursor = 1;
475 VSLQ_SetCursor(vut->vslq, &c);
476 AZ(c);
477 }
478
479 do
480 i = VSLQ_Dispatch(vut->vslq, vut_dispatch, vut);
481 while (i == vsl_more &&
482 VSIG_usr1 == vut->last_sigusr1 &&
483 VSIG_hup == vut->last_sighup);
484
485 if (i == vsl_more)
486 continue;
487 else if (i == vsl_end) {
488 if (vut->idle_f) {
489 i = vut->idle_f(vut);
490 if (i)
491 break;
492 }
493 VTIM_sleep(0.01);
494 continue;
495 } else if (i == vsl_e_eof)
496 break;
497
498 if (vut->vsm == NULL)
499 break;
500
501 /* XXX: Make continuation optional */
502
503 (void)VSLQ_Flush(vut->vslq, vut_dispatch, vut);
504
505 if (i == vsl_e_abandon) {
506 fprintf(stderr, "Log abandoned (vsl)\n");
507 VSLQ_SetCursor(vut->vslq, NULL);
508 hascursor = 0;
509 } else if (i == vsl_e_overrun) {
510 fprintf(stderr, "Log overrun\n");
511 VSLQ_SetCursor(vut->vslq, NULL);
512 hascursor = 0;
513 } else
514 fprintf(stderr, "Error %d from VSLQ_Dispatch()", i);
515 }
516
517 return (i);
518 }
519
520 /**********************************************************************/
521
522 void v_noreturn_
VUT_Usage(const struct VUT * vut,const struct vopt_spec * voc,int status)523 VUT_Usage(const struct VUT *vut, const struct vopt_spec *voc, int status)
524 {
525 const char **opt;
526
527 fprintf(stderr, "Usage: %s <options>\n\n", vut->progname);
528 fprintf(stderr, "Options:\n");
529 for (opt = voc->vopt_usage; *opt != NULL; opt += 2)
530 fprintf(stderr, " %-25s %s\n", *opt, *(opt + 1));
531 exit(status);
532 }
533
534 /**********************************************************************/
535
536
537 static void
print_nobrackets(const char * s)538 print_nobrackets(const char *s)
539 {
540 const char *e;
541
542 /* Remove whitespace */
543 while (isspace(*s))
544 s++;
545 e = s + strlen(s);
546 while (e > s && isspace(e[-1]))
547 e--;
548
549 /* Remove outer layer brackets if present */
550 if (e > s && *s == '[' && e[-1] == ']') {
551 s++;
552 e--;
553 }
554
555 printf("%.*s", (int)(e - s), s);
556 }
557
558 static void
print_tabbed(const char * string,int tabs)559 print_tabbed(const char *string, int tabs)
560 {
561 int i;
562 const char *c;
563
564 for (c = string; *c; c++) {
565 if (c == string || *(c - 1) == '\n')
566 for (i = 0; i < tabs; i++)
567 printf("\t");
568 printf("%c", *c);
569 }
570 }
571
572 static void
print_opt(const struct vopt_list * opt)573 print_opt(const struct vopt_list *opt)
574 {
575 print_nobrackets(opt->synopsis);
576 printf("\n\n");
577 print_tabbed(opt->ldesc, 1);
578 printf("\n\n");
579 }
580
581 static int
vut_synopsis(const struct vopt_spec * voc)582 vut_synopsis(const struct vopt_spec *voc)
583 {
584 printf(".. |synopsis| replace:: %s\n", voc->vopt_synopsis);
585 return (0);
586 }
587
588 static int
vut_options(const struct vopt_spec * voc)589 vut_options(const struct vopt_spec *voc)
590 {
591 int i;
592
593 for (i = 0; i < voc->vopt_list_n; i++)
594 print_opt(&voc->vopt_list[i]);
595 printf("--optstring\n"
596 "\tPrint the optstring parameter to ``getopt(3)`` to help"
597 " writing wrapper scripts.\n\n");
598 return (0);
599 }
600