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