1 /*
2 * Copyright (c) 2002-2012 Balabit
3 * Copyright (c) 1998-2012 Balázs Scheidler
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * As an additional exemption you are allowed to compile & link against the
20 * OpenSSL libraries as published by the OpenSSL project. See the file
21 * COPYING for details.
22 *
23 */
24
25 #include "cfg-tree.h"
26 #include "logmpx.h"
27 #include "logpipe.h"
28
29 #include <string.h>
30
31 static void _log_expr_node_free(LogExprNode *self);
32
33 LogExprNode *
log_expr_node_ref(LogExprNode * self)34 log_expr_node_ref(LogExprNode *self)
35 {
36 g_assert(!self || g_atomic_counter_get(&self->ref_cnt) > 0);
37
38 if (self)
39 {
40 g_atomic_counter_inc(&self->ref_cnt);
41 }
42 return self;
43 }
44
45 LogExprNode *
log_expr_node_unref(LogExprNode * self)46 log_expr_node_unref(LogExprNode *self)
47 {
48 g_assert(!self || g_atomic_counter_get(&self->ref_cnt));
49
50 if (self && (g_atomic_counter_dec_and_test(&self->ref_cnt)))
51 {
52 _log_expr_node_free(self);
53 return NULL;
54 }
55 return self;
56 }
57
58 /*
59 * Return the textual representation of a node content type.
60 */
61 const gchar *
log_expr_node_get_content_name(gint content)62 log_expr_node_get_content_name(gint content)
63 {
64 switch (content)
65 {
66 case ENC_PIPE:
67 return "log";
68 case ENC_SOURCE:
69 return "source";
70 case ENC_FILTER:
71 return "filter";
72 case ENC_PARSER:
73 return "parser";
74 case ENC_REWRITE:
75 return "rewrite";
76 case ENC_DESTINATION:
77 return "destination";
78 default:
79 g_assert_not_reached();
80 break;
81 }
82 }
83
84 /*
85 * Return the textual representation of a node layout.
86 */
87 const gchar *
log_expr_node_get_layout_name(gint layout)88 log_expr_node_get_layout_name(gint layout)
89 {
90 switch (layout)
91 {
92 case ENL_SINGLE:
93 return "single";
94 case ENL_REFERENCE:
95 return "reference";
96 case ENL_SEQUENCE:
97 return "sequence";
98 case ENL_JUNCTION:
99 return "junction";
100 default:
101 g_assert_not_reached();
102 break;
103 }
104 }
105
106 /* return the top-most rule that matches content. This is used to
107 * query the enclosing rule for a given LogExprNode. It is looking up
108 * the top-most node, so that we use the name of the enclosing block
109 * that the user specified. In-line defined, and thus anonymous
110 * expressions are automatically named. In that case this function
111 * will return a node matching @content but without an actual name.
112 */
113 LogExprNode *
log_expr_node_get_container_rule(LogExprNode * self,gint content)114 log_expr_node_get_container_rule(LogExprNode *self, gint content)
115 {
116 LogExprNode *node, *result = NULL;
117
118 node = self->parent;
119 while (node)
120 {
121 if (node->content == content)
122 {
123 result = node;
124 }
125 node = node->parent;
126 }
127 return result;
128 }
129
130 /**
131 * log_expr_node_append:
132 * @a: first LogExprNode
133 * @b: second LogExprNode
134 *
135 * This function appends @b to @a in a linked list using the ep_next field
136 * in LogExprNode.
137 **/
138 void
log_expr_node_append(LogExprNode * a,LogExprNode * b)139 log_expr_node_append(LogExprNode *a, LogExprNode *b)
140 {
141 a->next = b;
142 }
143
144 LogExprNode *
log_expr_node_append_tail(LogExprNode * a,LogExprNode * b)145 log_expr_node_append_tail(LogExprNode *a, LogExprNode *b)
146 {
147 if (a)
148 {
149 LogExprNode *p = a;
150 while (p->next)
151 p = p->next;
152 log_expr_node_append(p, b);
153 return a;
154 }
155 return b;
156 }
157
158 /*
159 * Format the location information for a LogExprNode. For nodes that
160 * have no location information, the parent is considered, this way
161 * always returning something close to the location that defined the
162 * node.
163 */
164 const gchar *
log_expr_node_format_location(LogExprNode * self,gchar * buf,gsize buf_len)165 log_expr_node_format_location(LogExprNode *self, gchar *buf, gsize buf_len)
166 {
167 LogExprNode *node = self;
168
169 while (node)
170 {
171 if (node->line || node->column)
172 {
173 g_snprintf(buf, buf_len, "%s:%d:%d", self->filename ? : "#buffer", node->line, node->column);
174 break;
175 }
176 node = node->parent;
177 }
178 if (!node)
179 strncpy(buf, "#unknown", buf_len);
180 return buf;
181 }
182
183 EVTTAG *
log_expr_node_location_tag(LogExprNode * self)184 log_expr_node_location_tag(LogExprNode *self)
185 {
186 gchar buf[128];
187
188 return evt_tag_str("location", log_expr_node_format_location(self, buf, sizeof(buf)));
189 }
190
191 /*
192 * Set the list of children of a LogExprNode. It automatically updates
193 * the children's "parent" pointers so that the tree can be traversed
194 * upwards too.
195 */
196 void
log_expr_node_set_children(LogExprNode * self,LogExprNode * children)197 log_expr_node_set_children(LogExprNode *self, LogExprNode *children)
198 {
199 LogExprNode *ep;
200
201 /* we don't currently support setting the children list multiple
202 * times. no inherent reason, just the proper free function would
203 * need to be written, until then this assert would reveal the case
204 * quite fast.
205 */
206
207 g_assert(self->children == NULL);
208
209 for (ep = children; ep; ep = ep->next)
210 ep->parent = self;
211
212 self->children = children;
213 }
214
215 /*
216 * Set the object associated with a node. The "object" member is used
217 * to store the LogPipe instance associated with ENL_SINGLE/ENC_PIPE
218 * nodes.
219 */
220 void
log_expr_node_set_object(LogExprNode * self,gpointer object,GDestroyNotify destroy)221 log_expr_node_set_object(LogExprNode *self, gpointer object, GDestroyNotify destroy)
222 {
223 self->object = object;
224 self->object_destroy = destroy;
225 }
226
227 /*
228 * The aux object is the secondary object associated with a node, it
229 * is mostly unused, except for nodes storing source and destination
230 * statements, in which case this contains a reference to the last
231 * item of the compiled sequence (for sources) or the first item of
232 * the compiled sequence (destinations).
233 *
234 * This mechanism is used to avoid having to clone source/destination
235 * pipes, which operation they don't support.
236 */
237 void
log_expr_node_set_aux(LogExprNode * self,gpointer aux,GDestroyNotify destroy)238 log_expr_node_set_aux(LogExprNode *self, gpointer aux, GDestroyNotify destroy)
239 {
240 self->aux = aux;
241 self->aux_destroy = destroy;
242 }
243
244 /**
245 * log_expr_node_new:
246 * @layout: layout of the children (ENL_*)
247 * @content: what kind of expression this node stores (ENC_*)
248 * @name: name of this rule (optional)
249 * @children: child nodes
250 * @flags: a combination of LC_* flags as specified by the administrator
251 * @yylloc: the lexer location in the configuration file.
252 *
253 * This function constructs a LogExprNode object which encapsulates a
254 * log expression in the configuration. See the note in cfg-tree.h for
255 * more information about LogExprNode objects and log expressions.
256 **/
257 LogExprNode *
log_expr_node_new(gint layout,gint content,const gchar * name,LogExprNode * children,guint32 flags,CFG_LTYPE * yylloc)258 log_expr_node_new(gint layout, gint content, const gchar *name, LogExprNode *children, guint32 flags, CFG_LTYPE *yylloc)
259 {
260 LogExprNode *self = g_new0(LogExprNode, 1);
261
262 g_atomic_counter_set(&self->ref_cnt, 1);
263
264 self->layout = layout;
265 self->content = content;
266 self->name = g_strdup(name);
267 log_expr_node_set_children(self, children);
268 self->flags = flags;
269 if (yylloc)
270 {
271 self->filename = g_strdup(yylloc->level->name);
272 self->line = yylloc->first_line;
273 self->column = yylloc->first_column;
274 }
275 return self;
276 }
277
278 /**
279 * log_expr_node_free:
280 * @self: LogExprNode instance
281 *
282 * This function frees the LogExprNode object encapsulating a log
283 * expression node pointed to by @self.
284 **/
285 static void
_log_expr_node_free(LogExprNode * self)286 _log_expr_node_free(LogExprNode *self)
287 {
288 LogExprNode *next, *p;
289
290 for (p = self->children ; p; p = next)
291 {
292 next = p->next;
293 log_expr_node_unref(p);
294 }
295 if (self->object && self->object_destroy)
296 self->object_destroy(self->object);
297 if (self->aux && self->aux_destroy)
298 self->aux_destroy(self->aux);
299 g_free(self->name);
300 g_free(self->filename);
301 g_free(self);
302 }
303
304 LogExprNode *
log_expr_node_new_pipe(LogPipe * pipe,CFG_LTYPE * yylloc)305 log_expr_node_new_pipe(LogPipe *pipe, CFG_LTYPE *yylloc)
306 {
307 LogExprNode *node = log_expr_node_new(ENL_SINGLE, ENC_PIPE, NULL, NULL, 0, yylloc);
308
309 log_expr_node_set_object(node, pipe, (GDestroyNotify) log_pipe_unref);
310 return node;
311 }
312
313 LogExprNode *
log_expr_node_new_source(const gchar * name,LogExprNode * children,CFG_LTYPE * yylloc)314 log_expr_node_new_source(const gchar *name, LogExprNode *children, CFG_LTYPE *yylloc)
315 {
316 return log_expr_node_new(ENL_SEQUENCE, ENC_SOURCE, name, children, 0, yylloc);
317 }
318
319 LogExprNode *
log_expr_node_new_source_reference(const gchar * name,CFG_LTYPE * yylloc)320 log_expr_node_new_source_reference(const gchar *name, CFG_LTYPE *yylloc)
321 {
322 return log_expr_node_new(ENL_REFERENCE, ENC_SOURCE, name, NULL, 0, yylloc);
323 }
324
325 LogExprNode *
log_expr_node_new_destination(const gchar * name,LogExprNode * children,CFG_LTYPE * yylloc)326 log_expr_node_new_destination(const gchar *name, LogExprNode *children, CFG_LTYPE *yylloc)
327 {
328 return log_expr_node_new(ENL_SEQUENCE, ENC_DESTINATION, name, children, 0, yylloc);
329 }
330
331 LogExprNode *
log_expr_node_new_destination_reference(const gchar * name,CFG_LTYPE * yylloc)332 log_expr_node_new_destination_reference(const gchar *name, CFG_LTYPE *yylloc)
333 {
334 return log_expr_node_new(ENL_REFERENCE, ENC_DESTINATION, name, NULL, 0, yylloc);
335 }
336
337 LogExprNode *
log_expr_node_new_filter(const gchar * name,LogExprNode * child,CFG_LTYPE * yylloc)338 log_expr_node_new_filter(const gchar *name, LogExprNode *child, CFG_LTYPE *yylloc)
339 {
340 return log_expr_node_new(ENL_SEQUENCE, ENC_FILTER, name, child, 0, yylloc);
341 }
342
343 LogExprNode *
log_expr_node_new_filter_reference(const gchar * name,CFG_LTYPE * yylloc)344 log_expr_node_new_filter_reference(const gchar *name, CFG_LTYPE *yylloc)
345 {
346 return log_expr_node_new(ENL_REFERENCE, ENC_FILTER, name, NULL, 0, yylloc);
347 }
348
349 LogExprNode *
log_expr_node_new_parser(const gchar * name,LogExprNode * children,CFG_LTYPE * yylloc)350 log_expr_node_new_parser(const gchar *name, LogExprNode *children, CFG_LTYPE *yylloc)
351 {
352 return log_expr_node_new(ENL_SEQUENCE, ENC_PARSER, name, children, 0, yylloc);
353 }
354
355 LogExprNode *
log_expr_node_new_parser_reference(const gchar * name,CFG_LTYPE * yylloc)356 log_expr_node_new_parser_reference(const gchar *name, CFG_LTYPE *yylloc)
357 {
358 return log_expr_node_new(ENL_REFERENCE, ENC_PARSER, name, NULL, 0, yylloc);
359 }
360
361 LogExprNode *
log_expr_node_new_rewrite(const gchar * name,LogExprNode * children,CFG_LTYPE * yylloc)362 log_expr_node_new_rewrite(const gchar *name, LogExprNode *children, CFG_LTYPE *yylloc)
363 {
364 return log_expr_node_new(ENL_SEQUENCE, ENC_REWRITE, name, children, 0, yylloc);
365 }
366
367 LogExprNode *
log_expr_node_new_rewrite_reference(const gchar * name,CFG_LTYPE * yylloc)368 log_expr_node_new_rewrite_reference(const gchar *name, CFG_LTYPE *yylloc)
369 {
370 return log_expr_node_new(ENL_REFERENCE, ENC_REWRITE, name, NULL, 0, yylloc);
371 }
372
373 LogExprNode *
log_expr_node_new_log(LogExprNode * children,guint32 flags,CFG_LTYPE * yylloc)374 log_expr_node_new_log(LogExprNode *children, guint32 flags, CFG_LTYPE *yylloc)
375 {
376 return log_expr_node_new(ENL_SEQUENCE, ENC_PIPE, NULL, children, flags, yylloc);
377 }
378
379 LogExprNode *
log_expr_node_new_sequence(LogExprNode * children,CFG_LTYPE * yylloc)380 log_expr_node_new_sequence(LogExprNode *children, CFG_LTYPE *yylloc)
381 {
382 return log_expr_node_new(ENL_SEQUENCE, ENC_PIPE, NULL, children, 0, yylloc);
383 }
384
385 LogExprNode *
log_expr_node_new_junction(LogExprNode * children,CFG_LTYPE * yylloc)386 log_expr_node_new_junction(LogExprNode *children, CFG_LTYPE *yylloc)
387 {
388 return log_expr_node_new(ENL_JUNCTION, ENC_PIPE, NULL, children, 0, yylloc);
389 }
390
391 /****************************************************************************
392 * Functions related to conditional nodes
393 *
394 * These are higher-level functions that map if-elif-else structure to
395 * LogExprNode instances. Rather than using a higher level data struct
396 * which then generates LogExprNode instances, we represent/manipulate the
397 * if-elif-else structure right within LogExprNode.
398 *
399 * A conditional node is simply a junction with two children:
400 *
401 * 1) the first child is the "TRUE" branch, with the filter expression
402 * attached and the final flag
403 *
404 * 2) the second child is the "FALSE" branch, possibly empty, but also
405 * the final flag.
406 *
407 * Basically this is the equivalent to:
408 *
409 * junction {
410 * channel {
411 * filter { EXPRESSION; };
412 * flags(final);
413 * };
414 * channel {
415 * flags(final);
416 * };
417 * };
418 *
419 * When parsing an if block, we generate both children immediately, with the
420 * empty 2nd channel, and then if an elif or else comes, the FALSE branch
421 * gets replaced.
422 *
423 * The series of if-elif-else sequences is represented by its first
424 * LogExprNode (e.g. the first if). When we need to add an else or elif,
425 * we would have to locate the last dangling if statement based on this
426 * first LogExprNode. The alternative would have been to store the last if
427 * statement in a variable, however that becomes pretty complicated if we
428 * need to handle nesting.
429 *
430 ****************************************************************************/
431
432 static LogExprNode *
log_expr_node_conditional_get_true_branch(LogExprNode * node)433 log_expr_node_conditional_get_true_branch(LogExprNode *node)
434 {
435 g_assert(node->layout == ENL_JUNCTION);
436
437 LogExprNode *branches = node->children;
438
439 g_assert(branches != NULL);
440 g_assert(branches->next != NULL);
441 g_assert(branches->next->next == NULL);
442
443 /* first child */
444 return branches;
445 }
446
447 static LogExprNode *
log_expr_node_conditional_get_false_branch(LogExprNode * node)448 log_expr_node_conditional_get_false_branch(LogExprNode *node)
449 {
450 g_assert(node->layout == ENL_JUNCTION);
451
452 LogExprNode *branches = node->children;
453 g_assert(branches != NULL);
454 g_assert(branches->next != NULL);
455 g_assert(branches->next->next == NULL);
456
457 /* second child */
458 return branches->next;
459 }
460
461 static gboolean
log_expr_node_conditional_is_branch_empty(LogExprNode * node)462 log_expr_node_conditional_is_branch_empty(LogExprNode *node)
463 {
464 return node->children == NULL;
465 }
466
467 /* this function locates the last dangling if, based on the very first if
468 * statement in a series of ifs at the same level */
469 static LogExprNode *
_locate_last_conditional_along_nested_else_blocks(LogExprNode * head)470 _locate_last_conditional_along_nested_else_blocks(LogExprNode *head)
471 {
472 while (1)
473 {
474 g_assert(log_expr_node_conditional_get_true_branch(head) != NULL);
475 g_assert(log_expr_node_conditional_get_false_branch(head) != NULL);
476
477 LogExprNode *false_branch = log_expr_node_conditional_get_false_branch(head);
478
479 /* check if this is the last else */
480 if (log_expr_node_conditional_is_branch_empty(false_branch))
481 return head;
482 head = false_branch->children;
483 }
484 g_assert_not_reached();
485 }
486
487 /* change the FALSE branch (e.g. the else case) of the last dangling if, specified by the head element */
488 void
log_expr_node_conditional_set_false_branch_of_the_last_if(LogExprNode * conditional_head_node,LogExprNode * false_expr)489 log_expr_node_conditional_set_false_branch_of_the_last_if(LogExprNode *conditional_head_node, LogExprNode *false_expr)
490 {
491 LogExprNode *conditional_node = _locate_last_conditional_along_nested_else_blocks(conditional_head_node);
492 LogExprNode *branches = conditional_node->children;
493
494 /* a conditional branch always have two children (see the constructor
495 * below), the first one is the "true" branch and the second one is the
496 * "false" branch, as they are constructed as final log channels with
497 * filter statement in the first one as the "if" expression. */
498
499 /* assert that we only have two children */
500 g_assert(branches != NULL);
501 g_assert(branches->next != NULL);
502 g_assert(branches->next->next == NULL);
503
504
505 /* construct the new false branch */
506 LogExprNode *false_branch = log_expr_node_new_log(
507 false_expr,
508 log_expr_node_lookup_flag("final"),
509 NULL
510 );
511
512 /* unlink and free the old one */
513 LogExprNode *old_false_branch = branches->next;
514 branches->next = false_branch;
515 false_branch->parent = conditional_node;
516 log_expr_node_unref(old_false_branch);
517 }
518
519 /*
520 */
521 LogExprNode *
log_expr_node_new_conditional_with_filter(LogExprNode * filter_pipe,LogExprNode * true_expr,CFG_LTYPE * yylloc)522 log_expr_node_new_conditional_with_filter(LogExprNode *filter_pipe, LogExprNode *true_expr, CFG_LTYPE *yylloc)
523 {
524 LogExprNode *filter_node = log_expr_node_new_filter(NULL, filter_pipe, NULL);
525
526 /*
527 * channel {
528 * filter { EXPRESSION };
529 * true_expr;
530 * flags(final);
531 * };
532 */
533 LogExprNode *true_branch = log_expr_node_new_log(
534 log_expr_node_append_tail(
535 filter_node,
536 log_expr_node_new_log(true_expr, LC_DROP_UNMATCHED, NULL)
537 ),
538 LC_FINAL,
539 NULL
540 );
541
542 /*
543 * channel {
544 * flags(final);
545 * };
546 *
547 * NOTE: the false branch may be modified later, once an else or elif is
548 * encountered in the configuration, see
549 * log_expr_node_conditional_set_false_branch_of_the_last_if() function
550 * above.
551 */
552 LogExprNode *false_branch = log_expr_node_new_log(
553 NULL,
554 LC_FINAL,
555 NULL
556 );
557 return log_expr_node_new_junction(
558 log_expr_node_append_tail(true_branch, false_branch),
559 yylloc
560 );
561 }
562
563 LogExprNode *
log_expr_node_new_conditional_with_block(LogExprNode * block,CFG_LTYPE * yylloc)564 log_expr_node_new_conditional_with_block(LogExprNode *block, CFG_LTYPE *yylloc)
565 {
566 /*
567 * channel {
568 * filtering_and_parsing_expr;
569 * flags(final);
570 * };
571 */
572 LogExprNode *true_branch = log_expr_node_new_log(
573 block,
574 LC_FINAL,
575 NULL
576 );
577
578 /*
579 * channel {
580 * flags(final);
581 * };
582 *
583 * NOTE: the false branch may be modified later, once an else or elif is
584 * encountered in the configuration, see
585 * log_expr_node_conditional_set_false_branch_of_the_last_if() function
586 * above.
587 */
588 LogExprNode *false_branch = log_expr_node_new_log(
589 NULL,
590 LC_FINAL,
591 NULL
592 );
593 return log_expr_node_new_junction(
594 log_expr_node_append_tail(true_branch, false_branch),
595 yylloc
596 );
597 }
598
599 /****************************************************************************/
600
601 gint
log_expr_node_lookup_flag(const gchar * flag)602 log_expr_node_lookup_flag(const gchar *flag)
603 {
604 if (strcmp(flag, "catch-all") == 0 || strcmp(flag, "catchall") == 0)
605 return LC_CATCHALL;
606 else if (strcmp(flag, "fallback") == 0)
607 return LC_FALLBACK;
608 else if (strcmp(flag, "final") == 0)
609 return LC_FINAL;
610 else if (strcmp(flag, "flow-control") == 0)
611 return LC_FLOW_CONTROL;
612 else if (strcmp(flag, "drop-unmatched") == 0)
613 return LC_DROP_UNMATCHED;
614 msg_error("Unknown log statement flag", evt_tag_str("flag", flag));
615 return 0;
616 }
617
618 LogPipe *
cfg_tree_new_pipe(CfgTree * self,LogExprNode * related_expr)619 cfg_tree_new_pipe(CfgTree *self, LogExprNode *related_expr)
620 {
621 LogPipe *pipe = log_pipe_new(self->cfg);
622 pipe->expr_node = related_expr;
623 g_ptr_array_add(self->initialized_pipes, pipe);
624 log_pipe_add_info(pipe, "cfg_tree_pipe");
625 return pipe;
626 }
627
628 LogMultiplexer *
cfg_tree_new_mpx(CfgTree * self,LogExprNode * related_expr)629 cfg_tree_new_mpx(CfgTree *self, LogExprNode *related_expr)
630 {
631 LogMultiplexer *pipe = log_multiplexer_new(self->cfg);
632 pipe->super.expr_node = related_expr;
633 g_ptr_array_add(self->initialized_pipes, pipe);
634 return pipe;
635 }
636
637 static gchar *
_format_anon_rule_name(CfgTree * self,gint content)638 _format_anon_rule_name(CfgTree *self, gint content)
639 {
640 return g_strdup_printf("#anon-%s%d", log_expr_node_get_content_name(content), self->anon_counters[content]++);
641 }
642
643 /*
644 * Return the name of the rule that contains a LogExprNode. Generates
645 * one automatically for anonymous log expressions.
646 *
647 * NOTE: this returns an allocated string, the caller must free that.
648 */
649 gchar *
cfg_tree_get_rule_name(CfgTree * self,gint content,LogExprNode * node)650 cfg_tree_get_rule_name(CfgTree *self, gint content, LogExprNode *node)
651 {
652 gchar *rule_name;
653
654 if (node)
655 {
656 LogExprNode *rule = log_expr_node_get_container_rule(node, content);
657 if (!rule->name)
658 rule->name = _format_anon_rule_name(self, content);
659 rule_name = g_strdup(rule->name);
660 }
661 else
662 {
663 rule_name = _format_anon_rule_name(self, content);
664 }
665
666 return rule_name;
667 }
668
669 /*
670 * Return a unique the name associated with a LogExprNode. It is of
671 * the format <rule>#<seqid>.
672 *
673 * NOTE: this returns an allocated string, the caller must free that.
674 */
675 gchar *
cfg_tree_get_child_id(CfgTree * self,gint content,LogExprNode * node)676 cfg_tree_get_child_id(CfgTree *self, gint content, LogExprNode *node)
677 {
678 gchar *rule_name = cfg_tree_get_rule_name(self, content, node);
679 gint cur_child_id;
680 gchar *res;
681
682 if (node)
683 {
684 LogExprNode *rule = log_expr_node_get_container_rule(node, content);
685 cur_child_id = rule->child_id++;
686 }
687 else
688 cur_child_id = 0;
689 res = g_strdup_printf("%s#%d", rule_name, cur_child_id);
690 g_free(rule_name);
691 return res;
692 }
693
694 /* hash foreach function to add all source objects to catch-all rules */
695 static void
cfg_tree_add_all_sources(gpointer key,gpointer value,gpointer user_data)696 cfg_tree_add_all_sources(gpointer key, gpointer value, gpointer user_data)
697 {
698 gpointer *args = (gpointer *) user_data;
699 LogExprNode *referring_rule = args[1];
700 LogExprNode *rule = (LogExprNode *) value;
701
702 if (rule->content != ENC_SOURCE)
703 return;
704
705 /* prepend a source reference */
706 referring_rule->children = log_expr_node_append_tail(log_expr_node_new_source_reference(rule->name, NULL),
707 referring_rule->children);
708 }
709
710 static gboolean
711 cfg_tree_compile_node(CfgTree *self, LogExprNode *node,
712 LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail);
713
714 static gboolean
cfg_tree_compile_single(CfgTree * self,LogExprNode * node,LogPipe ** outer_pipe_head,LogPipe ** outer_pipe_tail)715 cfg_tree_compile_single(CfgTree *self, LogExprNode *node,
716 LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail)
717 {
718 LogPipe *pipe;
719
720 g_assert(node->content == ENC_PIPE);
721
722 /* LC_XXX flags are currently only implemented for sequences, ensure that the grammar enforces this. */
723 g_assert(node->flags == 0);
724
725 pipe = node->object;
726
727 if ((pipe->flags & PIF_INLINED) == 0)
728 {
729 /* first reference to the pipe uses the same instance, further ones will get cloned */
730 pipe->flags |= PIF_INLINED;
731 /* The pipe object is borrowed, so the reference counter must be increased. */
732 log_pipe_ref(pipe);
733 }
734 else
735 {
736 /* ok, we are using this pipe again, it needs to be cloned */
737 pipe = log_pipe_clone(pipe);
738 if (!pipe)
739 {
740 msg_error("Error cloning pipe into its reference point, probably the element in question is not meant to be used in this situation",
741 log_expr_node_location_tag(node));
742 goto error;
743 }
744 pipe->flags |= PIF_INLINED;
745 }
746 g_ptr_array_add(self->initialized_pipes, pipe);
747 pipe->expr_node = node;
748
749 if ((pipe->flags & PIF_SOURCE) == 0)
750 *outer_pipe_head = pipe;
751 *outer_pipe_tail = pipe;
752 return TRUE;
753
754 error:
755 return FALSE;
756 }
757
758 static gboolean
cfg_tree_compile_reference(CfgTree * self,LogExprNode * node,LogPipe ** outer_pipe_head,LogPipe ** outer_pipe_tail)759 cfg_tree_compile_reference(CfgTree *self, LogExprNode *node,
760 LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail)
761 {
762 LogExprNode *referenced_node;
763
764 /* LC_XXX flags are currently only implemented for sequences, ensure that the grammar enforces this. */
765 g_assert(node->flags == 0);
766
767 if (!node->object)
768 {
769 referenced_node = cfg_tree_get_object(self, node->content, node->name);
770 }
771 else
772 referenced_node = node->object;
773
774 if (!referenced_node)
775 {
776 msg_error("Error resolving reference",
777 evt_tag_str("content", log_expr_node_get_content_name(node->content)),
778 evt_tag_str("name", node->name),
779 log_expr_node_location_tag(node));
780 goto error;
781 }
782
783 switch (referenced_node->content)
784 {
785 case ENC_SOURCE:
786 {
787 LogMultiplexer *mpx;
788 LogPipe *sub_pipe_head = NULL, *sub_pipe_tail = NULL;
789 LogPipe *attach_pipe = NULL;
790
791 if (!referenced_node->aux)
792 {
793 if (!cfg_tree_compile_node(self, referenced_node, &sub_pipe_head, &sub_pipe_tail))
794 goto error;
795 log_expr_node_set_aux(referenced_node, log_pipe_ref(sub_pipe_tail), (GDestroyNotify) log_pipe_unref);
796 }
797 else
798 {
799 sub_pipe_tail = referenced_node->aux;
800 }
801
802 attach_pipe = cfg_tree_new_pipe(self, node);
803
804 if (sub_pipe_tail)
805 {
806 /* when the source is empty, we'll get a NULL tail in
807 * sub_pipe_tail. We handle that by simply not connecting
808 * anything to the attachment point */
809
810 if (!sub_pipe_tail->pipe_next)
811 {
812 mpx = cfg_tree_new_mpx(self, referenced_node);
813 log_pipe_add_info(&mpx->super, "mpx(source)");
814 log_pipe_append(sub_pipe_tail, &mpx->super);
815 }
816 else
817 {
818 mpx = (LogMultiplexer *) sub_pipe_tail->pipe_next;
819 }
820 log_multiplexer_add_next_hop(mpx, attach_pipe);
821 }
822 *outer_pipe_head = NULL;
823 *outer_pipe_tail = attach_pipe;
824 break;
825 }
826 case ENC_DESTINATION:
827 {
828 LogMultiplexer *mpx;
829 LogPipe *sub_pipe_head = NULL, *sub_pipe_tail = NULL;
830
831 if (!referenced_node->aux)
832 {
833 if (!cfg_tree_compile_node(self, referenced_node, &sub_pipe_head, &sub_pipe_tail))
834 goto error;
835 log_expr_node_set_aux(referenced_node, log_pipe_ref(sub_pipe_head), (GDestroyNotify) log_pipe_unref);
836 }
837 else
838 {
839 sub_pipe_head = referenced_node->aux;
840 }
841
842 /* We need a new LogMultiplexer instance for two reasons:
843
844 1) we need to link something into the sequence, all
845 reference based destination invocations need a separate
846 LogPipe
847
848 2) we have to fork downwards to the destination, it may
849 change the message but we need the original one towards
850 our next chain
851 */
852
853 mpx = cfg_tree_new_mpx(self, node);
854 log_pipe_add_info(&mpx->super, "mpx(destination-reference)");
855
856 if (sub_pipe_head)
857 {
858 /* when the destination is empty */
859 log_multiplexer_add_next_hop(mpx, sub_pipe_head);
860 }
861 *outer_pipe_head = &mpx->super;
862 *outer_pipe_tail = NULL;
863 break;
864 }
865 default:
866 return cfg_tree_compile_node(self, referenced_node, outer_pipe_head, outer_pipe_tail);
867 }
868 return TRUE;
869
870 error:
871 return FALSE;
872 }
873
874 static void
cfg_tree_propagate_expr_node_properties_to_pipe(LogExprNode * node,LogPipe * pipe)875 cfg_tree_propagate_expr_node_properties_to_pipe(LogExprNode *node, LogPipe *pipe)
876 {
877 if (node->flags & LC_FALLBACK)
878 pipe->flags |= PIF_BRANCH_FALLBACK;
879
880 if (node->flags & LC_FINAL)
881 pipe->flags |= PIF_BRANCH_FINAL;
882
883 if (node->flags & LC_FLOW_CONTROL)
884 pipe->flags |= PIF_HARD_FLOW_CONTROL;
885
886 if (node->flags & LC_DROP_UNMATCHED)
887 pipe->flags |= PIF_DROP_UNMATCHED;
888
889 if (!pipe->expr_node)
890 pipe->expr_node = node;
891 }
892
893 /**
894 * cfg_tree_compile_sequence:
895 *
896 * Construct the sequential part of LogPipe pipeline as specified by
897 * the user. The sequential part is where no branches exist, pipes are
898 * merely linked to each other. This is in contrast with a "junction"
899 * where the processing is forked into different branches. Junctions
900 * are built using cfg_tree_compile_junction() above.
901 *
902 * The configuration is parsed into a series of LogExprNode
903 * elements, each giving a reference to a source, filter, parser,
904 * rewrite and destination. This function connects these so that their
905 * log_pipe_queue() method will dispatch the message correctly (which
906 * in turn boils down to setting the LogPipe->next member).
907 *
908 * The tree like structure is created using LogMultiplexer instances,
909 * pipes are connected back with a simple LogPipe instance that only
910 * forwards messages.
911 *
912 * The next member pointer is not holding a reference, but can be
913 * assumed to be kept alive as long as the configuration is running.
914 *
915 * Parameters:
916 * @self: the CfgTree instance
917 * @rule: the series of LogExprNode instances encapsulates as a LogExprNode
918 * @outer_pipe_tail: the last LogPipe to be used to chain further elements to this sequence
919 * @cfg: GlobalConfig instance
920 * @toplevel: whether this rule is a top-level one.
921 **/
922 static gboolean
cfg_tree_compile_sequence(CfgTree * self,LogExprNode * node,LogPipe ** outer_pipe_head,LogPipe ** outer_pipe_tail)923 cfg_tree_compile_sequence(CfgTree *self, LogExprNode *node,
924 LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail)
925 {
926 LogExprNode *ep;
927 LogPipe
928 *first_pipe, /* the head of the constructed pipeline */
929 *last_pipe; /* the current tail of the constructed pipeline */
930 LogPipe *source_join_pipe = NULL;
931 gboolean node_properties_propagated = FALSE;
932
933 if ((node->flags & LC_CATCHALL) != 0)
934 {
935 /* the catch-all resolution code clears this flag */
936
937 msg_error("Error in configuration, catch-all flag can only be specified for top-level log statements");
938 goto error;
939 }
940
941 /* the loop below creates a sequence of LogPipe instances which
942 * essentially execute the user configuration once it is
943 * started.
944 *
945 * The input of this is a log expression, denoted by a tree of
946 * LogExprNode structures, built by the parser. We are storing the
947 * sequence as a linked list, pipes are linked with their "next"
948 * field.
949 *
950 * The head of this list is pointed to by @first_pipe, the current
951 * end is known as @last_pipe.
952 *
953 * In case the sequence starts with a source LogPipe (PIF_SOURCE
954 * flag), the head of the list is _not_ tracked, in that case
955 * first_pipe is NULL.
956 *
957 */
958
959 first_pipe = last_pipe = NULL;
960
961 for (ep = node->children; ep; ep = ep->next)
962 {
963 LogPipe *sub_pipe_head = NULL, *sub_pipe_tail = NULL;
964
965 if (!cfg_tree_compile_node(self, ep, &sub_pipe_head, &sub_pipe_tail))
966 goto error;
967
968 /* add pipe to the current pipe_line, e.g. after last_pipe, update last_pipe & first_pipe */
969 if (sub_pipe_head)
970 {
971 if (!node_properties_propagated)
972 {
973 cfg_tree_propagate_expr_node_properties_to_pipe(node, sub_pipe_head);
974 node_properties_propagated = TRUE;
975 }
976 if (!first_pipe && !last_pipe)
977 {
978 /* we only remember the first pipe in case we're not in
979 * source mode. In source mode, only last_pipe is set */
980
981 first_pipe = sub_pipe_head;
982 }
983
984 if (last_pipe)
985 {
986 g_assert(last_pipe->pipe_next == NULL);
987 log_pipe_append(last_pipe, sub_pipe_head);
988 }
989
990 if (sub_pipe_tail)
991 {
992 last_pipe = sub_pipe_tail;
993 }
994 else
995 {
996 last_pipe = sub_pipe_head;
997 /* look for the final pipe */
998 while (last_pipe->pipe_next)
999 {
1000 last_pipe = last_pipe->pipe_next;
1001 }
1002 }
1003 sub_pipe_head = NULL;
1004 }
1005 else if (sub_pipe_tail)
1006 {
1007 /* source pipe */
1008
1009 if (first_pipe)
1010 {
1011 msg_error("Error compiling sequence, source-pipe follows a non-source one, please list source references/definitions first",
1012 log_expr_node_location_tag(ep));
1013 goto error;
1014 }
1015
1016 if (!source_join_pipe)
1017 {
1018 source_join_pipe = last_pipe = cfg_tree_new_pipe(self, node);
1019 }
1020 log_pipe_append(sub_pipe_tail, source_join_pipe);
1021 }
1022 }
1023
1024
1025 if (!first_pipe && !last_pipe)
1026 {
1027 /* this is an empty sequence, insert a do-nothing LogPipe */
1028 first_pipe = last_pipe = cfg_tree_new_pipe(self, node);
1029 }
1030
1031
1032 /* NOTE: if flow control is enabled, then we either need to have an
1033 * embedded log statement (in which case first_pipe is set, as we're not
1034 * starting with sources), OR we created a source_join_pipe already.
1035 *
1036 */
1037
1038 g_assert(((node->flags & LC_FLOW_CONTROL) && (first_pipe || source_join_pipe)) ||
1039 !(node->flags & LC_FLOW_CONTROL));
1040
1041 if (!node_properties_propagated)
1042 {
1043 /* we never encountered anything that would produce a head_pipe, e.g.
1044 * this sequence only contains a source and nothing else. In that
1045 * case, apply node flags to the last pipe. It should be picked up
1046 * when LogMultiplexer iterates over the branch in
1047 * log_multiplexer_init() as long as last_pipe is linked into the
1048 * pipe_next list and is not forked off at a LogMultiplexer.
1049 * */
1050
1051 cfg_tree_propagate_expr_node_properties_to_pipe(node, last_pipe);
1052 node_properties_propagated = TRUE;
1053 }
1054
1055 if (node->content == ENC_DESTINATION)
1056 {
1057 /* We want to leave pipe-next available to use for
1058 destinations. Config graph uses pipe-next to pass messages forward
1059 in a sequence layout. But pipe-next might be overridden (for
1060 example network destination with LogWriter) hence disjointing
1061 the config graph.
1062
1063 This patch links destinations in T form, instead of single link.
1064
1065 * (endpoint of sequence)
1066 |
1067 V
1068 * (multiplexer) -(next-hop)-> destination -(pipe-next*)-> logwriter
1069 |
1070 (pipe-next)
1071 |
1072 V
1073 * (rest of the sequence)
1074 That way destinations are free to use the pipe-next*
1075 */
1076
1077 last_pipe = first_pipe;
1078 }
1079
1080 *outer_pipe_tail = last_pipe;
1081 *outer_pipe_head = first_pipe;
1082 return TRUE;
1083 error:
1084
1085 /* we don't need to free anything, everything we allocated is recorded in
1086 * @self, thus will be freed whenever cfg_tree_free is called */
1087
1088 return FALSE;
1089 }
1090
1091 /**
1092 * cfg_tree_compile_junction():
1093 *
1094 * This function builds a junction within the configuration. A
1095 * junction is where processing is forked into several branches, each
1096 * doing its own business, and then the end of each branch is
1097 * collected at the end so that further processing can be done on the
1098 * combined output of each log branch.
1099 *
1100 * /-- branch --\
1101 * / \
1102 * ---+---- branch ----+---
1103 * \ /
1104 * \-- branch --/
1105 **/
1106 static gboolean
cfg_tree_compile_junction(CfgTree * self,LogExprNode * node,LogPipe ** outer_pipe_head,LogPipe ** outer_pipe_tail)1107 cfg_tree_compile_junction(CfgTree *self,
1108 LogExprNode *node,
1109 LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail)
1110 {
1111 LogExprNode *ep;
1112 LogPipe *join_pipe = NULL; /* the pipe where parallel branches are joined in a junction */
1113 LogMultiplexer *fork_mpx = NULL;
1114
1115 /* LC_XXX flags are currently only implemented for sequences, ensure that the grammar enforces this. */
1116 g_assert(node->flags == 0);
1117
1118 for (ep = node->children; ep; ep = ep->next)
1119 {
1120 LogPipe *sub_pipe_head = NULL, *sub_pipe_tail = NULL;
1121 gboolean is_first_branch = (ep == node->children);
1122
1123 if (!cfg_tree_compile_node(self, ep, &sub_pipe_head, &sub_pipe_tail))
1124 goto error;
1125
1126 if (sub_pipe_head)
1127 {
1128 /* ep is an intermediate LogPipe or a destination, we have to fork */
1129
1130 if (!is_first_branch && !fork_mpx)
1131 {
1132 msg_error("Error compiling junction, source and non-source branches are mixed",
1133 log_expr_node_location_tag(ep));
1134 goto error;
1135 }
1136 if (!fork_mpx)
1137 {
1138 fork_mpx = cfg_tree_new_mpx(self, node);
1139 log_pipe_add_info(&fork_mpx->super, "mpx(junction)");
1140 *outer_pipe_head = &fork_mpx->super;
1141 }
1142 log_multiplexer_add_next_hop(fork_mpx, sub_pipe_head);
1143 }
1144 else
1145 {
1146 /* ep is a "source" LogPipe (cause no sub_pipe_head returned by compile_node). */
1147
1148 if (fork_mpx)
1149 {
1150 msg_error("Error compiling junction, source and non-source branches are mixed",
1151 log_expr_node_location_tag(ep));
1152 goto error;
1153 }
1154 }
1155
1156 if (sub_pipe_tail && outer_pipe_tail)
1157 {
1158 if (!join_pipe)
1159 {
1160 join_pipe = cfg_tree_new_pipe(self, node);
1161 }
1162 log_pipe_append(sub_pipe_tail, join_pipe);
1163
1164 }
1165 }
1166
1167 if (outer_pipe_tail)
1168 *outer_pipe_tail = join_pipe;
1169 return TRUE;
1170 error:
1171
1172 /* we don't need to free anything, everything we allocated is recorded in
1173 * @self, thus will be freed whenever cfg_tree_free is called */
1174
1175 return FALSE;
1176 }
1177
1178 /*
1179 * cfg_tree_compile_node:
1180 *
1181 * This function takes care of compiling a LogExprNode.
1182 *
1183 */
1184 gboolean
cfg_tree_compile_node(CfgTree * self,LogExprNode * node,LogPipe ** outer_pipe_head,LogPipe ** outer_pipe_tail)1185 cfg_tree_compile_node(CfgTree *self, LogExprNode *node,
1186 LogPipe **outer_pipe_head, LogPipe **outer_pipe_tail)
1187 {
1188 gboolean result = FALSE;
1189 static gint indent = -1;
1190
1191 if (trace_flag)
1192 {
1193 gchar buf[128];
1194 gchar compile_message[256];
1195
1196 indent++;
1197 g_snprintf(compile_message, sizeof(compile_message),
1198 "%-*sCompiling %s %s [%s] at [%s]",
1199 indent * 2, "",
1200 node->name ? : "#unnamed",
1201 log_expr_node_get_layout_name(node->layout),
1202 log_expr_node_get_content_name(node->content),
1203 log_expr_node_format_location(node, buf, sizeof(buf)));
1204 msg_send_formatted_message(EVT_PRI_DEBUG, compile_message);
1205 }
1206
1207 switch (node->layout)
1208 {
1209 case ENL_SINGLE:
1210 result = cfg_tree_compile_single(self, node, outer_pipe_head, outer_pipe_tail);
1211 break;
1212 case ENL_REFERENCE:
1213 result = cfg_tree_compile_reference(self, node, outer_pipe_head, outer_pipe_tail);
1214 break;
1215 case ENL_SEQUENCE:
1216 result = cfg_tree_compile_sequence(self, node, outer_pipe_head, outer_pipe_tail);
1217 break;
1218 case ENL_JUNCTION:
1219 result = cfg_tree_compile_junction(self, node, outer_pipe_head, outer_pipe_tail);
1220 break;
1221 default:
1222 g_assert_not_reached();
1223 }
1224
1225 indent--;
1226 return result;
1227 }
1228
1229 gboolean
cfg_tree_compile_rule(CfgTree * self,LogExprNode * rule)1230 cfg_tree_compile_rule(CfgTree *self, LogExprNode *rule)
1231 {
1232 LogPipe *sub_pipe_head = NULL, *sub_pipe_tail = NULL;
1233
1234 return cfg_tree_compile_node(self, rule, &sub_pipe_head, &sub_pipe_tail);
1235 }
1236
1237 static gboolean
cfg_tree_objects_equal(gconstpointer v1,gconstpointer v2)1238 cfg_tree_objects_equal(gconstpointer v1, gconstpointer v2)
1239 {
1240 LogExprNode *r1 = (LogExprNode *) v1;
1241 LogExprNode *r2 = (LogExprNode *) v2;
1242
1243 if (r1->content != r2->content)
1244 return FALSE;
1245
1246 /* we assume that only rules with a name are hashed */
1247
1248 return strcmp(r1->name, r2->name) == 0;
1249 }
1250
1251 static guint
cfg_tree_objects_hash(gconstpointer v)1252 cfg_tree_objects_hash(gconstpointer v)
1253 {
1254 LogExprNode *r = (LogExprNode *) v;
1255
1256 /* we assume that only rules with a name are hashed */
1257 return r->content + g_str_hash(r->name);
1258 }
1259
1260 gboolean
cfg_tree_add_object(CfgTree * self,LogExprNode * rule)1261 cfg_tree_add_object(CfgTree *self, LogExprNode *rule)
1262 {
1263 gboolean res = TRUE;
1264
1265 if (rule->name)
1266 {
1267 /* only named rules can be stored as objects to be referenced later */
1268
1269 /* check if already present */
1270 res = (g_hash_table_lookup(self->objects, rule) == NULL);
1271
1272 /* key is the same as the object */
1273 g_hash_table_replace(self->objects, rule, rule);
1274 }
1275 else
1276 {
1277 /* unnamed rules are simply put in the rules array */
1278 g_ptr_array_add(self->rules, rule);
1279 }
1280
1281 return res;
1282 }
1283
1284 LogExprNode *
cfg_tree_get_object(CfgTree * self,gint content,const gchar * name)1285 cfg_tree_get_object(CfgTree *self, gint content, const gchar *name)
1286 {
1287 LogExprNode lookup_node;
1288
1289 memset(&lookup_node, 0, sizeof(lookup_node));
1290 lookup_node.content = content;
1291 lookup_node.name = (gchar *) name;
1292
1293 return g_hash_table_lookup(self->objects, &lookup_node);
1294 }
1295
1296 GList *
cfg_tree_get_objects(CfgTree * self)1297 cfg_tree_get_objects(CfgTree *self)
1298 {
1299 return g_hash_table_get_values(self->objects);
1300 }
1301
1302 gboolean
cfg_tree_add_template(CfgTree * self,LogTemplate * template)1303 cfg_tree_add_template(CfgTree *self, LogTemplate *template)
1304 {
1305 gboolean res = (g_hash_table_lookup(self->templates, template->name) == NULL);
1306 g_hash_table_replace(self->templates, template->name, template);
1307 return res;
1308 }
1309
1310 LogTemplate *
cfg_tree_lookup_template(CfgTree * self,const gchar * name)1311 cfg_tree_lookup_template(CfgTree *self, const gchar *name)
1312 {
1313 if (name)
1314 return log_template_ref(g_hash_table_lookup(self->templates, name));
1315 return NULL;
1316 }
1317
1318 LogTemplate *
cfg_tree_check_inline_template(CfgTree * self,const gchar * template_or_name,GError ** error)1319 cfg_tree_check_inline_template(CfgTree *self, const gchar *template_or_name, GError **error)
1320 {
1321 LogTemplate *template = cfg_tree_lookup_template(self, template_or_name);
1322
1323 if (template == NULL)
1324 {
1325 template = log_template_new(self->cfg, NULL);
1326 if (!log_template_compile(template, template_or_name, error))
1327 {
1328 log_template_unref(template);
1329 return NULL;
1330 }
1331 template->def_inline = TRUE;
1332 }
1333 return template;
1334 }
1335
1336 gboolean
cfg_tree_compile(CfgTree * self)1337 cfg_tree_compile(CfgTree *self)
1338 {
1339 gint i;
1340
1341 /* resolve references within the configuration */
1342 if (self->compiled)
1343 return TRUE;
1344
1345 for (i = 0; i < self->rules->len; i++)
1346 {
1347 LogExprNode *rule = (LogExprNode *) g_ptr_array_index(self->rules, i);
1348
1349 if ((rule->flags & LC_CATCHALL))
1350 {
1351 gpointer args[] = { self, rule };
1352
1353 g_hash_table_foreach(self->objects, cfg_tree_add_all_sources, args);
1354 rule->flags &= ~LC_CATCHALL;
1355 }
1356
1357 if (!cfg_tree_compile_rule(self, rule))
1358 {
1359 return FALSE;
1360 }
1361 }
1362 self->compiled = TRUE;
1363 return TRUE;
1364 }
1365
1366 static gboolean
_verify_unique_persist_names_among_pipes(const GPtrArray * initialized_pipes)1367 _verify_unique_persist_names_among_pipes(const GPtrArray *initialized_pipes)
1368 {
1369 GHashTable *pipe_persist_names = g_hash_table_new(g_str_hash, g_str_equal);
1370 gboolean result = TRUE;
1371
1372 for (gint i = 0; i < initialized_pipes->len; ++i)
1373 {
1374 LogPipe *current_pipe = g_ptr_array_index(initialized_pipes, i);
1375 const gchar *current_pipe_name = log_pipe_get_persist_name(current_pipe);
1376
1377 if (current_pipe_name != NULL)
1378 {
1379 if (g_hash_table_lookup_extended(pipe_persist_names, current_pipe_name, NULL, NULL))
1380 {
1381 msg_error("Error checking the uniqueness of the persist names, please override it "
1382 "with persist-name option. Shutting down.",
1383 evt_tag_str("persist_name", current_pipe_name),
1384 log_pipe_location_tag(current_pipe), NULL);
1385 result = FALSE;
1386 }
1387 else
1388 {
1389 g_hash_table_replace(pipe_persist_names,
1390 (gpointer)current_pipe_name,
1391 (gpointer)current_pipe_name);
1392 }
1393 }
1394 }
1395
1396 g_hash_table_destroy(pipe_persist_names);
1397
1398 return result;
1399 }
1400
1401 gboolean
cfg_tree_start(CfgTree * self)1402 cfg_tree_start(CfgTree *self)
1403 {
1404 gint i;
1405
1406 if (!cfg_tree_compile(self))
1407 return FALSE;
1408
1409 /*
1410 * As there are pipes that are dynamically created during init, these
1411 * pipes must be deinited before destroying the configuration, otherwise
1412 * circular references will inhibit the free of the configuration
1413 * structure.
1414 */
1415 for (i = 0; i < self->initialized_pipes->len; i++)
1416 {
1417 LogPipe *pipe = g_ptr_array_index(self->initialized_pipes, i);
1418
1419 if (!log_pipe_init(pipe))
1420 {
1421 msg_error("Error initializing message pipeline",
1422 evt_tag_str("plugin_name", pipe->plugin_name ? pipe->plugin_name : "not a plugin"),
1423 log_pipe_location_tag(pipe));
1424 return FALSE;
1425 }
1426 }
1427
1428 return _verify_unique_persist_names_among_pipes(self->initialized_pipes);
1429 }
1430
1431 gboolean
cfg_tree_stop(CfgTree * self)1432 cfg_tree_stop(CfgTree *self)
1433 {
1434 gboolean success = TRUE;
1435 gint i;
1436
1437 for (i = 0; i < self->initialized_pipes->len; i++)
1438 {
1439 if (!log_pipe_deinit(g_ptr_array_index(self->initialized_pipes, i)))
1440 success = FALSE;
1441 }
1442
1443 return success;
1444 }
1445
1446 gboolean
cfg_tree_on_inited(CfgTree * self)1447 cfg_tree_on_inited(CfgTree *self)
1448 {
1449 gint i;
1450
1451 for (i = 0; i < self->initialized_pipes->len; i++)
1452 {
1453 LogPipe *pipe = g_ptr_array_index(self->initialized_pipes, i);
1454
1455 if (!log_pipe_on_config_inited(pipe))
1456 {
1457 msg_error("Error executing on_config_inited hook",
1458 evt_tag_str("plugin_name", pipe->plugin_name ? pipe->plugin_name : "not a plugin"),
1459 log_pipe_location_tag(pipe));
1460 return FALSE;
1461 }
1462 }
1463
1464 return TRUE;
1465 }
1466
1467 void
cfg_tree_init_instance(CfgTree * self,GlobalConfig * cfg)1468 cfg_tree_init_instance(CfgTree *self, GlobalConfig *cfg)
1469 {
1470 memset(self, 0, sizeof(*self));
1471 self->initialized_pipes = g_ptr_array_new();
1472 self->objects = g_hash_table_new_full(cfg_tree_objects_hash, cfg_tree_objects_equal, NULL,
1473 (GDestroyNotify) log_expr_node_unref);
1474 self->templates = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, (GDestroyNotify) log_template_unref);
1475 self->rules = g_ptr_array_new();
1476 self->cfg = cfg;
1477 }
1478
1479 void
cfg_tree_free_instance(CfgTree * self)1480 cfg_tree_free_instance(CfgTree *self)
1481 {
1482 g_ptr_array_foreach(self->initialized_pipes, (GFunc) log_pipe_unref, NULL);
1483 g_ptr_array_free(self->initialized_pipes, TRUE);
1484
1485 g_ptr_array_foreach(self->rules, (GFunc) log_expr_node_unref, NULL);
1486 g_ptr_array_free(self->rules, TRUE);
1487
1488 g_hash_table_destroy(self->objects);
1489 g_hash_table_destroy(self->templates);
1490 self->cfg = NULL;
1491 }
1492