| | 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 |
|
#include <ctype.h> |
36 |
|
#include <math.h> |
37 |
|
#include <stdint.h> |
38 |
|
#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 |
80 |
vut_daemon(struct VUT *vut) |
73 |
|
{ |
74 |
80 |
if (daemonized) |
75 |
0 |
VUT_Error(vut, 1, "Already running as a daemon"); |
76 |
80 |
daemonized = 1; |
77 |
80 |
return (varnish_daemon(0, 0)); |
78 |
|
} |
79 |
|
|
80 |
|
static void |
81 |
160 |
vut_vpf_remove(void) |
82 |
|
{ |
83 |
|
|
84 |
160 |
CHECK_OBJ(&pfh_vut, VUT_MAGIC); |
85 |
160 |
AN(pfh); |
86 |
160 |
AN(pfh_vut.P_arg); |
87 |
|
|
88 |
160 |
VPF_Remove(pfh); |
89 |
160 |
free(pfh_vut.P_arg); |
90 |
160 |
ZERO_OBJ(&pfh_vut, sizeof pfh_vut); |
91 |
160 |
pfh = NULL; |
92 |
160 |
} |
93 |
|
|
94 |
|
static int v_matchproto_(VSLQ_dispatch_f) |
95 |
38942 |
vut_dispatch(struct VSL_data *vsl, struct VSL_transaction * const trans[], |
96 |
|
void *priv) |
97 |
|
{ |
98 |
|
struct VUT *vut; |
99 |
|
int i; |
100 |
|
|
101 |
38942 |
CAST_OBJ_NOTNULL(vut, priv, VUT_MAGIC); |
102 |
|
|
103 |
38942 |
if (vut->k_arg == 0) |
104 |
0 |
return (-1); /* End of file */ |
105 |
38942 |
AN(vut->dispatch_f); |
106 |
38942 |
i = vut->dispatch_f(vsl, trans, vut->dispatch_priv); |
107 |
38942 |
if (vut->k_arg > 0) |
108 |
120 |
vut->k_arg--; |
109 |
38942 |
if (i >= 0 && vut->k_arg == 0) |
110 |
120 |
return (-1); /* End of file */ |
111 |
38822 |
return (i); |
112 |
38942 |
} |
113 |
|
|
114 |
|
void |
115 |
3880 |
VUT_Error(struct VUT *vut, int status, const char *fmt, ...) |
116 |
|
{ |
117 |
|
va_list ap; |
118 |
|
|
119 |
3880 |
CHECK_OBJ_NOTNULL(vut, VUT_MAGIC); |
120 |
3880 |
AN(status); |
121 |
|
|
122 |
3880 |
va_start(ap, fmt); |
123 |
3880 |
if (vut->error_f != NULL) { |
124 |
0 |
vut->error_f(vut, status, fmt, ap); |
125 |
0 |
} else { |
126 |
3880 |
vfprintf(stderr, fmt, ap); |
127 |
3880 |
fprintf(stderr, "\n"); |
128 |
|
} |
129 |
3880 |
va_end(ap); |
130 |
3880 |
exit(status); |
131 |
|
} |
132 |
|
|
133 |
|
static void |
134 |
2360 |
vut_arg_q(struct VUT *vut, const char *arg) |
135 |
|
{ |
136 |
|
struct vsb *vsb; |
137 |
|
|
138 |
2360 |
AN(arg); |
139 |
2360 |
if (vut->q_arg == NULL) { |
140 |
2240 |
REPLACE(vut->q_arg, arg); |
141 |
2240 |
return; |
142 |
|
} |
143 |
|
|
144 |
120 |
vsb = VSB_new_auto(); |
145 |
120 |
AN(vsb); |
146 |
120 |
AZ(VSB_printf(vsb, "%s\n%s", vut->q_arg, arg)); |
147 |
120 |
AZ(VSB_finish(vsb)); |
148 |
|
|
149 |
120 |
REPLACE(vut->q_arg, VSB_data(vsb)); |
150 |
|
|
151 |
120 |
VSB_destroy(&vsb); |
152 |
2360 |
} |
153 |
|
|
154 |
|
int |
155 |
16080 |
VUT_Arg(struct VUT *vut, int opt, const char *arg) |
156 |
|
{ |
157 |
|
int i; |
158 |
|
char *p; |
159 |
|
|
160 |
16080 |
CHECK_OBJ_NOTNULL(vut, VUT_MAGIC); |
161 |
16080 |
AN(opt); |
162 |
|
|
163 |
16080 |
switch (opt) { |
164 |
|
case 'd': |
165 |
|
/* Head */ |
166 |
3000 |
vut->d_opt = 1; |
167 |
3000 |
return (1); |
168 |
|
case 'D': |
169 |
|
/* Daemon mode */ |
170 |
240 |
vut->D_opt = 1; |
171 |
240 |
return (1); |
172 |
|
case 'g': |
173 |
|
/* Grouping */ |
174 |
560 |
AN(arg); |
175 |
560 |
vut->g_arg = VSLQ_Name2Grouping(arg, -1); |
176 |
560 |
if (vut->g_arg == -2) |
177 |
40 |
VUT_Error(vut, 1, "Ambiguous grouping type: %s", arg); |
178 |
520 |
else if (vut->g_arg < 0) |
179 |
40 |
VUT_Error(vut, 1, "Unknown grouping type: %s", arg); |
180 |
480 |
return (1); |
181 |
|
case 'k': |
182 |
|
/* Log transaction limit */ |
183 |
160 |
AN(arg); |
184 |
160 |
vut->k_arg = (int)strtol(arg, &p, 10); |
185 |
160 |
if (*p != '\0' || vut->k_arg <= 0) |
186 |
40 |
VUT_Error(vut, 1, "-k: Invalid number '%s'", arg); |
187 |
120 |
return (1); |
188 |
|
case 'n': |
189 |
|
/* Varnish instance name */ |
190 |
3480 |
AN(arg); |
191 |
3480 |
REPLACE(vut->n_arg, arg); |
192 |
3480 |
return (1); |
193 |
|
case 'P': |
194 |
|
/* PID file */ |
195 |
160 |
AN(arg); |
196 |
160 |
REPLACE(vut->P_arg, arg); |
197 |
160 |
return (1); |
198 |
|
case 'Q': |
199 |
320 |
AN(arg); |
200 |
320 |
p = VFIL_readfile(NULL, arg, NULL); |
201 |
320 |
if (p == NULL) |
202 |
40 |
VUT_Error(vut, 1, "-Q %s: %s", arg, strerror(errno)); |
203 |
280 |
vut_arg_q(vut, p); |
204 |
280 |
free(p); |
205 |
280 |
return (1); |
206 |
|
case 'q': |
207 |
|
/* Query to use */ |
208 |
2080 |
AN(arg); |
209 |
2080 |
vut_arg_q(vut, arg); |
210 |
2080 |
return (1); |
211 |
|
case 'r': |
212 |
|
/* Binary file input */ |
213 |
320 |
AN(arg); |
214 |
320 |
REPLACE(vut->r_arg, arg); |
215 |
320 |
return (1); |
216 |
|
case 't': |
217 |
|
/* VSM connect timeout */ |
218 |
160 |
REPLACE(vut->t_arg, arg); |
219 |
160 |
return (1); |
220 |
|
case 'V': |
221 |
|
/* Print version number and exit */ |
222 |
200 |
VCS_Message(vut->progname); |
223 |
200 |
exit(0); |
224 |
|
default: |
225 |
5400 |
AN(vut->vsl); |
226 |
5400 |
i = VSL_Arg(vut->vsl, opt, arg); |
227 |
5400 |
if (i < 0) |
228 |
720 |
VUT_Error(vut, 1, "%s", VSL_Error(vut->vsl)); |
229 |
4680 |
return (i); |
230 |
|
} |
231 |
15000 |
} |
232 |
|
|
233 |
|
struct VUT * |
234 |
9240 |
VUT_Init(const char *progname, int argc, char * const *argv, |
235 |
|
const struct vopt_spec *voc) |
236 |
|
{ |
237 |
|
struct VUT *vut; |
238 |
|
|
239 |
9240 |
AN(progname); |
240 |
9240 |
AN(argv); |
241 |
9240 |
AN(voc); |
242 |
|
|
243 |
9240 |
VSIG_Arm_hup(); |
244 |
9240 |
VSIG_Arm_int(); |
245 |
9240 |
VSIG_Arm_term(); |
246 |
9240 |
VSIG_Arm_usr1(); |
247 |
|
|
248 |
9240 |
if (argc == 2 && !strcmp(argv[1], "--synopsis")) |
249 |
200 |
exit(vut_synopsis(voc)); |
250 |
9040 |
if (argc == 2 && !strcmp(argv[1], "--options")) |
251 |
200 |
exit(vut_options(voc)); |
252 |
8840 |
if (argc == 2 && !strcmp(argv[1], "--optstring")) { |
253 |
0 |
(void)printf("%s\n", voc->vopt_optstring); |
254 |
0 |
exit(0); |
255 |
|
} |
256 |
|
|
257 |
8840 |
ALLOC_OBJ(vut, VUT_MAGIC); |
258 |
8840 |
AN(vut); |
259 |
8840 |
vut->progname = progname; |
260 |
8840 |
vut->g_arg = VSL_g_vxid; |
261 |
8840 |
vut->k_arg = -1; |
262 |
8840 |
AZ(vut->vsl); |
263 |
8840 |
vut->vsl = VSL_New(); |
264 |
8840 |
AN(vut->vsl); |
265 |
8840 |
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 |
|
} |
288 |
|
|
289 |
|
void |
290 |
4720 |
VUT_Setup(struct VUT *vut) |
291 |
|
{ |
292 |
|
struct VSL_cursor *c; |
293 |
|
|
294 |
4720 |
CHECK_OBJ_NOTNULL(vut, VUT_MAGIC); |
295 |
4720 |
AN(vut->vsl); |
296 |
4720 |
AZ(vut->vsm); |
297 |
4720 |
AZ(vut->vslq); |
298 |
|
|
299 |
|
/* Check input arguments (2 used for bug in FlexeLint) */ |
300 |
14160 |
if ((vut->n_arg == NULL ? 0 : 2) + |
301 |
9440 |
(vut->r_arg == NULL ? 0 : 2) > 2) |
302 |
40 |
VUT_Error(vut, 1, "Only one of -n and -r options may be used"); |
303 |
|
|
304 |
4680 |
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 |
9360 |
vut->vslq = VSLQ_New(vut->vsl, NULL, |
309 |
4680 |
(enum VSL_grouping_e)vut->g_arg, vut->q_arg); |
310 |
4680 |
if (vut->vslq == NULL) |
311 |
2560 |
VUT_Error(vut, 1, "Query expression error:\n%s", |
312 |
1280 |
VSL_Error(vut->vsl)); |
313 |
|
|
314 |
|
/* Setup input */ |
315 |
3400 |
if (vut->r_arg) { |
316 |
280 |
c = VSL_CursorFile(vut->vsl, vut->r_arg, 0); |
317 |
280 |
if (c == NULL) |
318 |
80 |
VUT_Error(vut, 1, "%s", VSL_Error(vut->vsl)); |
319 |
200 |
VSLQ_SetCursor(vut->vslq, &c); |
320 |
200 |
AZ(c); |
321 |
200 |
} else { |
322 |
3120 |
vut->vsm = VSM_New(); |
323 |
3120 |
AN(vut->vsm); |
324 |
3120 |
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 |
3120 |
if (vut->t_arg && VSM_Arg(vut->vsm, 't', vut->t_arg) <= 0) |
327 |
120 |
VUT_Error(vut, 1, "%s", VSM_Error(vut->vsm)); |
328 |
3000 |
if (VSM_Attach(vut->vsm, STDERR_FILENO)) |
329 |
40 |
VUT_Error(vut, 1, "VSM: %s", VSM_Error(vut->vsm)); |
330 |
|
// Cursor is handled in VUT_Main() |
331 |
|
} |
332 |
|
|
333 |
|
/* Open PID file */ |
334 |
3160 |
if (vut->P_arg) { |
335 |
160 |
if (pfh != NULL) |
336 |
0 |
VUT_Error(vut, 1, "PID file already created"); |
337 |
160 |
pfh = VPF_Open(vut->P_arg, 0644, NULL); |
338 |
160 |
if (pfh == NULL) |
339 |
0 |
VUT_Error(vut, 1, |
340 |
0 |
"%s: %s", vut->P_arg, strerror(errno)); |
341 |
160 |
} |
342 |
|
|
343 |
|
/* Daemon mode */ |
344 |
3160 |
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 |
3160 |
if (vut->P_arg) { |
349 |
160 |
AN(pfh); |
350 |
160 |
VPF_Write(pfh); |
351 |
|
|
352 |
|
/* NB: move ownership to a global pseudo-VUT. */ |
353 |
160 |
INIT_OBJ(&pfh_vut, VUT_MAGIC); |
354 |
160 |
pfh_vut.P_arg = vut->P_arg; |
355 |
160 |
pfh_vut.error_f = vut->error_f; |
356 |
160 |
vut->P_arg = NULL; |
357 |
|
|
358 |
160 |
AZ(atexit(vut_vpf_remove)); |
359 |
160 |
} |
360 |
3160 |
} |
361 |
|
|
362 |
|
void |
363 |
3160 |
VUT_Fini(struct VUT **vutp) |
364 |
|
{ |
365 |
|
struct VUT *vut; |
366 |
|
|
367 |
3160 |
TAKE_OBJ_NOTNULL(vut, vutp, VUT_MAGIC); |
368 |
3160 |
AN(vut->progname); |
369 |
|
|
370 |
3160 |
free(vut->n_arg); |
371 |
3160 |
free(vut->q_arg); |
372 |
3160 |
free(vut->r_arg); |
373 |
3160 |
free(vut->t_arg); |
374 |
3160 |
AZ(vut->P_arg); |
375 |
|
|
376 |
3160 |
if (vut->vslq) |
377 |
3160 |
VSLQ_Delete(&vut->vslq); |
378 |
3160 |
if (vut->vsl) |
379 |
3160 |
VSL_Delete(vut->vsl); |
380 |
3160 |
if (vut->vsm) |
381 |
2960 |
VSM_Destroy(&vut->vsm); |
382 |
|
|
383 |
3160 |
FREE_OBJ(vut); |
384 |
3160 |
} |
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 |
3160 |
VUT_Main(struct VUT *vut) |
409 |
|
{ |
410 |
|
struct VSL_cursor *c; |
411 |
3160 |
int i = -1; |
412 |
3160 |
int hascursor = -1; |
413 |
3160 |
vtim_mono t_failcursor = NAN; |
414 |
|
|
415 |
3160 |
CHECK_OBJ_NOTNULL(vut, VUT_MAGIC); |
416 |
3160 |
AN(vut->vslq); |
417 |
|
|
418 |
286378 |
while (!VSIG_int && !VSIG_term) { |
419 |
285898 |
if (VSIG_hup != vut->last_sighup) { |
420 |
|
/* sighup callback */ |
421 |
160 |
vut->last_sighup = VSIG_hup; |
422 |
160 |
if (vut->sighup_f != NULL) |
423 |
80 |
i = vut->sighup_f(vut); |
424 |
|
else |
425 |
80 |
i = 1; |
426 |
160 |
if (i) |
427 |
80 |
break; |
428 |
80 |
} |
429 |
|
|
430 |
285818 |
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 |
285818 |
if (vut->vsm != NULL && |
453 |
285618 |
(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 |
285818 |
if (vut->vsm != NULL && hascursor < 1) { |
461 |
|
/* Reconnect VSM */ |
462 |
2960 |
AZ(vut->r_arg); |
463 |
2960 |
VTIM_sleep(0.1); |
464 |
5920 |
c = VSL_CursorVSM(vut->vsl, vut->vsm, |
465 |
2960 |
(vut->d_opt ? VSL_COPT_TAILSTOP : VSL_COPT_TAIL) |
466 |
2960 |
| VSL_COPT_BATCH); |
467 |
2960 |
if (c == NULL) { |
468 |
0 |
vut_CursorError(vut, &t_failcursor); |
469 |
0 |
VSL_ResetError(vut->vsl); |
470 |
0 |
continue; |
471 |
|
} |
472 |
2960 |
if (hascursor >= 0) |
473 |
0 |
fprintf(stderr, "Log reacquired\n"); |
474 |
2960 |
hascursor = 1; |
475 |
2960 |
VSLQ_SetCursor(vut->vslq, &c); |
476 |
2960 |
AZ(c); |
477 |
2960 |
} |
478 |
|
|
479 |
285818 |
do |
480 |
722608 |
i = VSLQ_Dispatch(vut->vslq, vut_dispatch, vut); |
481 |
436790 |
while (i == vsl_more && |
482 |
150972 |
VSIG_usr1 == vut->last_sigusr1 && |
483 |
150972 |
VSIG_hup == vut->last_sighup); |
484 |
|
|
485 |
285818 |
if (i == vsl_more) |
486 |
0 |
continue; |
487 |
285818 |
else if (i == vsl_end) { |
488 |
283218 |
if (vut->idle_f) { |
489 |
125246 |
i = vut->idle_f(vut); |
490 |
125246 |
if (i) |
491 |
0 |
break; |
492 |
125246 |
} |
493 |
283218 |
VTIM_sleep(0.01); |
494 |
283218 |
continue; |
495 |
2600 |
} else if (i == vsl_e_eof) |
496 |
2600 |
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 |
3160 |
return (i); |
518 |
|
} |
519 |
|
|
520 |
|
/**********************************************************************/ |
521 |
|
|
522 |
|
void v_noreturn_ |
523 |
400 |
VUT_Usage(const struct VUT *vut, const struct vopt_spec *voc, int status) |
524 |
|
{ |
525 |
|
const char **opt; |
526 |
|
|
527 |
400 |
fprintf(stderr, "Usage: %s <options>\n\n", vut->progname); |
528 |
400 |
fprintf(stderr, "Options:\n"); |
529 |
9760 |
for (opt = voc->vopt_usage; *opt != NULL; opt += 2) |
530 |
9360 |
fprintf(stderr, " %-25s %s\n", *opt, *(opt + 1)); |
531 |
400 |
exit(status); |
532 |
|
} |
533 |
|
|
534 |
|
/**********************************************************************/ |
535 |
|
|
536 |
|
|
537 |
|
static void |
538 |
4280 |
print_nobrackets(const char *s) |
539 |
|
{ |
540 |
|
const char *e; |
541 |
|
|
542 |
|
/* Remove whitespace */ |
543 |
4280 |
while (isspace(*s)) |
544 |
0 |
s++; |
545 |
4280 |
e = s + strlen(s); |
546 |
4280 |
while (e > s && isspace(e[-1])) |
547 |
0 |
e--; |
548 |
|
|
549 |
|
/* Remove outer layer brackets if present */ |
550 |
4280 |
if (e > s && *s == '[' && e[-1] == ']') { |
551 |
4280 |
s++; |
552 |
4280 |
e--; |
553 |
4280 |
} |
554 |
|
|
555 |
4280 |
printf("%.*s", (int)(e - s), s); |
556 |
4280 |
} |
557 |
|
|
558 |
|
static void |
559 |
4280 |
print_tabbed(const char *string, int tabs) |
560 |
|
{ |
561 |
|
int i; |
562 |
|
const char *c; |
563 |
|
|
564 |
669480 |
for (c = string; *c; c++) { |
565 |
665200 |
if (c == string || *(c - 1) == '\n') |
566 |
9200 |
for (i = 0; i < tabs; i++) |
567 |
9200 |
printf("\t"); |
568 |
665200 |
printf("%c", *c); |
569 |
665200 |
} |
570 |
4280 |
} |
571 |
|
|
572 |
|
static void |
573 |
4280 |
print_opt(const struct vopt_list *opt) |
574 |
|
{ |
575 |
4280 |
print_nobrackets(opt->synopsis); |
576 |
4280 |
printf("\n\n"); |
577 |
4280 |
print_tabbed(opt->ldesc, 1); |
578 |
4280 |
printf("\n\n"); |
579 |
4280 |
} |
580 |
|
|
581 |
|
static int |
582 |
200 |
vut_synopsis(const struct vopt_spec *voc) |
583 |
|
{ |
584 |
200 |
printf(".. |synopsis| replace:: %s\n", voc->vopt_synopsis); |
585 |
200 |
return (0); |
586 |
|
} |
587 |
|
|
588 |
|
static int |
589 |
200 |
vut_options(const struct vopt_spec *voc) |
590 |
|
{ |
591 |
|
int i; |
592 |
|
|
593 |
4480 |
for (i = 0; i < voc->vopt_list_n; i++) |
594 |
4280 |
print_opt(&voc->vopt_list[i]); |
595 |
200 |
printf("--optstring\n" |
596 |
|
"\tPrint the optstring parameter to ``getopt(3)`` to help" |
597 |
|
" writing wrapper scripts.\n\n"); |
598 |
200 |
return (0); |
599 |
|
} |