1 /*
2  * Copyright (c) 2002-2011 Balabit
3  * Copyright (c) 1998-2011 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 %code requires {
26 
27 #pragma GCC diagnostic ignored "-Wswitch-default"
28 
29 #include "pragma-parser.h"
30 #include "plugin.h"
31 #include "cfg.h"
32 #include "messages.h"
33 
34 #include <string.h>
35 
36 }
37 
38 %define api.prefix {pragma_}
39 %lex-param {CfgLexer *lexer}
40 %parse-param {CfgLexer *lexer}
41 %parse-param {gpointer *result}
42 %parse-param {gpointer arg}
43 
44 
45 %require "3.7.6"
46 %locations
47 %define api.pure
48 %define api.value.type {CFG_STYPE}
49 %define api.location.type {CFG_LTYPE}
50 %define parse.error verbose
51 
52 %code {
53 
54 # define YYLLOC_DEFAULT(Current, Rhs, N)                                \
55   do {                                                                  \
56     if (N)                                                              \
57       {                                                                 \
58         (Current).level = YYRHSLOC(Rhs, 1).level;                       \
59         (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;          \
60         (Current).first_column = YYRHSLOC (Rhs, 1).first_column;        \
61         (Current).last_line    = YYRHSLOC (Rhs, N).last_line;           \
62         (Current).last_column  = YYRHSLOC (Rhs, N).last_column;         \
63       }                                                                 \
64     else                                                                \
65       {                                                                 \
66         (Current).level = YYRHSLOC(Rhs, 0).level;                       \
67         (Current).first_line   = (Current).last_line   =                \
68           YYRHSLOC (Rhs, 0).last_line;                                  \
69         (Current).first_column = (Current).last_column =                \
70           YYRHSLOC (Rhs, 0).last_column;                                \
71       }                                                                 \
72   } while (0)
73 
74 #define CHECK_ERROR_WITHOUT_MESSAGE(val, token) do {                    \
75     if (!(val))                                                         \
76       {                                                                 \
77         YYERROR;                                                        \
78       }                                                                 \
79   } while (0)
80 
81 #define CHECK_ERROR(val, token, errorfmt, ...) do {                     \
82     if (!(val))                                                         \
83       {                                                                 \
84         if (errorfmt)                                                   \
85           {                                                             \
86             gchar __buf[256];                                           \
87             g_snprintf(__buf, sizeof(__buf), errorfmt, ## __VA_ARGS__); \
88             yyerror(& (token), lexer, NULL, NULL, __buf);               \
89           }                                                             \
90         YYERROR;                                                        \
91       }                                                                 \
92   } while (0)
93 
94 #define CHECK_ERROR_GERROR(val, token, error, errorfmt, ...) do {       \
95     if (!(val))                                                         \
96       {                                                                 \
97         if (errorfmt)                                                   \
98           {                                                             \
99             gchar __buf[256];                                           \
100             g_snprintf(__buf, sizeof(__buf), errorfmt ", error=%s", ## __VA_ARGS__, error->message); \
101             yyerror(& (token), lexer, NULL, NULL, __buf);               \
102           }                                                             \
103         g_clear_error(&error);						\
104         YYERROR;                                                        \
105       }                                                                 \
106   } while (0)
107 
108 #define YYMAXDEPTH 20000
109 
110 
111 }
112 
113 /* plugin types, must be equal to the numerical values of the plugin type in plugin.h */
114 
115 %token LL_CONTEXT_ROOT                1
116 %token LL_CONTEXT_DESTINATION         2
117 %token LL_CONTEXT_SOURCE              3
118 %token LL_CONTEXT_PARSER              4
119 %token LL_CONTEXT_REWRITE             5
120 %token LL_CONTEXT_FILTER              6
121 %token LL_CONTEXT_LOG                 7
122 %token LL_CONTEXT_BLOCK_DEF           8
123 %token LL_CONTEXT_BLOCK_REF           9
124 %token LL_CONTEXT_BLOCK_CONTENT       10
125 %token LL_CONTEXT_BLOCK_ARG           11
126 %token LL_CONTEXT_PRAGMA              12
127 %token LL_CONTEXT_FORMAT              13
128 %token LL_CONTEXT_TEMPLATE_FUNC       14
129 %token LL_CONTEXT_INNER_DEST          15
130 %token LL_CONTEXT_INNER_SRC           16
131 %token LL_CONTEXT_CLIENT_PROTO        17
132 %token LL_CONTEXT_SERVER_PROTO        18
133 %token LL_CONTEXT_OPTIONS             19
134 %token LL_CONTEXT_CONFIG              20
135 
136 /* this is a placeholder for unit tests, must be the latest & largest */
137 %token LL_CONTEXT_MAX                 21
138 
139 
140 /* statements */
141 %token KW_SOURCE                      10000
142 %token KW_FILTER                      10001
143 %token KW_PARSER                      10002
144 %token KW_DESTINATION                 10003
145 %token KW_LOG                         10004
146 %token KW_OPTIONS                     10005
147 %token KW_INCLUDE                     10006
148 %token KW_BLOCK                       10007
149 %token KW_JUNCTION                    10008
150 %token KW_CHANNEL                     10009
151 %token KW_IF                          10010
152 %token KW_ELSE                        10011
153 %token KW_ELIF                        10012
154 
155 /* source & destination items */
156 %token KW_INTERNAL                    10020
157 %token KW_SYSLOG                      10060
158 
159 /* option items */
160 %token KW_MARK_FREQ                   10071
161 %token KW_STATS_FREQ                  10072
162 %token KW_STATS_LEVEL                 10073
163 %token KW_STATS_LIFETIME              10074
164 %token KW_FLUSH_LINES                 10075
165 %token KW_SUPPRESS                    10076
166 %token KW_FLUSH_TIMEOUT               10077
167 %token KW_LOG_MSG_SIZE                10078
168 %token KW_FILE_TEMPLATE               10079
169 %token KW_PROTO_TEMPLATE              10080
170 %token KW_MARK_MODE                   10081
171 %token KW_ENCODING                    10082
172 %token KW_TYPE                        10083
173 %token KW_STATS_MAX_DYNAMIC           10084
174 %token KW_MIN_IW_SIZE_PER_READER      10085
175 %token KW_WORKERS                     10086
176 %token KW_BATCH_LINES                 10087
177 %token KW_BATCH_TIMEOUT               10088
178 %token KW_TRIM_LARGE_MESSAGES         10089
179 
180 %token KW_CHAIN_HOSTNAMES             10090
181 %token KW_NORMALIZE_HOSTNAMES         10091
182 %token KW_KEEP_HOSTNAME               10092
183 %token KW_CHECK_HOSTNAME              10093
184 %token KW_BAD_HOSTNAME                10094
185 
186 %token KW_KEEP_TIMESTAMP              10100
187 
188 %token KW_USE_DNS                     10110
189 %token KW_USE_FQDN                    10111
190 %token KW_CUSTOM_DOMAIN               10112
191 
192 %token KW_DNS_CACHE                   10120
193 %token KW_DNS_CACHE_SIZE              10121
194 
195 %token KW_DNS_CACHE_EXPIRE            10130
196 %token KW_DNS_CACHE_EXPIRE_FAILED     10131
197 %token KW_DNS_CACHE_HOSTS             10132
198 
199 %token KW_PERSIST_ONLY                10140
200 %token KW_USE_RCPTID                  10141
201 %token KW_USE_UNIQID                  10142
202 
203 %token KW_TZ_CONVERT                  10150
204 %token KW_TS_FORMAT                   10151
205 %token KW_FRAC_DIGITS                 10152
206 
207 %token KW_LOG_FIFO_SIZE               10160
208 %token KW_LOG_FETCH_LIMIT             10162
209 %token KW_LOG_IW_SIZE                 10163
210 %token KW_LOG_PREFIX                  10164
211 %token KW_PROGRAM_OVERRIDE            10165
212 %token KW_HOST_OVERRIDE               10166
213 
214 %token KW_THROTTLE                    10170
215 %token KW_THREADED                    10171
216 %token KW_PASS_UNIX_CREDENTIALS       10231
217 
218 %token KW_PERSIST_NAME                10302
219 
220 %token KW_READ_OLD_RECORDS            10304
221 %token KW_USE_SYSLOGNG_PID            10305
222 
223 /* log statement options */
224 %token KW_FLAGS                       10190
225 
226 /* reader options */
227 %token KW_PAD_SIZE                    10200
228 %token KW_TIME_ZONE                   10201
229 %token KW_RECV_TIME_ZONE              10202
230 %token KW_SEND_TIME_ZONE              10203
231 %token KW_LOCAL_TIME_ZONE             10204
232 %token KW_FORMAT                      10205
233 
234 /* destination writer options */
235 %token KW_TRUNCATE_SIZE               10206
236 
237 /* timers */
238 %token KW_TIME_REOPEN                 10210
239 %token KW_TIME_REAP                   10211
240 %token KW_TIME_SLEEP                  10212
241 
242 /* destination options */
243 %token KW_TMPL_ESCAPE                 10220
244 
245 /* driver specific options */
246 %token KW_OPTIONAL                    10230
247 
248 /* file related options */
249 %token KW_CREATE_DIRS                 10240
250 
251 %token KW_OWNER                       10250
252 %token KW_GROUP                       10251
253 %token KW_PERM                        10252
254 
255 %token KW_DIR_OWNER                   10260
256 %token KW_DIR_GROUP                   10261
257 %token KW_DIR_PERM                    10262
258 
259 %token KW_TEMPLATE                    10270
260 %token KW_TEMPLATE_ESCAPE             10271
261 %token KW_TEMPLATE_FUNCTION           10272
262 
263 %token KW_DEFAULT_FACILITY            10300
264 %token KW_DEFAULT_SEVERITY            10301
265 
266 %token KW_PORT                        10323
267 /* misc options */
268 
269 %token KW_USE_TIME_RECVD              10340
270 
271 /* filter items*/
272 %token KW_FACILITY                    10350
273 %token KW_SEVERITY                    10351
274 %token KW_HOST                        10352
275 %token KW_MATCH                       10353
276 %token KW_MESSAGE                     10354
277 %token KW_NETMASK                     10355
278 %token KW_TAGS                        10356
279 %token KW_NETMASK6                    10357
280 
281 /* parser items */
282 
283 /* rewrite items */
284 %token KW_REWRITE                     10370
285 %token KW_CONDITION                   10371
286 %token KW_VALUE                       10372
287 
288 /* yes/no switches */
289 
290 %token KW_YES                         10380
291 %token KW_NO                          10381
292 
293 %token KW_IFDEF                       10410
294 %token KW_ENDIF                       10411
295 
296 %token LL_DOTDOT                      10420
297 %token LL_DOTDOTDOT                   10421
298 %token LL_PRAGMA                      10422
299 %token LL_EOL                         10423
300 %token LL_ERROR                       10424
301 %token LL_ARROW                       10425
302 
303 %token <cptr> LL_IDENTIFIER           10430
304 %token <num>  LL_NUMBER               10431
305 %token <fnum> LL_FLOAT                10432
306 %token <cptr> LL_STRING               10433
307 %token <token> LL_TOKEN               10434
308 %token <cptr> LL_BLOCK                10435
309 
310 %destructor { free($$); } <cptr>
311 
312 /* value pairs */
313 %token KW_VALUE_PAIRS                 10500
314 %token KW_EXCLUDE                     10502
315 %token KW_PAIR                        10503
316 %token KW_KEY                         10504
317 %token KW_SCOPE                       10505
318 %token KW_SHIFT                       10506
319 %token KW_SHIFT_LEVELS                10507
320 %token KW_REKEY                       10508
321 %token KW_ADD_PREFIX                  10509
322 %token KW_REPLACE_PREFIX              10510
323 
324 %token KW_ON_ERROR                    10511
325 
326 %token KW_RETRIES                     10512
327 
328 %token KW_FETCH_NO_DATA_DELAY         10513
329 
330 %type   <ptr> source_content
331 %type	<ptr> source_items
332 %type	<ptr> source_item
333 %type   <ptr> source_afinter
334 %type   <ptr> source_plugin
335 %type   <ptr> source_afinter_params
336 
337 %type   <ptr> dest_content
338 %type	<ptr> dest_items
339 %type	<ptr> dest_item
340 %type   <ptr> dest_plugin
341 
342 %type   <ptr> template_content
343 %type   <ptr> template_content_list
344 
345 %type   <ptr> filter_content
346 
347 %type   <ptr> parser_content
348 
349 %type   <ptr> rewrite_content
350 
351 %type	<ptr> log_items
352 %type	<ptr> log_item
353 
354 %type   <ptr> log_last_junction
355 %type   <ptr> log_junction
356 %type   <ptr> log_content
357 %type   <ptr> log_conditional
358 %type   <ptr> log_if
359 %type   <ptr> log_forks
360 %type   <ptr> log_fork
361 
362 %type	<num> log_flags
363 %type   <num> log_flags_items
364 
365 %type   <ptr> value_pair_option
366 
367 %type	<num> yesno
368 %type   <num> dnsmode
369 %type	<num> dest_writer_options_flags
370 
371 %type	<cptr> string
372 %type	<cptr> string_or_number
373 %type	<cptr> normalized_flag
374 %type   <ptr> string_list
375 %type   <ptr> string_list_build
376 %type   <num> facility_string
377 %type   <num> severity_string
378 
379 %type   <num> positive_integer
380 %type   <num> positive_integer64
381 %type   <num> nonnegative_integer
382 %type   <num> nonnegative_integer64
383 %type   <fnum> positive_float
384 %type   <fnum> nonnegative_float
385 %type	<cptr> path_no_check
386 %type	<cptr> path_secret
387 %type	<cptr> path_check
388 %type	<cptr> path
389 
390 
391 %token KW_VERSION
392 %token KW_VERSION_CURRENT
393 %token KW_DEFINE
394 %token KW_MODULE
395 %token KW_REQUIRES
396 
397 %code {
398 
399 #include <stdlib.h>
400 
401 #define PRAGMA_BEGIN() ({ lexer->tokenize_eol++; })
402 #define PRAGMA_END() ({ lexer->tokenize_eol--; })
403 #define PRAGMA_ERROR() ({ PRAGMA_END(); YYERROR; })
404 
405 CfgArgs *last_module_args = NULL;
406 
407 }
408 
409 %type   <cptr> requires_message
410 
411 %%
412 
413 
414 start
415         : { PRAGMA_BEGIN(); }
416           stmt                                  { if (yychar != PRAGMA_EMPTY) { cfg_lexer_unput_token(lexer, &yylval); } PRAGMA_END(); YYACCEPT; }
417 
418 stmt
419 	: stmt_without_eol LL_EOL
420 	| stmt_with_eol
421 	;
422 
423 stmt_without_eol
424         : version_stmt
425         | define_stmt
426         | module_stmt
427         ;
428 
429 	/* LL_EOL as a token needs to be consumed by the rules below, as they can
430 	 * change the lexer buffer by the time they return to the grammar. */
431 stmt_with_eol
432         : include_stmt
433         | requires_stmt
434         ;
435 
436 version_stmt
437         : KW_VERSION ':' KW_VERSION_CURRENT
438         {
439           if (!cfg_set_current_version(configuration))
440             PRAGMA_ERROR();
441         }
442         | KW_VERSION ':' string_or_number
443           {
444             guint parsed_version = process_version_string($3);
445             free($3);
446             if (parsed_version == 0)
447                 PRAGMA_ERROR();
448             if (!cfg_set_version(configuration, parsed_version))
449                 PRAGMA_ERROR();
450           }
451 
452 define_stmt
453 	: KW_DEFINE LL_IDENTIFIER string_or_number
454           {
455             msg_debug("Global value changed",
456                       evt_tag_str("define", $2),
457                       evt_tag_str("value", $3));
458 	    cfg_args_set(configuration->globals, $2, $3);
459             free($2);
460             free($3);
461           }
462 
463 module_stmt
464 	: KW_MODULE string { last_module_args = cfg_args_new(); } module_params
465           {
466             gboolean success = cfg_load_module_with_args(configuration, $2, last_module_args);
467             free($2);
468 
469             cfg_args_unref(last_module_args);
470             last_module_args = NULL;
471 
472             if (!success)
473               PRAGMA_ERROR();
474           }
475 	;
476 
477 module_params
478 	: module_param module_params
479 	|
480 	;
481 
482 module_param
483 	: LL_IDENTIFIER '(' string_or_number ')'		{ cfg_args_set(last_module_args, $1, $3); free($1); free($3); }
484 	;
485 
486 include_stmt
487         : KW_INCLUDE string LL_EOL
488           {
489             CHECK_ERROR(cfg_lexer_include_file(lexer, $2), @2, "Error including %s", $2);
490             free($2);
491           }
492         ;
493 
494 requires_stmt
495 	: KW_REQUIRES string requires_message LL_EOL
496           {
497             if (!cfg_is_module_available(configuration, $2))
498               {
499                 if (0 == lexer->include_depth || $3)
500                   {
501                     msg_error("Cannot load required module",
502                               evt_tag_str("module", $2),
503                               evt_tag_str("details", $3 ? : "none"),
504                               cfg_lexer_format_location_tag(lexer,&@1));
505                     free($2);
506                     PRAGMA_ERROR();
507                   }
508                 else
509                   {
510                     msg_debug("Included file was skipped because of a missing module",
511                               evt_tag_str("module", $2),
512                               cfg_lexer_format_location_tag(lexer,&@1));
513                     cfg_lexer_start_next_include(lexer);
514                   }
515               }
516             free($2);
517           }
518 	;
519 
520 requires_message
521 	: string		{ $$ = $1; }
522 	| 			{ $$ = NULL; }
523 	;
524 
525 
526 source_content
527         :
528           { cfg_lexer_push_context(lexer, LL_CONTEXT_SOURCE, NULL, "source statement"); }
529           source_items
530           { cfg_lexer_pop_context(lexer); }
531           {
532             $$ = log_expr_node_new_junction($2, &@$);
533           }
534         ;
535 
536 source_items
537         : source_item semicolons source_items	{ $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); }
538         | log_fork semicolons source_items      { $$ = log_expr_node_append_tail($1,  $3); }
539 	|					{ $$ = NULL; }
540 	;
541 
542 source_item
543 	: source_afinter			{ $$ = $1; }
544         | source_plugin                         { $$ = $1; }
545 	;
546 
547 source_plugin
548         : LL_IDENTIFIER
549           {
550             Plugin *p;
551             gint context = LL_CONTEXT_SOURCE;
552 
553             p = cfg_find_plugin(configuration, context, $1);
554             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
555 
556             last_driver = (LogDriver *) cfg_parse_plugin(configuration, p, &@1, NULL);
557             free($1);
558             if (!last_driver)
559               {
560                 YYERROR;
561               }
562             $$ = last_driver;
563           }
564         ;
565 
566 source_afinter
567 	: KW_INTERNAL '(' source_afinter_params ')'			{ $$ = $3; }
568 	;
569 
570 source_afinter_params
571         : {
572             last_driver = afinter_sd_new(configuration);
573             last_source_options = &((AFInterSourceDriver *) last_driver)->source_options.super;
574           }
575           source_afinter_options { $$ = last_driver; }
576         ;
577 
578 source_afinter_options
579         : source_afinter_option source_afinter_options
580         |
581         ;
582 
583 source_afinter_option
584         : KW_LOG_FIFO_SIZE '(' positive_integer ')'	{ ((AFInterSourceOptions *) last_source_options)->queue_capacity = $3; }
585         | source_option
586         ;
587 
588 
589 filter_content
590         : {
591             FilterExprNode *last_filter_expr = NULL;
592 
593 	    CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &last_filter_expr, NULL), @$);
594 
595             $$ = log_expr_node_new_pipe(log_filter_pipe_new(last_filter_expr, configuration), &@$);
596 	  }
597 	;
598 
599 parser_content
600         :
601           {
602             LogExprNode *last_parser_expr = NULL;
603 
604             CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&parser_expr_parser, lexer, (gpointer *) &last_parser_expr, NULL), @$);
605             $$ = last_parser_expr;
606           }
607         ;
608 
609 rewrite_content
610         :
611           {
612             LogExprNode *last_rewrite_expr = NULL;
613 
614             CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&rewrite_expr_parser, lexer, (gpointer *) &last_rewrite_expr, NULL), @$);
615             $$ = last_rewrite_expr;
616           }
617         ;
618 
619 dest_content
620          : { cfg_lexer_push_context(lexer, LL_CONTEXT_DESTINATION, NULL, "destination statement"); }
621             dest_items
622            { cfg_lexer_pop_context(lexer); }
623            {
624              $$ = log_expr_node_new_junction($2, &@$);
625            }
626          ;
627 
628 
629 dest_items
630         /* all destination drivers are added as an independent branch in a junction*/
631         : dest_item semicolons dest_items	{ $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); }
632         | log_fork semicolons dest_items        { $$ = log_expr_node_append_tail($1,  $3); }
633 	|					{ $$ = NULL; }
634 	;
635 
636 dest_item
637         : dest_plugin                           { $$ = $1; }
638 	;
639 
640 dest_plugin
641         : LL_IDENTIFIER
642           {
643             Plugin *p;
644             gint context = LL_CONTEXT_DESTINATION;
645 
646             p = cfg_find_plugin(configuration, context, $1);
647             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
648 
649             last_driver = (LogDriver *) cfg_parse_plugin(configuration, p, &@1, NULL);
650             free($1);
651             if (!last_driver)
652               {
653                 YYERROR;
654               }
655             $$ = last_driver;
656           }
657         ;
658 
659 log_items
660 	: log_item semicolons log_items		{ log_expr_node_append_tail($1, $3); $$ = $1; }
661 	|					{ $$ = NULL; }
662 	;
663 
664 log_item
665         : KW_SOURCE '(' string ')'		{ $$ = log_expr_node_new_source_reference($3, &@$); free($3); }
666         | KW_SOURCE '{' source_content '}'      { $$ = log_expr_node_new_source(NULL, $3, &@$); }
667         | KW_FILTER '(' string ')'		{ $$ = log_expr_node_new_filter_reference($3, &@$); free($3); }
668         | KW_FILTER '{' filter_content '}'      { $$ = log_expr_node_new_filter(NULL, $3, &@$); }
669         | KW_PARSER '(' string ')'              { $$ = log_expr_node_new_parser_reference($3, &@$); free($3); }
670         | KW_PARSER '{' parser_content '}'      { $$ = log_expr_node_new_parser(NULL, $3, &@$); }
671         | KW_REWRITE '(' string ')'             { $$ = log_expr_node_new_rewrite_reference($3, &@$); free($3); }
672         | KW_REWRITE '{' rewrite_content '}'    { $$ = log_expr_node_new_rewrite(NULL, $3, &@$); }
673         | KW_DESTINATION '(' string ')'		{ $$ = log_expr_node_new_destination_reference($3, &@$); free($3); }
674         | KW_DESTINATION '{' dest_content '}'   { $$ = log_expr_node_new_destination(NULL, $3, &@$); }
675         | log_conditional			{ $$ = $1; }
676         | log_junction                          { $$ = $1; }
677 	;
678 
679 log_junction
680         : KW_JUNCTION '{' log_forks '}'         { $$ = log_expr_node_new_junction($3, &@$); }
681         ;
682 
683 log_last_junction
684 
685         /* this rule matches the last set of embedded log {}
686          * statements at the end of the log {} block.
687          * It is the final junction and was the only form of creating
688          * a processing tree before syslog-ng 3.4.
689          *
690          * We emulate if the user was writing junction {} explicitly.
691          */
692         : log_forks                             { $$ = $1 ? log_expr_node_new_junction($1, &@1) :  NULL; }
693         ;
694 
695 
696 log_forks
697         : log_fork semicolons log_forks		{ log_expr_node_append_tail($1, $3); $$ = $1; }
698         |                                       { $$ = NULL; }
699         ;
700 
701 log_fork
702         : KW_LOG '{' log_content '}'            { $$ = $3; }
703         | KW_CHANNEL '{' log_content '}'        { $$ = $3; }
704         ;
705 
706 log_conditional
707         : log_if				{ $$ = $1; }
708         | log_if KW_ELSE '{' log_content '}'
709           {
710             log_expr_node_conditional_set_false_branch_of_the_last_if($1, $4);
711             $$ = $1;
712           }
713         ;
714 
715 log_if
716         : KW_IF '(' filter_content ')' '{' log_content '}'
717           {
718             $$ = log_expr_node_new_conditional_with_filter($3, $6, &@$);
719           }
720         | KW_IF '{' log_content '}'
721           {
722             $$ = log_expr_node_new_conditional_with_block($3, &@$);
723           }
724         | log_if KW_ELIF '(' filter_content ')' '{' log_content '}'
725           {
726             LogExprNode *false_branch;
727 
728             false_branch = log_expr_node_new_conditional_with_filter($4, $7, &@$);
729             log_expr_node_conditional_set_false_branch_of_the_last_if($1, false_branch);
730             $$ = $1;
731           }
732         | log_if KW_ELIF '{' log_content '}'
733           {
734             LogExprNode *false_branch;
735 
736             false_branch = log_expr_node_new_conditional_with_block($4, &@$);
737             log_expr_node_conditional_set_false_branch_of_the_last_if($1, false_branch);
738             $$ = $1;
739           }
740         ;
741 
742 log_content
743         : log_items log_last_junction log_flags                { $$ = log_expr_node_new_log(log_expr_node_append_tail($1, $2), $3, &@$); }
744         ;
745 
746 log_flags
747 	: KW_FLAGS '(' log_flags_items ')' semicolons	{ $$ = $3; }
748 	|					{ $$ = 0; }
749 	;
750 
751 log_flags_items
752 	: normalized_flag log_flags_items	{ $$ = log_expr_node_lookup_flag($1) | $2; free($1); }
753 	|					{ $$ = 0; }
754 	;
755 
756 
757 template_content_inner
758         : string
759         {
760           GError *error = NULL;
761 
762           CHECK_ERROR_GERROR(log_template_compile(last_template, $1, &error), @1, error, "Error compiling template");
763           free($1);
764         }
765         | LL_IDENTIFIER '(' string ')'
766         {
767           GError *error = NULL;
768 
769           CHECK_ERROR_GERROR(log_template_compile(last_template, $3, &error), @3, error, "Error compiling template");
770           free($3);
771 
772           CHECK_ERROR_GERROR(log_template_set_type_hint(last_template, $1, &error), @1, error, "Error setting the template type-hint \"%s\"", $1);
773           free($1);
774         }
775         ;
776 
777 template_content
778         : { last_template = log_template_new(configuration, NULL); } template_content_inner	{ $$ = last_template; }
779         ;
780 
781 template_content_list
782 	: template_content template_content_list { $$ = g_list_prepend($2, $1); }
783 	| { $$ = NULL; }
784 	;
785 
786 
787 
788 string
789 	: LL_IDENTIFIER
790 	| LL_STRING
791 	;
792 
793 yesno
794 	: KW_YES				{ $$ = 1; }
795 	| KW_NO					{ $$ = 0; }
796 	| LL_NUMBER				{ $$ = $1; }
797 	;
798 
799 dnsmode
800 	: yesno					{ $$ = $1; }
801 	| KW_PERSIST_ONLY                       { $$ = 2; }
802 	;
803 
804 nonnegative_integer64
805         : LL_NUMBER
806           {
807             CHECK_ERROR(($1 >= 0), @1, "It cannot be negative");
808           }
809         ;
810 
811 nonnegative_integer
812         : nonnegative_integer64
813           {
814             CHECK_ERROR(($1 <= G_MAXINT32), @1, "Must be smaller than 2^31");
815           }
816         ;
817 
818 positive_integer64
819         : LL_NUMBER
820           {
821             CHECK_ERROR(($1 > 0), @1, "Must be positive");
822           }
823         ;
824 
825 positive_integer
826         : positive_integer64
827           {
828             CHECK_ERROR(($1 <= G_MAXINT32), @1, "Must be smaller than 2^31");
829           }
830         ;
831 
832 nonnegative_float
833         : LL_FLOAT
834           {
835             CHECK_ERROR(($1 >= 0), @1, "It cannot be negative");
836           }
837         | nonnegative_integer
838           {
839             $$ = (double) $1;
840           }
841         ;
842 
843 positive_float
844         : LL_FLOAT
845           {
846             CHECK_ERROR(($1 > 0), @1, "Must be positive");
847           }
848         | positive_integer
849           {
850             $$ = (double) $1;
851           }
852         ;
853 
854 string_or_number
855         : string                                { $$ = $1; }
856         | LL_NUMBER                             { $$ = strdup(lexer->token_text->str); }
857         | LL_FLOAT                              { $$ = strdup(lexer->token_text->str); }
858         ;
859 
860 path
861 	: string
862 	  {
863             struct stat buffer;
864             int ret = stat($1, &buffer);
865             CHECK_ERROR((ret == 0), @1, "File \"%s\" not found: %s", $1, strerror(errno));
866             $$ = $1;
867 	  }
868 	;
869 
870 path_check
871     : path { cfg_path_track_file(configuration, $1, "path_check"); }
872     ;
873 
874 path_secret
875     : path { cfg_path_track_file(configuration, $1, "path_secret"); }
876     ;
877 
878 path_no_check
879     : string { cfg_path_track_file(configuration, $1, "path_no_check"); }
880     ;
881 
882 normalized_flag
883         : string                                { $$ = normalize_flag($1); free($1); }
884         ;
885 
886 string_list
887         : string_list_build                     { $$ = $1; }
888         ;
889 
890 string_list_build
891         : string string_list_build		{ $$ = g_list_prepend($2, g_strdup($1)); free($1); }
892         |					{ $$ = NULL; }
893         ;
894 
895 semicolons
896         : ';'
897         | ';' semicolons
898         ;
899 
900 severity_string
901         : string
902 	  {
903 	    /* return the numeric value of the "level" */
904 	    int n = syslog_name_lookup_severity_by_name($1);
905 	    CHECK_ERROR((n != -1), @1, "Unknown priority level\"%s\"", $1);
906 	    free($1);
907             $$ = n;
908 	  }
909         ;
910 
911 facility_string
912         : string
913           {
914             /* return the numeric value of facility */
915 	    int n = syslog_name_lookup_facility_by_name($1);
916 	    CHECK_ERROR((n != -1), @1, "Unknown facility \"%s\"", $1);
917 	    free($1);
918 	    $$ = n;
919 	  }
920         | KW_SYSLOG 				{ $$ = LOG_SYSLOG; }
921         ;
922 
923 parser_opt
924         : KW_TEMPLATE '(' string ')'            {
925                                                   LogTemplate *template;
926                                                   GError *error = NULL;
927 
928                                                   template = cfg_tree_check_inline_template(&configuration->tree, $3, &error);
929                                                   CHECK_ERROR_GERROR(template != NULL, @3, error, "Error compiling template");
930                                                   log_parser_set_template(last_parser, template);
931                                                   free($3);
932                                                 }
933         ;
934 
935 driver_option
936         : KW_PERSIST_NAME '(' string ')' { log_pipe_set_persist_name(&last_driver->super, $3); free($3); }
937         ;
938 
939 inner_source
940         : LL_IDENTIFIER
941           {
942             Plugin *p;
943             gint context = LL_CONTEXT_INNER_SRC;
944             gpointer value;
945 
946             p = cfg_find_plugin(configuration, context, $1);
947             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
948 
949             value = cfg_parse_plugin(configuration, p, &@1, last_driver);
950 
951             free($1);
952             if (!value)
953               {
954                 YYERROR;
955               }
956             if (!log_driver_add_plugin(last_driver, (LogDriverPlugin *) value))
957               {
958                 log_driver_plugin_free(value);
959                 CHECK_ERROR(TRUE, @1, "Error while registering the plugin %s in this destination", $1);
960               }
961           }
962         ;
963 
964 /* All source drivers should incorporate this rule, implies driver_option */
965 source_driver_option
966         : inner_source
967         | driver_option
968         ;
969 
970 inner_dest
971         : LL_IDENTIFIER
972           {
973             Plugin *p;
974             gint context = LL_CONTEXT_INNER_DEST;
975             gpointer value;
976 
977             p = cfg_find_plugin(configuration, context, $1);
978             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
979 
980             value = cfg_parse_plugin(configuration, p, &@1, last_driver);
981 
982             free($1);
983             if (!value)
984               {
985                 YYERROR;
986               }
987             if (!log_driver_add_plugin(last_driver, (LogDriverPlugin *) value))
988               {
989                 log_driver_plugin_free(value);
990                 CHECK_ERROR(TRUE, @1, "Error while registering the plugin %s in this destination", $1);
991               }
992           }
993         ;
994 
995 /* implies driver_option */
996 dest_driver_option
997         /* NOTE: plugins need to set "last_driver" in order to incorporate this rule in their grammar */
998 
999 	: KW_LOG_FIFO_SIZE '(' positive_integer ')'	{ ((LogDestDriver *) last_driver)->log_fifo_size = $3; }
1000 	| KW_THROTTLE '(' nonnegative_integer ')'         { ((LogDestDriver *) last_driver)->throttle = $3; }
1001         | inner_dest
1002         | driver_option
1003         ;
1004 
1005 threaded_dest_driver_batch_option
1006         : KW_BATCH_LINES '(' nonnegative_integer ')' { log_threaded_dest_driver_set_batch_lines(last_driver, $3); }
1007         | KW_BATCH_TIMEOUT '(' positive_integer ')' { log_threaded_dest_driver_set_batch_timeout(last_driver, $3); }
1008         ;
1009 
1010 threaded_dest_driver_workers_option
1011         : KW_WORKERS '(' positive_integer ')'  { log_threaded_dest_driver_set_num_workers(last_driver, $3); }
1012         ;
1013 
1014 /* implies dest_driver_option */
1015 threaded_dest_driver_general_option
1016 	: KW_RETRIES '(' positive_integer ')'
1017         {
1018           log_threaded_dest_driver_set_max_retries_on_error(last_driver, $3);
1019         }
1020         | KW_TIME_REOPEN '(' positive_integer ')' { log_threaded_dest_driver_set_time_reopen(last_driver, $3); }
1021         | dest_driver_option
1022         ;
1023 
1024 /* implies source_driver_option and source_option */
1025 threaded_source_driver_option
1026 	: KW_FORMAT '(' string ')' { log_threaded_source_driver_get_parse_options(last_driver)->format = g_strdup($3); free($3); }
1027         | KW_FLAGS '(' threaded_source_driver_option_flags ')'
1028         | { last_msg_format_options = log_threaded_source_driver_get_parse_options(last_driver); } msg_format_option
1029         | { last_source_options = log_threaded_source_driver_get_source_options(last_driver); } source_option
1030         | source_driver_option
1031         ;
1032 
1033 threaded_fetcher_driver_option
1034         : KW_FETCH_NO_DATA_DELAY '(' nonnegative_float ')' { log_threaded_fetcher_driver_set_fetch_no_data_delay(last_driver, $3); }
1035         | KW_TIME_REOPEN '(' positive_integer ')' { log_threaded_fetcher_driver_set_time_reopen(last_driver, $3); }
1036         ;
1037 
1038 threaded_source_driver_option_flags
1039 	: string threaded_source_driver_option_flags
1040         {
1041           CHECK_ERROR(msg_format_options_process_flag(log_threaded_source_driver_get_parse_options(last_driver), $1), @1, "Unknown flag \"%s\"", $1);
1042           free($1);
1043         }
1044         |
1045         ;
1046 
1047 /* LogSource related options */
1048 source_option
1049         /* NOTE: plugins need to set "last_source_options" in order to incorporate this rule in their grammar */
1050 	: KW_LOG_IW_SIZE '(' positive_integer ')'	{ last_source_options->init_window_size = $3; }
1051 	| KW_CHAIN_HOSTNAMES '(' yesno ')'	{ last_source_options->chain_hostnames = $3; }
1052 	| KW_KEEP_HOSTNAME '(' yesno ')'	{ last_source_options->keep_hostname = $3; }
1053 	| KW_PROGRAM_OVERRIDE '(' string ')'	{ last_source_options->program_override = g_strdup($3); free($3); }
1054 	| KW_HOST_OVERRIDE '(' string ')'	{ last_source_options->host_override = g_strdup($3); free($3); }
1055 	| KW_LOG_PREFIX '(' string ')'	        { gchar *p = strrchr($3, ':'); if (p) *p = 0; last_source_options->program_override = g_strdup($3); free($3); }
1056 	| KW_KEEP_TIMESTAMP '(' yesno ')'	{ last_source_options->keep_timestamp = $3; }
1057 	| KW_READ_OLD_RECORDS '(' yesno ')'	{ last_source_options->read_old_records = $3; }
1058 	| KW_USE_SYSLOGNG_PID '(' yesno ')'	{ last_source_options->use_syslogng_pid = $3; }
1059         | KW_TAGS '(' string_list ')'		{ log_source_options_set_tags(last_source_options, $3); }
1060         | { last_host_resolve_options = &last_source_options->host_resolve_options; } host_resolve_option
1061         ;
1062 
1063 /* LogReader related options, implies source_option */
1064 source_reader_option
1065         /* NOTE: plugins need to set "last_reader_options" in order to incorporate this rule in their grammar */
1066 
1067 	: KW_CHECK_HOSTNAME '(' yesno ')'	{ last_reader_options->check_hostname = $3; }
1068 	| KW_FLAGS '(' source_reader_option_flags ')'
1069 	| KW_LOG_FETCH_LIMIT '(' positive_integer ')'	{ last_reader_options->fetch_limit = $3; }
1070         | KW_FORMAT '(' string ')'              { last_reader_options->parse_options.format = g_strdup($3); free($3); }
1071         | { last_source_options = &last_reader_options->super; } source_option
1072         | { last_proto_server_options = &last_reader_options->proto_options.super; } source_proto_option
1073         | { last_msg_format_options = &last_reader_options->parse_options; } msg_format_option
1074 	;
1075 
1076 source_reader_option_flags
1077         : string source_reader_option_flags     { CHECK_ERROR(log_reader_options_process_flag(last_reader_options, $1), @1, "Unknown flag \"%s\"", $1); free($1); }
1078         | KW_CHECK_HOSTNAME source_reader_option_flags     { log_reader_options_process_flag(last_reader_options, "check-hostname"); }
1079 	|
1080 	;
1081 
1082 /* LogProtoSource related options */
1083 source_proto_option
1084         : KW_ENCODING '(' string ')'
1085           {
1086             CHECK_ERROR(log_proto_server_options_set_encoding(last_proto_server_options, $3),
1087                         @3,
1088                         "unknown encoding \"%s\"", $3);
1089             free($3);
1090           }
1091         | KW_LOG_MSG_SIZE '(' positive_integer ')'      { last_proto_server_options->max_msg_size = $3; }
1092         | KW_TRIM_LARGE_MESSAGES '(' yesno ')'          { last_proto_server_options->trim_large_messages = $3; }
1093         ;
1094 
1095 host_resolve_option
1096         : KW_USE_FQDN '(' yesno ')'             { last_host_resolve_options->use_fqdn = $3; }
1097         | KW_USE_DNS '(' dnsmode ')'            { last_host_resolve_options->use_dns = $3; }
1098 	| KW_DNS_CACHE '(' yesno ')' 		{ last_host_resolve_options->use_dns_cache = $3; }
1099 	| KW_NORMALIZE_HOSTNAMES '(' yesno ')'	{ last_host_resolve_options->normalize_hostnames = $3; }
1100 	;
1101 
1102 msg_format_option
1103 	: KW_TIME_ZONE '(' string ')'		{ last_msg_format_options->recv_time_zone = g_strdup($3); free($3); }
1104 	| KW_DEFAULT_SEVERITY '(' severity_string ')'
1105 	  {
1106 	    if (last_msg_format_options->default_pri == 0xFFFF)
1107 	      last_msg_format_options->default_pri = LOG_USER;
1108 	    last_msg_format_options->default_pri = (last_msg_format_options->default_pri & ~LOG_PRIMASK) | $3;
1109           }
1110 	| KW_DEFAULT_FACILITY '(' facility_string ')'
1111 	  {
1112 	    if (last_msg_format_options->default_pri == 0xFFFF)
1113 	      last_msg_format_options->default_pri = LOG_NOTICE;
1114 	    last_msg_format_options->default_pri = (last_msg_format_options->default_pri & LOG_PRIMASK) | $3;
1115           }
1116         ;
1117 
1118 dest_writer_options
1119 	: dest_writer_option dest_writer_options
1120 	|
1121 	;
1122 
1123 dest_writer_option
1124         /* NOTE: plugins need to set "last_writer_options" in order to incorporate this rule in their grammar */
1125 
1126 	: KW_FLAGS '(' dest_writer_options_flags ')' { last_writer_options->options = $3; }
1127 	| KW_FLUSH_LINES '(' nonnegative_integer ')'		{ last_writer_options->flush_lines = $3; }
1128 	| KW_FLUSH_TIMEOUT '(' positive_integer ')'	{ }
1129         | KW_SUPPRESS '(' nonnegative_integer ')'            { last_writer_options->suppress = $3; }
1130 	| KW_TEMPLATE '(' string ')'       	{
1131                                                   GError *error = NULL;
1132 
1133                                                   last_writer_options->template = cfg_tree_check_inline_template(&configuration->tree, $3, &error);
1134                                                   CHECK_ERROR_GERROR(last_writer_options->template != NULL, @3, error, "Error compiling template");
1135 	                                          free($3);
1136 	                                        }
1137 	| KW_TEMPLATE_ESCAPE '(' yesno ')'	{ log_writer_options_set_template_escape(last_writer_options, $3); }
1138 	| KW_PAD_SIZE '(' nonnegative_integer ')'         { last_writer_options->padding = $3; }
1139 	| KW_TRUNCATE_SIZE '(' nonnegative_integer ')'         { last_writer_options->truncate_size = $3; }
1140 	| KW_MARK_FREQ '(' nonnegative_integer ')'        { last_writer_options->mark_freq = $3; }
1141         | KW_MARK_MODE '(' KW_INTERNAL ')'      { log_writer_options_set_mark_mode(last_writer_options, "internal"); }
1142 	| KW_MARK_MODE '(' string ')'
1143 	  {
1144 	    CHECK_ERROR(cfg_lookup_mark_mode($3) != -1, @3, "illegal mark mode \"%s\"", $3);
1145             log_writer_options_set_mark_mode(last_writer_options, $3);
1146             free($3);
1147           }
1148 	| KW_TIME_REOPEN '(' positive_integer ')' { last_writer_options->time_reopen = $3; }
1149         | { last_template_options = &last_writer_options->template_options; } template_option
1150 	;
1151 
1152 dest_writer_options_flags
1153 	: normalized_flag dest_writer_options_flags   { $$ = log_writer_options_lookup_flag($1) | $2; free($1); }
1154 	|					      { $$ = 0; }
1155 	;
1156 
1157 file_perm_option
1158 	: KW_OWNER '(' string_or_number ')'	{ file_perm_options_set_file_uid(last_file_perm_options, $3); free($3); }
1159 	| KW_OWNER '(' ')'	                { file_perm_options_dont_change_file_uid(last_file_perm_options); }
1160 	| KW_GROUP '(' string_or_number ')'	{ file_perm_options_set_file_gid(last_file_perm_options, $3); free($3); }
1161 	| KW_GROUP '(' ')'	                { file_perm_options_dont_change_file_gid(last_file_perm_options); }
1162 	| KW_PERM '(' LL_NUMBER ')'		{ file_perm_options_set_file_perm(last_file_perm_options, $3); }
1163 	| KW_PERM '(' ')'		        { file_perm_options_dont_change_file_perm(last_file_perm_options); }
1164         | KW_DIR_OWNER '(' string_or_number ')'	{ file_perm_options_set_dir_uid(last_file_perm_options, $3); free($3); }
1165 	| KW_DIR_OWNER '(' ')'	                { file_perm_options_dont_change_dir_uid(last_file_perm_options); }
1166 	| KW_DIR_GROUP '(' string_or_number ')'	{ file_perm_options_set_dir_gid(last_file_perm_options, $3); free($3); }
1167 	| KW_DIR_GROUP '(' ')'	                { file_perm_options_dont_change_dir_gid(last_file_perm_options); }
1168 	| KW_DIR_PERM '(' LL_NUMBER ')'		{ file_perm_options_set_dir_perm(last_file_perm_options, $3); }
1169 	| KW_DIR_PERM '(' ')'		        { file_perm_options_dont_change_dir_perm(last_file_perm_options); }
1170         ;
1171 
1172 template_option
1173 	: KW_TS_FORMAT '(' string ')'		{ last_template_options->ts_format = cfg_ts_format_value($3); free($3); }
1174 	| KW_FRAC_DIGITS '(' nonnegative_integer ')'	{ last_template_options->frac_digits = $3; }
1175 	| KW_TIME_ZONE '(' string ')'		{ last_template_options->time_zone[LTZ_SEND] = g_strdup($3); free($3); }
1176 	| KW_SEND_TIME_ZONE '(' string ')'      { last_template_options->time_zone[LTZ_SEND] = g_strdup($3); free($3); }
1177 	| KW_LOCAL_TIME_ZONE '(' string ')'     { last_template_options->time_zone[LTZ_LOCAL] = g_strdup($3); free($3); }
1178 	| KW_ON_ERROR '(' string ')'
1179         {
1180           gint on_error;
1181 
1182           CHECK_ERROR(log_template_on_error_parse($3, &on_error), @3, "Invalid on-error() setting \"%s\"", $3);
1183           free($3);
1184 
1185           log_template_options_set_on_error(last_template_options, on_error);
1186         }
1187 	;
1188 
1189 matcher_option
1190         : KW_TYPE '(' string ')'		{ CHECK_ERROR(log_matcher_options_set_type(last_matcher_options, $3), @3, "unknown matcher type \"%s\"", $3); free($3); }
1191         | KW_FLAGS '(' matcher_flags ')'
1192         ;
1193 
1194 matcher_flags
1195         : string matcher_flags			{ CHECK_ERROR(log_matcher_options_process_flag(last_matcher_options, $1), @1, "unknown matcher flag \"%s\"", $1); free($1); }
1196         |
1197         ;
1198 
1199 value_pair_option
1200 	: KW_VALUE_PAIRS
1201           {
1202             last_value_pairs = value_pairs_new();
1203           }
1204           '(' vp_options ')'
1205           { $$ = last_value_pairs; }
1206 	;
1207 
1208 vp_options
1209 	: vp_option vp_options
1210 	|
1211 	;
1212 
1213 vp_option
1214         : KW_PAIR '(' string ':' template_content ')'
1215           {
1216             value_pairs_add_pair(last_value_pairs, $3, $5);
1217             free($3);
1218           }
1219         | KW_PAIR '(' string template_content ')'
1220           {
1221             value_pairs_add_pair(last_value_pairs, $3, $4);
1222             free($3);
1223           }
1224         | KW_KEY '(' string KW_REKEY '('
1225           {
1226             last_vp_transset = value_pairs_transform_set_new($3);
1227             value_pairs_add_glob_pattern(last_value_pairs, $3, TRUE);
1228             free($3);
1229           }
1230           vp_rekey_options ')'                           { value_pairs_add_transforms(last_value_pairs, last_vp_transset); } ')'
1231 	| KW_KEY '(' string_list ')'		         { value_pairs_add_glob_patterns(last_value_pairs, $3, TRUE); }
1232         | KW_REKEY '(' string
1233           {
1234             last_vp_transset = value_pairs_transform_set_new($3);
1235             free($3);
1236           }
1237           vp_rekey_options ')'                           { value_pairs_add_transforms(last_value_pairs, last_vp_transset); }
1238         | KW_EXCLUDE '(' string_list ')'                 { value_pairs_add_glob_patterns(last_value_pairs, $3, FALSE); }
1239 	| KW_SCOPE '(' vp_scope_list ')'
1240 	;
1241 
1242 vp_scope_list
1243 	: string vp_scope_list                           { value_pairs_add_scope(last_value_pairs, $1); free($1); }
1244 	|
1245 	;
1246 
1247 vp_rekey_options
1248 	: vp_rekey_option vp_rekey_options
1249         |
1250 	;
1251 
1252 vp_rekey_option
1253 	: KW_SHIFT '(' positive_integer ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_shift($3)); }
1254 	| KW_SHIFT_LEVELS '(' positive_integer ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_shift_levels($3)); }
1255 	| KW_ADD_PREFIX '(' string ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_add_prefix($3)); free($3); }
1256 	| KW_REPLACE_PREFIX '(' string string ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_replace_prefix($3, $4)); free($3); free($4); }
1257 	;
1258 
1259 rewrite_expr_opt
1260         : KW_VALUE '(' string ')'
1261           {
1262             const gchar *p = $3;
1263             if (p[0] == '$')
1264               {
1265                 msg_warning("Value references in rewrite rules should not use the '$' prefix, those are only needed in templates",
1266                             evt_tag_str("value", $3),
1267                             cfg_lexer_format_location_tag(lexer, &@3));
1268                 p++;
1269               }
1270             last_rewrite->value_handle = log_msg_get_value_handle(p);
1271             CHECK_ERROR(!log_msg_is_handle_macro(last_rewrite->value_handle), @3, "%s is read-only, it cannot be changed in rewrite rules", p);
1272 	    CHECK_ERROR(log_msg_is_value_name_valid(p), @3, "%s is not a valid name for a name-value pair, perhaps a misspelled .SDATA reference?", p);
1273             free($3);
1274           }
1275         | rewrite_condition_opt
1276         ;
1277 
1278 rewrite_condition_opt
1279         : KW_CONDITION '('
1280           {
1281             FilterExprNode *filter_expr;
1282 
1283             CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &filter_expr, NULL), @1);
1284             log_rewrite_set_condition(last_rewrite, filter_expr);
1285           } ')'
1286         ;
1287 
1288 
1289 
1290 %%
1291