/* * Copyright (c) 2002-2011 Balabit * Copyright (c) 1998-2011 Balázs Scheidler * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * As an additional exemption you are allowed to compile & link against the * OpenSSL libraries as published by the OpenSSL project. See the file * COPYING for details. * */ %code requires { #pragma GCC diagnostic ignored "-Wswitch-default" #include "pragma-parser.h" #include "plugin.h" #include "cfg.h" #include "messages.h" #include } %define api.prefix {pragma_} %lex-param {CfgLexer *lexer} %parse-param {CfgLexer *lexer} %parse-param {gpointer *result} %parse-param {gpointer arg} %require "3.7.6" %locations %define api.pure %define api.value.type {CFG_STYPE} %define api.location.type {CFG_LTYPE} %define parse.error verbose %code { # define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ if (N) \ { \ (Current).level = YYRHSLOC(Rhs, 1).level; \ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ } \ else \ { \ (Current).level = YYRHSLOC(Rhs, 0).level; \ (Current).first_line = (Current).last_line = \ YYRHSLOC (Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC (Rhs, 0).last_column; \ } \ } while (0) #define CHECK_ERROR_WITHOUT_MESSAGE(val, token) do { \ if (!(val)) \ { \ YYERROR; \ } \ } while (0) #define CHECK_ERROR(val, token, errorfmt, ...) do { \ if (!(val)) \ { \ if (errorfmt) \ { \ gchar __buf[256]; \ g_snprintf(__buf, sizeof(__buf), errorfmt, ## __VA_ARGS__); \ yyerror(& (token), lexer, NULL, NULL, __buf); \ } \ YYERROR; \ } \ } while (0) #define CHECK_ERROR_GERROR(val, token, error, errorfmt, ...) do { \ if (!(val)) \ { \ if (errorfmt) \ { \ gchar __buf[256]; \ g_snprintf(__buf, sizeof(__buf), errorfmt ", error=%s", ## __VA_ARGS__, error->message); \ yyerror(& (token), lexer, NULL, NULL, __buf); \ } \ g_clear_error(&error); \ YYERROR; \ } \ } while (0) #define YYMAXDEPTH 20000 } /* plugin types, must be equal to the numerical values of the plugin type in plugin.h */ %token LL_CONTEXT_ROOT 1 %token LL_CONTEXT_DESTINATION 2 %token LL_CONTEXT_SOURCE 3 %token LL_CONTEXT_PARSER 4 %token LL_CONTEXT_REWRITE 5 %token LL_CONTEXT_FILTER 6 %token LL_CONTEXT_LOG 7 %token LL_CONTEXT_BLOCK_DEF 8 %token LL_CONTEXT_BLOCK_REF 9 %token LL_CONTEXT_BLOCK_CONTENT 10 %token LL_CONTEXT_BLOCK_ARG 11 %token LL_CONTEXT_PRAGMA 12 %token LL_CONTEXT_FORMAT 13 %token LL_CONTEXT_TEMPLATE_FUNC 14 %token LL_CONTEXT_INNER_DEST 15 %token LL_CONTEXT_INNER_SRC 16 %token LL_CONTEXT_CLIENT_PROTO 17 %token LL_CONTEXT_SERVER_PROTO 18 %token LL_CONTEXT_OPTIONS 19 %token LL_CONTEXT_CONFIG 20 /* this is a placeholder for unit tests, must be the latest & largest */ %token LL_CONTEXT_MAX 21 /* statements */ %token KW_SOURCE 10000 %token KW_FILTER 10001 %token KW_PARSER 10002 %token KW_DESTINATION 10003 %token KW_LOG 10004 %token KW_OPTIONS 10005 %token KW_INCLUDE 10006 %token KW_BLOCK 10007 %token KW_JUNCTION 10008 %token KW_CHANNEL 10009 %token KW_IF 10010 %token KW_ELSE 10011 %token KW_ELIF 10012 /* source & destination items */ %token KW_INTERNAL 10020 %token KW_SYSLOG 10060 /* option items */ %token KW_MARK_FREQ 10071 %token KW_STATS_FREQ 10072 %token KW_STATS_LEVEL 10073 %token KW_STATS_LIFETIME 10074 %token KW_FLUSH_LINES 10075 %token KW_SUPPRESS 10076 %token KW_FLUSH_TIMEOUT 10077 %token KW_LOG_MSG_SIZE 10078 %token KW_FILE_TEMPLATE 10079 %token KW_PROTO_TEMPLATE 10080 %token KW_MARK_MODE 10081 %token KW_ENCODING 10082 %token KW_TYPE 10083 %token KW_STATS_MAX_DYNAMIC 10084 %token KW_MIN_IW_SIZE_PER_READER 10085 %token KW_WORKERS 10086 %token KW_BATCH_LINES 10087 %token KW_BATCH_TIMEOUT 10088 %token KW_TRIM_LARGE_MESSAGES 10089 %token KW_CHAIN_HOSTNAMES 10090 %token KW_NORMALIZE_HOSTNAMES 10091 %token KW_KEEP_HOSTNAME 10092 %token KW_CHECK_HOSTNAME 10093 %token KW_BAD_HOSTNAME 10094 %token KW_KEEP_TIMESTAMP 10100 %token KW_USE_DNS 10110 %token KW_USE_FQDN 10111 %token KW_CUSTOM_DOMAIN 10112 %token KW_DNS_CACHE 10120 %token KW_DNS_CACHE_SIZE 10121 %token KW_DNS_CACHE_EXPIRE 10130 %token KW_DNS_CACHE_EXPIRE_FAILED 10131 %token KW_DNS_CACHE_HOSTS 10132 %token KW_PERSIST_ONLY 10140 %token KW_USE_RCPTID 10141 %token KW_USE_UNIQID 10142 %token KW_TZ_CONVERT 10150 %token KW_TS_FORMAT 10151 %token KW_FRAC_DIGITS 10152 %token KW_LOG_FIFO_SIZE 10160 %token KW_LOG_FETCH_LIMIT 10162 %token KW_LOG_IW_SIZE 10163 %token KW_LOG_PREFIX 10164 %token KW_PROGRAM_OVERRIDE 10165 %token KW_HOST_OVERRIDE 10166 %token KW_THROTTLE 10170 %token KW_THREADED 10171 %token KW_PASS_UNIX_CREDENTIALS 10231 %token KW_PERSIST_NAME 10302 %token KW_READ_OLD_RECORDS 10304 %token KW_USE_SYSLOGNG_PID 10305 /* log statement options */ %token KW_FLAGS 10190 /* reader options */ %token KW_PAD_SIZE 10200 %token KW_TIME_ZONE 10201 %token KW_RECV_TIME_ZONE 10202 %token KW_SEND_TIME_ZONE 10203 %token KW_LOCAL_TIME_ZONE 10204 %token KW_FORMAT 10205 /* destination writer options */ %token KW_TRUNCATE_SIZE 10206 /* timers */ %token KW_TIME_REOPEN 10210 %token KW_TIME_REAP 10211 %token KW_TIME_SLEEP 10212 /* destination options */ %token KW_TMPL_ESCAPE 10220 /* driver specific options */ %token KW_OPTIONAL 10230 /* file related options */ %token KW_CREATE_DIRS 10240 %token KW_OWNER 10250 %token KW_GROUP 10251 %token KW_PERM 10252 %token KW_DIR_OWNER 10260 %token KW_DIR_GROUP 10261 %token KW_DIR_PERM 10262 %token KW_TEMPLATE 10270 %token KW_TEMPLATE_ESCAPE 10271 %token KW_TEMPLATE_FUNCTION 10272 %token KW_DEFAULT_FACILITY 10300 %token KW_DEFAULT_SEVERITY 10301 %token KW_PORT 10323 /* misc options */ %token KW_USE_TIME_RECVD 10340 /* filter items*/ %token KW_FACILITY 10350 %token KW_SEVERITY 10351 %token KW_HOST 10352 %token KW_MATCH 10353 %token KW_MESSAGE 10354 %token KW_NETMASK 10355 %token KW_TAGS 10356 %token KW_NETMASK6 10357 /* parser items */ /* rewrite items */ %token KW_REWRITE 10370 %token KW_CONDITION 10371 %token KW_VALUE 10372 /* yes/no switches */ %token KW_YES 10380 %token KW_NO 10381 %token KW_IFDEF 10410 %token KW_ENDIF 10411 %token LL_DOTDOT 10420 %token LL_DOTDOTDOT 10421 %token LL_PRAGMA 10422 %token LL_EOL 10423 %token LL_ERROR 10424 %token LL_ARROW 10425 %token LL_IDENTIFIER 10430 %token LL_NUMBER 10431 %token LL_FLOAT 10432 %token LL_STRING 10433 %token LL_TOKEN 10434 %token LL_BLOCK 10435 %destructor { free($$); } /* value pairs */ %token KW_VALUE_PAIRS 10500 %token KW_EXCLUDE 10502 %token KW_PAIR 10503 %token KW_KEY 10504 %token KW_SCOPE 10505 %token KW_SHIFT 10506 %token KW_SHIFT_LEVELS 10507 %token KW_REKEY 10508 %token KW_ADD_PREFIX 10509 %token KW_REPLACE_PREFIX 10510 %token KW_ON_ERROR 10511 %token KW_RETRIES 10512 %token KW_FETCH_NO_DATA_DELAY 10513 %type source_content %type source_items %type source_item %type source_afinter %type source_plugin %type source_afinter_params %type dest_content %type dest_items %type dest_item %type dest_plugin %type template_content %type template_content_list %type filter_content %type parser_content %type rewrite_content %type log_items %type log_item %type log_last_junction %type log_junction %type log_content %type log_conditional %type log_if %type log_forks %type log_fork %type log_flags %type log_flags_items %type value_pair_option %type yesno %type dnsmode %type dest_writer_options_flags %type string %type string_or_number %type normalized_flag %type string_list %type string_list_build %type facility_string %type severity_string %type positive_integer %type positive_integer64 %type nonnegative_integer %type nonnegative_integer64 %type positive_float %type nonnegative_float %type path_no_check %type path_secret %type path_check %type path %token KW_VERSION %token KW_VERSION_CURRENT %token KW_DEFINE %token KW_MODULE %token KW_REQUIRES %code { #include #define PRAGMA_BEGIN() ({ lexer->tokenize_eol++; }) #define PRAGMA_END() ({ lexer->tokenize_eol--; }) #define PRAGMA_ERROR() ({ PRAGMA_END(); YYERROR; }) CfgArgs *last_module_args = NULL; } %type requires_message %% start : { PRAGMA_BEGIN(); } stmt { if (yychar != PRAGMA_EMPTY) { cfg_lexer_unput_token(lexer, &yylval); } PRAGMA_END(); YYACCEPT; } stmt : stmt_without_eol LL_EOL | stmt_with_eol ; stmt_without_eol : version_stmt | define_stmt | module_stmt ; /* LL_EOL as a token needs to be consumed by the rules below, as they can * change the lexer buffer by the time they return to the grammar. */ stmt_with_eol : include_stmt | requires_stmt ; version_stmt : KW_VERSION ':' KW_VERSION_CURRENT { if (!cfg_set_current_version(configuration)) PRAGMA_ERROR(); } | KW_VERSION ':' string_or_number { guint parsed_version = process_version_string($3); free($3); if (parsed_version == 0) PRAGMA_ERROR(); if (!cfg_set_version(configuration, parsed_version)) PRAGMA_ERROR(); } define_stmt : KW_DEFINE LL_IDENTIFIER string_or_number { msg_debug("Global value changed", evt_tag_str("define", $2), evt_tag_str("value", $3)); cfg_args_set(configuration->globals, $2, $3); free($2); free($3); } module_stmt : KW_MODULE string { last_module_args = cfg_args_new(); } module_params { gboolean success = cfg_load_module_with_args(configuration, $2, last_module_args); free($2); cfg_args_unref(last_module_args); last_module_args = NULL; if (!success) PRAGMA_ERROR(); } ; module_params : module_param module_params | ; module_param : LL_IDENTIFIER '(' string_or_number ')' { cfg_args_set(last_module_args, $1, $3); free($1); free($3); } ; include_stmt : KW_INCLUDE string LL_EOL { CHECK_ERROR(cfg_lexer_include_file(lexer, $2), @2, "Error including %s", $2); free($2); } ; requires_stmt : KW_REQUIRES string requires_message LL_EOL { if (!cfg_is_module_available(configuration, $2)) { if (0 == lexer->include_depth || $3) { msg_error("Cannot load required module", evt_tag_str("module", $2), evt_tag_str("details", $3 ? : "none"), cfg_lexer_format_location_tag(lexer,&@1)); free($2); PRAGMA_ERROR(); } else { msg_debug("Included file was skipped because of a missing module", evt_tag_str("module", $2), cfg_lexer_format_location_tag(lexer,&@1)); cfg_lexer_start_next_include(lexer); } } free($2); } ; requires_message : string { $$ = $1; } | { $$ = NULL; } ; source_content : { cfg_lexer_push_context(lexer, LL_CONTEXT_SOURCE, NULL, "source statement"); } source_items { cfg_lexer_pop_context(lexer); } { $$ = log_expr_node_new_junction($2, &@$); } ; source_items : source_item semicolons source_items { $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); } | log_fork semicolons source_items { $$ = log_expr_node_append_tail($1, $3); } | { $$ = NULL; } ; source_item : source_afinter { $$ = $1; } | source_plugin { $$ = $1; } ; source_plugin : LL_IDENTIFIER { Plugin *p; gint context = LL_CONTEXT_SOURCE; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1); last_driver = (LogDriver *) cfg_parse_plugin(configuration, p, &@1, NULL); free($1); if (!last_driver) { YYERROR; } $$ = last_driver; } ; source_afinter : KW_INTERNAL '(' source_afinter_params ')' { $$ = $3; } ; source_afinter_params : { last_driver = afinter_sd_new(configuration); last_source_options = &((AFInterSourceDriver *) last_driver)->source_options.super; } source_afinter_options { $$ = last_driver; } ; source_afinter_options : source_afinter_option source_afinter_options | ; source_afinter_option : KW_LOG_FIFO_SIZE '(' positive_integer ')' { ((AFInterSourceOptions *) last_source_options)->queue_capacity = $3; } | source_option ; filter_content : { FilterExprNode *last_filter_expr = NULL; CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &last_filter_expr, NULL), @$); $$ = log_expr_node_new_pipe(log_filter_pipe_new(last_filter_expr, configuration), &@$); } ; parser_content : { LogExprNode *last_parser_expr = NULL; CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&parser_expr_parser, lexer, (gpointer *) &last_parser_expr, NULL), @$); $$ = last_parser_expr; } ; rewrite_content : { LogExprNode *last_rewrite_expr = NULL; CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&rewrite_expr_parser, lexer, (gpointer *) &last_rewrite_expr, NULL), @$); $$ = last_rewrite_expr; } ; dest_content : { cfg_lexer_push_context(lexer, LL_CONTEXT_DESTINATION, NULL, "destination statement"); } dest_items { cfg_lexer_pop_context(lexer); } { $$ = log_expr_node_new_junction($2, &@$); } ; dest_items /* all destination drivers are added as an independent branch in a junction*/ : dest_item semicolons dest_items { $$ = log_expr_node_append_tail(log_expr_node_new_pipe($1, &@1), $3); } | log_fork semicolons dest_items { $$ = log_expr_node_append_tail($1, $3); } | { $$ = NULL; } ; dest_item : dest_plugin { $$ = $1; } ; dest_plugin : LL_IDENTIFIER { Plugin *p; gint context = LL_CONTEXT_DESTINATION; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1); last_driver = (LogDriver *) cfg_parse_plugin(configuration, p, &@1, NULL); free($1); if (!last_driver) { YYERROR; } $$ = last_driver; } ; log_items : log_item semicolons log_items { log_expr_node_append_tail($1, $3); $$ = $1; } | { $$ = NULL; } ; log_item : KW_SOURCE '(' string ')' { $$ = log_expr_node_new_source_reference($3, &@$); free($3); } | KW_SOURCE '{' source_content '}' { $$ = log_expr_node_new_source(NULL, $3, &@$); } | KW_FILTER '(' string ')' { $$ = log_expr_node_new_filter_reference($3, &@$); free($3); } | KW_FILTER '{' filter_content '}' { $$ = log_expr_node_new_filter(NULL, $3, &@$); } | KW_PARSER '(' string ')' { $$ = log_expr_node_new_parser_reference($3, &@$); free($3); } | KW_PARSER '{' parser_content '}' { $$ = log_expr_node_new_parser(NULL, $3, &@$); } | KW_REWRITE '(' string ')' { $$ = log_expr_node_new_rewrite_reference($3, &@$); free($3); } | KW_REWRITE '{' rewrite_content '}' { $$ = log_expr_node_new_rewrite(NULL, $3, &@$); } | KW_DESTINATION '(' string ')' { $$ = log_expr_node_new_destination_reference($3, &@$); free($3); } | KW_DESTINATION '{' dest_content '}' { $$ = log_expr_node_new_destination(NULL, $3, &@$); } | log_conditional { $$ = $1; } | log_junction { $$ = $1; } ; log_junction : KW_JUNCTION '{' log_forks '}' { $$ = log_expr_node_new_junction($3, &@$); } ; log_last_junction /* this rule matches the last set of embedded log {} * statements at the end of the log {} block. * It is the final junction and was the only form of creating * a processing tree before syslog-ng 3.4. * * We emulate if the user was writing junction {} explicitly. */ : log_forks { $$ = $1 ? log_expr_node_new_junction($1, &@1) : NULL; } ; log_forks : log_fork semicolons log_forks { log_expr_node_append_tail($1, $3); $$ = $1; } | { $$ = NULL; } ; log_fork : KW_LOG '{' log_content '}' { $$ = $3; } | KW_CHANNEL '{' log_content '}' { $$ = $3; } ; log_conditional : log_if { $$ = $1; } | log_if KW_ELSE '{' log_content '}' { log_expr_node_conditional_set_false_branch_of_the_last_if($1, $4); $$ = $1; } ; log_if : KW_IF '(' filter_content ')' '{' log_content '}' { $$ = log_expr_node_new_conditional_with_filter($3, $6, &@$); } | KW_IF '{' log_content '}' { $$ = log_expr_node_new_conditional_with_block($3, &@$); } | log_if KW_ELIF '(' filter_content ')' '{' log_content '}' { LogExprNode *false_branch; false_branch = log_expr_node_new_conditional_with_filter($4, $7, &@$); log_expr_node_conditional_set_false_branch_of_the_last_if($1, false_branch); $$ = $1; } | log_if KW_ELIF '{' log_content '}' { LogExprNode *false_branch; false_branch = log_expr_node_new_conditional_with_block($4, &@$); log_expr_node_conditional_set_false_branch_of_the_last_if($1, false_branch); $$ = $1; } ; log_content : log_items log_last_junction log_flags { $$ = log_expr_node_new_log(log_expr_node_append_tail($1, $2), $3, &@$); } ; log_flags : KW_FLAGS '(' log_flags_items ')' semicolons { $$ = $3; } | { $$ = 0; } ; log_flags_items : normalized_flag log_flags_items { $$ = log_expr_node_lookup_flag($1) | $2; free($1); } | { $$ = 0; } ; template_content_inner : string { GError *error = NULL; CHECK_ERROR_GERROR(log_template_compile(last_template, $1, &error), @1, error, "Error compiling template"); free($1); } | LL_IDENTIFIER '(' string ')' { GError *error = NULL; CHECK_ERROR_GERROR(log_template_compile(last_template, $3, &error), @3, error, "Error compiling template"); free($3); CHECK_ERROR_GERROR(log_template_set_type_hint(last_template, $1, &error), @1, error, "Error setting the template type-hint \"%s\"", $1); free($1); } ; template_content : { last_template = log_template_new(configuration, NULL); } template_content_inner { $$ = last_template; } ; template_content_list : template_content template_content_list { $$ = g_list_prepend($2, $1); } | { $$ = NULL; } ; string : LL_IDENTIFIER | LL_STRING ; yesno : KW_YES { $$ = 1; } | KW_NO { $$ = 0; } | LL_NUMBER { $$ = $1; } ; dnsmode : yesno { $$ = $1; } | KW_PERSIST_ONLY { $$ = 2; } ; nonnegative_integer64 : LL_NUMBER { CHECK_ERROR(($1 >= 0), @1, "It cannot be negative"); } ; nonnegative_integer : nonnegative_integer64 { CHECK_ERROR(($1 <= G_MAXINT32), @1, "Must be smaller than 2^31"); } ; positive_integer64 : LL_NUMBER { CHECK_ERROR(($1 > 0), @1, "Must be positive"); } ; positive_integer : positive_integer64 { CHECK_ERROR(($1 <= G_MAXINT32), @1, "Must be smaller than 2^31"); } ; nonnegative_float : LL_FLOAT { CHECK_ERROR(($1 >= 0), @1, "It cannot be negative"); } | nonnegative_integer { $$ = (double) $1; } ; positive_float : LL_FLOAT { CHECK_ERROR(($1 > 0), @1, "Must be positive"); } | positive_integer { $$ = (double) $1; } ; string_or_number : string { $$ = $1; } | LL_NUMBER { $$ = strdup(lexer->token_text->str); } | LL_FLOAT { $$ = strdup(lexer->token_text->str); } ; path : string { struct stat buffer; int ret = stat($1, &buffer); CHECK_ERROR((ret == 0), @1, "File \"%s\" not found: %s", $1, strerror(errno)); $$ = $1; } ; path_check : path { cfg_path_track_file(configuration, $1, "path_check"); } ; path_secret : path { cfg_path_track_file(configuration, $1, "path_secret"); } ; path_no_check : string { cfg_path_track_file(configuration, $1, "path_no_check"); } ; normalized_flag : string { $$ = normalize_flag($1); free($1); } ; string_list : string_list_build { $$ = $1; } ; string_list_build : string string_list_build { $$ = g_list_prepend($2, g_strdup($1)); free($1); } | { $$ = NULL; } ; semicolons : ';' | ';' semicolons ; severity_string : string { /* return the numeric value of the "level" */ int n = syslog_name_lookup_severity_by_name($1); CHECK_ERROR((n != -1), @1, "Unknown priority level\"%s\"", $1); free($1); $$ = n; } ; facility_string : string { /* return the numeric value of facility */ int n = syslog_name_lookup_facility_by_name($1); CHECK_ERROR((n != -1), @1, "Unknown facility \"%s\"", $1); free($1); $$ = n; } | KW_SYSLOG { $$ = LOG_SYSLOG; } ; parser_opt : KW_TEMPLATE '(' string ')' { LogTemplate *template; GError *error = NULL; template = cfg_tree_check_inline_template(&configuration->tree, $3, &error); CHECK_ERROR_GERROR(template != NULL, @3, error, "Error compiling template"); log_parser_set_template(last_parser, template); free($3); } ; driver_option : KW_PERSIST_NAME '(' string ')' { log_pipe_set_persist_name(&last_driver->super, $3); free($3); } ; inner_source : LL_IDENTIFIER { Plugin *p; gint context = LL_CONTEXT_INNER_SRC; gpointer value; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1); value = cfg_parse_plugin(configuration, p, &@1, last_driver); free($1); if (!value) { YYERROR; } if (!log_driver_add_plugin(last_driver, (LogDriverPlugin *) value)) { log_driver_plugin_free(value); CHECK_ERROR(TRUE, @1, "Error while registering the plugin %s in this destination", $1); } } ; /* All source drivers should incorporate this rule, implies driver_option */ source_driver_option : inner_source | driver_option ; inner_dest : LL_IDENTIFIER { Plugin *p; gint context = LL_CONTEXT_INNER_DEST; gpointer value; p = cfg_find_plugin(configuration, context, $1); CHECK_ERROR(p, @1, "%s plugin %s not found", cfg_lexer_lookup_context_name_by_type(context), $1); value = cfg_parse_plugin(configuration, p, &@1, last_driver); free($1); if (!value) { YYERROR; } if (!log_driver_add_plugin(last_driver, (LogDriverPlugin *) value)) { log_driver_plugin_free(value); CHECK_ERROR(TRUE, @1, "Error while registering the plugin %s in this destination", $1); } } ; /* implies driver_option */ dest_driver_option /* NOTE: plugins need to set "last_driver" in order to incorporate this rule in their grammar */ : KW_LOG_FIFO_SIZE '(' positive_integer ')' { ((LogDestDriver *) last_driver)->log_fifo_size = $3; } | KW_THROTTLE '(' nonnegative_integer ')' { ((LogDestDriver *) last_driver)->throttle = $3; } | inner_dest | driver_option ; threaded_dest_driver_batch_option : KW_BATCH_LINES '(' nonnegative_integer ')' { log_threaded_dest_driver_set_batch_lines(last_driver, $3); } | KW_BATCH_TIMEOUT '(' positive_integer ')' { log_threaded_dest_driver_set_batch_timeout(last_driver, $3); } ; threaded_dest_driver_workers_option : KW_WORKERS '(' positive_integer ')' { log_threaded_dest_driver_set_num_workers(last_driver, $3); } ; /* implies dest_driver_option */ threaded_dest_driver_general_option : KW_RETRIES '(' positive_integer ')' { log_threaded_dest_driver_set_max_retries_on_error(last_driver, $3); } | KW_TIME_REOPEN '(' positive_integer ')' { log_threaded_dest_driver_set_time_reopen(last_driver, $3); } | dest_driver_option ; /* implies source_driver_option and source_option */ threaded_source_driver_option : KW_FORMAT '(' string ')' { log_threaded_source_driver_get_parse_options(last_driver)->format = g_strdup($3); free($3); } | KW_FLAGS '(' threaded_source_driver_option_flags ')' | { last_msg_format_options = log_threaded_source_driver_get_parse_options(last_driver); } msg_format_option | { last_source_options = log_threaded_source_driver_get_source_options(last_driver); } source_option | source_driver_option ; threaded_fetcher_driver_option : KW_FETCH_NO_DATA_DELAY '(' nonnegative_float ')' { log_threaded_fetcher_driver_set_fetch_no_data_delay(last_driver, $3); } | KW_TIME_REOPEN '(' positive_integer ')' { log_threaded_fetcher_driver_set_time_reopen(last_driver, $3); } ; threaded_source_driver_option_flags : string threaded_source_driver_option_flags { CHECK_ERROR(msg_format_options_process_flag(log_threaded_source_driver_get_parse_options(last_driver), $1), @1, "Unknown flag \"%s\"", $1); free($1); } | ; /* LogSource related options */ source_option /* NOTE: plugins need to set "last_source_options" in order to incorporate this rule in their grammar */ : KW_LOG_IW_SIZE '(' positive_integer ')' { last_source_options->init_window_size = $3; } | KW_CHAIN_HOSTNAMES '(' yesno ')' { last_source_options->chain_hostnames = $3; } | KW_KEEP_HOSTNAME '(' yesno ')' { last_source_options->keep_hostname = $3; } | KW_PROGRAM_OVERRIDE '(' string ')' { last_source_options->program_override = g_strdup($3); free($3); } | KW_HOST_OVERRIDE '(' string ')' { last_source_options->host_override = g_strdup($3); free($3); } | KW_LOG_PREFIX '(' string ')' { gchar *p = strrchr($3, ':'); if (p) *p = 0; last_source_options->program_override = g_strdup($3); free($3); } | KW_KEEP_TIMESTAMP '(' yesno ')' { last_source_options->keep_timestamp = $3; } | KW_READ_OLD_RECORDS '(' yesno ')' { last_source_options->read_old_records = $3; } | KW_USE_SYSLOGNG_PID '(' yesno ')' { last_source_options->use_syslogng_pid = $3; } | KW_TAGS '(' string_list ')' { log_source_options_set_tags(last_source_options, $3); } | { last_host_resolve_options = &last_source_options->host_resolve_options; } host_resolve_option ; /* LogReader related options, implies source_option */ source_reader_option /* NOTE: plugins need to set "last_reader_options" in order to incorporate this rule in their grammar */ : KW_CHECK_HOSTNAME '(' yesno ')' { last_reader_options->check_hostname = $3; } | KW_FLAGS '(' source_reader_option_flags ')' | KW_LOG_FETCH_LIMIT '(' positive_integer ')' { last_reader_options->fetch_limit = $3; } | KW_FORMAT '(' string ')' { last_reader_options->parse_options.format = g_strdup($3); free($3); } | { last_source_options = &last_reader_options->super; } source_option | { last_proto_server_options = &last_reader_options->proto_options.super; } source_proto_option | { last_msg_format_options = &last_reader_options->parse_options; } msg_format_option ; source_reader_option_flags : string source_reader_option_flags { CHECK_ERROR(log_reader_options_process_flag(last_reader_options, $1), @1, "Unknown flag \"%s\"", $1); free($1); } | KW_CHECK_HOSTNAME source_reader_option_flags { log_reader_options_process_flag(last_reader_options, "check-hostname"); } | ; /* LogProtoSource related options */ source_proto_option : KW_ENCODING '(' string ')' { CHECK_ERROR(log_proto_server_options_set_encoding(last_proto_server_options, $3), @3, "unknown encoding \"%s\"", $3); free($3); } | KW_LOG_MSG_SIZE '(' positive_integer ')' { last_proto_server_options->max_msg_size = $3; } | KW_TRIM_LARGE_MESSAGES '(' yesno ')' { last_proto_server_options->trim_large_messages = $3; } ; host_resolve_option : KW_USE_FQDN '(' yesno ')' { last_host_resolve_options->use_fqdn = $3; } | KW_USE_DNS '(' dnsmode ')' { last_host_resolve_options->use_dns = $3; } | KW_DNS_CACHE '(' yesno ')' { last_host_resolve_options->use_dns_cache = $3; } | KW_NORMALIZE_HOSTNAMES '(' yesno ')' { last_host_resolve_options->normalize_hostnames = $3; } ; msg_format_option : KW_TIME_ZONE '(' string ')' { last_msg_format_options->recv_time_zone = g_strdup($3); free($3); } | KW_DEFAULT_SEVERITY '(' severity_string ')' { if (last_msg_format_options->default_pri == 0xFFFF) last_msg_format_options->default_pri = LOG_USER; last_msg_format_options->default_pri = (last_msg_format_options->default_pri & ~LOG_PRIMASK) | $3; } | KW_DEFAULT_FACILITY '(' facility_string ')' { if (last_msg_format_options->default_pri == 0xFFFF) last_msg_format_options->default_pri = LOG_NOTICE; last_msg_format_options->default_pri = (last_msg_format_options->default_pri & LOG_PRIMASK) | $3; } ; dest_writer_options : dest_writer_option dest_writer_options | ; dest_writer_option /* NOTE: plugins need to set "last_writer_options" in order to incorporate this rule in their grammar */ : KW_FLAGS '(' dest_writer_options_flags ')' { last_writer_options->options = $3; } | KW_FLUSH_LINES '(' nonnegative_integer ')' { last_writer_options->flush_lines = $3; } | KW_FLUSH_TIMEOUT '(' positive_integer ')' { } | KW_SUPPRESS '(' nonnegative_integer ')' { last_writer_options->suppress = $3; } | KW_TEMPLATE '(' string ')' { GError *error = NULL; last_writer_options->template = cfg_tree_check_inline_template(&configuration->tree, $3, &error); CHECK_ERROR_GERROR(last_writer_options->template != NULL, @3, error, "Error compiling template"); free($3); } | KW_TEMPLATE_ESCAPE '(' yesno ')' { log_writer_options_set_template_escape(last_writer_options, $3); } | KW_PAD_SIZE '(' nonnegative_integer ')' { last_writer_options->padding = $3; } | KW_TRUNCATE_SIZE '(' nonnegative_integer ')' { last_writer_options->truncate_size = $3; } | KW_MARK_FREQ '(' nonnegative_integer ')' { last_writer_options->mark_freq = $3; } | KW_MARK_MODE '(' KW_INTERNAL ')' { log_writer_options_set_mark_mode(last_writer_options, "internal"); } | KW_MARK_MODE '(' string ')' { CHECK_ERROR(cfg_lookup_mark_mode($3) != -1, @3, "illegal mark mode \"%s\"", $3); log_writer_options_set_mark_mode(last_writer_options, $3); free($3); } | KW_TIME_REOPEN '(' positive_integer ')' { last_writer_options->time_reopen = $3; } | { last_template_options = &last_writer_options->template_options; } template_option ; dest_writer_options_flags : normalized_flag dest_writer_options_flags { $$ = log_writer_options_lookup_flag($1) | $2; free($1); } | { $$ = 0; } ; file_perm_option : KW_OWNER '(' string_or_number ')' { file_perm_options_set_file_uid(last_file_perm_options, $3); free($3); } | KW_OWNER '(' ')' { file_perm_options_dont_change_file_uid(last_file_perm_options); } | KW_GROUP '(' string_or_number ')' { file_perm_options_set_file_gid(last_file_perm_options, $3); free($3); } | KW_GROUP '(' ')' { file_perm_options_dont_change_file_gid(last_file_perm_options); } | KW_PERM '(' LL_NUMBER ')' { file_perm_options_set_file_perm(last_file_perm_options, $3); } | KW_PERM '(' ')' { file_perm_options_dont_change_file_perm(last_file_perm_options); } | KW_DIR_OWNER '(' string_or_number ')' { file_perm_options_set_dir_uid(last_file_perm_options, $3); free($3); } | KW_DIR_OWNER '(' ')' { file_perm_options_dont_change_dir_uid(last_file_perm_options); } | KW_DIR_GROUP '(' string_or_number ')' { file_perm_options_set_dir_gid(last_file_perm_options, $3); free($3); } | KW_DIR_GROUP '(' ')' { file_perm_options_dont_change_dir_gid(last_file_perm_options); } | KW_DIR_PERM '(' LL_NUMBER ')' { file_perm_options_set_dir_perm(last_file_perm_options, $3); } | KW_DIR_PERM '(' ')' { file_perm_options_dont_change_dir_perm(last_file_perm_options); } ; template_option : KW_TS_FORMAT '(' string ')' { last_template_options->ts_format = cfg_ts_format_value($3); free($3); } | KW_FRAC_DIGITS '(' nonnegative_integer ')' { last_template_options->frac_digits = $3; } | KW_TIME_ZONE '(' string ')' { last_template_options->time_zone[LTZ_SEND] = g_strdup($3); free($3); } | KW_SEND_TIME_ZONE '(' string ')' { last_template_options->time_zone[LTZ_SEND] = g_strdup($3); free($3); } | KW_LOCAL_TIME_ZONE '(' string ')' { last_template_options->time_zone[LTZ_LOCAL] = g_strdup($3); free($3); } | KW_ON_ERROR '(' string ')' { gint on_error; CHECK_ERROR(log_template_on_error_parse($3, &on_error), @3, "Invalid on-error() setting \"%s\"", $3); free($3); log_template_options_set_on_error(last_template_options, on_error); } ; matcher_option : KW_TYPE '(' string ')' { CHECK_ERROR(log_matcher_options_set_type(last_matcher_options, $3), @3, "unknown matcher type \"%s\"", $3); free($3); } | KW_FLAGS '(' matcher_flags ')' ; matcher_flags : string matcher_flags { CHECK_ERROR(log_matcher_options_process_flag(last_matcher_options, $1), @1, "unknown matcher flag \"%s\"", $1); free($1); } | ; value_pair_option : KW_VALUE_PAIRS { last_value_pairs = value_pairs_new(); } '(' vp_options ')' { $$ = last_value_pairs; } ; vp_options : vp_option vp_options | ; vp_option : KW_PAIR '(' string ':' template_content ')' { value_pairs_add_pair(last_value_pairs, $3, $5); free($3); } | KW_PAIR '(' string template_content ')' { value_pairs_add_pair(last_value_pairs, $3, $4); free($3); } | KW_KEY '(' string KW_REKEY '(' { last_vp_transset = value_pairs_transform_set_new($3); value_pairs_add_glob_pattern(last_value_pairs, $3, TRUE); free($3); } vp_rekey_options ')' { value_pairs_add_transforms(last_value_pairs, last_vp_transset); } ')' | KW_KEY '(' string_list ')' { value_pairs_add_glob_patterns(last_value_pairs, $3, TRUE); } | KW_REKEY '(' string { last_vp_transset = value_pairs_transform_set_new($3); free($3); } vp_rekey_options ')' { value_pairs_add_transforms(last_value_pairs, last_vp_transset); } | KW_EXCLUDE '(' string_list ')' { value_pairs_add_glob_patterns(last_value_pairs, $3, FALSE); } | KW_SCOPE '(' vp_scope_list ')' ; vp_scope_list : string vp_scope_list { value_pairs_add_scope(last_value_pairs, $1); free($1); } | ; vp_rekey_options : vp_rekey_option vp_rekey_options | ; vp_rekey_option : KW_SHIFT '(' positive_integer ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_shift($3)); } | KW_SHIFT_LEVELS '(' positive_integer ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_shift_levels($3)); } | KW_ADD_PREFIX '(' string ')' { value_pairs_transform_set_add_func(last_vp_transset, value_pairs_new_transform_add_prefix($3)); free($3); } | 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); } ; rewrite_expr_opt : KW_VALUE '(' string ')' { const gchar *p = $3; if (p[0] == '$') { msg_warning("Value references in rewrite rules should not use the '$' prefix, those are only needed in templates", evt_tag_str("value", $3), cfg_lexer_format_location_tag(lexer, &@3)); p++; } last_rewrite->value_handle = log_msg_get_value_handle(p); CHECK_ERROR(!log_msg_is_handle_macro(last_rewrite->value_handle), @3, "%s is read-only, it cannot be changed in rewrite rules", p); 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); free($3); } | rewrite_condition_opt ; rewrite_condition_opt : KW_CONDITION '(' { FilterExprNode *filter_expr; CHECK_ERROR_WITHOUT_MESSAGE(cfg_parser_parse(&filter_expr_parser, lexer, (gpointer *) &filter_expr, NULL), @1); log_rewrite_set_condition(last_rewrite, filter_expr); } ')' ; %%