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