1 /*
2  * Copyright (c) 2012 Nagy, Attila <bra@fsn.hu>
3  * Copyright (c) 2012-2014 Balabit
4  * Copyright (c) 2012-2014 Gergely Nagy <algernon@balabit.hu>
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published
8  * by the Free Software Foundation, or (at your option) any later version.
9  *
10  * This program 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
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; 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 #include "afamqp-parser.h"
28 
29 }
30 
31 %code {
32 
33 #include "cfg-grammar-internal.h"
34 
35 }
36 
37 %define api.prefix {afamqp_}
38 %lex-param {CfgLexer *lexer}
39 %parse-param {CfgLexer *lexer}
40 %parse-param {LogDriver **instance}
41 %parse-param {gpointer arg}
42 
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_AMQP
392 %token KW_EXCHANGE
393 %token KW_EXCHANGE_DECLARE
394 %token KW_EXCHANGE_TYPE
395 %token KW_PERSISTENT
396 %token KW_VHOST
397 %token KW_ROUTING_KEY
398 %token KW_BODY
399 %token KW_AUTH_METHOD
400 %token KW_PASSWORD
401 %token KW_USERNAME
402 %token KW_MAX_CHANNEL
403 %token KW_FRAME_SIZE
404 %token KW_HEARTBEAT
405 %token KW_CA_FILE
406 %token KW_KEY_FILE
407 %token KW_CERT_FILE
408 %token KW_PEER_VERIFY
409 %token KW_TLS
410 
411 %%
412 
413 start
414         : LL_CONTEXT_DESTINATION KW_AMQP
415           {
416             last_driver = *instance = afamqp_dd_new(configuration);
417           }
418           '(' afamqp_options ')'		{ YYACCEPT; }
419 	;
420 
421 afamqp_options
422         : afamqp_option afamqp_options
423 	|
424 	;
425 
426 afamqp_option
427 	: KW_HOST '(' string ')'                   { afamqp_dd_set_host(last_driver, $3); free($3); }
428 	| KW_PORT '(' positive_integer ')'         { afamqp_dd_set_port(last_driver, $3); }
429 	| KW_VHOST '(' string ')'                  { afamqp_dd_set_vhost(last_driver, $3); free($3); }
430 	| KW_EXCHANGE '(' string ')'               { afamqp_dd_set_exchange(last_driver, $3); free($3); }
431 	| KW_EXCHANGE_DECLARE '(' yesno ')'        { afamqp_dd_set_exchange_declare(last_driver, $3); }
432 	| KW_EXCHANGE_TYPE '(' string ')'          { afamqp_dd_set_exchange_type(last_driver, $3); free($3); }
433 	| KW_ROUTING_KEY '(' template_content ')'  { afamqp_dd_set_routing_key(last_driver, $3); }
434 	| KW_BODY '(' template_content ')'         { afamqp_dd_set_body(last_driver, $3); }
435 	| KW_PERSISTENT '(' yesno ')'              { afamqp_dd_set_persistent(last_driver, $3); }
436 	| KW_AUTH_METHOD '(' string ')'            { CHECK_ERROR(afamqp_dd_set_auth_method(last_driver, $3), @3, "unknown auth-method() argument"); free($3); }
437 	| KW_USERNAME '(' string ')'               { afamqp_dd_set_user(last_driver, $3); free($3); }
438 	| KW_PASSWORD '(' string ')'               { afamqp_dd_set_password(last_driver, $3); free($3); }
439 	| KW_MAX_CHANNEL '(' positive_integer ')'  { afamqp_dd_set_max_channel(last_driver, $3); }
440 	| KW_FRAME_SIZE '(' positive_integer ')'   { afamqp_dd_set_frame_size(last_driver, $3); }
441 	| KW_HEARTBEAT '(' nonnegative_integer ')' { afamqp_dd_set_offered_heartbeat(last_driver, $3); }
442 	| value_pair_option                        { afamqp_dd_set_value_pairs(last_driver, $1); }
443 	| threaded_dest_driver_general_option
444 	| afamqp_tls_option
445 	| KW_TLS '(' afamqp_tls_options ')'
446 	| { last_template_options = afamqp_dd_get_template_options(last_driver); } template_option
447 	;
448 
449 
450 afamqp_tls_options
451     : afamqp_tls_option afamqp_tls_options
452     |
453     ;
454 
455 afamqp_tls_option
456     : KW_CA_FILE '(' path_check ')'        { afamqp_dd_set_ca_file(last_driver, $3); free($3); }
457     | KW_KEY_FILE '(' path_secret ')'      { afamqp_dd_set_key_file(last_driver, $3); free($3); }
458     | KW_CERT_FILE '(' path_check ')'      { afamqp_dd_set_cert_file(last_driver, $3); free($3); }
459     | KW_PEER_VERIFY '(' yesno ')'         { afamqp_dd_set_peer_verify(last_driver, $3); }
460     ;
461 
462 
463 source_content
464         :
465           { cfg_lexer_push_context(lexer, LL_CONTEXT_SOURCE, NULL, "source statement"); }
466           source_items
467           { cfg_lexer_pop_context(lexer); }
468           {
469             $$ = log_expr_node_new_junction($2, &@$);
470           }
471         ;
472 
473 source_items
474         : source_item semicolons source_items	{ $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); }
475         | log_fork semicolons source_items      { $$ = log_expr_node_append_tail($1,  $3); }
476 	|					{ $$ = NULL; }
477 	;
478 
479 source_item
480 	: source_afinter			{ $$ = $1; }
481         | source_plugin                         { $$ = $1; }
482 	;
483 
484 source_plugin
485         : LL_IDENTIFIER
486           {
487             Plugin *p;
488             gint context = LL_CONTEXT_SOURCE;
489 
490             p = cfg_find_plugin(configuration, context, $1);
491             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
492 
493             last_driver = (LogDriver *) cfg_parse_plugin(configuration, p, &@1, NULL);
494             free($1);
495             if (!last_driver)
496               {
497                 YYERROR;
498               }
499             $$ = last_driver;
500           }
501         ;
502 
503 source_afinter
504 	: KW_INTERNAL '(' source_afinter_params ')'			{ $$ = $3; }
505 	;
506 
507 source_afinter_params
508         : {
509             last_driver = afinter_sd_new(configuration);
510             last_source_options = &((AFInterSourceDriver *) last_driver)->source_options.super;
511           }
512           source_afinter_options { $$ = last_driver; }
513         ;
514 
515 source_afinter_options
516         : source_afinter_option source_afinter_options
517         |
518         ;
519 
520 source_afinter_option
521         : KW_LOG_FIFO_SIZE '(' positive_integer ')'	{ ((AFInterSourceOptions *) last_source_options)->queue_capacity = $3; }
522         | source_option
523         ;
524 
525 
526 filter_content
527         : {
528             FilterExprNode *last_filter_expr = NULL;
529 
530 	    CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &last_filter_expr, NULL), @$);
531 
532             $$ = log_expr_node_new_pipe(log_filter_pipe_new(last_filter_expr, configuration), &@$);
533 	  }
534 	;
535 
536 parser_content
537         :
538           {
539             LogExprNode *last_parser_expr = NULL;
540 
541             CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&parser_expr_parser, lexer, (gpointer *) &last_parser_expr, NULL), @$);
542             $$ = last_parser_expr;
543           }
544         ;
545 
546 rewrite_content
547         :
548           {
549             LogExprNode *last_rewrite_expr = NULL;
550 
551             CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&rewrite_expr_parser, lexer, (gpointer *) &last_rewrite_expr, NULL), @$);
552             $$ = last_rewrite_expr;
553           }
554         ;
555 
556 dest_content
557          : { cfg_lexer_push_context(lexer, LL_CONTEXT_DESTINATION, NULL, "destination statement"); }
558             dest_items
559            { cfg_lexer_pop_context(lexer); }
560            {
561              $$ = log_expr_node_new_junction($2, &@$);
562            }
563          ;
564 
565 
566 dest_items
567         /* all destination drivers are added as an independent branch in a junction*/
568         : dest_item semicolons dest_items	{ $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); }
569         | log_fork semicolons dest_items        { $$ = log_expr_node_append_tail($1,  $3); }
570 	|					{ $$ = NULL; }
571 	;
572 
573 dest_item
574         : dest_plugin                           { $$ = $1; }
575 	;
576 
577 dest_plugin
578         : LL_IDENTIFIER
579           {
580             Plugin *p;
581             gint context = LL_CONTEXT_DESTINATION;
582 
583             p = cfg_find_plugin(configuration, context, $1);
584             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
585 
586             last_driver = (LogDriver *) cfg_parse_plugin(configuration, p, &@1, NULL);
587             free($1);
588             if (!last_driver)
589               {
590                 YYERROR;
591               }
592             $$ = last_driver;
593           }
594         ;
595 
596 log_items
597 	: log_item semicolons log_items		{ log_expr_node_append_tail($1, $3); $$ = $1; }
598 	|					{ $$ = NULL; }
599 	;
600 
601 log_item
602         : KW_SOURCE '(' string ')'		{ $$ = log_expr_node_new_source_reference($3, &@$); free($3); }
603         | KW_SOURCE '{' source_content '}'      { $$ = log_expr_node_new_source(NULL, $3, &@$); }
604         | KW_FILTER '(' string ')'		{ $$ = log_expr_node_new_filter_reference($3, &@$); free($3); }
605         | KW_FILTER '{' filter_content '}'      { $$ = log_expr_node_new_filter(NULL, $3, &@$); }
606         | KW_PARSER '(' string ')'              { $$ = log_expr_node_new_parser_reference($3, &@$); free($3); }
607         | KW_PARSER '{' parser_content '}'      { $$ = log_expr_node_new_parser(NULL, $3, &@$); }
608         | KW_REWRITE '(' string ')'             { $$ = log_expr_node_new_rewrite_reference($3, &@$); free($3); }
609         | KW_REWRITE '{' rewrite_content '}'    { $$ = log_expr_node_new_rewrite(NULL, $3, &@$); }
610         | KW_DESTINATION '(' string ')'		{ $$ = log_expr_node_new_destination_reference($3, &@$); free($3); }
611         | KW_DESTINATION '{' dest_content '}'   { $$ = log_expr_node_new_destination(NULL, $3, &@$); }
612         | log_conditional			{ $$ = $1; }
613         | log_junction                          { $$ = $1; }
614 	;
615 
616 log_junction
617         : KW_JUNCTION '{' log_forks '}'         { $$ = log_expr_node_new_junction($3, &@$); }
618         ;
619 
620 log_last_junction
621 
622         /* this rule matches the last set of embedded log {}
623          * statements at the end of the log {} block.
624          * It is the final junction and was the only form of creating
625          * a processing tree before syslog-ng 3.4.
626          *
627          * We emulate if the user was writing junction {} explicitly.
628          */
629         : log_forks                             { $$ = $1 ? log_expr_node_new_junction($1, &@1) :  NULL; }
630         ;
631 
632 
633 log_forks
634         : log_fork semicolons log_forks		{ log_expr_node_append_tail($1, $3); $$ = $1; }
635         |                                       { $$ = NULL; }
636         ;
637 
638 log_fork
639         : KW_LOG '{' log_content '}'            { $$ = $3; }
640         | KW_CHANNEL '{' log_content '}'        { $$ = $3; }
641         ;
642 
643 log_conditional
644         : log_if				{ $$ = $1; }
645         | log_if KW_ELSE '{' log_content '}'
646           {
647             log_expr_node_conditional_set_false_branch_of_the_last_if($1, $4);
648             $$ = $1;
649           }
650         ;
651 
652 log_if
653         : KW_IF '(' filter_content ')' '{' log_content '}'
654           {
655             $$ = log_expr_node_new_conditional_with_filter($3, $6, &@$);
656           }
657         | KW_IF '{' log_content '}'
658           {
659             $$ = log_expr_node_new_conditional_with_block($3, &@$);
660           }
661         | log_if KW_ELIF '(' filter_content ')' '{' log_content '}'
662           {
663             LogExprNode *false_branch;
664 
665             false_branch = log_expr_node_new_conditional_with_filter($4, $7, &@$);
666             log_expr_node_conditional_set_false_branch_of_the_last_if($1, false_branch);
667             $$ = $1;
668           }
669         | log_if KW_ELIF '{' log_content '}'
670           {
671             LogExprNode *false_branch;
672 
673             false_branch = log_expr_node_new_conditional_with_block($4, &@$);
674             log_expr_node_conditional_set_false_branch_of_the_last_if($1, false_branch);
675             $$ = $1;
676           }
677         ;
678 
679 log_content
680         : log_items log_last_junction log_flags                { $$ = log_expr_node_new_log(log_expr_node_append_tail($1, $2), $3, &@$); }
681         ;
682 
683 log_flags
684 	: KW_FLAGS '(' log_flags_items ')' semicolons	{ $$ = $3; }
685 	|					{ $$ = 0; }
686 	;
687 
688 log_flags_items
689 	: normalized_flag log_flags_items	{ $$ = log_expr_node_lookup_flag($1) | $2; free($1); }
690 	|					{ $$ = 0; }
691 	;
692 
693 
694 template_content_inner
695         : string
696         {
697           GError *error = NULL;
698 
699           CHECK_ERROR_GERROR(log_template_compile(last_template, $1, &error), @1, error, "Error compiling template");
700           free($1);
701         }
702         | LL_IDENTIFIER '(' string ')'
703         {
704           GError *error = NULL;
705 
706           CHECK_ERROR_GERROR(log_template_compile(last_template, $3, &error), @3, error, "Error compiling template");
707           free($3);
708 
709           CHECK_ERROR_GERROR(log_template_set_type_hint(last_template, $1, &error), @1, error, "Error setting the template type-hint \"%s\"", $1);
710           free($1);
711         }
712         ;
713 
714 template_content
715         : { last_template = log_template_new(configuration, NULL); } template_content_inner	{ $$ = last_template; }
716         ;
717 
718 template_content_list
719 	: template_content template_content_list { $$ = g_list_prepend($2, $1); }
720 	| { $$ = NULL; }
721 	;
722 
723 
724 
725 string
726 	: LL_IDENTIFIER
727 	| LL_STRING
728 	;
729 
730 yesno
731 	: KW_YES				{ $$ = 1; }
732 	| KW_NO					{ $$ = 0; }
733 	| LL_NUMBER				{ $$ = $1; }
734 	;
735 
736 dnsmode
737 	: yesno					{ $$ = $1; }
738 	| KW_PERSIST_ONLY                       { $$ = 2; }
739 	;
740 
741 nonnegative_integer64
742         : LL_NUMBER
743           {
744             CHECK_ERROR(($1 >= 0), @1, "It cannot be negative");
745           }
746         ;
747 
748 nonnegative_integer
749         : nonnegative_integer64
750           {
751             CHECK_ERROR(($1 <= G_MAXINT32), @1, "Must be smaller than 2^31");
752           }
753         ;
754 
755 positive_integer64
756         : LL_NUMBER
757           {
758             CHECK_ERROR(($1 > 0), @1, "Must be positive");
759           }
760         ;
761 
762 positive_integer
763         : positive_integer64
764           {
765             CHECK_ERROR(($1 <= G_MAXINT32), @1, "Must be smaller than 2^31");
766           }
767         ;
768 
769 nonnegative_float
770         : LL_FLOAT
771           {
772             CHECK_ERROR(($1 >= 0), @1, "It cannot be negative");
773           }
774         | nonnegative_integer
775           {
776             $$ = (double) $1;
777           }
778         ;
779 
780 positive_float
781         : LL_FLOAT
782           {
783             CHECK_ERROR(($1 > 0), @1, "Must be positive");
784           }
785         | positive_integer
786           {
787             $$ = (double) $1;
788           }
789         ;
790 
791 string_or_number
792         : string                                { $$ = $1; }
793         | LL_NUMBER                             { $$ = strdup(lexer->token_text->str); }
794         | LL_FLOAT                              { $$ = strdup(lexer->token_text->str); }
795         ;
796 
797 path
798 	: string
799 	  {
800             struct stat buffer;
801             int ret = stat($1, &buffer);
802             CHECK_ERROR((ret == 0), @1, "File \"%s\" not found: %s", $1, strerror(errno));
803             $$ = $1;
804 	  }
805 	;
806 
807 path_check
808     : path { cfg_path_track_file(configuration, $1, "path_check"); }
809     ;
810 
811 path_secret
812     : path { cfg_path_track_file(configuration, $1, "path_secret"); }
813     ;
814 
815 path_no_check
816     : string { cfg_path_track_file(configuration, $1, "path_no_check"); }
817     ;
818 
819 normalized_flag
820         : string                                { $$ = normalize_flag($1); free($1); }
821         ;
822 
823 string_list
824         : string_list_build                     { $$ = $1; }
825         ;
826 
827 string_list_build
828         : string string_list_build		{ $$ = g_list_prepend($2, g_strdup($1)); free($1); }
829         |					{ $$ = NULL; }
830         ;
831 
832 semicolons
833         : ';'
834         | ';' semicolons
835         ;
836 
837 severity_string
838         : string
839 	  {
840 	    /* return the numeric value of the "level" */
841 	    int n = syslog_name_lookup_severity_by_name($1);
842 	    CHECK_ERROR((n != -1), @1, "Unknown priority level\"%s\"", $1);
843 	    free($1);
844             $$ = n;
845 	  }
846         ;
847 
848 facility_string
849         : string
850           {
851             /* return the numeric value of facility */
852 	    int n = syslog_name_lookup_facility_by_name($1);
853 	    CHECK_ERROR((n != -1), @1, "Unknown facility \"%s\"", $1);
854 	    free($1);
855 	    $$ = n;
856 	  }
857         | KW_SYSLOG 				{ $$ = LOG_SYSLOG; }
858         ;
859 
860 parser_opt
861         : KW_TEMPLATE '(' string ')'            {
862                                                   LogTemplate *template;
863                                                   GError *error = NULL;
864 
865                                                   template = cfg_tree_check_inline_template(&configuration->tree, $3, &error);
866                                                   CHECK_ERROR_GERROR(template != NULL, @3, error, "Error compiling template");
867                                                   log_parser_set_template(last_parser, template);
868                                                   free($3);
869                                                 }
870         ;
871 
872 driver_option
873         : KW_PERSIST_NAME '(' string ')' { log_pipe_set_persist_name(&last_driver->super, $3); free($3); }
874         ;
875 
876 inner_source
877         : LL_IDENTIFIER
878           {
879             Plugin *p;
880             gint context = LL_CONTEXT_INNER_SRC;
881             gpointer value;
882 
883             p = cfg_find_plugin(configuration, context, $1);
884             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
885 
886             value = cfg_parse_plugin(configuration, p, &@1, last_driver);
887 
888             free($1);
889             if (!value)
890               {
891                 YYERROR;
892               }
893             if (!log_driver_add_plugin(last_driver, (LogDriverPlugin *) value))
894               {
895                 log_driver_plugin_free(value);
896                 CHECK_ERROR(TRUE, @1, "Error while registering the plugin %s in this destination", $1);
897               }
898           }
899         ;
900 
901 /* All source drivers should incorporate this rule, implies driver_option */
902 source_driver_option
903         : inner_source
904         | driver_option
905         ;
906 
907 inner_dest
908         : LL_IDENTIFIER
909           {
910             Plugin *p;
911             gint context = LL_CONTEXT_INNER_DEST;
912             gpointer value;
913 
914             p = cfg_find_plugin(configuration, context, $1);
915             CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1);
916 
917             value = cfg_parse_plugin(configuration, p, &@1, last_driver);
918 
919             free($1);
920             if (!value)
921               {
922                 YYERROR;
923               }
924             if (!log_driver_add_plugin(last_driver, (LogDriverPlugin *) value))
925               {
926                 log_driver_plugin_free(value);
927                 CHECK_ERROR(TRUE, @1, "Error while registering the plugin %s in this destination", $1);
928               }
929           }
930         ;
931 
932 /* implies driver_option */
933 dest_driver_option
934         /* NOTE: plugins need to set "last_driver" in order to incorporate this rule in their grammar */
935 
936 	: KW_LOG_FIFO_SIZE '(' positive_integer ')'	{ ((LogDestDriver *) last_driver)->log_fifo_size = $3; }
937 	| KW_THROTTLE '(' nonnegative_integer ')'         { ((LogDestDriver *) last_driver)->throttle = $3; }
938         | inner_dest
939         | driver_option
940         ;
941 
942 threaded_dest_driver_batch_option
943         : KW_BATCH_LINES '(' nonnegative_integer ')' { log_threaded_dest_driver_set_batch_lines(last_driver, $3); }
944         | KW_BATCH_TIMEOUT '(' positive_integer ')' { log_threaded_dest_driver_set_batch_timeout(last_driver, $3); }
945         ;
946 
947 threaded_dest_driver_workers_option
948         : KW_WORKERS '(' positive_integer ')'  { log_threaded_dest_driver_set_num_workers(last_driver, $3); }
949         ;
950 
951 /* implies dest_driver_option */
952 threaded_dest_driver_general_option
953 	: KW_RETRIES '(' positive_integer ')'
954         {
955           log_threaded_dest_driver_set_max_retries_on_error(last_driver, $3);
956         }
957         | KW_TIME_REOPEN '(' positive_integer ')' { log_threaded_dest_driver_set_time_reopen(last_driver, $3); }
958         | dest_driver_option
959         ;
960 
961 /* implies source_driver_option and source_option */
962 threaded_source_driver_option
963 	: KW_FORMAT '(' string ')' { log_threaded_source_driver_get_parse_options(last_driver)->format = g_strdup($3); free($3); }
964         | KW_FLAGS '(' threaded_source_driver_option_flags ')'
965         | { last_msg_format_options = log_threaded_source_driver_get_parse_options(last_driver); } msg_format_option
966         | { last_source_options = log_threaded_source_driver_get_source_options(last_driver); } source_option
967         | source_driver_option
968         ;
969 
970 threaded_fetcher_driver_option
971         : KW_FETCH_NO_DATA_DELAY '(' nonnegative_float ')' { log_threaded_fetcher_driver_set_fetch_no_data_delay(last_driver, $3); }
972         | KW_TIME_REOPEN '(' positive_integer ')' { log_threaded_fetcher_driver_set_time_reopen(last_driver, $3); }
973         ;
974 
975 threaded_source_driver_option_flags
976 	: string threaded_source_driver_option_flags
977         {
978           CHECK_ERROR(msg_format_options_process_flag(log_threaded_source_driver_get_parse_options(last_driver), $1), @1, "Unknown flag \"%s\"", $1);
979           free($1);
980         }
981         |
982         ;
983 
984 /* LogSource related options */
985 source_option
986         /* NOTE: plugins need to set "last_source_options" in order to incorporate this rule in their grammar */
987 	: KW_LOG_IW_SIZE '(' positive_integer ')'	{ last_source_options->init_window_size = $3; }
988 	| KW_CHAIN_HOSTNAMES '(' yesno ')'	{ last_source_options->chain_hostnames = $3; }
989 	| KW_KEEP_HOSTNAME '(' yesno ')'	{ last_source_options->keep_hostname = $3; }
990 	| KW_PROGRAM_OVERRIDE '(' string ')'	{ last_source_options->program_override = g_strdup($3); free($3); }
991 	| KW_HOST_OVERRIDE '(' string ')'	{ last_source_options->host_override = g_strdup($3); free($3); }
992 	| KW_LOG_PREFIX '(' string ')'	        { gchar *p = strrchr($3, ':'); if (p) *p = 0; last_source_options->program_override = g_strdup($3); free($3); }
993 	| KW_KEEP_TIMESTAMP '(' yesno ')'	{ last_source_options->keep_timestamp = $3; }
994 	| KW_READ_OLD_RECORDS '(' yesno ')'	{ last_source_options->read_old_records = $3; }
995 	| KW_USE_SYSLOGNG_PID '(' yesno ')'	{ last_source_options->use_syslogng_pid = $3; }
996         | KW_TAGS '(' string_list ')'		{ log_source_options_set_tags(last_source_options, $3); }
997         | { last_host_resolve_options = &last_source_options->host_resolve_options; } host_resolve_option
998         ;
999 
1000 /* LogReader related options, implies source_option */
1001 source_reader_option
1002         /* NOTE: plugins need to set "last_reader_options" in order to incorporate this rule in their grammar */
1003 
1004 	: KW_CHECK_HOSTNAME '(' yesno ')'	{ last_reader_options->check_hostname = $3; }
1005 	| KW_FLAGS '(' source_reader_option_flags ')'
1006 	| KW_LOG_FETCH_LIMIT '(' positive_integer ')'	{ last_reader_options->fetch_limit = $3; }
1007         | KW_FORMAT '(' string ')'              { last_reader_options->parse_options.format = g_strdup($3); free($3); }
1008         | { last_source_options = &last_reader_options->super; } source_option
1009         | { last_proto_server_options = &last_reader_options->proto_options.super; } source_proto_option
1010         | { last_msg_format_options = &last_reader_options->parse_options; } msg_format_option
1011 	;
1012 
1013 source_reader_option_flags
1014         : string source_reader_option_flags     { CHECK_ERROR(log_reader_options_process_flag(last_reader_options, $1), @1, "Unknown flag \"%s\"", $1); free($1); }
1015         | KW_CHECK_HOSTNAME source_reader_option_flags     { log_reader_options_process_flag(last_reader_options, "check-hostname"); }
1016 	|
1017 	;
1018 
1019 /* LogProtoSource related options */
1020 source_proto_option
1021         : KW_ENCODING '(' string ')'
1022           {
1023             CHECK_ERROR(log_proto_server_options_set_encoding(last_proto_server_options, $3),
1024                         @3,
1025                         "unknown encoding \"%s\"", $3);
1026             free($3);
1027           }
1028         | KW_LOG_MSG_SIZE '(' positive_integer ')'      { last_proto_server_options->max_msg_size = $3; }
1029         | KW_TRIM_LARGE_MESSAGES '(' yesno ')'          { last_proto_server_options->trim_large_messages = $3; }
1030         ;
1031 
1032 host_resolve_option
1033         : KW_USE_FQDN '(' yesno ')'             { last_host_resolve_options->use_fqdn = $3; }
1034         | KW_USE_DNS '(' dnsmode ')'            { last_host_resolve_options->use_dns = $3; }
1035 	| KW_DNS_CACHE '(' yesno ')' 		{ last_host_resolve_options->use_dns_cache = $3; }
1036 	| KW_NORMALIZE_HOSTNAMES '(' yesno ')'	{ last_host_resolve_options->normalize_hostnames = $3; }
1037 	;
1038 
1039 msg_format_option
1040 	: KW_TIME_ZONE '(' string ')'		{ last_msg_format_options->recv_time_zone = g_strdup($3); free($3); }
1041 	| KW_DEFAULT_SEVERITY '(' severity_string ')'
1042 	  {
1043 	    if (last_msg_format_options->default_pri == 0xFFFF)
1044 	      last_msg_format_options->default_pri = LOG_USER;
1045 	    last_msg_format_options->default_pri = (last_msg_format_options->default_pri & ~LOG_PRIMASK) | $3;
1046           }
1047 	| KW_DEFAULT_FACILITY '(' facility_string ')'
1048 	  {
1049 	    if (last_msg_format_options->default_pri == 0xFFFF)
1050 	      last_msg_format_options->default_pri = LOG_NOTICE;
1051 	    last_msg_format_options->default_pri = (last_msg_format_options->default_pri & LOG_PRIMASK) | $3;
1052           }
1053         ;
1054 
1055 dest_writer_options
1056 	: dest_writer_option dest_writer_options
1057 	|
1058 	;
1059 
1060 dest_writer_option
1061         /* NOTE: plugins need to set "last_writer_options" in order to incorporate this rule in their grammar */
1062 
1063 	: KW_FLAGS '(' dest_writer_options_flags ')' { last_writer_options->options = $3; }
1064 	| KW_FLUSH_LINES '(' nonnegative_integer ')'		{ last_writer_options->flush_lines = $3; }
1065 	| KW_FLUSH_TIMEOUT '(' positive_integer ')'	{ }
1066         | KW_SUPPRESS '(' nonnegative_integer ')'            { last_writer_options->suppress = $3; }
1067 	| KW_TEMPLATE '(' string ')'       	{
1068                                                   GError *error = NULL;
1069 
1070                                                   last_writer_options->template = cfg_tree_check_inline_template(&configuration->tree, $3, &error);
1071                                                   CHECK_ERROR_GERROR(last_writer_options->template != NULL, @3, error, "Error compiling template");
1072 	                                          free($3);
1073 	                                        }
1074 	| KW_TEMPLATE_ESCAPE '(' yesno ')'	{ log_writer_options_set_template_escape(last_writer_options, $3); }
1075 	| KW_PAD_SIZE '(' nonnegative_integer ')'         { last_writer_options->padding = $3; }
1076 	| KW_TRUNCATE_SIZE '(' nonnegative_integer ')'         { last_writer_options->truncate_size = $3; }
1077 	| KW_MARK_FREQ '(' nonnegative_integer ')'        { last_writer_options->mark_freq = $3; }
1078         | KW_MARK_MODE '(' KW_INTERNAL ')'      { log_writer_options_set_mark_mode(last_writer_options, "internal"); }
1079 	| KW_MARK_MODE '(' string ')'
1080 	  {
1081 	    CHECK_ERROR(cfg_lookup_mark_mode($3) != -1, @3, "illegal mark mode \"%s\"", $3);
1082             log_writer_options_set_mark_mode(last_writer_options, $3);
1083             free($3);
1084           }
1085 	| KW_TIME_REOPEN '(' positive_integer ')' { last_writer_options->time_reopen = $3; }
1086         | { last_template_options = &last_writer_options->template_options; } template_option
1087 	;
1088 
1089 dest_writer_options_flags
1090 	: normalized_flag dest_writer_options_flags   { $$ = log_writer_options_lookup_flag($1) | $2; free($1); }
1091 	|					      { $$ = 0; }
1092 	;
1093 
1094 file_perm_option
1095 	: KW_OWNER '(' string_or_number ')'	{ file_perm_options_set_file_uid(last_file_perm_options, $3); free($3); }
1096 	| KW_OWNER '(' ')'	                { file_perm_options_dont_change_file_uid(last_file_perm_options); }
1097 	| KW_GROUP '(' string_or_number ')'	{ file_perm_options_set_file_gid(last_file_perm_options, $3); free($3); }
1098 	| KW_GROUP '(' ')'	                { file_perm_options_dont_change_file_gid(last_file_perm_options); }
1099 	| KW_PERM '(' LL_NUMBER ')'		{ file_perm_options_set_file_perm(last_file_perm_options, $3); }
1100 	| KW_PERM '(' ')'		        { file_perm_options_dont_change_file_perm(last_file_perm_options); }
1101         | KW_DIR_OWNER '(' string_or_number ')'	{ file_perm_options_set_dir_uid(last_file_perm_options, $3); free($3); }
1102 	| KW_DIR_OWNER '(' ')'	                { file_perm_options_dont_change_dir_uid(last_file_perm_options); }
1103 	| KW_DIR_GROUP '(' string_or_number ')'	{ file_perm_options_set_dir_gid(last_file_perm_options, $3); free($3); }
1104 	| KW_DIR_GROUP '(' ')'	                { file_perm_options_dont_change_dir_gid(last_file_perm_options); }
1105 	| KW_DIR_PERM '(' LL_NUMBER ')'		{ file_perm_options_set_dir_perm(last_file_perm_options, $3); }
1106 	| KW_DIR_PERM '(' ')'		        { file_perm_options_dont_change_dir_perm(last_file_perm_options); }
1107         ;
1108 
1109 template_option
1110 	: KW_TS_FORMAT '(' string ')'		{ last_template_options->ts_format = cfg_ts_format_value($3); free($3); }
1111 	| KW_FRAC_DIGITS '(' nonnegative_integer ')'	{ last_template_options->frac_digits = $3; }
1112 	| KW_TIME_ZONE '(' string ')'		{ last_template_options->time_zone[LTZ_SEND] = g_strdup($3); free($3); }
1113 	| KW_SEND_TIME_ZONE '(' string ')'      { last_template_options->time_zone[LTZ_SEND] = g_strdup($3); free($3); }
1114 	| KW_LOCAL_TIME_ZONE '(' string ')'     { last_template_options->time_zone[LTZ_LOCAL] = g_strdup($3); free($3); }
1115 	| KW_ON_ERROR '(' string ')'
1116         {
1117           gint on_error;
1118 
1119           CHECK_ERROR(log_template_on_error_parse($3, &on_error), @3, "Invalid on-error() setting \"%s\"", $3);
1120           free($3);
1121 
1122           log_template_options_set_on_error(last_template_options, on_error);
1123         }
1124 	;
1125 
1126 matcher_option
1127         : KW_TYPE '(' string ')'		{ CHECK_ERROR(log_matcher_options_set_type(last_matcher_options, $3), @3, "unknown matcher type \"%s\"", $3); free($3); }
1128         | KW_FLAGS '(' matcher_flags ')'
1129         ;
1130 
1131 matcher_flags
1132         : string matcher_flags			{ CHECK_ERROR(log_matcher_options_process_flag(last_matcher_options, $1), @1, "unknown matcher flag \"%s\"", $1); free($1); }
1133         |
1134         ;
1135 
1136 value_pair_option
1137 	: KW_VALUE_PAIRS
1138           {
1139             last_value_pairs = value_pairs_new();
1140           }
1141           '(' vp_options ')'
1142           { $$ = last_value_pairs; }
1143 	;
1144 
1145 vp_options
1146 	: vp_option vp_options
1147 	|
1148 	;
1149 
1150 vp_option
1151         : KW_PAIR '(' string ':' template_content ')'
1152           {
1153             value_pairs_add_pair(last_value_pairs, $3, $5);
1154             free($3);
1155           }
1156         | KW_PAIR '(' string template_content ')'
1157           {
1158             value_pairs_add_pair(last_value_pairs, $3, $4);
1159             free($3);
1160           }
1161         | KW_KEY '(' string KW_REKEY '('
1162           {
1163             last_vp_transset = value_pairs_transform_set_new($3);
1164             value_pairs_add_glob_pattern(last_value_pairs, $3, TRUE);
1165             free($3);
1166           }
1167           vp_rekey_options ')'                           { value_pairs_add_transforms(last_value_pairs, last_vp_transset); } ')'
1168 	| KW_KEY '(' string_list ')'		         { value_pairs_add_glob_patterns(last_value_pairs, $3, TRUE); }
1169         | KW_REKEY '(' string
1170           {
1171             last_vp_transset = value_pairs_transform_set_new($3);
1172             free($3);
1173           }
1174           vp_rekey_options ')'                           { value_pairs_add_transforms(last_value_pairs, last_vp_transset); }
1175         | KW_EXCLUDE '(' string_list ')'                 { value_pairs_add_glob_patterns(last_value_pairs, $3, FALSE); }
1176 	| KW_SCOPE '(' vp_scope_list ')'
1177 	;
1178 
1179 vp_scope_list
1180 	: string vp_scope_list                           { value_pairs_add_scope(last_value_pairs, $1); free($1); }
1181 	|
1182 	;
1183 
1184 vp_rekey_options
1185 	: vp_rekey_option vp_rekey_options
1186         |
1187 	;
1188 
1189 vp_rekey_option
1190 	: KW_SHIFT '(' positive_integer ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_shift($3)); }
1191 	| KW_SHIFT_LEVELS '(' positive_integer ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_shift_levels($3)); }
1192 	| KW_ADD_PREFIX '(' string ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_add_prefix($3)); free($3); }
1193 	| 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); }
1194 	;
1195 
1196 rewrite_expr_opt
1197         : KW_VALUE '(' string ')'
1198           {
1199             const gchar *p = $3;
1200             if (p[0] == '$')
1201               {
1202                 msg_warning("Value references in rewrite rules should not use the '$' prefix, those are only needed in templates",
1203                             evt_tag_str("value", $3),
1204                             cfg_lexer_format_location_tag(lexer, &@3));
1205                 p++;
1206               }
1207             last_rewrite->value_handle = log_msg_get_value_handle(p);
1208             CHECK_ERROR(!log_msg_is_handle_macro(last_rewrite->value_handle), @3, "%s is read-only, it cannot be changed in rewrite rules", p);
1209 	    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);
1210             free($3);
1211           }
1212         | rewrite_condition_opt
1213         ;
1214 
1215 rewrite_condition_opt
1216         : KW_CONDITION '('
1217           {
1218             FilterExprNode *filter_expr;
1219 
1220             CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &filter_expr, NULL), @1);
1221             log_rewrite_set_condition(last_rewrite, filter_expr);
1222           } ')'
1223         ;
1224 
1225 
1226 
1227 %%
1228