1 /***
2  * Copyright 2020 HAProxy Technologies
3  *
4  * This file is part of the HAProxy OpenTracing filter.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20 #include "include.h"
21 
22 
23 #ifdef DEBUG_OT
24 struct flt_ot_debug               flt_ot_debug;
25 THREAD_LOCAL int                  dbg_indent_level = 0;
26 #endif
27 
28 #ifdef OTC_DBG_MEM
29 static struct otc_dbg_mem_data    dbg_mem_data[1000000];
30 static struct otc_dbg_mem         dbg_mem;
31 #endif
32 
33 static struct flt_ot_conf        *flt_ot_current_config = NULL;
34 static struct flt_ot_conf_tracer *flt_ot_current_tracer = NULL;
35 static struct flt_ot_conf_group  *flt_ot_current_group = NULL;
36 static struct flt_ot_conf_scope  *flt_ot_current_scope = NULL;
37 static struct flt_ot_conf_span   *flt_ot_current_span = NULL;
38 
39 
40 /***
41  * NAME
42  *   flt_ot_parse_strdup -
43  *
44  * ARGUMENTS
45  *   ptr     -
46  *   str     -
47  *   err     -
48  *   err_msg -
49  *
50  * DESCRIPTION
51  *   -
52  *
53  * RETURN VALUE
54  *   Returns ERR_NONE (== 0) in case of success,
55  *   or a combination of ERR_* flags if an error is encountered.
56  */
flt_ot_parse_strdup(char ** ptr,const char * str,char ** err,const char * err_msg)57 static int flt_ot_parse_strdup(char **ptr, const char *str, char **err, const char *err_msg)
58 {
59 	int retval = ERR_NONE;
60 
61 	FLT_OT_FUNC("%p:%p, %p, %p:%p, \"%s\"", FLT_OT_DPTR_ARGS(ptr), str, FLT_OT_DPTR_ARGS(err), err_msg);
62 
63 	*ptr = FLT_OT_STRDUP(str);
64 	if (*ptr == NULL) {
65 		FLT_OT_PARSE_ERR(err, "'%s' : out of memory", err_msg);
66 
67 		retval |= ERR_ABORT | ERR_ALERT;
68 	}
69 
70 	FLT_OT_RETURN(retval);
71 }
72 
73 
74 /***
75  * NAME
76  *   flt_ot_parse_keyword -
77  *
78  * ARGUMENTS
79  *   ptr     -
80  *   args    -
81  *   cur_arg -
82  *   pos     -
83  *   err     -
84  *   err_msg -
85  *
86  * DESCRIPTION
87  *   -
88  *
89  * RETURN VALUE
90  *   Returns ERR_NONE (== 0) in case of success,
91  *   or a combination of ERR_* flags if an error is encountered.
92  */
flt_ot_parse_keyword(char ** ptr,char ** args,int cur_arg,int pos,char ** err,const char * err_msg)93 static int flt_ot_parse_keyword(char **ptr, char **args, int cur_arg, int pos, char **err, const char *err_msg)
94 {
95 	int retval = ERR_NONE;
96 
97 	FLT_OT_FUNC("%p:%p, %p, %d, %d, %p:%p, \"%s\"", FLT_OT_DPTR_ARGS(ptr), args, cur_arg, pos, FLT_OT_DPTR_ARGS(err), err_msg);
98 
99 	if (*ptr != NULL) {
100 		if (cur_arg == pos)
101 			FLT_OT_PARSE_ERR(err, FLT_OT_FMT_TYPE "%s already set", err_msg);
102 		else
103 			FLT_OT_PARSE_ERR(err, "'%s' : %s already set", args[cur_arg], err_msg);
104 	}
105 	else if (!FLT_OT_ARG_ISVALID(pos + 1)) {
106 		if (cur_arg == pos)
107 			FLT_OT_PARSE_ERR(err, FLT_OT_FMT_TYPE "no %s set", err_msg);
108 		else
109 			FLT_OT_PARSE_ERR(err, "'%s' : no %s set", args[cur_arg], err_msg);
110 	}
111 	else {
112 		retval = flt_ot_parse_strdup(ptr, args[pos + 1], err, args[cur_arg]);
113 	}
114 
115 	FLT_OT_RETURN(retval);
116 }
117 
118 
119 /***
120  * NAME
121  *   flt_ot_parse_invalid_char -
122  *
123  * ARGUMENTS
124  *   name -
125  *   type -
126  *
127  * DESCRIPTION
128  *   -
129  *
130  * RETURN VALUE
131  *   -
132  */
flt_ot_parse_invalid_char(const char * name,int type)133 static const char *flt_ot_parse_invalid_char(const char *name, int type)
134 {
135 	const char *retptr = NULL;
136 
137 	FLT_OT_FUNC("\"%s\", %d", name, type);
138 
139 	if (!FLT_OT_STR_ISVALID(name))
140 		FLT_OT_RETURN(retptr);
141 
142 	if (type == 1) {
143 		retptr = invalid_char(name);
144 	}
145 	else if (type == 2) {
146 		retptr = invalid_domainchar(name);
147 	}
148 	else if (type == 3) {
149 		retptr = invalid_prefix_char(name);
150 	}
151 	else if (type == 4) {
152 		retptr = name;
153 
154 		/*
155 		 * Allowed characters are letters, numbers and '_', the first
156 		 * character in the string must not be a number.
157 		 */
158 		if (!isdigit(*retptr))
159 			for (++retptr; (*retptr == '_') || isalnum(*retptr); retptr++);
160 
161 		if (*retptr == '\0')
162 			retptr = NULL;
163 	}
164 
165 	FLT_OT_RETURN(retptr);
166 }
167 
168 
169 /***
170  * NAME
171  *   flt_ot_parse_cfg_check -
172  *
173  * ARGUMENTS
174  *   file            -
175  *   linenum         -
176  *   args            -
177  *   id              -
178  *   parse_data      -
179  *   parse_data_size -
180  *   pdata           -
181  *   err             -
182  *
183  * DESCRIPTION
184  *   -
185  *
186  * RETURN VALUE
187  *   Returns ERR_NONE (== 0) in case of success,
188  *   or a combination of ERR_* flags if an error is encountered.
189  */
flt_ot_parse_cfg_check(const char * file,int linenum,char ** args,const void * id,const struct flt_ot_parse_data * parse_data,size_t parse_data_size,const struct flt_ot_parse_data ** pdata,char ** err)190 static int flt_ot_parse_cfg_check(const char *file, int linenum, char **args, const void *id, const struct flt_ot_parse_data *parse_data, size_t parse_data_size, const struct flt_ot_parse_data **pdata, char **err)
191 {
192 	int i, argc, retval = ERR_NONE;
193 
194 	FLT_OT_FUNC("\"%s\", %d, %p, %p, %p, %zu, %p:%p, %p:%p", file, linenum, args, id, parse_data, parse_data_size, FLT_OT_DPTR_ARGS(pdata), FLT_OT_DPTR_ARGS(err));
195 
196 	FLT_OT_ARGS_DUMP();
197 
198 	*pdata = NULL;
199 
200 	/* First check here if args[0] is the correct keyword. */
201 	for (i = 0; (*pdata == NULL) && (i < parse_data_size); i++)
202 		if (strcmp(parse_data[i].name, args[0]) == 0)
203 			*pdata = parse_data + i;
204 
205 	if (*pdata == NULL)
206 		FLT_OT_PARSE_ERR(err, "'%s' : unknown keyword", args[0]);
207 	else
208 		argc = flt_ot_args_count(args);
209 
210 	if ((retval & ERR_CODE) || (id == NULL))
211 		/* Do nothing. */;
212 	else if ((id != flt_ot_current_tracer) && (flt_ot_current_config->tracer == NULL))
213 		FLT_OT_PARSE_ERR(err, "tracer not defined");
214 
215 	/*
216 	 * Checking that fewer arguments are specified in the configuration
217 	 * line than is required.
218 	 */
219 	if (!(retval & ERR_CODE))
220 		if (argc < (*pdata)->args_min)
221 			FLT_OT_PARSE_ERR(err, "'%s' : too few arguments (use '%s%s')", args[0], (*pdata)->name, (*pdata)->usage);
222 
223 	/*
224 	 * Checking that more arguments are specified in the configuration
225 	 * line than the maximum allowed.
226 	 */
227 	if (!(retval & ERR_CODE) && ((*pdata)->args_max > 0))
228 		if (argc > (*pdata)->args_max)
229 			FLT_OT_PARSE_ERR(err, "'%s' : too many arguments (use '%s%s')", args[0], (*pdata)->name, (*pdata)->usage);
230 
231 	/* Checking that the first argument has only allowed characters. */
232 	if (!(retval & ERR_CODE) && ((*pdata)->check_name > 0)) {
233 		const char *ic;
234 
235 		ic = flt_ot_parse_invalid_char(args[1], (*pdata)->check_name);
236 		if (ic != NULL)
237 			FLT_OT_PARSE_ERR(err, "%s '%s' : invalid character '%c'", args[0], args[1], *ic);
238 	}
239 
240 	/* Checking that the data group name is defined. */
241 	if (!(retval & ERR_CODE) && (*pdata)->flag_check_id && (id == NULL))
242 		FLT_OT_PARSE_ERR(err, "'%s' : %s ID not set (use '%s%s')", args[0], parse_data[1].name, parse_data[1].name, parse_data[1].usage);
243 
244 	FLT_OT_RETURN(retval);
245 }
246 
247 
248 /***
249  * NAME
250  *   flt_ot_parse_cfg_sample_expr -
251  *
252  * ARGUMENTS
253  *   file    -
254  *   linenum -
255  *   args    -
256  *   idx     -
257  *   head    -
258  *   err     -
259  *
260  * DESCRIPTION
261  *   -
262  *
263  * RETURN VALUE
264  *   Returns ERR_NONE (== 0) in case of success,
265  *   or a combination of ERR_* flags if an error is encountered.
266  */
flt_ot_parse_cfg_sample_expr(const char * file,int linenum,char ** args,int * idx,struct list * head,char ** err)267 static int flt_ot_parse_cfg_sample_expr(const char *file, int linenum, char **args, int *idx, struct list *head, char **err)
268 {
269 	struct flt_ot_conf_sample_expr *expr;
270 	int                             retval = ERR_NONE;
271 
272 	FLT_OT_FUNC("\"%s\", %d, %p, %p, %p, %p:%p", file, linenum, args, idx, head, FLT_OT_DPTR_ARGS(err));
273 
274 	expr = flt_ot_conf_sample_expr_init(args[*idx], linenum, head, err);
275 	if (expr != NULL) {
276 		expr->expr = sample_parse_expr(args, idx, file, linenum, err, &(flt_ot_current_config->proxy->conf.args), NULL);
277 		if (expr->expr != NULL)
278 			FLT_OT_DBG(3, "sample expression '%s' added", expr->value);
279 		else
280 			retval |= ERR_ABORT | ERR_ALERT;
281 	} else {
282 			retval |= ERR_ABORT | ERR_ALERT;
283 	}
284 
285 	if (retval & ERR_CODE)
286 		flt_ot_conf_sample_expr_free(&expr);
287 
288 	FLT_OT_RETURN(retval);
289 }
290 
291 
292 /***
293  * NAME
294  *   flt_ot_parse_cfg_sample -
295  *
296  * ARGUMENTS
297  *   file    -
298  *   linenum -
299  *   args    -
300  *   head    -
301  *   err     -
302  *
303  * DESCRIPTION
304  *   -
305  *
306  * RETURN VALUE
307  *   Returns ERR_NONE (== 0) in case of success,
308  *   or a combination of ERR_* flags if an error is encountered.
309  */
flt_ot_parse_cfg_sample(const char * file,int linenum,char ** args,struct list * head,char ** err)310 static int flt_ot_parse_cfg_sample(const char *file, int linenum, char **args, struct list *head, char **err)
311 {
312 	struct flt_ot_conf_sample *sample;
313 	int                        idx = 2, retval = ERR_NONE;
314 
315 	FLT_OT_FUNC("\"%s\", %d, %p, %p, %p:%p", file, linenum, args, head, FLT_OT_DPTR_ARGS(err));
316 
317 	sample = flt_ot_conf_sample_init(args, linenum, head, err);
318 	if (sample == NULL)
319 		FLT_OT_PARSE_ERR(err, "'%s' : out of memory", args[0]);
320 
321 	if (!(retval & ERR_CODE)) {
322 		flt_ot_current_config->proxy->conf.args.ctx  = ARGC_OT;
323 		flt_ot_current_config->proxy->conf.args.file = file;
324 		flt_ot_current_config->proxy->conf.args.line = linenum;
325 
326 		while (!(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(idx))
327 			retval = flt_ot_parse_cfg_sample_expr(file, linenum, args, &idx, &(sample->exprs), err);
328 
329 		flt_ot_current_config->proxy->conf.args.file = NULL;
330 		flt_ot_current_config->proxy->conf.args.line = 0;
331 	}
332 
333 	if (retval & ERR_CODE)
334 		flt_ot_conf_sample_free(&sample);
335 	else
336 		FLT_OT_DBG(3, "sample '%s' -> '%s' added", sample->key, sample->value);
337 
338 	FLT_OT_RETURN(retval);
339 }
340 
341 
342 /***
343  * NAME
344  *   flt_ot_parse_cfg_str -
345  *
346  * ARGUMENTS
347  *   file    -
348  *   linenum -
349  *   args    -
350  *   head    -
351  *   err     -
352  *
353  * DESCRIPTION
354  *   -
355  *
356  * RETURN VALUE
357  *   Returns ERR_NONE (== 0) in case of success,
358  *   or a combination of ERR_* flags if an error is encountered.
359  */
flt_ot_parse_cfg_str(const char * file,int linenum,char ** args,struct list * head,char ** err)360 static int flt_ot_parse_cfg_str(const char *file, int linenum, char **args, struct list *head, char **err)
361 {
362 	struct flt_ot_conf_str *str = NULL;
363 	int                     i, retval = ERR_NONE;
364 
365 	FLT_OT_FUNC("\"%s\", %d, %p, %p, %p:%p", file, linenum, args, head, FLT_OT_DPTR_ARGS(err));
366 
367 	for (i = 1; !(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(i); i++)
368 		if (flt_ot_conf_str_init(args[i], linenum, head, err) == NULL)
369 			retval |= ERR_ABORT | ERR_ALERT;
370 
371 	if (retval & ERR_CODE)
372 		flt_ot_conf_str_free(&str);
373 
374 	FLT_OT_RETURN(retval);
375 }
376 
377 
378 /***
379  * NAME
380  *   flt_ot_parse_cfg_file -
381  *
382  * ARGUMENTS
383  *   ptr     -
384  *   file    -
385  *   linenum -
386  *   args    -
387  *   err     -
388  *   err_msg -
389  *
390  * DESCRIPTION
391  *   -
392  *
393  * RETURN VALUE
394  *   Returns ERR_NONE (== 0) in case of success,
395  *   or a combination of ERR_* flags if an error is encountered.
396  */
flt_ot_parse_cfg_file(char ** ptr,const char * file,int linenum,char ** args,char ** err,const char * err_msg)397 static int flt_ot_parse_cfg_file(char **ptr, const char *file, int linenum, char **args, char **err, const char *err_msg)
398 {
399 	int retval = ERR_NONE;
400 
401 	FLT_OT_FUNC("%p:%p, \"%s\", %d, %p, %p:%p, \"%s\"", FLT_OT_DPTR_ARGS(ptr), file, linenum, args, FLT_OT_DPTR_ARGS(err), err_msg);
402 
403 	if (!FLT_OT_ARG_ISVALID(1))
404 		FLT_OT_PARSE_ERR(err, "'%s' : no %s specified", flt_ot_current_tracer->id, err_msg);
405 	else if (alertif_too_many_args(1, file, linenum, args, &retval))
406 		retval |= ERR_ABORT | ERR_ALERT;
407 	else if (access(args[1], R_OK) == -1)
408 		FLT_OT_PARSE_ERR(err, "'%s' : %s", args[1], strerror(errno));
409 	else
410 		retval = flt_ot_parse_keyword(ptr, args, 0, 0, err, err_msg);
411 
412 	FLT_OT_RETURN(retval);
413 }
414 
415 
416 /***
417  * NAME
418  *   flt_ot_parse_check_scope -
419  *
420  * ARGUMENTS
421  *   This function takes no arguments.
422  *
423  * DESCRIPTION
424  *   -
425  *
426  * RETURN VALUE
427  *   Returns TRUE in case the configuration is not in the currently defined
428  *   scope, FALSE otherwise.
429  */
flt_ot_parse_check_scope(void)430 static bool flt_ot_parse_check_scope(void)
431 {
432 	bool retval = 0;
433 
434 	if ((cfg_scope != NULL) && (flt_ot_current_config->id != NULL) && (strcmp(flt_ot_current_config->id, cfg_scope) != 0)) {
435 		FLT_OT_DBG(1, "cfg_scope: '%s', id: '%s'", cfg_scope, flt_ot_current_config->id);
436 
437 		retval = 1;
438 	}
439 
440 	return retval;
441 }
442 
443 
444 /***
445  * NAME
446  *   flt_ot_parse_cfg_tracer -
447  *
448  * ARGUMENTS
449  *   file    -
450  *   linenum -
451  *   args    -
452  *   kw_mod  -
453  *
454  * DESCRIPTION
455  *   -
456  *
457  * RETURN VALUE
458  *   Returns ERR_NONE (== 0) in case of success,
459  *   or a combination of ERR_* flags if an error is encountered.
460  */
flt_ot_parse_cfg_tracer(const char * file,int linenum,char ** args,int kw_mod)461 static int flt_ot_parse_cfg_tracer(const char *file, int linenum, char **args, int kw_mod)
462 {
463 #define FLT_OT_PARSE_TRACER_DEF(a,b,c,d,e,f,g)   { FLT_OT_PARSE_TRACER_##a, b, c, d, e, f, g },
464 	static const struct flt_ot_parse_data  parse_data[] = { FLT_OT_PARSE_TRACER_DEFINES };
465 #undef FLT_OT_PARSE_TRACER_DEF
466 	const struct flt_ot_parse_data        *pdata = NULL;
467 	char                                  *err = NULL, *err_log = NULL;
468 	int                                    i, retval = ERR_NONE;
469 
470 	FLT_OT_FUNC("\"%s\", %d, %p, 0x%08x", file, linenum, args, kw_mod);
471 
472 	if (flt_ot_parse_check_scope())
473 		FLT_OT_RETURN(retval);
474 
475 	retval = flt_ot_parse_cfg_check(file, linenum, args, flt_ot_current_tracer, parse_data, FLT_OT_TABLESIZE(parse_data), &pdata, &err);
476 	if (retval & ERR_CODE) {
477 		FLT_OT_PARSE_IFERR_ALERT();
478 
479 		FLT_OT_RETURN(retval);
480 	}
481 
482 	if (pdata->keyword == FLT_OT_PARSE_TRACER_ID) {
483 		if (flt_ot_current_config->tracer != NULL) {
484 			FLT_OT_PARSE_ERR(&err, "'%s' : tracer can be defined only once", args[1]);
485 		} else {
486 			flt_ot_current_tracer = flt_ot_conf_tracer_init(args[1], linenum, &err);
487 			if (flt_ot_current_tracer == NULL)
488 				retval |= ERR_ABORT | ERR_ALERT;
489 		}
490 	}
491 	else if (pdata->keyword == FLT_OT_PARSE_TRACER_LOG) {
492 		if (parse_logsrv(args, &(flt_ot_current_tracer->proxy_log.logsrvs), kw_mod == KWM_NO, file, linenum, &err_log) == 0) {
493 			FLT_OT_PARSE_ERR(&err, "'%s %s ...' : %s", args[0], args[1], err_log);
494 			FLT_OT_FREE_CLEAR(err_log);
495 
496 			retval |= ERR_ABORT | ERR_ALERT;
497 		} else {
498 			flt_ot_current_tracer->logging |= FLT_OT_LOGGING_ON;
499 		}
500 	}
501 	else if (pdata->keyword == FLT_OT_PARSE_TRACER_CONFIG) {
502 		retval = flt_ot_parse_cfg_file(&(flt_ot_current_tracer->config), file, linenum, args, &err, "configuration file");
503 	}
504 	else if (pdata->keyword == FLT_OT_PARSE_TRACER_PLUGIN) {
505 		retval = flt_ot_parse_cfg_file(&(flt_ot_current_tracer->plugin), file, linenum, args, &err, "plugin library");
506 	}
507 	else if (pdata->keyword == FLT_OT_PARSE_TRACER_GROUPS) {
508 		for (i = 1; !(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(i); i++)
509 			if (flt_ot_conf_ph_init(args[i], linenum, &(flt_ot_current_tracer->ph_groups), &err) == NULL)
510 				retval |= ERR_ABORT | ERR_ALERT;
511 	}
512 	else if (pdata->keyword == FLT_OT_PARSE_TRACER_SCOPES) {
513 		for (i = 1; !(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(i); i++)
514 			if (flt_ot_conf_ph_init(args[i], linenum, &(flt_ot_current_tracer->ph_scopes), &err) == NULL)
515 				retval |= ERR_ABORT | ERR_ALERT;
516 	}
517 	else if (pdata->keyword == FLT_OT_PARSE_TRACER_ACL) {
518 		if (strcasecmp(args[1], "or") == 0)
519 			FLT_OT_PARSE_ERR(&err, "'%s %s ...' : invalid ACL name", args[0], args[1]);
520 		else if (parse_acl((const char **)args + 1, &(flt_ot_current_tracer->acls), &err, &(flt_ot_current_config->proxy->conf.args), file, linenum) == NULL)
521 			retval |= ERR_ABORT | ERR_ALERT;
522 	}
523 	else if (pdata->keyword == FLT_OT_PARSE_TRACER_RATE_LIMIT) {
524 		flt_ot_current_tracer->rate_limit = FLT_OT_FLOAT_U32(flt_ot_strtod(args[1], 0.0, FLT_OT_RATE_LIMIT_MAX, &err), FLT_OT_RATE_LIMIT_MAX);
525 	}
526 	else if (pdata->keyword == FLT_OT_PARSE_TRACER_OPTION) {
527 		if (strcmp(args[1], FLT_OT_PARSE_OPTION_DISABLED) == 0) {
528 			flt_ot_current_tracer->flag_disabled = (kw_mod == KWM_NO) ? 0 : 1;
529 		}
530 		else if (strcmp(args[1], FLT_OT_PARSE_OPTION_HARDERR) == 0) {
531 			flt_ot_current_tracer->flag_harderr = (kw_mod == KWM_NO) ? 0 : 1;
532 		}
533 		else if (strcmp(args[1], FLT_OT_PARSE_OPTION_NOLOGNORM) == 0) {
534 			if (kw_mod == KWM_NO)
535 				flt_ot_current_tracer->logging &= ~FLT_OT_LOGGING_NOLOGNORM;
536 			else
537 				flt_ot_current_tracer->logging |= FLT_OT_LOGGING_NOLOGNORM;
538 		}
539 		else
540 			FLT_OT_PARSE_ERR(&err, "'%s' : unknown option '%s'", args[0], args[1]);
541 	}
542 #ifdef DEBUG_OT
543 	else if (pdata->keyword == FLT_OT_PARSE_TRACER_DEBUG_LEVEL) {
544 		flt_ot_debug.level = flt_ot_strtoll(args[1], 0, 255, &err);
545 	}
546 #else
547 	else {
548 		FLT_OT_PARSE_WARNING("'%s' : keyword ignored", file, linenum, args[0]);
549 	}
550 #endif
551 
552 	FLT_OT_PARSE_IFERR_ALERT();
553 
554 	if ((retval & ERR_CODE) && (flt_ot_current_tracer != NULL))
555 		flt_ot_conf_tracer_free(&flt_ot_current_tracer);
556 
557 	FLT_OT_RETURN(retval);
558 }
559 
560 
561 /***
562  * NAME
563  *   flt_ot_post_parse_cfg_tracer -
564  *
565  * ARGUMENTS
566  *   This function takes no arguments.
567  *
568  * DESCRIPTION
569  *   -
570  *
571  * RETURN VALUE
572  *   Returns ERR_NONE (== 0) in case of success,
573  *   or a combination of ERR_* flags if an error is encountered.
574  */
flt_ot_post_parse_cfg_tracer(void)575 static int flt_ot_post_parse_cfg_tracer(void)
576 {
577 	char errbuf[BUFSIZ] = "";
578 	int  retval = ERR_NONE;
579 
580 	FLT_OT_FUNC("");
581 
582 	if (flt_ot_current_tracer == NULL)
583 		FLT_OT_RETURN(retval);
584 
585 	flt_ot_current_config->tracer = flt_ot_current_tracer;
586 
587 	if (flt_ot_current_tracer->id == NULL)
588 		FLT_OT_RETURN(retval);
589 
590 	if (flt_ot_current_tracer->config == NULL) {
591 		FLT_OT_POST_PARSE_ALERT("tracer '%s' has no configuration file specified", flt_ot_current_tracer->cfg_line, flt_ot_current_tracer->id);
592 	} else {
593 		flt_ot_current_tracer->cfgbuf = otc_file_read(flt_ot_current_tracer->config, "#", errbuf, sizeof(errbuf));
594 		if (flt_ot_current_tracer->cfgbuf == NULL)
595 			FLT_OT_POST_PARSE_ALERT("tracer '%s' %s", flt_ot_current_tracer->cfg_line, flt_ot_current_tracer->id, (*errbuf == '\0') ? "cannot load configuration file" : errbuf);
596 	}
597 
598 	if (flt_ot_current_tracer->plugin == NULL)
599 		FLT_OT_POST_PARSE_ALERT("tracer '%s' has no plugin library specified", flt_ot_current_tracer->cfg_line, flt_ot_current_tracer->id);
600 
601 	flt_ot_current_tracer = NULL;
602 
603 	FLT_OT_RETURN(retval);
604 }
605 
606 
607 /***
608  * NAME
609  *   flt_ot_parse_cfg_group -
610  *
611  * ARGUMENTS
612  *   file    -
613  *   linenum -
614  *   args    -
615  *   kw_mod  -
616  *
617  * DESCRIPTION
618  *   -
619  *
620  * RETURN VALUE
621  *   Returns ERR_NONE (== 0) in case of success,
622  *   or a combination of ERR_* flags if an error is encountered.
623  */
flt_ot_parse_cfg_group(const char * file,int linenum,char ** args,int kw_mod)624 static int flt_ot_parse_cfg_group(const char *file, int linenum, char **args, int kw_mod)
625 {
626 #define FLT_OT_PARSE_GROUP_DEF(a,b,c,d,e,f,g)   { FLT_OT_PARSE_GROUP_##a, b, c, d, e, f, g },
627 	static const struct flt_ot_parse_data  parse_data[] = { FLT_OT_PARSE_GROUP_DEFINES };
628 #undef FLT_OT_PARSE_GROUP_DEF
629 	const struct flt_ot_parse_data        *pdata = NULL;
630 	char                                  *err = NULL;
631 	int                                    i, retval = ERR_NONE;
632 
633 	FLT_OT_FUNC("\"%s\", %d, %p, 0x%08x", file, linenum, args, kw_mod);
634 
635 	if (flt_ot_parse_check_scope())
636 		FLT_OT_RETURN(retval);
637 
638 	retval = flt_ot_parse_cfg_check(file, linenum, args, flt_ot_current_group, parse_data, FLT_OT_TABLESIZE(parse_data), &pdata, &err);
639 	if (retval & ERR_CODE) {
640 		FLT_OT_PARSE_IFERR_ALERT();
641 
642 		FLT_OT_RETURN(retval);
643 	}
644 
645 	if (pdata->keyword == FLT_OT_PARSE_GROUP_ID) {
646 		flt_ot_current_group = flt_ot_conf_group_init(args[1], linenum, &(flt_ot_current_config->groups), &err);
647 		if (flt_ot_current_config == NULL)
648 			retval |= ERR_ABORT | ERR_ALERT;
649 	}
650 	else if (pdata->keyword == FLT_OT_PARSE_GROUP_SCOPES) {
651 		for (i = 1; !(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(i); i++)
652 			if (flt_ot_conf_ph_init(args[i], linenum, &(flt_ot_current_group->ph_scopes), &err) == NULL)
653 				retval |= ERR_ABORT | ERR_ALERT;
654 	}
655 
656 	FLT_OT_PARSE_IFERR_ALERT();
657 
658 	if ((retval & ERR_CODE) && (flt_ot_current_group != NULL))
659 		flt_ot_conf_group_free(&flt_ot_current_group);
660 
661 	FLT_OT_RETURN(retval);
662 }
663 
664 
665 /***
666  * NAME
667  *   flt_ot_post_parse_cfg_group -
668  *
669  * ARGUMENTS
670  *   This function takes no arguments.
671  *
672  * DESCRIPTION
673  *   -
674  *
675  * RETURN VALUE
676  *   Returns ERR_NONE (== 0) in case of success,
677  *   or a combination of ERR_* flags if an error is encountered.
678  */
flt_ot_post_parse_cfg_group(void)679 static int flt_ot_post_parse_cfg_group(void)
680 {
681 	int retval = ERR_NONE;
682 
683 	FLT_OT_FUNC("");
684 
685 	if (flt_ot_current_group == NULL)
686 		FLT_OT_RETURN(retval);
687 
688 	/* Check that the group has at least one scope defined. */
689 	if (LIST_ISEMPTY(&(flt_ot_current_group->ph_scopes)))
690 		FLT_OT_POST_PARSE_ALERT("group '%s' has no defined scope(s)", flt_ot_current_group->cfg_line, flt_ot_current_group->id);
691 
692 	flt_ot_current_group = NULL;
693 
694 	FLT_OT_RETURN(retval);
695 }
696 
697 
698 /***
699  * NAME
700  *   flt_ot_parse_cfg_scope_ctx -
701  *
702  * ARGUMENTS
703  *   args    -
704  *   cur_arg -
705  *   err     -
706  *
707  * DESCRIPTION
708  *   -
709  *
710  * RETURN VALUE
711  *   Returns ERR_NONE (== 0) in case of success,
712  *   or a combination of ERR_* flags if an error is encountered.
713  */
flt_ot_parse_cfg_scope_ctx(char ** args,int cur_arg,char ** err)714 static int flt_ot_parse_cfg_scope_ctx(char **args, int cur_arg, char **err)
715 {
716 	uint8_t flags = 0;
717 	int     retval = ERR_NONE;
718 
719 	FLT_OT_FUNC("%p, %d, %p:%p", args, cur_arg, FLT_OT_DPTR_ARGS(err));
720 
721 	if (strcmp(args[cur_arg], FLT_OT_PARSE_CTX_USE_HEADERS) == 0)
722 		flags = FLT_OT_CTX_USE_HEADERS;
723 	else if (strcmp(args[cur_arg], FLT_OT_PARSE_CTX_USE_VARS) == 0)
724 		flags = FLT_OT_CTX_USE_VARS;
725 	else
726 		FLT_OT_PARSE_ERR(err, "'%s' : invalid context storage type", args[0]);
727 
728 	if (flags == 0)
729 		/* Do nothing. */;
730 	else if (flt_ot_current_span->ctx_flags & flags)
731 		FLT_OT_PARSE_ERR(err, "'%s' : %s already used", args[0], args[cur_arg]);
732 	else
733 		flt_ot_current_span->ctx_flags |= flags;
734 
735 	FLT_OT_DBG(2, "ctx_flags: 0x%02hhx (0x%02hhx)", flt_ot_current_span->ctx_flags, flags);
736 
737 	FLT_OT_RETURN(retval);
738 }
739 
740 
741 /***
742  * NAME
743  *   flt_ot_parse_acl -
744  *
745  * ARGUMENTS
746  *   file    -
747  *   linenum -
748  *   px      -
749  *   args    -
750  *   err     -
751  *   head    -
752  *
753  * DESCRIPTION
754  *   -
755  *
756  * RETURN VALUE
757  *   -
758  */
flt_ot_parse_acl(const char * file,int linenum,struct proxy * px,const char ** args,char ** err,struct list * head,...)759 static struct acl_cond *flt_ot_parse_acl(const char *file, int linenum, struct proxy *px, const char **args, char **err, struct list *head, ...)
760 {
761 	va_list          ap;
762 	int              n = 0;
763 	struct acl_cond *retptr = NULL;
764 
765 	FLT_OT_FUNC("\"%s\", %d, %p, %p, %p:%p, %p, ...", file, linenum, px, args, FLT_OT_DPTR_ARGS(err), head);
766 
767 	for (va_start(ap, head); (retptr == NULL) && (head != NULL); head = va_arg(ap, typeof(head)), n++) {
768 		retptr = build_acl_cond(file, linenum, head, px, args, (n == 0) ? err : NULL);
769 		if (retptr != NULL)
770 			FLT_OT_DBG(2, "ACL build done, using list %p %d", head, n);
771 	}
772 	va_end(ap);
773 
774 	if ((retptr != NULL) && (err != NULL))
775 		FLT_OT_FREE_CLEAR(*err);
776 
777 	FLT_OT_RETURN(retptr);
778 }
779 
780 
781 /***
782  * NAME
783  *   flt_ot_parse_cfg_scope -
784  *
785  * ARGUMENTS
786  *   file    -
787  *   linenum -
788  *   args    -
789  *   kw_mod  -
790  *
791  * DESCRIPTION
792  *   Function used to load the scope block configuration.
793  *
794  * RETURN VALUE
795  *   Returns ERR_NONE (== 0) in case of success,
796  *   or a combination of ERR_* flags if an error is encountered.
797  */
flt_ot_parse_cfg_scope(const char * file,int linenum,char ** args,int kw_mod)798 static int flt_ot_parse_cfg_scope(const char *file, int linenum, char **args, int kw_mod)
799 {
800 #define FLT_OT_PARSE_SCOPE_DEF(a,b,c,d,e,f,g)   { FLT_OT_PARSE_SCOPE_##a, b, c, d, e, f, g },
801 	static const struct flt_ot_parse_data  parse_data[] = { FLT_OT_PARSE_SCOPE_DEFINES };
802 #undef FLT_OT_PARSE_SCOPE_DEF
803 	const struct flt_ot_parse_data        *pdata = NULL;
804 	char                                  *err = NULL;
805 	int                                    i, retval = ERR_NONE;
806 
807 	FLT_OT_FUNC("\"%s\", %d, %p, 0x%08x", file, linenum, args, kw_mod);
808 
809 	if (flt_ot_parse_check_scope())
810 		FLT_OT_RETURN(retval);
811 
812 	retval = flt_ot_parse_cfg_check(file, linenum, args, flt_ot_current_span, parse_data, FLT_OT_TABLESIZE(parse_data), &pdata, &err);
813 	if (retval & ERR_CODE) {
814 		FLT_OT_PARSE_IFERR_ALERT();
815 
816 		FLT_OT_RETURN(retval);
817 	}
818 
819 	if (pdata->keyword == FLT_OT_PARSE_SCOPE_ID) {
820 		/* Initialization of a new scope. */
821 		flt_ot_current_scope = flt_ot_conf_scope_init(args[1], linenum, &(flt_ot_current_config->scopes), &err);
822 		if (flt_ot_current_scope == NULL)
823 			retval |= ERR_ABORT | ERR_ALERT;
824 	}
825 	else if (pdata->keyword == FLT_OT_PARSE_SCOPE_SPAN) {
826 		/*
827 		 * Checking if this is the beginning of the definition of
828 		 * a new span.
829 		 */
830 		if (flt_ot_current_span != NULL) {
831 			FLT_OT_DBG(3, "span '%s' (done)", flt_ot_current_span->id);
832 
833 			flt_ot_current_span = NULL;
834 		}
835 
836 		/* Initialization of a new span. */
837 		flt_ot_current_span = flt_ot_conf_span_init(args[1], linenum, &(flt_ot_current_scope->spans), &err);
838 
839 		/*
840 		 * In case the span has a defined reference,
841 		 * the correctness of the arguments is checked here.
842 		 */
843 		if (flt_ot_current_span == NULL) {
844 			retval |= ERR_ABORT | ERR_ALERT;
845 		}
846 		else if (FLT_OT_ARG_ISVALID(2)) {
847 			for (i = 2; (i < pdata->args_max) && FLT_OT_ARG_ISVALID(i); i++)
848 				if (strcmp(args[i], FLT_OT_PARSE_SPAN_ROOT) == 0) {
849 					if (flt_ot_current_span->flag_root)
850 						FLT_OT_PARSE_ERR(&err, "'%s' : already set (use '%s%s')", args[i], pdata->name, pdata->usage);
851 					else
852 						flt_ot_current_span->flag_root = 1;
853 				}
854 				else if ((strcmp(args[i], FLT_OT_PARSE_SPAN_REF_CHILD) == 0) || (strcmp(args[i], FLT_OT_PARSE_SPAN_REF_FOLLOWS) == 0)) {
855 					if (!FLT_OT_ARG_ISVALID(i + 1)) {
856 						FLT_OT_PARSE_ERR(&err, "'%s' : too few arguments (use '%s%s')", args[i], pdata->name, pdata->usage);
857 					}
858 					else if (strcmp(args[i++], FLT_OT_PARSE_SPAN_REF_CHILD) == 0) {
859 						flt_ot_current_span->ref_type   = otc_span_reference_child_of;
860 						flt_ot_current_span->ref_id_len = strlen(args[i]);
861 
862 						retval = flt_ot_parse_strdup(&(flt_ot_current_span->ref_id), args[i], &err, args[1]);
863 					}
864 					else {
865 						flt_ot_current_span->ref_type   = otc_span_reference_follows_from;
866 						flt_ot_current_span->ref_id_len = strlen(args[i]);
867 
868 						retval = flt_ot_parse_strdup(&(flt_ot_current_span->ref_id), args[i], &err, args[1]);
869 					}
870 				}
871 				else {
872 					FLT_OT_PARSE_ERR(&err, "'%s' : invalid argument (use '%s%s')", args[i], pdata->name, pdata->usage);
873 				}
874 		}
875 		else {
876 			/*
877 			 * This is not a faulty configuration, only such a case
878 			 * will be logged.
879 			 */
880 			FLT_OT_DBG(3, "new span '%s' without reference", flt_ot_current_span->id);
881 		}
882 	}
883 	else if (pdata->keyword == FLT_OT_PARSE_SCOPE_TAG) {
884 		retval = flt_ot_parse_cfg_sample(file, linenum, args, &(flt_ot_current_span->tags), &err);
885 	}
886 	else if (pdata->keyword == FLT_OT_PARSE_SCOPE_LOG) {
887 		retval = flt_ot_parse_cfg_sample(file, linenum, args, &(flt_ot_current_span->logs), &err);
888 	}
889 	else if (pdata->keyword == FLT_OT_PARSE_SCOPE_BAGGAGE) {
890 		retval = flt_ot_parse_cfg_sample(file, linenum, args, &(flt_ot_current_span->baggages), &err);
891 	}
892 	else if (pdata->keyword == FLT_OT_PARSE_SCOPE_INJECT) {
893 		/*
894 		 * Automatic context name generation can be specified here
895 		 * if the contents of the FLT_OT_PARSE_CTX_AUTONAME macro
896 		 * are used as the name.  In that case, if the context is
897 		 * after a particular event, it gets its name; otherwise
898 		 * it gets the name of the current span.
899 		 */
900 		if (flt_ot_current_span->ctx_id != NULL)
901 			FLT_OT_PARSE_ERR(&err, "'%s' : only one context per span is allowed", args[1]);
902 		else if (strcmp(args[1], FLT_OT_PARSE_CTX_AUTONAME) != 0)
903 			retval = flt_ot_parse_strdup(&(flt_ot_current_span->ctx_id), args[1], &err, args[0]);
904 		else if (flt_ot_current_scope->event != FLT_OT_EVENT_REQ_NONE)
905 			retval = flt_ot_parse_strdup(&(flt_ot_current_span->ctx_id), flt_ot_event_data[flt_ot_current_scope->event].name, &err, args[0]);
906 		else
907 			retval = flt_ot_parse_strdup(&(flt_ot_current_span->ctx_id), flt_ot_current_span->id, &err, args[0]);
908 
909 		if (flt_ot_current_span->ctx_id != NULL) {
910 			flt_ot_current_span->ctx_id_len = strlen(flt_ot_current_span->ctx_id);
911 
912 			/*
913 			 * Here is checked the context storage type; which, if
914 			 * not explicitly specified, is set to HTTP headers.
915 			 *
916 			 * It is possible to use both types of context storage
917 			 * at the same time.
918 			 */
919 			if (FLT_OT_ARG_ISVALID(2)) {
920 				retval = flt_ot_parse_cfg_scope_ctx(args, 2, &err);
921 				if (!(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(3))
922 					retval = flt_ot_parse_cfg_scope_ctx(args, 3, &err);
923 			} else {
924 				flt_ot_current_span->ctx_flags = FLT_OT_CTX_USE_HEADERS;
925 			}
926 		}
927 	}
928 	else if (pdata->keyword == FLT_OT_PARSE_SCOPE_EXTRACT) {
929 		struct flt_ot_conf_context *conf_ctx;
930 
931 		/*
932 		 * Here is checked the context storage type; which, if
933 		 * not explicitly specified, is set to HTTP headers.
934 		 */
935 		conf_ctx = flt_ot_conf_context_init(args[1], linenum, &(flt_ot_current_scope->contexts), &err);
936 		if (conf_ctx == NULL)
937 			retval |= ERR_ABORT | ERR_ALERT;
938 		else if (!FLT_OT_ARG_ISVALID(2))
939 			conf_ctx->flags = FLT_OT_CTX_USE_HEADERS;
940 		else if (strcmp(args[2], FLT_OT_PARSE_CTX_USE_HEADERS) == 0)
941 			conf_ctx->flags = FLT_OT_CTX_USE_HEADERS;
942 		else if (strcmp(args[2], FLT_OT_PARSE_CTX_USE_VARS) == 0)
943 			conf_ctx->flags = FLT_OT_CTX_USE_VARS;
944 		else
945 			FLT_OT_PARSE_ERR(&err, "'%s' : invalid context storage type", args[2]);
946 	}
947 	else if (pdata->keyword == FLT_OT_PARSE_SCOPE_FINISH) {
948 		retval = flt_ot_parse_cfg_str(file, linenum, args, &(flt_ot_current_scope->finish), &err);
949 	}
950 	else if (pdata->keyword == FLT_OT_PARSE_SCOPE_ACL) {
951 		if (strcasecmp(args[1], "or") == 0)
952 			FLT_OT_PARSE_ERR(&err, "'%s %s ...' : invalid ACL name", args[0], args[1]);
953 		else if (parse_acl((const char **)args + 1, &(flt_ot_current_scope->acls), &err, &(flt_ot_current_config->proxy->conf.args), file, linenum) == NULL)
954 			retval |= ERR_ABORT | ERR_ALERT;
955 	}
956 	else if (pdata->keyword == FLT_OT_PARSE_SCOPE_EVENT) {
957 		/* Scope can only have one event defined. */
958 		if (flt_ot_current_scope->event != FLT_OT_EVENT_REQ_NONE) {
959 			FLT_OT_PARSE_ERR(&err, "'%s' : event already set", flt_ot_current_scope->id);
960 		} else {
961 			/* Check the event name. */
962 			for (i = 0; i < FLT_OT_TABLESIZE(flt_ot_event_data); i++)
963 				if (strcmp(flt_ot_event_data[i].name, args[1]) == 0) {
964 					flt_ot_current_scope->event = i;
965 
966 					break;
967 				}
968 
969 			/*
970 			 * The event can have some condition defined and this
971 			 * is checked here.
972 			 */
973 			if (flt_ot_current_scope->event == FLT_OT_EVENT_REQ_NONE) {
974 				FLT_OT_PARSE_ERR(&err, "'%s' : unknown event", args[1]);
975 			}
976 			else if (!FLT_OT_ARG_ISVALID(2)) {
977 				/* Do nothing. */
978 			}
979 			else if ((strcmp(args[2], FLT_OT_CONDITION_IF) == 0) || (strcmp(args[2], FLT_OT_CONDITION_UNLESS) == 0)) {
980 				/*
981 				 * We will first try to build ACL condition using
982 				 * local settings and then if that fails, using
983 				 * global settings (from tracer block).  If it
984 				 * also fails, then try to use ACL defined in
985 				 * the HAProxy configuration.
986 				 */
987 				flt_ot_current_scope->cond = flt_ot_parse_acl(file, linenum, flt_ot_current_config->proxy, (const char **)args + 2, &err, &(flt_ot_current_scope->acls), &(flt_ot_current_config->tracer->acls), &(flt_ot_current_config->proxy->acl), NULL);
988 				if (flt_ot_current_scope->cond == NULL)
989 					retval |= ERR_ABORT | ERR_ALERT;
990 			}
991 			else {
992 				FLT_OT_PARSE_ERR(&err, "'%s' : expects either 'if' or 'unless' followed by a condition but found '%s'", args[1], args[2]);
993 			}
994 
995 			if (!(retval & ERR_CODE))
996 				FLT_OT_DBG(3, "event '%s'", args[1]);
997 		}
998 	}
999 
1000 	FLT_OT_PARSE_IFERR_ALERT();
1001 
1002 	if ((retval & ERR_CODE) && (flt_ot_current_scope != NULL)) {
1003 		flt_ot_conf_scope_free(&flt_ot_current_scope);
1004 
1005 		flt_ot_current_span = NULL;
1006 	}
1007 
1008 	FLT_OT_RETURN(retval);
1009 }
1010 
1011 
1012 /***
1013  * NAME
1014  *   flt_ot_post_parse_cfg_scope -
1015  *
1016  * ARGUMENTS
1017  *   This function takes no arguments.
1018  *
1019  * DESCRIPTION
1020  *   In this function the correctness of the complete scope block is examined.
1021  *   This does not mean that all elements are checked here, but only those for
1022  *   which it has not been possible to establish their complete correctness in
1023  *   the function flt_ot_parse_cfg_scope().
1024  *
1025  * RETURN VALUE
1026  *   Returns ERR_NONE (== 0) in case of success,
1027  *   or a combination of ERR_* flags if an error is encountered.
1028  */
flt_ot_post_parse_cfg_scope(void)1029 static int flt_ot_post_parse_cfg_scope(void)
1030 {
1031 	struct flt_ot_conf_span *conf_span;
1032 	int                      retval = ERR_NONE;
1033 
1034 	FLT_OT_FUNC("");
1035 
1036 	if (flt_ot_current_scope == NULL)
1037 		FLT_OT_RETURN(retval);
1038 
1039 	/* If span context inject is used, check that this is possible. */
1040 	list_for_each_entry(conf_span, &(flt_ot_current_scope->spans), list)
1041 		if ((conf_span->ctx_id != NULL) && (conf_span->ctx_flags & FLT_OT_CTX_USE_HEADERS))
1042 			if (!flt_ot_event_data[flt_ot_current_scope->event].flag_http_inject)
1043 				FLT_OT_POST_PARSE_ALERT("inject '%s' : cannot use on this event", conf_span->cfg_line, conf_span->ctx_id);
1044 
1045 	if (retval & ERR_CODE)
1046 		flt_ot_conf_scope_free(&flt_ot_current_scope);
1047 
1048 	flt_ot_current_scope = NULL;
1049 	flt_ot_current_span  = NULL;
1050 
1051 	FLT_OT_RETURN(retval);
1052 }
1053 
1054 
1055 /***
1056  * NAME
1057  *   flt_ot_parse_cfg -
1058  *
1059  * ARGUMENTS
1060  *   conf     -
1061  *   flt_name -
1062  *   err      -
1063  *
1064  * DESCRIPTION
1065  *   -
1066  *
1067  * RETURN VALUE
1068  *   Returns ERR_NONE (== 0) in case of success,
1069  *   or a combination of ERR_* flags if an error is encountered.
1070  */
flt_ot_parse_cfg(struct flt_ot_conf * conf,const char * flt_name,char ** err)1071 static int flt_ot_parse_cfg(struct flt_ot_conf *conf, const char *flt_name, char **err)
1072 {
1073 	struct list backup_sections;
1074 	int         retval = ERR_ABORT | ERR_ALERT;
1075 
1076 	FLT_OT_FUNC("%p, \"%s\", %p:%p", conf, flt_name, FLT_OT_DPTR_ARGS(err));
1077 
1078 	flt_ot_current_config = conf;
1079 
1080 	/* Backup sections. */
1081 	LIST_INIT(&backup_sections);
1082 	cfg_backup_sections(&backup_sections);
1083 
1084 	/* Register new OT sections and parse the OT filter configuration file. */
1085 	if (!cfg_register_section(FLT_OT_PARSE_SECTION_TRACER_ID, flt_ot_parse_cfg_tracer, flt_ot_post_parse_cfg_tracer))
1086 		/* Do nothing. */;
1087 	else if (!cfg_register_section(FLT_OT_PARSE_SECTION_GROUP_ID, flt_ot_parse_cfg_group, flt_ot_post_parse_cfg_group))
1088 		/* Do nothing. */;
1089 	else if (!cfg_register_section(FLT_OT_PARSE_SECTION_SCOPE_ID, flt_ot_parse_cfg_scope, flt_ot_post_parse_cfg_scope))
1090 		/* Do nothing. */;
1091 	else if (access(conf->cfg_file, R_OK) == -1)
1092 		FLT_OT_PARSE_ERR(err, "'%s' : %s", conf->cfg_file, strerror(errno));
1093 	else
1094 		retval = readcfgfile(conf->cfg_file);
1095 
1096 	/* Unregister OT sections and restore previous sections. */
1097 	cfg_unregister_sections();
1098 	cfg_restore_sections(&backup_sections);
1099 
1100 	flt_ot_current_config = NULL;
1101 
1102 	FLT_OT_RETURN(retval);
1103 }
1104 
1105 
1106 /***
1107  * NAME
1108  *   flt_ot_parse -
1109  *
1110  * ARGUMENTS
1111  *   args    -
1112  *   cur_arg -
1113  *   px      -
1114  *   fconf   -
1115  *   err     -
1116  *   private -
1117  *
1118  * DESCRIPTION
1119  *   -
1120  *
1121  * RETURN VALUE
1122  *   Returns ERR_NONE (== 0) in case of success,
1123  *   or a combination of ERR_* flags if an error is encountered.
1124  */
flt_ot_parse(char ** args,int * cur_arg,struct proxy * px,struct flt_conf * fconf,char ** err,void * private)1125 static int flt_ot_parse(char **args, int *cur_arg, struct proxy *px, struct flt_conf *fconf, char **err, void *private)
1126 {
1127 	struct flt_ot_conf *conf = NULL;
1128 	int                 pos, retval = ERR_NONE;
1129 
1130 #ifdef DEBUG_OT
1131 	FLT_OT_RUN_ONCE(
1132 #  ifndef DEBUG_OT_SYSTIME
1133 		(void)memcpy(&(flt_ot_debug.start), &now, sizeof(flt_ot_debug.start));
1134 #  endif
1135 
1136 		flt_ot_debug.level = FLT_OT_DEBUG_LEVEL;
1137 	);
1138 #endif
1139 
1140 	FLT_OT_FUNC("%p, %p, %p, %p, %p:%p, %p", args, cur_arg, px, fconf, FLT_OT_DPTR_ARGS(err), private);
1141 
1142 #ifdef OTC_DBG_MEM
1143 	FLT_OT_RUN_ONCE(
1144 		if (otc_dbg_mem_init(&dbg_mem, dbg_mem_data, FLT_OT_TABLESIZE(dbg_mem_data), 0xff) == -1) {
1145 			FLT_OT_PARSE_ERR(err, "cannot initialize memory debugger");
1146 
1147 			FLT_OT_RETURN(retval);
1148 		}
1149 	);
1150 #endif
1151 
1152 	FLT_OT_ARGS_DUMP();
1153 
1154 	conf = flt_ot_conf_init(px);
1155 	if (conf == NULL) {
1156 		FLT_OT_PARSE_ERR(err, "'%s' : out of memory", args[*cur_arg]);
1157 
1158 		FLT_OT_RETURN(retval);
1159 	}
1160 
1161 	for (pos = *cur_arg + 1; !(retval & ERR_CODE) && FLT_OT_ARG_ISVALID(pos); pos++) {
1162 		FLT_OT_DBG(3, "args[%d:2] : { '%s' '%s' }", pos, args[pos], args[pos + 1]);
1163 
1164 		if (strcmp(args[pos], FLT_OT_OPT_FILTER_ID) == 0) {
1165 			retval = flt_ot_parse_keyword(&(conf->id), args, *cur_arg, pos, err, "name");
1166 			pos++;
1167 		}
1168 		else if (strcmp(args[pos], FLT_OT_OPT_CONFIG) == 0) {
1169 			retval = flt_ot_parse_keyword(&(conf->cfg_file), args, *cur_arg, pos, err, "configuration file");
1170 			if (!(retval & ERR_CODE))
1171 				retval = flt_ot_parse_cfg(conf, args[*cur_arg], err);
1172 			pos++;
1173 		}
1174 		else {
1175 			FLT_OT_PARSE_ERR(err, "'%s' : unknown keyword '%s'", args[*cur_arg], args[pos]);
1176 		}
1177 	}
1178 
1179 	/* If the OpenTracing filter ID is not set, use default name. */
1180 	if (!(retval & ERR_CODE) && (conf->id == NULL)) {
1181 		ha_warning("parsing : " FLT_OT_FMT_TYPE FLT_OT_FMT_NAME "'no filter id set, using default id '%s'\n", FLT_OT_OPT_FILTER_ID_DEFAULT);
1182 
1183 		retval = flt_ot_parse_strdup(&(conf->id), FLT_OT_OPT_FILTER_ID_DEFAULT, err, args[*cur_arg]);
1184 	}
1185 
1186 	if (!(retval & ERR_CODE) && (conf->cfg_file == NULL))
1187 		FLT_OT_PARSE_ERR(err, "'%s' : no configuration file specified", args[*cur_arg]);
1188 
1189 	if (retval & ERR_CODE) {
1190 		flt_ot_conf_free(&conf);
1191 	} else {
1192 		fconf->id   = ot_flt_id;
1193 		fconf->ops  = &flt_ot_ops;
1194 		fconf->conf = conf;
1195 
1196 		*cur_arg = pos;
1197 
1198 		FLT_OT_DBG(3, "filter set: id '%s', config '%s'", conf->id, conf->cfg_file);
1199 	}
1200 
1201 	FLT_OT_RETURN(retval);
1202 }
1203 
1204 
1205 /* Declare the filter parser for FLT_OT_OPT_NAME keyword. */
1206 static struct flt_kw_list flt_kws = { FLT_OT_SCOPE, { }, {
1207 		{ FLT_OT_OPT_NAME, flt_ot_parse, NULL },
1208 		{ NULL, NULL, NULL },
1209 	}
1210 };
1211 
1212 INITCALL1(STG_REGISTER, flt_register_keywords, &flt_kws);
1213 
1214 /*
1215  * Local variables:
1216  *  c-indent-level: 8
1217  *  c-basic-offset: 8
1218  * End:
1219  *
1220  * vi: noexpandtab shiftwidth=8 tabstop=8
1221  */
1222