From 1eeeb6f603326234f1d17a16d3c55f8458f7177b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 30 Jun 2011 16:38:25 +0200 Subject: first try towards a flex/bison based config parser --- grammar/conf-fmt | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ grammar/makefile | 8 +++ grammar/rscript.l | 23 +++++++++ grammar/samp | 11 +++++ grammar/utils.c | 45 +++++++++++++++++ 5 files changed, 232 insertions(+) create mode 100644 grammar/conf-fmt create mode 100644 grammar/makefile create mode 100644 grammar/rscript.l create mode 100644 grammar/samp create mode 100644 grammar/utils.c diff --git a/grammar/conf-fmt b/grammar/conf-fmt new file mode 100644 index 00000000..e34ab784 --- /dev/null +++ b/grammar/conf-fmt @@ -0,0 +1,145 @@ +PRI filter: + +- facility and severity may be numeric (but discouraged) +- format: facility "." priority [";" next-selector] (no whitespace) +- facility: + * auth, authpriv, cron, daemon, kern, lpr, mail, mark, news, security + (same as auth), syslog, user, uucp and local0 through local7 + * multiple +- "priority" (actually severity): + * debug, info, notice, warning, warn (same as warning), + err, error (same as err), crit, alert, emerg, panic (same as + emerg). The keywords error, warn and panic are deprecated and + should not be used anymore. + * "=" in front of sev --> exactly this + * "!" in front of sev --> ignore this priority + * "=" and "!" can be combined +- * => all fac/severities +- a '\' at end of line means that the following line f is a + continuation line. If so, leading whitespace is stripped from + f and then f as appended to the end of the current line, replacing + the backslash and all whitespace following it. + This makes it somewhat easier to grab selectors from an old-style + config stream. + '\' [WHITESPACE]* LF + + +DEBIAN SAMPLE +This probably includes everything that is problematic... + +# /etc/rsyslog.conf Configuration file for rsyslog. +# +# For more information see +# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html + + +################# +#### MODULES #### +################# + +$ModLoad imuxsock # provides support for local system logging +$ModLoad imklog # provides kernel logging support (previously done by rklogd) +#$ModLoad immark # provides --MARK-- message capability + +# provides UDP syslog reception +#$ModLoad imudp +#$UDPServerRun 514 + +# provides TCP syslog reception +#$ModLoad imtcp +#$InputTCPServerRun 514 + + +########################### +#### GLOBAL DIRECTIVES #### +########################### + +# +# Use traditional timestamp format. +# To enable high precision timestamps, comment out the following line. +# +#$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat + +# +# Set the default permissions for all log files. +# +$FileOwner root +$FileGroup adm +$FileCreateMode 0640 +$DirCreateMode 0755 +$Umask 0022 + +# +# Include all config files in /etc/rsyslog.d/ +# +$IncludeConfig /etc/rsyslog.d/*.conf + + +############### +#### RULES #### +############### + +# +# First some standard log files. Log by facility. +# +auth,authpriv.* /var/log/auth.log +*.*;auth,authpriv.none -/var/log/syslog +#cron.* /var/log/cron.log +daemon.* -/var/log/daemon.log +kern.* -/var/log/kern.log +lpr.* -/var/log/lpr.log +mail.* -/var/log/mail.log +user.* -/var/log/user.log + +# +# Logging for the mail system. Split it up so that +# it is easy to write scripts to parse these files. +# +mail.info -/var/log/mail.info +mail.warn -/var/log/mail.warn +mail.err /var/log/mail.err + +# +# Logging for INN news system. +# +news.crit /var/log/news/news.crit +news.err /var/log/news/news.err +news.notice -/var/log/news/news.notice + +# +# Some "catch-all" log files. +# +*.=debug;\ + auth,authpriv.none;\ + news.none;mail.none -/var/log/debug +*.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -/var/log/messages + +# +# Emergencies are sent to everybody logged in. +# +*.emerg * + +# +# I like to have messages displayed on the console, but only on a virtual +# console I usually leave idle. +# +#daemon,mail.*;\ +# news.=crit;news.=err;news.=notice;\ +# *.=debug;*.=info;\ +# *.=notice;*.=warn /dev/tty8 + +# The named pipe /dev/xconsole is for the `xconsole' utility. To use it, +# you must invoke `xconsole' with the `-file' option: +# +# $ xconsole -file /dev/xconsole [...] +# +# NOTE: adjust the list below, or you'll go crazy if you have a reasonably +# busy site.. +# +daemon.*;mail.*;\ + news.err;\ + *.=debug;*.=info;\ + *.=notice;*.=warn |/dev/xconsole diff --git a/grammar/makefile b/grammar/makefile new file mode 100644 index 00000000..520d836b --- /dev/null +++ b/grammar/makefile @@ -0,0 +1,8 @@ +rscript: lex.yy.c utils.o + gcc -o rscript lex.yy.c utils.o -lestr -lfl + +lex.yy.c: rscript.l + flex rscript.l + +utils.o: utils.c + gcc -c utils.c diff --git a/grammar/rscript.l b/grammar/rscript.l new file mode 100644 index 00000000..eb2c23ad --- /dev/null +++ b/grammar/rscript.l @@ -0,0 +1,23 @@ +%{ +#include +%} + +%% + + +. { printf("%s", yytext); } + +%% +int +main(int argc, char *argv[]) +{ + es_str_t *str; + YY_BUFFER_STATE bp; + char ln[10240]; + + readConfFile(stdin, &str); + //printf("buffer: %s\n", es_getBufAddr(str)); + bp = yy_scan_buffer(es_getBufAddr(str), es_strlen(str)); + //yy_switch_to_buffer(bp); + yylex(); +} diff --git a/grammar/samp b/grammar/samp new file mode 100644 index 00000000..91d475b0 --- /dev/null +++ b/grammar/samp @@ -0,0 +1,11 @@ +daemon.*;mail.*;\ + news.err;\ + *.=debug;*.=info;\ + *.=notice;*.=warn |/dev/xconsole +*.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -/var/log/messages + +mail.info -/var/log/mail.info + diff --git a/grammar/utils.c b/grammar/utils.c new file mode 100644 index 00000000..f9c50bc9 --- /dev/null +++ b/grammar/utils.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include "libestr.h" + +void +readConfFile(FILE *fp, es_str_t **str) +{ + int c; + char ln[10240]; + int len, i; + int start; /* start index of to be submitted text */ + char *fgetsRet; + int bContLine = 0; + + *str = es_newStr(4096); + + while(fgets(ln, sizeof(ln), fp) != NULL) { + len = strlen(ln); + /* if we are continuation line, we need to drop leading WS */ + if(bContLine) { + for(start = 0 ; start < len && isspace(ln[start]) ; ++start) + /* JUST SCAN */; + } else { + start = 0; + } + for(i = len - 1 ; i >= start && isspace(ln[i]) ; --i) + /* JUST SCAN */; + if(i >= 0) { + if(ln[i] == '\\') { + --i; + bContLine = 1; + } else { + bContLine = 0; + } + /* add relevant data to buffer */ + es_addBuf(str, ln+start, i+1 - start); + if(!bContLine) + es_addChar(str, '\n'); + } + } + /* indicate end of buffer to flex */ + es_addChar(str, '\0'); + es_addChar(str, '\0'); +} -- cgit v1.2.3 From 0a1f27bba26c436b1c7042a2d3cc479dc1512e0a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 30 Jun 2011 17:55:48 +0200 Subject: worked on detecting old-style PRI filter --- grammar/debian.conf | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rscript.l | 1 + 2 files changed, 118 insertions(+) create mode 100644 grammar/debian.conf diff --git a/grammar/debian.conf b/grammar/debian.conf new file mode 100644 index 00000000..ad5d2217 --- /dev/null +++ b/grammar/debian.conf @@ -0,0 +1,117 @@ +# /etc/rsyslog.conf Configuration file for rsyslog. +# +# For more information see +# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html + + +################# +#### MODULES #### +################# + +$ModLoad imuxsock # provides support for local system logging +$ModLoad imklog # provides kernel logging support (previously done by rklogd) +#$ModLoad immark # provides --MARK-- message capability + +# provides UDP syslog reception +#$ModLoad imudp +#$UDPServerRun 514 + +# provides TCP syslog reception +#$ModLoad imtcp +#$InputTCPServerRun 514 + + +########################### +#### GLOBAL DIRECTIVES #### +########################### + +# +# Use traditional timestamp format. +# To enable high precision timestamps, comment out the following line. +# +#$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat + +# +# Set the default permissions for all log files. +# +$FileOwner root +$FileGroup adm +$FileCreateMode 0640 +$DirCreateMode 0755 +$Umask 0022 + +# +# Include all config files in /etc/rsyslog.d/ +# +$IncludeConfig /etc/rsyslog.d/*.conf + + +############### +#### RULES #### +############### + +# +# First some standard log files. Log by facility. +# +auth,authpriv.* /var/log/auth.log +*.*;auth,authpriv.none -/var/log/syslog +#cron.* /var/log/cron.log +daemon.* -/var/log/daemon.log +kern.* -/var/log/kern.log +lpr.* -/var/log/lpr.log +mail.* -/var/log/mail.log +user.* -/var/log/user.log + +# +# Logging for the mail system. Split it up so that +# it is easy to write scripts to parse these files. +# +mail.info -/var/log/mail.info +mail.warn -/var/log/mail.warn +mail.err /var/log/mail.err + +# +# Logging for INN news system. +# +news.crit /var/log/news/news.crit +news.err /var/log/news/news.err +news.notice -/var/log/news/news.notice + +# +# Some "catch-all" log files. +# +*.=debug;\ + auth,authpriv.none;\ + news.none;mail.none -/var/log/debug +*.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -/var/log/messages + +# +# Emergencies are sent to everybody logged in. +# +*.emerg * + +# +# I like to have messages displayed on the console, but only on a virtual +# console I usually leave idle. +# +#daemon,mail.*;\ +# news.=crit;news.=err;news.=notice;\ +# *.=debug;*.=info;\ +# *.=notice;*.=warn /dev/tty8 + +# The named pipe /dev/xconsole is for the `xconsole' utility. To use it, +# you must invoke `xconsole' with the `-file' option: +# +# $ xconsole -file /dev/xconsole [...] +# +# NOTE: adjust the list below, or you'll go crazy if you have a reasonably +# busy site.. +# +daemon.*;mail.*;\ + news.err;\ + *.=debug;*.=info;\ + *.=notice;*.=warn |/dev/xconsole + diff --git a/grammar/rscript.l b/grammar/rscript.l index eb2c23ad..18286d5e 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -5,6 +5,7 @@ %% +^[ \t]*[\*a-z]+.[!=;.\*a-z]+ { printf("PRI: '%s'\n", yytext); } . { printf("%s", yytext); } %% -- cgit v1.2.3 From 1f69bcb67fad8920867120b8ad310b5f60a7cc62 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 30 Jun 2011 19:03:48 +0200 Subject: milestone: first shot at rules to read old config file objects --- grammar/debian.conf | 2 ++ grammar/rscript.l | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/grammar/debian.conf b/grammar/debian.conf index ad5d2217..e5e54fde 100644 --- a/grammar/debian.conf +++ b/grammar/debian.conf @@ -115,3 +115,5 @@ daemon.*;mail.*;\ *.=debug;*.=info;\ *.=notice;*.=warn |/dev/xconsole +# samples added to get full "flavor" of what we need to support... +:msg, contains, "error" /var/log/somelog diff --git a/grammar/rscript.l b/grammar/rscript.l index 18286d5e..dd86fbe9 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -1,3 +1,8 @@ +%option noyywrap nodefault case-insensitive + /*%option noyywrap nodefault case-insensitive */ + +%x OLDACT + /* old-style action expected -- need to parse differently */ %{ #include %} @@ -5,8 +10,32 @@ %% -^[ \t]*[\*a-z]+.[!=;.\*a-z]+ { printf("PRI: '%s'\n", yytext); } -. { printf("%s", yytext); } +\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); } + +^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { + printf("PROP-FILT: '%s'\n", yytext); + BEGIN OLDACT; + } + +^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("PRI-FILT: '%s'\n", yytext); + BEGIN OLDACT; + } + +#.*\n /* skip comments in input */ +.|\n { if(yytext[0] != '\n') printf("%s", yytext); } + +\* | +-\/[^ \t\n]+ | +\|[^ \t\n]+ | +\/[^ \t\n]+ { printf("old style action: '%s'\n", yytext); + BEGIN INITIAL; + } +[ \t\n] +.|\n { printf("invalid sequence in OLDACT mode: %s\n", + yytext); + } + + %% int -- cgit v1.2.3 From 8cd026b1cbb0f22f498963c862136c22d2920a15 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 1 Jul 2011 12:40:29 +0200 Subject: milestone: grammar contains rules for object blocks --- grammar/debian.new | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rscript.l | 60 +++++++++++++++++++++--------- 2 files changed, 149 insertions(+), 18 deletions(-) create mode 100644 grammar/debian.new diff --git a/grammar/debian.new b/grammar/debian.new new file mode 100644 index 00000000..a6574f62 --- /dev/null +++ b/grammar/debian.new @@ -0,0 +1,107 @@ +# /etc/rsyslog.conf Configuration file for rsyslog. +# +# For more information see +# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html + + +################# +#### MODULES #### +################# + +module( + name=imuxsock # provides support for local system logging + ) +$ModLoad imklog # provides kernel logging support (previously done by rklogd) +#$ModLoad immark # provides --MARK-- message capability + +# provides UDP syslog reception +#$ModLoad imudp +#$UDPServerRun 514 +module(name=imudp) +input(type=imudp port=514) + +# provides TCP syslog reception +#$ModLoad imtcp +#$InputTCPServerRun 514 + + +########################### +#### GLOBAL DIRECTIVES #### +########################### + +# +# Use traditional timestamp format. +# To enable high precision timestamps, comment out the following line. +# +#$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat + +# +# Set the default permissions for all log files. +# +$FileOwner root +$FileGroup adm +$FileCreateMode 0640 +$DirCreateMode 0755 +$Umask 0022 + +# +# Include all config files in /etc/rsyslog.d/ +# +$IncludeConfig /etc/rsyslog.d/*.conf + + +############### +#### RULES #### +############### + +# +# First some standard log files. Log by facility. +# +auth,authpriv.* /var/log/auth.log +*.*;auth,authpriv.none -/var/log/syslog +#cron.* /var/log/cron.log + +# +# Some "catch-all" log files. +# +*.=debug;\ + auth,authpriv.none;\ + news.none;mail.none -/var/log/debug +*.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -/var/log/messages + +# +# Emergencies are sent to everybody logged in. +# +*.emerg * + +# +# I like to have messages displayed on the console, but only on a virtual +# console I usually leave idle. +# +#daemon,mail.*;\ +# news.=crit;news.=err;news.=notice;\ +# *.=debug;*.=info;\ +# *.=notice;*.=warn /dev/tty8 + +# The named pipe /dev/xconsole is for the `xconsole' utility. To use it, +# you must invoke `xconsole' with the `-file' option: +# +# $ xconsole -file /dev/xconsole [...] +# +# NOTE: adjust the list below, or you'll go crazy if you have a reasonably +# busy site.. +# +daemon.*;mail.*;\ + news.err;\ + *.=debug;*.=info;\ + *.=notice;*.=warn |/dev/xconsole + +global (dnscache=yes arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") +# samples added to get full "flavor" of what we need to support... +:msg, contains, "error" /var/log/somelog +action(type=omfile target=/var/log/mail/log) +*.* * # test +*.info :ommysql:, tra, la , la # comment (comment to be part of old style line!) diff --git a/grammar/rscript.l b/grammar/rscript.l index dd86fbe9..b5d23d7a 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -1,41 +1,65 @@ %option noyywrap nodefault case-insensitive /*%option noyywrap nodefault case-insensitive */ -%x OLDACT - /* old-style action expected -- need to parse differently */ +%x INOBJ + /* INOBJ is selected if we are inside an object (name/value pairs!) */ %{ #include %} %% - -\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); } - +"global"[ \n\t]*"(" { printf("OBJ GLOBAL begin\n"); + BEGIN INOBJ; + } +"input"[ \n\t]*"(" { printf("OBJ INPUT begin\n"); + BEGIN INOBJ; + } +"module"[ \n\t]*"(" { printf("OBJ MODULE begin\n"); + BEGIN INOBJ; + } +"action"[ \n\t]*"(" { printf("OBJ ACTION begin\n"); + BEGIN INOBJ; + } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { printf("PROP-FILT: '%s'\n", yytext); - BEGIN OLDACT; + /*BEGIN OLDACT;*/ } ^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("PRI-FILT: '%s'\n", yytext); - BEGIN OLDACT; + /*BEGIN OLDACT;*/ } - -#.*\n /* skip comments in input */ -.|\n { if(yytext[0] != '\n') printf("%s", yytext); } -\* | --\/[^ \t\n]+ | -\|[^ \t\n]+ | -\/[^ \t\n]+ { printf("old style action: '%s'\n", yytext); - BEGIN INITIAL; +"*" | +[\|\.\/\-:][^\n]+ { printf("old style action: '%s'\n", yytext); + } + +")" { printf("OBJ end\n"); + BEGIN INITIAL; + } +[a-z][a-z0-9_]* { printf("INOBJ: name '%s'\n", yytext); + } +"=" { printf("INOBJ: equals\n"); } -[ \t\n] -.|\n { printf("invalid sequence in OLDACT mode: %s\n", - yytext); +[a-z0-9\.,_\+\-\/]* | +\"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { + printf("INOBJ: value '%s'\n", yytext); + BEGIN INOBJ; } +#.*\n /* skip comments in input */ +[ \n\t] +. { printf("INOBJ: invalid char '%s'\n", yytext); } + /* CFSYSLINE is valid in all modes */ +\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); } +\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); } + +\#.*\n /* skip comments in input */ +[\n\t ] /* drop whitespace */ +. { printf("invalid char: %s\n", yytext); + } + /*<> { printf("EOF reached\n"); }*/ %% int -- cgit v1.2.3 From 4ccdf6ea624c66024bce7cbede53049b5f218fb0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 1 Jul 2011 14:39:20 +0200 Subject: milestone: lexer now correctly identifies (almost) all constructs --- grammar/debian.new | 32 +++++++++++++++++++++- grammar/rscript.l | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/grammar/debian.new b/grammar/debian.new index a6574f62..4d55735c 100644 --- a/grammar/debian.new +++ b/grammar/debian.new @@ -103,5 +103,35 @@ global (dnscache=yes arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") # samples added to get full "flavor" of what we need to support... :msg, contains, "error" /var/log/somelog action(type=omfile target=/var/log/mail/log) -*.* * # test +*.* /* comment */ * # test *.info :ommysql:, tra, la , la # comment (comment to be part of old style line!) + +# from SUSE: +if ( \ + /* kernel up to warning except of firewall */ \ + ($syslogfacility-text == 'kern') and \ + ($syslogseverity <= 4 /* warning */ ) and not \ + ($msg contains 'IN=' and $msg contains 'OUT=') \ + ) or ( \ + /* up to errors except of facility authpriv */ \ + ($syslogseverity <= 3 /* errors */ ) and not \ + ($syslogfacility-text == 'authpriv') \ + ) \ +then /dev/tty10 +& |/dev/xconsole +# +# slightly modified to not use continuation lines +if ( /* kernel up to warning except of firewall */ + ($syslogfacility-text == 'kern') and + ($syslogseverity <= 4 /* warning */ ) and not + ($msg contains 'IN=' and $msg contains 'OUT=') + ) or ( + /* up to errors except of facility authpriv */ + ($syslogseverity <= 3 /* errors */ ) and not + ($syslogfacility-text == 'authpriv') + ) +then /dev/tty10 +& |/dev/xconsole + +*.* rger # write to user (ugly...) +ruleset name diff --git a/grammar/rscript.l b/grammar/rscript.l index b5d23d7a..10ce1748 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -1,14 +1,77 @@ + /* lex file for rsyslog config format v2. + * Please note: this file introduces the new config format, but maintains + * backward compatibility. In order to do so, the grammar is not 100% clean, + * but IMHO still sufficiently easy both to understand for programmers + * maitaining the code as well as users writing the config file. Users are, + * of course, encouraged to use new constructs only. But it needs to be noted + * that some of the legacy constructs (specifically the in-front-of-action + * PRI filter) are very hard to beat in ease of use, at least for simpler + * cases. So while we hope that cfsysline support can be dropped some time in + * the future, we will probably keep these useful constructs. + * + * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH + * Released under the GNU GPL v3. For details see LICENSE file. + */ + %option noyywrap nodefault case-insensitive /*%option noyywrap nodefault case-insensitive */ %x INOBJ /* INOBJ is selected if we are inside an object (name/value pairs!) */ +%x COMMENT + /* COMMENT is "the usual trick" to handle C-style comments */ +%x EXPR + /* EXPR is a bit ugly, but we need it to support pre v6-syntax. The problem + * is that cfsysline statement start with $..., the same like variables in + * an expression. However, cfsysline statements can never appear inside an + * expression. So we create a specific expr mode, which is turned on after + * we lexed a keyword that needs to be followed by an expression (using + * knowledge from the upper layer...). In expr mode, we strictly do + * expression-based parsing. Expr mode is stopped when we reach a token + * that can not be part of an expression (currently only "then"). As I + * wrote this ugly, but the price needed to pay in order to remain + * compatible to the previous format. + */ %{ #include +static int preCommentState; %} %% + /* keywords */ +"if" { printf("IF\n"); + BEGIN EXPR; + } +"then" { printf("THEN\n"); + BEGIN INITIAL; + } +"or" { printf("OR\n"); } +"and" { printf("AND\n"); } +"not" { printf("NOT\n"); } +"(" { printf("LPAREN\n"); } +")" { printf("RPAREN\n"); } +"==" { printf("==\n"); } +"<=" { printf("<=\n"); } +">=" { printf(">=\n"); } +"!=" | +"<>" { printf("!=\n"); } +"<" { printf("<\n"); } +">" { printf(">\n"); } +"contains" { printf("CONTAINS\n"); } +"contains_i" { printf("CONTAINS_I\n"); } +"startswith" { printf("STARTSWITH\n"); } +"startswith_i" { printf("STARTSWITH_I\n"); } +-?0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } +-?0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } +-?([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); } +\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); } +\'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); } +[ \t\n] +. { printf("invalid char in expr: %s\n", yytext); } +"&" { printf("AMPER\n"); } +"ruleset" { printf("RULESET\n"); } + "global"[ \n\t]*"(" { printf("OBJ GLOBAL begin\n"); BEGIN INOBJ; } @@ -23,17 +86,18 @@ } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { printf("PROP-FILT: '%s'\n", yytext); - /*BEGIN OLDACT;*/ } ^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("PRI-FILT: '%s'\n", yytext); - /*BEGIN OLDACT;*/ } "*" | -[\|\.\/\-:][^\n]+ { printf("old style action: '%s'\n", yytext); +\/[^*][^\n]* | +[\|\.\-:][^\n]+ { printf("old style action: '%s'\n", yytext); } +[a-z0-9_\-\+]+ { printf("name: '%s'\n", yytext); } + ")" { printf("OBJ end\n"); BEGIN INITIAL; } @@ -46,6 +110,15 @@ printf("INOBJ: value '%s'\n", yytext); BEGIN INOBJ; } +"/*" { preCommentState = YY_START; + BEGIN COMMENT; + } +"/*" { preCommentState = YY_START; + BEGIN COMMENT; + } +"*/" { BEGIN preCommentState; } +([^*]|\n)+|. + #.*\n /* skip comments in input */ [ \n\t] . { printf("INOBJ: invalid char '%s'\n", yytext); } -- cgit v1.2.3 From aff06b40a68eeb88fb37a0ef67ab7be1b4aaf701 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 1 Jul 2011 15:35:14 +0200 Subject: milestone: done some more twists to the lexer --- grammar/debian.new | 35 +++++++++++++++++++++++++++++++---- grammar/rscript.l | 3 +-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/grammar/debian.new b/grammar/debian.new index 4d55735c..e995a2e8 100644 --- a/grammar/debian.new +++ b/grammar/debian.new @@ -9,7 +9,7 @@ ################# module( - name=imuxsock # provides support for local system logging + name="imuxsock" # provides support for local system logging ) $ModLoad imklog # provides kernel logging support (previously done by rklogd) #$ModLoad immark # provides --MARK-- message capability @@ -17,8 +17,8 @@ $ModLoad imklog # provides kernel logging support (previously done by rklogd) # provides UDP syslog reception #$ModLoad imudp #$UDPServerRun 514 -module(name=imudp) -input(type=imudp port=514) +module(name="imudp") +input(type="imudp" port="514") # provides TCP syslog reception #$ModLoad imtcp @@ -99,7 +99,7 @@ daemon.*;mail.*;\ *.=debug;*.=info;\ *.=notice;*.=warn |/dev/xconsole -global (dnscache=yes arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") +global (dnscache="yes" arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") # samples added to get full "flavor" of what we need to support... :msg, contains, "error" /var/log/somelog action(type=omfile target=/var/log/mail/log) @@ -135,3 +135,30 @@ then /dev/tty10 *.* rger # write to user (ugly...) ruleset name + +# FEDORA, a bit more complex config +# ### begin forwarding rule ### +# The statement between the begin ... end define a SINGLE forwarding +# rule. They belong together, do NOT split them. If you create multiple +# forwarding rules, duplicate the whole block! +# Remote Logging (we use TCP for reliable delivery) +# +# An on-disk queue is created for this action. If the remote host is +# down, messages are spooled to disk and sent when it is up again. +#$WorkDirectory /var/spppl/rsyslog # where to place spool files +#$ActionQueueFileName fwdRule1 # unique name prefix for spool files +#$ActionQueueMaxDiskSpace 1g # 1gb space limit (use as much as possible) +#$ActionQueueSaveOnShutdown on # save messages to disk on shutdown +#$ActionQueueType LinkedList # run asynchronously +#$ActionResumeRetryCount -1 # infinite retries if host is down +# remote host is: name/ip:port, e.g. 192.168.0.1:514, port optional +#*.* @@remote-host:514 +# ### end of the forwarding rule ### +if $msg contains "error" then + action(type="omfwd" protocol="tcp" target="10.0.0.1:514" + action.retryCount="-1" + queue.type="linkedList" queue.fileName="fwdRule" queue.maxDiskSpace="1g" + queue.saveOnShutdown="on" + ) + & action(type="omfile" target="/var/log/somelog.log") + & action(type="omuser" target="all") diff --git a/grammar/rscript.l b/grammar/rscript.l index 10ce1748..f94ad43a 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -101,11 +101,10 @@ static int preCommentState; ")" { printf("OBJ end\n"); BEGIN INITIAL; } -[a-z][a-z0-9_]* { printf("INOBJ: name '%s'\n", yytext); +[a-z][a-z0-9_\.]* { printf("INOBJ: name '%s'\n", yytext); } "=" { printf("INOBJ: equals\n"); } -[a-z0-9\.,_\+\-\/]* | \"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { printf("INOBJ: value '%s'\n", yytext); BEGIN INOBJ; -- cgit v1.2.3 From 1ee14507b37bd7cb252341e7f6bdb6398407f1fd Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 2 Jul 2011 12:39:53 +0200 Subject: milestone: grammar for objects and cfsysline created --- grammar/makefile | 11 ++++--- grammar/rscript.l | 88 +++++++++++++++++++++++++++++++------------------------ grammar/rscript.y | 57 +++++++++++++++++++++++++++++++++++ grammar/utils.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++- grammar/utils.h | 52 ++++++++++++++++++++++++++++++++ 5 files changed, 242 insertions(+), 43 deletions(-) create mode 100644 grammar/rscript.y create mode 100644 grammar/utils.h diff --git a/grammar/makefile b/grammar/makefile index 520d836b..29aab217 100644 --- a/grammar/makefile +++ b/grammar/makefile @@ -1,8 +1,11 @@ -rscript: lex.yy.c utils.o - gcc -o rscript lex.yy.c utils.o -lestr -lfl +rscript: lex.yy.c utils.o rscript.tab.h utils.h + gcc -o rscript lex.yy.c rscript.tab.c utils.o -lestr -lex.yy.c: rscript.l +lex.yy.c: rscript.l rscript.tab.h flex rscript.l -utils.o: utils.c +rscript.tab.h: rscript.y + bison -d rscript.y + +utils.o: utils.c utils.h gcc -c utils.c diff --git a/grammar/rscript.l b/grammar/rscript.l index f94ad43a..73843692 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -33,7 +33,10 @@ * compatible to the previous format. */ %{ +#include #include +#include "utils.h" +#include "rscript.tab.h" static int preCommentState; %} @@ -72,68 +75,76 @@ static int preCommentState; "&" { printf("AMPER\n"); } "ruleset" { printf("RULESET\n"); } -"global"[ \n\t]*"(" { printf("OBJ GLOBAL begin\n"); - BEGIN INOBJ; - } -"input"[ \n\t]*"(" { printf("OBJ INPUT begin\n"); - BEGIN INOBJ; - } -"module"[ \n\t]*"(" { printf("OBJ MODULE begin\n"); - BEGIN INOBJ; - } -"action"[ \n\t]*"(" { printf("OBJ ACTION begin\n"); - BEGIN INOBJ; - } +"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; + BEGIN INOBJ; return BEGINOBJ; } +"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; + BEGIN INOBJ; return BEGINOBJ; } +"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; + BEGIN INOBJ; return BEGINOBJ; } +"action"[ \n\t]*"(" { yylval.objType = CNFOBJ_ACTION; + BEGIN INOBJ; return BEGINOBJ; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { printf("PROP-FILT: '%s'\n", yytext); } -^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("PRI-FILT: '%s'\n", yytext); - } +^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("PRI-FILT: '%s'\n", yytext); + } "*" | \/[^*][^\n]* | -[\|\.\-:][^\n]+ { printf("old style action: '%s'\n", yytext); - } +[\|\.\-:][^\n]+ { printf("old style action: '%s'\n", yytext); + } -[a-z0-9_\-\+]+ { printf("name: '%s'\n", yytext); } +[a-z0-9_\-\+]+ { printf("name: '%s'\n", yytext); } -")" { printf("OBJ end\n"); - BEGIN INITIAL; - } +")" { printf("OBJ end\n"); + BEGIN INITIAL; + return ENDOBJ; + } [a-z][a-z0-9_\.]* { printf("INOBJ: name '%s'\n", yytext); - } -"=" { printf("INOBJ: equals\n"); - } + yylval.estr = es_newStrFromCStr(yytext, yyleng); + return NAME; + } +"=" { printf("INOBJ: equals (%s)\n", yytext); + return(yytext[0]); + } \"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { - printf("INOBJ: value '%s'\n", yytext); - BEGIN INOBJ; - } -"/*" { preCommentState = YY_START; - BEGIN COMMENT; - } -"/*" { preCommentState = YY_START; - BEGIN COMMENT; - } -"*/" { BEGIN preCommentState; } + printf("INOBJ: value '%s'\n", yytext); + yylval.estr = es_newStrFromCStr(yytext+1, yyleng-2); + return VALUE; + } +"/*" { preCommentState = YY_START; + BEGIN COMMENT; + } +"/*" { preCommentState = YY_START; + BEGIN COMMENT; + } +"*/" { BEGIN preCommentState; } ([^*]|\n)+|. #.*\n /* skip comments in input */ [ \n\t] -. { printf("INOBJ: invalid char '%s'\n", yytext); } +. { printf("INOBJ: invalid char '%s'\n", yytext); } /* CFSYSLINE is valid in all modes */ -\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); } -\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); } +\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); + yylval.s = yytext; + return CFSYSLINE; + } +\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); + yylval.s = yytext; + return CFSYSLINE; + } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ -. { printf("invalid char: %s\n", yytext); - } +. { printf("invalid char: %s\n", yytext); + } /*<> { printf("EOF reached\n"); }*/ %% + /* int main(int argc, char *argv[]) { @@ -147,3 +158,4 @@ main(int argc, char *argv[]) //yy_switch_to_buffer(bp); yylex(); } +*/ diff --git a/grammar/rscript.y b/grammar/rscript.y new file mode 100644 index 00000000..6954d38d --- /dev/null +++ b/grammar/rscript.y @@ -0,0 +1,57 @@ + +%{ +#include +#include +#include "utils.h" +#define YYDEBUG 1 +%} + +%union { + char *s; + es_str_t *estr; + enum cnfobjType objType; + struct cnfobj *obj; + struct nvlst *nvlst; +} + +%token NAME +%token VALUE +%token BEGINOBJ +%token ENDOBJ +%token CFSYSLINE + +%type nv nvlst +%type obj + +%% + /* conf: | conf global | conf action*/ +conf: + | obj conf + | cfsysline conf + +obj: BEGINOBJ nvlst ENDOBJ { printf("XXXX: global processed\n"); + $$ = cnfobjNew($1, $2); + cnfobjPrint($$); + cnfobjDestruct($$); + } +cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1); + } +nvlst: { $$ = NULL; } + | nvlst nv { printf("XXXX: nvlst $1: %p, $2 %p\n", $1,$2); + $2->next = $1; + $$ = $2; + } +nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } + +%% +int yyerror(char *s) +{ + printf("yyerror called: %s\n", s); +} + +int main() +{ + yydebug = 0; + return yyparse(); +} + diff --git a/grammar/utils.c b/grammar/utils.c index f9c50bc9..ccc9fbc7 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -1,7 +1,9 @@ #include +#include #include #include -#include "libestr.h" +#include +#include "utils.h" void readConfFile(FILE *fp, es_str_t **str) @@ -43,3 +45,76 @@ readConfFile(FILE *fp, es_str_t **str) es_addChar(str, '\0'); es_addChar(str, '\0'); } + +struct nvlst* +nvlstNew(es_str_t *name, es_str_t *value) +{ + struct nvlst *lst; + + if((lst = malloc(sizeof(struct nvlst))) != NULL) { + lst->next = NULL; + lst->name = name; + lst->value = value; + } + + return lst; +} + +void +nvlstDestruct(struct nvlst *lst) +{ + struct nvlst *toDel; + + while(lst != NULL) { + toDel = lst; + lst = lst->next; + es_deleteStr(toDel->name); + es_deleteStr(toDel->value); + free(toDel); + } +} + + +void +nvlstPrint(struct nvlst *lst) +{ + char *name, *value; + printf("nvlst %p:\n", lst); + while(lst != NULL) { + name = es_str2cstr(lst->name, NULL); + value = es_str2cstr(lst->value, NULL); + printf("\tname: '%s', value '%s'\n", name, value); + free(name); + free(value); + lst = lst->next; + } +} + +struct cnfobj* +cnfobjNew(enum cnfobjType objType, struct nvlst *lst) +{ + struct cnfobj *o; + + if((o = malloc(sizeof(struct nvlst))) != NULL) { + o->objType = objType; + o->nvlst = lst; + } + + return o; +} + +void +cnfobjDestruct(struct cnfobj *o) +{ + if(o != NULL) { + nvlstDestruct(o->nvlst); + free(o); + } +} + +void +cnfobjPrint(struct cnfobj *o) +{ + printf("obj: '%s'\n", cnfobjType2str(o->objType)); + nvlstPrint(o->nvlst); +} diff --git a/grammar/utils.h b/grammar/utils.h new file mode 100644 index 00000000..45176a50 --- /dev/null +++ b/grammar/utils.h @@ -0,0 +1,52 @@ +#ifndef INC_UTILS_H +#define INC_UTILS_H +#include + +enum cnfobjType { + CNFOBJ_ACTION, + CNFOBJ_GLOBAL, + CNFOBJ_INPUT, + CNFOBJ_MODULE, + CNFOBJ_INVALID = 0 +}; + +static inline char* +cnfobjType2str(enum cnfobjType ot) +{ + switch(ot) { + case CNFOBJ_ACTION: + return "action"; + break; + case CNFOBJ_GLOBAL: + return "global"; + break; + case CNFOBJ_INPUT: + return "input"; + break; + case CNFOBJ_MODULE: + return "module"; + break; + default:return "error: invalid cnfobjType"; + } +} + +struct cnfobj { + enum cnfobjType objType; + struct nvlst *nvlst; +}; + +struct nvlst { + struct nvlst *next; + es_str_t *name; + es_str_t *value; +}; + + +void readConfFile(FILE *fp, es_str_t **str); +struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); +void nvlstDestruct(struct nvlst *lst); +void nvlstPrint(struct nvlst *lst); +struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst); +void cnfobjDestruct(struct cnfobj *o); +void cnfobjPrint(struct cnfobj *o); +#endif -- cgit v1.2.3 From 62e95c10ba84871fd5ad97fccd75664b07620013 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 2 Jul 2011 18:32:35 +0200 Subject: milestone: some support for rules in grammar --- grammar/rscript.l | 118 +++++++++++++++++++++--------------------------------- grammar/rscript.y | 33 +++++++++++---- grammar/utils.c | 12 ++++++ grammar/utils.h | 3 ++ 4 files changed, 85 insertions(+), 81 deletions(-) diff --git a/grammar/rscript.l b/grammar/rscript.l index 73843692..ccc39a2f 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -43,82 +43,60 @@ static int preCommentState; %% /* keywords */ -"if" { printf("IF\n"); - BEGIN EXPR; - } -"then" { printf("THEN\n"); - BEGIN INITIAL; - } -"or" { printf("OR\n"); } -"and" { printf("AND\n"); } -"not" { printf("NOT\n"); } -"(" { printf("LPAREN\n"); } -")" { printf("RPAREN\n"); } -"==" { printf("==\n"); } -"<=" { printf("<=\n"); } -">=" { printf(">=\n"); } +"if" { printf("IF\n"); BEGIN EXPR; } +"then" { printf("THEN\n"); BEGIN INITIAL; } +"or" { printf("OR\n"); } +"and" { printf("AND\n"); } +"not" { printf("NOT\n"); } +"(" { printf("LPAREN\n"); } +")" { printf("RPAREN\n"); } +"==" { printf("==\n"); } +"<=" { printf("<=\n"); } +">=" { printf(">=\n"); } "!=" | -"<>" { printf("!=\n"); } -"<" { printf("<\n"); } -">" { printf(">\n"); } -"contains" { printf("CONTAINS\n"); } -"contains_i" { printf("CONTAINS_I\n"); } -"startswith" { printf("STARTSWITH\n"); } -"startswith_i" { printf("STARTSWITH_I\n"); } --?0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } --?0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } --?([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); } -\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); } -\'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); } +"<>" { printf("!=\n"); } +"<" { printf("<\n"); } +">" { printf(">\n"); } +"contains" { printf("CONTAINS\n"); } +"contains_i" { printf("CONTAINS_I\n"); } +"startswith" { printf("STARTSWITH\n"); } +"startswith_i" { printf("STARTSWITH_I\n"); } +-?0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } +-?0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } +-?([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); } +\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); } +\'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); } [ \t\n] -. { printf("invalid char in expr: %s\n", yytext); } -"&" { printf("AMPER\n"); } -"ruleset" { printf("RULESET\n"); } +. { printf("invalid char in expr: %s\n", yytext); } +"&" { return '&'; } +"ruleset" { printf("RULESET\n"); } -"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; - BEGIN INOBJ; return BEGINOBJ; } -"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; - BEGIN INOBJ; return BEGINOBJ; } -"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; - BEGIN INOBJ; return BEGINOBJ; } -"action"[ \n\t]*"(" { yylval.objType = CNFOBJ_ACTION; - BEGIN INOBJ; return BEGINOBJ; } +"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; + BEGIN INOBJ; return BEGINOBJ; } +"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; + BEGIN INOBJ; return BEGINOBJ; } +"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; + BEGIN INOBJ; return BEGINOBJ; } +"action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { - printf("PROP-FILT: '%s'\n", yytext); - } - -^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("PRI-FILT: '%s'\n", yytext); + printf("PROP-FILT: '%s'\n", yytext); } +^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("token prifilt '%s'\n", yytext); yylval.s = strdup(yytext); return PRIFILT; } + "*" | \/[^*][^\n]* | -[\|\.\-:][^\n]+ { printf("old style action: '%s'\n", yytext); - } - +[\|\.\-:][^\n]+ { printf("toke legacy_action '%s'\n", yytext);yylval.s = strdup(yytext); return LEGACY_ACTION; } [a-z0-9_\-\+]+ { printf("name: '%s'\n", yytext); } - -")" { printf("OBJ end\n"); - BEGIN INITIAL; - return ENDOBJ; - } -[a-z][a-z0-9_\.]* { printf("INOBJ: name '%s'\n", yytext); - yylval.estr = es_newStrFromCStr(yytext, yyleng); - return NAME; - } -"=" { printf("INOBJ: equals (%s)\n", yytext); - return(yytext[0]); - } +")" { BEGIN INITIAL; return ENDOBJ; } +[a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); + return NAME; } +"=" { return(yytext[0]); } \"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { - printf("INOBJ: value '%s'\n", yytext); yylval.estr = es_newStrFromCStr(yytext+1, yyleng-2); - return VALUE; - } -"/*" { preCommentState = YY_START; - BEGIN COMMENT; - } -"/*" { preCommentState = YY_START; - BEGIN COMMENT; - } + return VALUE; } +"/*" { preCommentState = YY_START; BEGIN COMMENT; } +"/*" { preCommentState = YY_START; BEGIN COMMENT; } "*/" { BEGIN preCommentState; } ([^*]|\n)+|. @@ -127,14 +105,8 @@ static int preCommentState; . { printf("INOBJ: invalid char '%s'\n", yytext); } /* CFSYSLINE is valid in all modes */ -\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); - yylval.s = yytext; - return CFSYSLINE; - } -\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); - yylval.s = yytext; - return CFSYSLINE; - } +\$[a-z]+.*$ { yylval.s = yytext; return CFSYSLINE; } +\$[a-z]+.*$ { yylval.s = yytext; return CFSYSLINE; } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ diff --git a/grammar/rscript.y b/grammar/rscript.y index 6954d38d..5bd8f0f9 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -19,30 +19,47 @@ %token BEGINOBJ %token ENDOBJ %token CFSYSLINE +%token BEGIN_ACTION +%token LEGACY_ACTION +%token PRIFILT +%token PROPFILT %type nv nvlst %type obj +%type actlst +%type act %% - /* conf: | conf global | conf action*/ -conf: +conf: /* empty (to end recursion) */ | obj conf | cfsysline conf + | rule conf -obj: BEGINOBJ nvlst ENDOBJ { printf("XXXX: global processed\n"); - $$ = cnfobjNew($1, $2); +obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); cnfobjPrint($$); cnfobjDestruct($$); } +obj: BEGIN_ACTION nvlst ENDOBJ { struct cnfobj *t = cnfobjNew(CNFOBJ_ACTION, $2); + cnfobjPrint(t); + cnfobjDestruct(t); + printf("XXXX: this is an new-style action!\n"); + } cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1); } nvlst: { $$ = NULL; } - | nvlst nv { printf("XXXX: nvlst $1: %p, $2 %p\n", $1,$2); - $2->next = $1; - $$ = $2; - } + | nvlst nv { $2->next = $1; $$ = $2; } nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } +rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); } + | PROPFILT actlst + +actlst: act { printf("action (end actlst) %s\n", $1);$$=$1; } + | actlst '&' act { printf("in actionlist %s\n", $3); } +act: BEGIN_ACTION nvlst ENDOBJ { $$ = "obj"; } + | LEGACY_ACTION { printf("legacy action: '%s'\n", $1); + /*free($1);*/ + $$ = $1;} + %% int yyerror(char *s) { diff --git a/grammar/utils.c b/grammar/utils.c index ccc9fbc7..a505704f 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -118,3 +118,15 @@ cnfobjPrint(struct cnfobj *o) printf("obj: '%s'\n", cnfobjType2str(o->objType)); nvlstPrint(o->nvlst); } + +/* debug helper */ +void +cstrPrint(char *text, es_str_t *estr) +{ + char *str; + printf("in cstrPrint, estr %p\n", estr); + str = es_str2cstr(estr, NULL); + printf("2: in cstrPrint, estr %p\n", estr); + printf("%s%s", text, str); + free(str); +} diff --git a/grammar/utils.h b/grammar/utils.h index 45176a50..66b05647 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -49,4 +49,7 @@ void nvlstPrint(struct nvlst *lst); struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst); void cnfobjDestruct(struct cnfobj *o); void cnfobjPrint(struct cnfobj *o); + +/* debug helper */ +void cstrPrint(char *text, es_str_t *estr); #endif -- cgit v1.2.3 From 1cdab4d2b548a0db54b5a2c5404f3f78e012113e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 3 Jul 2011 13:10:37 +0200 Subject: milestone: support for action list added to grammar --- grammar/rscript.l | 4 +- grammar/rscript.y | 33 +++++++++++---- grammar/utils.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- grammar/utils.h | 22 ++++++++++ 4 files changed, 163 insertions(+), 13 deletions(-) diff --git a/grammar/rscript.l b/grammar/rscript.l index ccc39a2f..750a3e81 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -105,8 +105,8 @@ static int preCommentState; . { printf("INOBJ: invalid char '%s'\n", yytext); } /* CFSYSLINE is valid in all modes */ -\$[a-z]+.*$ { yylval.s = yytext; return CFSYSLINE; } -\$[a-z]+.*$ { yylval.s = yytext; return CFSYSLINE; } +\$[a-z]+.*$ { yylval.s = strdup(yytext); return CFSYSLINE; } +\$[a-z]+.*$ { yylval.s = strdup(yytext); return CFSYSLINE; } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ diff --git a/grammar/rscript.y b/grammar/rscript.y index 5bd8f0f9..15348e4d 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -12,6 +12,7 @@ enum cnfobjType objType; struct cnfobj *obj; struct nvlst *nvlst; + struct cnfactlst *actlst; } %token NAME @@ -26,9 +27,20 @@ %type nv nvlst %type obj -%type actlst -%type act +%type actlst +%type act + +%expect 2 +/* two shift/reduce conflicts are created by the CFSYSLINE construct, which we + * unfortunately can not avoid. The problem is that CFSYSLINE can occur both in + * global context as well as within an action. It's not permitted somewhere else, + * but this is suficient for conflicts. The "dangling else" built-in resolution + * works well to solve this issue, so we accept it (it's a wonder that our + * old style grammar doesn't work at all, so we better do not complain...). + * Use "bison -v rscript.y" if more conflicts arise and check rscript.out for + * were exactly these conflicts exits. + */ %% conf: /* empty (to end recursion) */ | obj conf @@ -50,15 +62,20 @@ nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } -rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); } +rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); + $2 = cnfactlstReverse($2); + cnfactlstPrint($2); } | PROPFILT actlst -actlst: act { printf("action (end actlst) %s\n", $1);$$=$1; } - | actlst '&' act { printf("in actionlist %s\n", $3); } -act: BEGIN_ACTION nvlst ENDOBJ { $$ = "obj"; } +actlst: act { printf("action (end actlst)\n");$$=$1; } + | actlst '&' act { printf("in actionlist \n"); + $3->next = $1; $$ = $3; } + | actlst CFSYSLINE { printf("in actionlist/CFSYSLINE: %s\n", $2); + $$ = cnfactlstAddSysline($1, $2); } + +act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } | LEGACY_ACTION { printf("legacy action: '%s'\n", $1); - /*free($1);*/ - $$ = $1;} + $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } %% int yyerror(char *s) diff --git a/grammar/utils.c b/grammar/utils.c index a505704f..28e1a04a 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -74,7 +74,6 @@ nvlstDestruct(struct nvlst *lst) } } - void nvlstPrint(struct nvlst *lst) { @@ -119,14 +118,126 @@ cnfobjPrint(struct cnfobj *o) nvlstPrint(o->nvlst); } + +struct cnfactlst* +cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine) +{ + struct cnfactlst *actlst; + + if((actlst = malloc(sizeof(struct cnfactlst))) != NULL) { + actlst->next = NULL; + actlst->syslines = NULL; + actlst->actType = actType; + if(actType == CNFACT_V2) + actlst->data.lst = lst; + else + actlst->data.legActLine = actLine; + } + return actlst; +} + +struct cnfactlst* +cnfactlstAddSysline(struct cnfactlst* actlst, char *line) +{ + struct cnfcfsyslinelst *cflst; + + if((cflst = malloc(sizeof(struct cnfcfsyslinelst))) != NULL) { + cflst->next = NULL; + cflst->line = line; + if(actlst->syslines == NULL) { + actlst->syslines = cflst; + } else { + cflst->next = actlst->syslines; + actlst->syslines = cflst; + } + } + return actlst; +} + +void +cnfactlstDestruct(struct cnfactlst *actlst) +{ + struct cnfactlst *toDel; + + while(actlst != NULL) { + toDel = actlst; + actlst = actlst->next; + if(toDel->actType == CNFACT_V2) + nvlstDestruct(toDel->data.lst); + else + free(toDel->data.legActLine); + free(toDel); + } + +} + +static inline struct cnfcfsyslinelst* +cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) +{ + struct cnfcfsyslinelst *curr, *prev; + + if(lst == NULL) + return; + prev = lst; + lst = lst->next; + prev->next = NULL; + while(lst != NULL) { + curr = lst; + lst = lst->next; + curr->next = prev; + prev = curr; + } + return prev; +} + +struct cnfactlst* +cnfactlstReverse(struct cnfactlst *actlst) +{ + struct cnfactlst *curr, *prev; + + prev = actlst; + actlst = actlst->next; + prev->next = NULL; + while(actlst != NULL) { + curr = actlst; + actlst = actlst->next; + curr->syslines = cnfcfsyslinelstReverse(curr->syslines); + curr->next = prev; + prev = curr; + } + return prev; +} + +void +cnfactlstPrint(struct cnfactlst *actlst) +{ + struct cnfcfsyslinelst *cflst; + + printf("---------- cnfactlst %p:\n", actlst); + while(actlst != NULL) { + if(actlst->actType == CNFACT_V2) { + printf("V2 action type: "); + nvlstPrint(actlst->data.lst); + } else { + printf("legacy action line: '%s'\n", + actlst->data.legActLine); + } + for( cflst = actlst->syslines + ; cflst != NULL ; cflst = cflst->next) { + printf("cfsysline: '%s'\n", cflst->line); + } + actlst = actlst->next; + } + printf("----------\n"); +} + /* debug helper */ void cstrPrint(char *text, es_str_t *estr) { char *str; - printf("in cstrPrint, estr %p\n", estr); str = es_str2cstr(estr, NULL); - printf("2: in cstrPrint, estr %p\n", estr); printf("%s%s", text, str); free(str); } + diff --git a/grammar/utils.h b/grammar/utils.h index 66b05647..2a6ba10a 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -30,6 +30,8 @@ cnfobjType2str(enum cnfobjType ot) } } +enum cnfactType { CNFACT_V2, CNFACT_LEGACY }; + struct cnfobj { enum cnfobjType objType; struct nvlst *nvlst; @@ -41,6 +43,21 @@ struct nvlst { es_str_t *value; }; +struct cnfcfsyslinelst { + struct cnfcfsyslinelst *next; + char *line; +}; + +struct cnfactlst { + struct cnfactlst *next; + struct cnfcfsyslinelst *syslines; + enum cnfactType actType; + union { + struct nvlst *lst; + char *legActLine; + } data; +}; + void readConfFile(FILE *fp, es_str_t **str); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); @@ -49,6 +66,11 @@ void nvlstPrint(struct nvlst *lst); struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst); void cnfobjDestruct(struct cnfobj *o); void cnfobjPrint(struct cnfobj *o); +struct cnfactlst* cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine); +void cnfactlstDestruct(struct cnfactlst *actlst); +void cnfactlstPrint(struct cnfactlst *actlst); +struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); +struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); -- cgit v1.2.3 From 65076e28dfed0765e51c69be81a7842331aae1d2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 3 Jul 2011 17:09:09 +0200 Subject: milestone: grammar for basic if/then construct (no expr) --- grammar/mini.samp | 32 ++++++++++++++++++++++++++++++++ grammar/rscript.l | 13 +++++++------ grammar/rscript.y | 35 ++++++++++++++++++++++++++--------- 3 files changed, 65 insertions(+), 15 deletions(-) create mode 100644 grammar/mini.samp diff --git a/grammar/mini.samp b/grammar/mini.samp new file mode 100644 index 00000000..54efacec --- /dev/null +++ b/grammar/mini.samp @@ -0,0 +1,32 @@ +#global (dnscache="yes" arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") +action(type="omuser" target="all") +global (dnscache="no" b="2") +$FileOwner root +*.* * +$action somelog 1 +& /var/log/somelog +$action log2 1 +$action log2 2 +$action log2 3 +& action(type="fwd" target="10.1.1.2") +& /var/log/log2 + +if 1 then /var/log/log3 +/* sample bwlow is v7 +if 1 then { /var/log/log3 + if 2 then /var/log/log4 + *.* /var/log/log4b +} +*/ +*.* { /var/log/log5 + /var/log/log6 + $port 514 + @@fwd + rger + } +if 1/*pri("*.*")*/ then { + action(type="omfile" taget="/var/log/log5") + action(type="omfile" taget="/var/log/log6") + action(type="omfwd" taget="10.0.0.1" port="514") + action(type="omwusr" taget="rger") +} diff --git a/grammar/rscript.l b/grammar/rscript.l index 750a3e81..d6dab45b 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -43,8 +43,8 @@ static int preCommentState; %% /* keywords */ -"if" { printf("IF\n"); BEGIN EXPR; } -"then" { printf("THEN\n"); BEGIN INITIAL; } +"if" { BEGIN EXPR; return IF; } +"then" { BEGIN INITIAL; return THEN; } "or" { printf("OR\n"); } "and" { printf("AND\n"); } "not" { printf("NOT\n"); } @@ -63,12 +63,14 @@ static int preCommentState; "startswith_i" { printf("STARTSWITH_I\n"); } -?0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } -?0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } --?([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); } +-?([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); return NUMBER; } \$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); } \'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); } [ \t\n] . { printf("invalid char in expr: %s\n", yytext); } "&" { return '&'; } +"{" { return '{'; } +"}" { return '}'; } "ruleset" { printf("RULESET\n"); } "global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; @@ -86,8 +88,8 @@ static int preCommentState; "*" | \/[^*][^\n]* | -[\|\.\-:][^\n]+ { printf("toke legacy_action '%s'\n", yytext);yylval.s = strdup(yytext); return LEGACY_ACTION; } -[a-z0-9_\-\+]+ { printf("name: '%s'\n", yytext); } +[\|\.\-\@:~][^\n]+ | +[a-z0-9_\-\+]+ { yylval.s = strdup(yytext); return LEGACY_ACTION; } ")" { BEGIN INITIAL; return ENDOBJ; } [a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); return NAME; } @@ -106,7 +108,6 @@ static int preCommentState; /* CFSYSLINE is valid in all modes */ \$[a-z]+.*$ { yylval.s = strdup(yytext); return CFSYSLINE; } -\$[a-z]+.*$ { yylval.s = strdup(yytext); return CFSYSLINE; } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ diff --git a/grammar/rscript.y b/grammar/rscript.y index 15348e4d..7e9365c5 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -24,14 +24,18 @@ %token LEGACY_ACTION %token PRIFILT %token PROPFILT +%token IF +%token THEN +%token NUMBER %type nv nvlst %type obj %type actlst %type act +%type cfsysline +%type block - -%expect 2 +%expect 3 /* two shift/reduce conflicts are created by the CFSYSLINE construct, which we * unfortunately can not avoid. The problem is that CFSYSLINE can occur both in * global context as well as within an action. It's not permitted somewhere else, @@ -47,17 +51,17 @@ conf: /* empty (to end recursion) */ | cfsysline conf | rule conf -obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); +obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); cnfobjPrint($$); cnfobjDestruct($$); } -obj: BEGIN_ACTION nvlst ENDOBJ { struct cnfobj *t = cnfobjNew(CNFOBJ_ACTION, $2); + | BEGIN_ACTION nvlst ENDOBJ { struct cnfobj *t = cnfobjNew(CNFOBJ_ACTION, $2); cnfobjPrint(t); cnfobjDestruct(t); printf("XXXX: this is an new-style action!\n"); } -cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1); - } +cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1); } + nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } @@ -66,12 +70,25 @@ rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); $2 = cnfactlstReverse($2); cnfactlstPrint($2); } | PROPFILT actlst + | scriptfilt + +scriptfilt: IF NUMBER THEN actlst { printf("if filter detected\n"); } + +/* note: we can do some limited block-structuring with the v6 engine. In that case, + * we must not support additonal filters inside the blocks, so they must consist of + * "act", only. We can implement that via the "&" actlist logic. + */ +block: actlst + | block actlst + /* v7: | actlst + v7: | block rule */ -actlst: act { printf("action (end actlst)\n");$$=$1; } - | actlst '&' act { printf("in actionlist \n"); +actlst: act { printf("action (end actlst)\n");$$=$1; } + | actlst '&' act { printf("in actionlist \n"); $3->next = $1; $$ = $3; } - | actlst CFSYSLINE { printf("in actionlist/CFSYSLINE: %s\n", $2); + | actlst cfsysline { printf("in actionlist/CFSYSLINE: %s\n", $2); $$ = cnfactlstAddSysline($1, $2); } + | '{' block '}' { $$ = $2; } act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } | LEGACY_ACTION { printf("legacy action: '%s'\n", $1); -- cgit v1.2.3 From 719962c1f0f1ee1a6d5b5389417fb68adcde431b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 3 Jul 2011 18:13:23 +0200 Subject: milestone: added grammar for arithmetic expressions --- grammar/makefile | 7 ++++-- grammar/mini.samp | 2 +- grammar/rscript.l | 26 ++++++++++++-------- grammar/rscript.y | 28 +++++++++++++++++++-- grammar/utils.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- grammar/utils.h | 28 +++++++++++++++++++++ 6 files changed, 146 insertions(+), 18 deletions(-) diff --git a/grammar/makefile b/grammar/makefile index 29aab217..eb6c9522 100644 --- a/grammar/makefile +++ b/grammar/makefile @@ -1,5 +1,5 @@ rscript: lex.yy.c utils.o rscript.tab.h utils.h - gcc -o rscript lex.yy.c rscript.tab.c utils.o -lestr + gcc -g -o rscript lex.yy.c rscript.tab.c utils.o -lestr lex.yy.c: rscript.l rscript.tab.h flex rscript.l @@ -8,4 +8,7 @@ rscript.tab.h: rscript.y bison -d rscript.y utils.o: utils.c utils.h - gcc -c utils.c + gcc -g -Wall -c utils.c + +clean: + rm *.o diff --git a/grammar/mini.samp b/grammar/mini.samp index 54efacec..6aae758d 100644 --- a/grammar/mini.samp +++ b/grammar/mini.samp @@ -24,7 +24,7 @@ if 1 then { /var/log/log3 @@fwd rger } -if 1/*pri("*.*")*/ then { +if 2*4/5--(10-3)/*pri("*.*")*/ then { action(type="omfile" taget="/var/log/log5") action(type="omfile" taget="/var/log/log6") action(type="omfwd" taget="10.0.0.1" port="514") diff --git a/grammar/rscript.l b/grammar/rscript.l index d6dab45b..f7e51e25 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -45,11 +45,16 @@ static int preCommentState; /* keywords */ "if" { BEGIN EXPR; return IF; } "then" { BEGIN INITIAL; return THEN; } -"or" { printf("OR\n"); } -"and" { printf("AND\n"); } -"not" { printf("NOT\n"); } -"(" { printf("LPAREN\n"); } -")" { printf("RPAREN\n"); } +"or" { return OR; } +"and" { return AND; } +"not" { return NOT; } +"*" | +"/" | +"%" | +"+" | +"-" | +"(" | +")" { return yytext[0]; } "==" { printf("==\n"); } "<=" { printf("<=\n"); } ">=" { printf(">=\n"); } @@ -61,11 +66,12 @@ static int preCommentState; "contains_i" { printf("CONTAINS_I\n"); } "startswith" { printf("STARTSWITH\n"); } "startswith_i" { printf("STARTSWITH_I\n"); } --?0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } --?0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } --?([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); return NUMBER; } -\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); } -\'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); } +0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } +0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } +([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); + yylval.n = atoll(yytext); return NUMBER; } +\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); return VAR; } +\'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); return STRING; } [ \t\n] . { printf("invalid char in expr: %s\n", yytext); } "&" { return '&'; } diff --git a/grammar/rscript.y b/grammar/rscript.y index 7e9365c5..3b680990 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -8,11 +8,13 @@ %union { char *s; + long long n; es_str_t *estr; enum cnfobjType objType; struct cnfobj *obj; struct nvlst *nvlst; struct cnfactlst *actlst; + struct cnfexpr *expr; } %token NAME @@ -26,7 +28,12 @@ %token PROPFILT %token IF %token THEN -%token NUMBER +%token OR +%token AND +%token NOT +%token VAR +%token STRING +%token NUMBER %type nv nvlst %type obj @@ -34,6 +41,12 @@ %type act %type cfsysline %type block +%type expr + +%left AND OR +%left '+' '-' +%left '*' '/' '%' +%nonassoc UMINUS NOT %expect 3 /* two shift/reduce conflicts are created by the CFSYSLINE construct, which we @@ -72,7 +85,7 @@ rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); | PROPFILT actlst | scriptfilt -scriptfilt: IF NUMBER THEN actlst { printf("if filter detected\n"); } +scriptfilt: IF expr THEN actlst { printf("if filter detected, expr:\n"); cnfexprPrint($2,0); } /* note: we can do some limited block-structuring with the v6 engine. In that case, * we must not support additonal filters inside the blocks, so they must consist of @@ -94,6 +107,17 @@ act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } | LEGACY_ACTION { printf("legacy action: '%s'\n", $1); $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } +expr: expr '+' expr { $$ = cnfexprNew('+', $1, $3); } + | expr '-' expr { $$ = cnfexprNew('-', $1, $3); } + | expr '*' expr { $$ = cnfexprNew('*', $1, $3); } + | expr '/' expr { $$ = cnfexprNew('/', $1, $3); } + | expr '%' expr { $$ = cnfexprNew('%', $1, $3); } + | '(' expr ')' { $$ = $2; printf("( expr)\n"); } + | '-' expr %prec UMINUS { printf("uminus\n"); $$ = cnfexprNew('M', NULL, $2); } + | NUMBER { $$ = cnfnumvalNew($1); } + | STRING { $$ = cnfstringvalNew($1); } + | VAR { printf("variables not yet implemented!\n"); } + %% int yyerror(char *s) { diff --git a/grammar/utils.c b/grammar/utils.c index 28e1a04a..c26a856c 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -8,11 +8,9 @@ void readConfFile(FILE *fp, es_str_t **str) { - int c; char ln[10240]; int len, i; int start; /* start index of to be submitted text */ - char *fgetsRet; int bContLine = 0; *str = es_newStr(4096); @@ -177,7 +175,7 @@ cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) struct cnfcfsyslinelst *curr, *prev; if(lst == NULL) - return; + return NULL; prev = lst; lst = lst->next; prev->next = NULL; @@ -231,6 +229,75 @@ cnfactlstPrint(struct cnfactlst *actlst) printf("----------\n"); } +struct cnfexpr* +cnfexprNew(int nodetype, struct cnfexpr *l, struct cnfexpr *r) +{ + struct cnfexpr *expr; + if((expr = malloc(sizeof(struct cnfexpr))) != NULL) { + expr->nodetype = nodetype; + expr->l = l; + expr->r = r; + } + return expr; +} + + +inline static void +doIndent(indent) +{ + int i; + for(i = 0 ; i < indent ; ++i) + printf(" "); +} +void +cnfexprPrint(struct cnfexpr *expr, int indent) +{ + //printf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); + switch(expr->nodetype) { + case 'N': + doIndent(indent); + printf("%lld\n", ((struct cnfnumval*)expr)->val); + break; + case '+': + case '-': + case '*': + case '/': + case '%': + case 'M': + if(expr->l != NULL) + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("%c\n", (char) expr->nodetype); + cnfexprPrint(expr->r, indent+1); + break; + default: + printf("error: unknown nodetype\n"); + break; + } +} + +struct cnfnumval* +cnfnumvalNew(long long val) +{ + struct cnfnumval *numval; + if((numval = malloc(sizeof(struct cnfnumval))) != NULL) { + numval->nodetype = 'N'; + numval->val = val; + } + return numval; +} + +struct cnfstringval* +cnfstringvalNew(es_str_t *estr) +{ + struct cnfstringval *strval; + if((strval = malloc(sizeof(struct cnfstringval))) != NULL) { + strval->nodetype = 'S'; + strval->estr = estr; + } + return strval; +} + /* debug helper */ void cstrPrint(char *text, es_str_t *estr) diff --git a/grammar/utils.h b/grammar/utils.h index 2a6ba10a..a402d4b2 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -58,6 +58,30 @@ struct cnfactlst { } data; }; +/* the following structures support expressions, and may (very much later + * be the sole foundation for the AST. + */ +struct cnfexpr { + int nodetype; + struct cnfexpr *l; + struct cnfexpr *r; +}; + +struct cnfnumval { + int nodetype; + long long val; +}; + +struct cnfstringval { + int nodetype; + es_str_t *estr; +}; + +/* future extensions +struct x { + int nodetype; +}; +*/ void readConfFile(FILE *fp, es_str_t **str); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); @@ -71,6 +95,10 @@ void cnfactlstDestruct(struct cnfactlst *actlst); void cnfactlstPrint(struct cnfactlst *actlst); struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); +struct cnfexpr* cnfexprNew(int nodetype, struct cnfexpr *l, struct cnfexpr *r); +void cnfexprPrint(struct cnfexpr *expr, int indent); +struct cnfnumval* cnfnumvalNew(long long val); +struct cnfstringval* cnfstringvalNew(es_str_t *estr); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); -- cgit v1.2.3 From 849e4aa8e6437cbfb6efbc7379414fcf517e6db9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 3 Jul 2011 18:19:32 +0200 Subject: grammar: small optimization during expr creation --- grammar/mini.samp | 2 +- grammar/utils.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/grammar/mini.samp b/grammar/mini.samp index 6aae758d..9e00b7cf 100644 --- a/grammar/mini.samp +++ b/grammar/mini.samp @@ -24,7 +24,7 @@ if 1 then { /var/log/log3 @@fwd rger } -if 2*4/5--(10-3)/*pri("*.*")*/ then { +if 2*4/-5--(10-3)/*pri("*.*")*/ then { action(type="omfile" taget="/var/log/log5") action(type="omfile" taget="/var/log/log6") action(type="omfwd" taget="10.0.0.1" port="514") diff --git a/grammar/utils.c b/grammar/utils.c index c26a856c..bc300aaf 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -233,11 +233,20 @@ struct cnfexpr* cnfexprNew(int nodetype, struct cnfexpr *l, struct cnfexpr *r) { struct cnfexpr *expr; + + /* optimize some constructs during parsing */ + if(nodetype == 'M' && r->nodetype == 'N') { + ((struct cnfnumval*)r)->val *= -1; + expr = r; + goto done; + } + if((expr = malloc(sizeof(struct cnfexpr))) != NULL) { expr->nodetype = nodetype; expr->l = l; expr->r = r; } +done: return expr; } -- cgit v1.2.3 From 71003f146cc2dacfa8fc7c084404f3399812b64a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 08:34:13 +0200 Subject: milestone: added operations to expr, added evaluation --- grammar/mini.samp | 2 +- grammar/rscript.l | 19 +++--- grammar/rscript.y | 26 +++++++- grammar/utils.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++++- grammar/utils.h | 19 ++++-- 5 files changed, 233 insertions(+), 20 deletions(-) diff --git a/grammar/mini.samp b/grammar/mini.samp index 9e00b7cf..8e00917f 100644 --- a/grammar/mini.samp +++ b/grammar/mini.samp @@ -24,7 +24,7 @@ if 1 then { /var/log/log3 @@fwd rger } -if 2*4/-5--(10-3)/*pri("*.*")*/ then { +if not 1==0 and 2*4/-5--(10-3)>7/*pri("*.*")*/ then { action(type="omfile" taget="/var/log/log5") action(type="omfile" taget="/var/log/log6") action(type="omfwd" taget="10.0.0.1" port="514") diff --git a/grammar/rscript.l b/grammar/rscript.l index f7e51e25..596becaf 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -55,21 +55,20 @@ static int preCommentState; "-" | "(" | ")" { return yytext[0]; } -"==" { printf("==\n"); } -"<=" { printf("<=\n"); } -">=" { printf(">=\n"); } +"==" { return CMP_EQ; } +"<=" { return CMP_LE; } +">=" { return CMP_GE; } "!=" | -"<>" { printf("!=\n"); } -"<" { printf("<\n"); } -">" { printf(">\n"); } +"<>" { return CMP_NE; } +"<" { return CMP_LT; } +">" { return CMP_GT; } "contains" { printf("CONTAINS\n"); } "contains_i" { printf("CONTAINS_I\n"); } "startswith" { printf("STARTSWITH\n"); } "startswith_i" { printf("STARTSWITH_I\n"); } -0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } -0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } -([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); - yylval.n = atoll(yytext); return NUMBER; } +0[0-7]+ | /* octal number */ +0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ +([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } \$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); return VAR; } \'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); return STRING; } [ \t\n] diff --git a/grammar/rscript.y b/grammar/rscript.y index 3b680990..3652eec2 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -34,6 +34,12 @@ %token VAR %token STRING %token NUMBER +%token CMP_EQ +%token CMP_NE +%token CMP_LE +%token CMP_GE +%token CMP_LT +%token CMP_GT %type nv nvlst %type obj @@ -44,12 +50,13 @@ %type expr %left AND OR +%left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT %left '+' '-' %left '*' '/' '%' %nonassoc UMINUS NOT %expect 3 -/* two shift/reduce conflicts are created by the CFSYSLINE construct, which we +/* these shift/reduce conflicts are created by the CFSYSLINE construct, which we * unfortunately can not avoid. The problem is that CFSYSLINE can occur both in * global context as well as within an action. It's not permitted somewhere else, * but this is suficient for conflicts. The "dangling else" built-in resolution @@ -85,7 +92,11 @@ rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); | PROPFILT actlst | scriptfilt -scriptfilt: IF expr THEN actlst { printf("if filter detected, expr:\n"); cnfexprPrint($2,0); } +scriptfilt: IF expr THEN actlst { printf("if filter detected, expr:\n"); cnfexprPrint($2,0); + struct exprret r; + cnfexprEval($2, &r); + printf("eval result: %lld\n", r.d.n); + } /* note: we can do some limited block-structuring with the v6 engine. In that case, * we must not support additonal filters inside the blocks, so they must consist of @@ -107,7 +118,16 @@ act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } | LEGACY_ACTION { printf("legacy action: '%s'\n", $1); $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } -expr: expr '+' expr { $$ = cnfexprNew('+', $1, $3); } +expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } + | expr OR expr { $$ = cnfexprNew(OR, $1, $3); } + | NOT expr { $$ = cnfexprNew(NOT, NULL, $2); } + | expr CMP_EQ expr { $$ = cnfexprNew(CMP_EQ, $1, $3); } + | expr CMP_NE expr { $$ = cnfexprNew(CMP_NE, $1, $3); } + | expr CMP_LE expr { $$ = cnfexprNew(CMP_LE, $1, $3); } + | expr CMP_GE expr { $$ = cnfexprNew(CMP_GE, $1, $3); } + | expr CMP_LT expr { $$ = cnfexprNew(CMP_LT, $1, $3); } + | expr CMP_GT expr { $$ = cnfexprNew(CMP_GT, $1, $3); } + | expr '+' expr { $$ = cnfexprNew('+', $1, $3); } | expr '-' expr { $$ = cnfexprNew('-', $1, $3); } | expr '*' expr { $$ = cnfexprNew('*', $1, $3); } | expr '/' expr { $$ = cnfexprNew('/', $1, $3); } diff --git a/grammar/utils.c b/grammar/utils.c index bc300aaf..4087bd81 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -4,6 +4,7 @@ #include #include #include "utils.h" +#include "rscript.tab.h" void readConfFile(FILE *fp, es_str_t **str) @@ -230,7 +231,7 @@ cnfactlstPrint(struct cnfactlst *actlst) } struct cnfexpr* -cnfexprNew(int nodetype, struct cnfexpr *l, struct cnfexpr *r) +cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r) { struct cnfexpr *expr; @@ -250,6 +251,134 @@ done: return expr; } +/* ensure that retval is a number; if string is no number, + * emit error message and set number to 0. + */ +static inline long long +exprret2Number(struct exprret *r) +{ + if(r->datatype == 'S') { + printf("toNumber CONVERSION MISSING\n"); abort(); + } + return r->d.n; +} + +/* ensure that retval is a string; if string is no number, + * emit error message and set number to 0. + */ +static inline es_str_t * +exprret2String(struct exprret *r) +{ + if(r->datatype == 'N') { + printf("toString CONVERSION MISSING\n"); abort(); + } + return r->d.estr; +} + +#define COMP_NUM_BINOP(x) \ + cnfexprEval(expr->l, &l); \ + cnfexprEval(expr->r, &r); \ + ret->datatype = 'N'; \ + ret->d.n = exprret2Number(&l) x exprret2Number(&r) + +/* evaluate an expression. + * Note that we try to avoid malloc whenever possible (because on + * the large overhead it has, especially on highly threaded programs). + * As such, the each caller level must provide buffer space for the + * result on its stack during recursion. This permits the callee to store + * the return value without malloc. As the value is a somewhat larger + * struct, we could otherwise not return it without malloc. + * Note that we implement boolean shortcut operations. For our needs, there + * simply is no case where full evaluation would make any sense at all. + */ +void +cnfexprEval(struct cnfexpr *expr, struct exprret *ret) +{ + struct exprret r, l; /* memory for subexpression results */ + + printf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + switch(expr->nodetype) { + case CMP_EQ: + COMP_NUM_BINOP(==); + break; + case CMP_NE: + COMP_NUM_BINOP(!=); + break; + case CMP_LE: + COMP_NUM_BINOP(<=); + break; + case CMP_GE: + COMP_NUM_BINOP(>=); + break; + case CMP_LT: + COMP_NUM_BINOP(<); + break; + case CMP_GT: + COMP_NUM_BINOP(>); + break; + case OR: + cnfexprEval(expr->l, &l); + ret->datatype = 'N'; + if(exprret2Number(&l)) { + ret->d.n = 1ll; + } else { + cnfexprEval(expr->r, &r); + if(exprret2Number(&r)) + ret->d.n = 1ll; + else + ret->d.n = 0ll; + } + break; + case AND: + cnfexprEval(expr->l, &l); + ret->datatype = 'N'; + if(exprret2Number(&l)) { + cnfexprEval(expr->r, &r); + if(exprret2Number(&r)) + ret->d.n = 1ll; + else + ret->d.n = 0ll; + } else { + ret->d.n = 0ll; + } + break; + case NOT: + cnfexprEval(expr->r, &r); + ret->datatype = 'N'; + ret->d.n = !exprret2Number(&l); + break; + case 'N': + ret->datatype = 'N'; + ret->d.n = ((struct cnfnumval*)expr)->val; + break; + case '+': + COMP_NUM_BINOP(+); + break; + case '-': + COMP_NUM_BINOP(-); + break; + case '*': + COMP_NUM_BINOP(*); + break; + case '/': + COMP_NUM_BINOP(/); + break; + case '%': + COMP_NUM_BINOP(%); + break; + case 'M': + cnfexprEval(expr->r, &r); + ret->datatype = 'N'; + ret->d.n = -exprret2Number(&r); + break; + default: + ret->datatype = 'N'; + ret->d.n = 0ll; + printf("eval error: unknown nodetype %u\n", + (unsigned) expr->nodetype); + break; + } +} inline static void doIndent(indent) @@ -263,6 +392,59 @@ cnfexprPrint(struct cnfexpr *expr, int indent) { //printf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); switch(expr->nodetype) { + case CMP_EQ: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("==\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_NE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("!=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_LE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("<=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_GE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf(">=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_LT: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("<\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_GT: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf(">\n"); + cnfexprPrint(expr->r, indent+1); + break; + case OR: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("OR\n"); + cnfexprPrint(expr->r, indent+1); + break; + case AND: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("AND\n"); + cnfexprPrint(expr->r, indent+1); + break; + case NOT: + doIndent(indent); + printf("NOT\n"); + cnfexprPrint(expr->r, indent+1); + break; case 'N': doIndent(indent); printf("%lld\n", ((struct cnfnumval*)expr)->val); @@ -280,7 +462,8 @@ cnfexprPrint(struct cnfexpr *expr, int indent) cnfexprPrint(expr->r, indent+1); break; default: - printf("error: unknown nodetype\n"); + printf("error: unknown nodetype %u\n", + (unsigned) expr->nodetype); break; } } diff --git a/grammar/utils.h b/grammar/utils.h index a402d4b2..f52bc1e0 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -62,18 +62,18 @@ struct cnfactlst { * be the sole foundation for the AST. */ struct cnfexpr { - int nodetype; + unsigned nodetype; struct cnfexpr *l; struct cnfexpr *r; }; struct cnfnumval { - int nodetype; + unsigned nodetype; long long val; }; struct cnfstringval { - int nodetype; + unsigned nodetype; es_str_t *estr; }; @@ -83,6 +83,16 @@ struct x { }; */ +/* the return value of an expresion evaluation */ +struct exprret { + union { + es_str_t *estr; + long long n; + } d; + char datatype; /* 'N' - number, 'S' - string */ +}; + + void readConfFile(FILE *fp, es_str_t **str); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); void nvlstDestruct(struct nvlst *lst); @@ -95,8 +105,9 @@ void cnfactlstDestruct(struct cnfactlst *actlst); void cnfactlstPrint(struct cnfactlst *actlst); struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); -struct cnfexpr* cnfexprNew(int nodetype, struct cnfexpr *l, struct cnfexpr *r); +struct cnfexpr* cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r); void cnfexprPrint(struct cnfexpr *expr, int indent); +void cnfexprEval(struct cnfexpr *expr, struct exprret *ret); struct cnfnumval* cnfnumvalNew(long long val); struct cnfstringval* cnfstringvalNew(es_str_t *estr); -- cgit v1.2.3 From 25cd9f59ad3a0daa2662e44b2e844116ad487450 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 09:36:12 +0200 Subject: milestone: added comparison ops, prepring for flex include processing --- grammar/mini.samp | 2 +- grammar/parserif.h | 6 ++++++ grammar/rscript.l | 38 ++++++++++++++++++++++++-------------- grammar/rscript.y | 16 +++++++++++++--- grammar/utils.c | 40 +++++++++++++++++++++++++++++++++++++++- 5 files changed, 83 insertions(+), 19 deletions(-) create mode 100644 grammar/parserif.h diff --git a/grammar/mini.samp b/grammar/mini.samp index 8e00917f..71cfbb69 100644 --- a/grammar/mini.samp +++ b/grammar/mini.samp @@ -24,7 +24,7 @@ if 1 then { /var/log/log3 @@fwd rger } -if not 1==0 and 2*4/-5--(10-3)>7/*pri("*.*")*/ then { +if not (1==0) and 2*4/-5--(10-3)>7/*pri("*.*")*/ then { action(type="omfile" taget="/var/log/log5") action(type="omfile" taget="/var/log/log6") action(type="omfwd" taget="10.0.0.1" port="514") diff --git a/grammar/parserif.h b/grammar/parserif.h new file mode 100644 index 00000000..e22b7d34 --- /dev/null +++ b/grammar/parserif.h @@ -0,0 +1,6 @@ +#ifndef PARSERIF_H_DEFINED +#define PARSERIF_H_DEFINED +extern int cnfSetLexFile(char*); +extern int yyparse(); +extern int yydebug; +#endif diff --git a/grammar/rscript.l b/grammar/rscript.l index 596becaf..b7c3e521 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -62,10 +62,10 @@ static int preCommentState; "<>" { return CMP_NE; } "<" { return CMP_LT; } ">" { return CMP_GT; } -"contains" { printf("CONTAINS\n"); } -"contains_i" { printf("CONTAINS_I\n"); } -"startswith" { printf("STARTSWITH\n"); } -"startswith_i" { printf("STARTSWITH_I\n"); } +"contains" { return CMP_CONTAINS; } +"contains_i" { return CMP_CONTAINSI; } +"startswith" { return CMP_STARTSWITH; } +"startswith_i" { return CMP_STARTSWITHI; } 0[0-7]+ | /* octal number */ 0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ ([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } @@ -100,7 +100,7 @@ static int preCommentState; return NAME; } "=" { return(yytext[0]); } \"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { - yylval.estr = es_newStrFromCStr(yytext+1, yyleng-2); + yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); return VALUE; } "/*" { preCommentState = YY_START; BEGIN COMMENT; } "/*" { preCommentState = YY_START; BEGIN COMMENT; } @@ -122,18 +122,28 @@ static int preCommentState; /*<> { printf("EOF reached\n"); }*/ %% - /* -int -main(int argc, char *argv[]) +/* set a new buffers. Returns 0 on success, something else otherwise. */ +int cnfSetLexFile(char *fname) { es_str_t *str; YY_BUFFER_STATE bp; - char ln[10240]; + FILE *fp; + int r = 0; - readConfFile(stdin, &str); - //printf("buffer: %s\n", es_getBufAddr(str)); + if(fname == NULL) { + fp = stdin; + } else { + if((fp = fopen(fname, "r")) == NULL) { + r = 1; + goto done; + } + } + readConfFile(fp, &str); + if(fp != stdin) + fclose(fp); bp = yy_scan_buffer(es_getBufAddr(str), es_strlen(str)); - //yy_switch_to_buffer(bp); - yylex(); + yylineno = 1; + +done: + return r; } -*/ diff --git a/grammar/rscript.y b/grammar/rscript.y index 3652eec2..8bf0e55a 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -40,6 +40,10 @@ %token CMP_GE %token CMP_LT %token CMP_GT +%token CMP_CONTAINS +%token CMP_CONTAINSI +%token CMP_STARTSWITH +%token CMP_STARTSWITHI %type nv nvlst %type obj @@ -50,7 +54,7 @@ %type expr %left AND OR -%left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT +%left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT CMP_CONTAINS CMP_CONTAINSI CMP_STARTSWITH CMP_STARTSWITHI %left '+' '-' %left '*' '/' '%' %nonassoc UMINUS NOT @@ -127,6 +131,10 @@ expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | expr CMP_GE expr { $$ = cnfexprNew(CMP_GE, $1, $3); } | expr CMP_LT expr { $$ = cnfexprNew(CMP_LT, $1, $3); } | expr CMP_GT expr { $$ = cnfexprNew(CMP_GT, $1, $3); } + | expr CMP_CONTAINS expr { $$ = cnfexprNew(CMP_CONTAINS, $1, $3); } + | expr CMP_CONTAINSI expr { $$ = cnfexprNew(CMP_CONTAINSI, $1, $3); } + | expr CMP_STARTSWITH expr { $$ = cnfexprNew(CMP_STARTSWITH, $1, $3); } + | expr CMP_STARTSWITHI expr { $$ = cnfexprNew(CMP_STARTSWITHI, $1, $3); } | expr '+' expr { $$ = cnfexprNew('+', $1, $3); } | expr '-' expr { $$ = cnfexprNew('-', $1, $3); } | expr '*' expr { $$ = cnfexprNew('*', $1, $3); } @@ -134,8 +142,8 @@ expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | expr '%' expr { $$ = cnfexprNew('%', $1, $3); } | '(' expr ')' { $$ = $2; printf("( expr)\n"); } | '-' expr %prec UMINUS { printf("uminus\n"); $$ = cnfexprNew('M', NULL, $2); } - | NUMBER { $$ = cnfnumvalNew($1); } - | STRING { $$ = cnfstringvalNew($1); } + | NUMBER { $$ = (struct cnfexpr*) cnfnumvalNew($1); } + | STRING { $$ = (struct cnfexpr*) cnfstringvalNew($1); } | VAR { printf("variables not yet implemented!\n"); } %% @@ -144,9 +152,11 @@ int yyerror(char *s) printf("yyerror called: %s\n", s); } +/* int main() { yydebug = 0; return yyparse(); } +*/ diff --git a/grammar/utils.c b/grammar/utils.c index 4087bd81..d09a34a9 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -4,6 +4,7 @@ #include #include #include "utils.h" +#include "parserif.h" #include "rscript.tab.h" void @@ -345,7 +346,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) case NOT: cnfexprEval(expr->r, &r); ret->datatype = 'N'; - ret->d.n = !exprret2Number(&l); + ret->d.n = !exprret2Number(&r); break; case 'N': ret->datatype = 'N'; @@ -428,6 +429,30 @@ cnfexprPrint(struct cnfexpr *expr, int indent) printf(">\n"); cnfexprPrint(expr->r, indent+1); break; + case CMP_CONTAINS: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("CONTAINS\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_CONTAINSI: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("CONTAINS_I\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_STARTSWITH: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("STARTSWITH\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_STARTSWITHI: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("STARTSWITH_I\n"); + cnfexprPrint(expr->r, indent+1); + break; case OR: cnfexprPrint(expr->l, indent+1); doIndent(indent); @@ -500,3 +525,16 @@ cstrPrint(char *text, es_str_t *estr) free(str); } + +int +main(int argc, char *argv[]) +{ + int r; + + cnfSetLexFile(argc == 1 ? NULL : argv[1]); + yydebug = 0; + r = yyparse(); + printf("yyparse() returned %d\n", r); + return r; +} + -- cgit v1.2.3 From 4598557192c46e43edc5cc09b89c30045aacdb33 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 11:24:04 +0200 Subject: milestone: support for include files added support for directories will be added during rsyslog integration --- grammar/debian.conf | 2 +- grammar/rscript.l | 98 ++++++++++++++++++++++++++++++++++++++++++++++++----- grammar/rscript.y | 1 + grammar/utils.c | 16 +++++++-- 4 files changed, 106 insertions(+), 11 deletions(-) diff --git a/grammar/debian.conf b/grammar/debian.conf index e5e54fde..79c1f07d 100644 --- a/grammar/debian.conf +++ b/grammar/debian.conf @@ -43,7 +43,7 @@ $Umask 0022 # # Include all config files in /etc/rsyslog.d/ # -$IncludeConfig /etc/rsyslog.d/*.conf +#$IncludeConfig /etc/rsyslog.d/*.conf ############### diff --git a/grammar/rscript.l b/grammar/rscript.l index b7c3e521..7e7ab925 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -13,13 +13,17 @@ * Released under the GNU GPL v3. For details see LICENSE file. */ -%option noyywrap nodefault case-insensitive +%option noyywrap nodefault case-insensitive yylineno /*%option noyywrap nodefault case-insensitive */ %x INOBJ /* INOBJ is selected if we are inside an object (name/value pairs!) */ %x COMMENT /* COMMENT is "the usual trick" to handle C-style comments */ +%x INCL + /* INCL is in $IncludeConfig processing (skip to include file) */ +%x LINENO + /* LINENO: support for setting the linenumber */ %x EXPR /* EXPR is a bit ugly, but we need it to support pre v6-syntax. The problem * is that cfsysline statement start with $..., the same like variables in @@ -37,7 +41,16 @@ #include #include "utils.h" #include "rscript.tab.h" -static int preCommentState; +static int preCommentState; /* save for lex state before a comment */ + +struct bufstack { + struct bufstack *prev; + YY_BUFFER_STATE bs; + int lineno; + char *fn; +} *currbs = NULL; + +char *currfn; /* name of currently processed file */ %} %% @@ -77,6 +90,23 @@ static int preCommentState; "{" { return '{'; } "}" { return '}'; } "ruleset" { printf("RULESET\n"); } + /* line number support because the "preprocessor" combines lines and so needs + * to tell us the real source line. + */ +"preprocfilelinenumber(" { BEGIN LINENO; } +[0-9]+ { printf("linno was %d, set to %d\n", yylineno, atoi(yytext) -1); + yylineno = atoi(yytext) - 1; } +")" { BEGIN INITIAL; } +.|\n + /* $IncludeConfig must be detected as part of CFSYSLINE, because this is + * always the longest match :-( + */ +.|\n +[^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) + yyterminate(); + BEGIN INITIAL; + } + "global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; BEGIN INOBJ; return BEGINOBJ; } @@ -107,28 +137,36 @@ static int preCommentState; "*/" { BEGIN preCommentState; } ([^*]|\n)+|. -#.*\n /* skip comments in input */ +#.*$ /* skip comments in input */ [ \n\t] . { printf("INOBJ: invalid char '%s'\n", yytext); } /* CFSYSLINE is valid in all modes */ -\$[a-z]+.*$ { yylval.s = strdup(yytext); return CFSYSLINE; } +\$[a-z]+.*$ { /* see common on $IncludeConfig above */ + if(!strncasecmp(yytext, "$includeconfig ", 14)) { + yyless(14); + BEGIN INCL; + } else { + yylval.s = strdup(yytext); + return CFSYSLINE; + } + } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ . { printf("invalid char: %s\n", yytext); } - /*<> { printf("EOF reached\n"); }*/ +<> { if(popfile() != 0) yyterminate(); } %% /* set a new buffers. Returns 0 on success, something else otherwise. */ int cnfSetLexFile(char *fname) { - es_str_t *str; - YY_BUFFER_STATE bp; + es_str_t *str = NULL; FILE *fp; int r = 0; + struct bufstack *bs; if(fname == NULL) { fp = stdin; @@ -141,9 +179,53 @@ int cnfSetLexFile(char *fname) readConfFile(fp, &str); if(fp != stdin) fclose(fp); - bp = yy_scan_buffer(es_getBufAddr(str), es_strlen(str)); + + /* maintain stack */ + if((bs = malloc(sizeof(struct bufstack))) == NULL) { + r = 1; + goto done; + } + + if(currbs != NULL) + currbs->lineno = yylineno; + bs->prev = currbs; + bs->fn = strdup(fname); + bs->bs = yy_scan_buffer(es_getBufAddr(str), es_strlen(str)); + currbs = bs; + currfn = bs->fn; yylineno = 1; done: + if(r != 0) { + if(str != NULL) + es_deleteStr(str); + } return r; } + + +/* returns 0 on success, something else otherwise */ +int +popfile(void) +{ + struct bufstack *bs = currbs; + + if(bs == NULL) + return 1; + + /* delte current entry */ + yy_delete_buffer(bs->bs); + free(bs->fn); + + /* switch back to previous */ + currbs = bs->prev; + free(bs); + + if(currbs == NULL) + return 1; /* all processed */ + + yy_switch_to_buffer(currbs->bs); + yylineno = currbs->lineno; + currfn = currbs->fn; + return 0; +} diff --git a/grammar/rscript.y b/grammar/rscript.y index 8bf0e55a..440a5525 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -4,6 +4,7 @@ #include #include "utils.h" #define YYDEBUG 1 +extern int yylineno; %} %union { diff --git a/grammar/utils.c b/grammar/utils.c index d09a34a9..4e93c26c 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -11,13 +11,23 @@ void readConfFile(FILE *fp, es_str_t **str) { char ln[10240]; + char buf[512]; + int lenBuf; + int bWriteLineno = 0; int len, i; int start; /* start index of to be submitted text */ int bContLine = 0; + int lineno = 0; *str = es_newStr(4096); while(fgets(ln, sizeof(ln), fp) != NULL) { + ++lineno; + if(bWriteLineno) { + bWriteLineno = 0; + lenBuf = sprintf(buf, "PreprocFileLineNumber(%d)\n", lineno); + es_addBuf(str, buf, lenBuf); + } len = strlen(ln); /* if we are continuation line, we need to drop leading WS */ if(bContLine) { @@ -33,13 +43,15 @@ readConfFile(FILE *fp, es_str_t **str) --i; bContLine = 1; } else { + if(bContLine) /* write line number if we had cont line */ + bWriteLineno = 1; bContLine = 0; } /* add relevant data to buffer */ es_addBuf(str, ln+start, i+1 - start); - if(!bContLine) - es_addChar(str, '\n'); } + if(!bContLine) + es_addChar(str, '\n'); } /* indicate end of buffer to flex */ es_addChar(str, '\0'); -- cgit v1.2.3 From b966576f1e740966b35579d612050f4dfc09606c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 11:57:55 +0200 Subject: milestone: added BSD-style blocks --- grammar/debian.conf | 4 ++++ grammar/rscript.l | 8 ++++++-- grammar/rscript.y | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/grammar/debian.conf b/grammar/debian.conf index 79c1f07d..91a67307 100644 --- a/grammar/debian.conf +++ b/grammar/debian.conf @@ -110,6 +110,10 @@ news.notice -/var/log/news/news.notice # NOTE: adjust the list below, or you'll go crazy if you have a reasonably # busy site.. # +!ThisTag ++host1 +-host2 ++* daemon.*;mail.*;\ news.err;\ *.=debug;*.=info;\ diff --git a/grammar/rscript.l b/grammar/rscript.l index 7e7ab925..a4c37c81 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -122,9 +122,10 @@ char *currfn; /* name of currently processed file */ ^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("token prifilt '%s'\n", yytext); yylval.s = strdup(yytext); return PRIFILT; } "*" | +\-\/[^*][^\n]* | \/[^*][^\n]* | [\|\.\-\@:~][^\n]+ | -[a-z0-9_\-\+]+ { yylval.s = strdup(yytext); return LEGACY_ACTION; } +[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); printf("LEGACY_ACT: '%s'\n", yytext);return LEGACY_ACTION; } ")" { BEGIN INITIAL; return ENDOBJ; } [a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); return NAME; } @@ -141,7 +142,6 @@ char *currfn; /* name of currently processed file */ [ \n\t] . { printf("INOBJ: invalid char '%s'\n", yytext); } - /* CFSYSLINE is valid in all modes */ \$[a-z]+.*$ { /* see common on $IncludeConfig above */ if(!strncasecmp(yytext, "$includeconfig ", 14)) { yyless(14); @@ -151,6 +151,10 @@ char *currfn; /* name of currently processed file */ return CFSYSLINE; } } +![^ \t\n]+[ \t]*$ { printf("BSD TAG '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } +[+-]\*[ \t\n]*#.*$ { printf("BSD HOST '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +[+-]\*[ \t\n]*$ { printf("BSD HOST '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { printf("BSD HOST '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ diff --git a/grammar/rscript.y b/grammar/rscript.y index 440a5525..186d0981 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -27,6 +27,8 @@ extern int yylineno; %token LEGACY_ACTION %token PRIFILT %token PROPFILT +%token BSD_TAG_SELECTOR +%token BSD_HOST_SELECTOR %token IF %token THEN %token OR @@ -73,8 +75,10 @@ extern int yylineno; %% conf: /* empty (to end recursion) */ | obj conf - | cfsysline conf | rule conf + | cfsysline conf + | BSD_TAG_SELECTOR conf + | BSD_HOST_SELECTOR conf obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); cnfobjPrint($$); -- cgit v1.2.3 From 3613f7e1bf0e5eb06d2049eaebb0f39afb71d153 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 12:22:48 +0200 Subject: milestone: PROPFILT added to grammar --- grammar/debian.conf | 1 - grammar/rscript.l | 14 ++++++++------ grammar/rscript.y | 14 ++++++++------ 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/grammar/debian.conf b/grammar/debian.conf index 91a67307..166cde52 100644 --- a/grammar/debian.conf +++ b/grammar/debian.conf @@ -118,6 +118,5 @@ daemon.*;mail.*;\ news.err;\ *.=debug;*.=info;\ *.=notice;*.=warn |/dev/xconsole - # samples added to get full "flavor" of what we need to support... :msg, contains, "error" /var/log/somelog diff --git a/grammar/rscript.l b/grammar/rscript.l index a4c37c81..6472ca13 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -117,6 +117,7 @@ char *currfn; /* name of currently processed file */ "action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { printf("PROP-FILT: '%s'\n", yytext); + return PROPFILT; } ^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("token prifilt '%s'\n", yytext); yylval.s = strdup(yytext); return PRIFILT; } @@ -124,8 +125,9 @@ char *currfn; /* name of currently processed file */ "*" | \-\/[^*][^\n]* | \/[^*][^\n]* | -[\|\.\-\@:~][^\n]+ | -[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); printf("LEGACY_ACT: '%s'\n", yytext);return LEGACY_ACTION; } +:[a-z0-9]+:[^\n]* | +[\|\.\-\@~][^\n]+ | +[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); printf("LEGA ACT: '%s'\n", yytext);return LEGACY_ACTION; } ")" { BEGIN INITIAL; return ENDOBJ; } [a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); return NAME; } @@ -151,10 +153,10 @@ char *currfn; /* name of currently processed file */ return CFSYSLINE; } } -![^ \t\n]+[ \t]*$ { printf("BSD TAG '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } -[+-]\*[ \t\n]*#.*$ { printf("BSD HOST '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -[+-]\*[ \t\n]*$ { printf("BSD HOST '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { printf("BSD HOST '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +![^ \t\n]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } +[+-]\*[ \t\n]*#.*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +[+-]\*[ \t\n]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ diff --git a/grammar/rscript.y b/grammar/rscript.y index 186d0981..8dc00620 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -75,10 +75,10 @@ extern int yylineno; %% conf: /* empty (to end recursion) */ | obj conf - | rule conf - | cfsysline conf - | BSD_TAG_SELECTOR conf - | BSD_HOST_SELECTOR conf + | rule conf { printf("RULE processed, back in main\n"); } + | cfsysline conf { printf("cfsysline: %s\n", $1); } + | BSD_TAG_SELECTOR conf { printf("BSD tag '%s'\n", $1); } + | BSD_HOST_SELECTOR conf { printf("BSD host '%s'\n", $1); } obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); cnfobjPrint($$); @@ -89,7 +89,7 @@ obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); cnfobjDestruct(t); printf("XXXX: this is an new-style action!\n"); } -cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1); } +cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1);$$ = $1 } nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } @@ -98,7 +98,9 @@ nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); $2 = cnfactlstReverse($2); cnfactlstPrint($2); } - | PROPFILT actlst + | PROPFILT actlst { printf("PROPFILT: %s\n", $1); free($1); + $2 = cnfactlstReverse($2); + cnfactlstPrint($2); } | scriptfilt scriptfilt: IF expr THEN actlst { printf("if filter detected, expr:\n"); cnfexprPrint($2,0); -- cgit v1.2.3 From 11f50cfe836ec104b4167e7c6c5d207a4d8fe081 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 12:38:36 +0200 Subject: bugfix(new bug): cfsyslines were not properly reversed during parsing --- grammar/utils.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/grammar/utils.c b/grammar/utils.c index 4e93c26c..f25977d5 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -187,12 +187,10 @@ static inline struct cnfcfsyslinelst* cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) { struct cnfcfsyslinelst *curr, *prev; - +printf("syslinerevers on %p\n", lst); if(lst == NULL) return NULL; - prev = lst; - lst = lst->next; - prev->next = NULL; + prev = NULL; while(lst != NULL) { curr = lst; lst = lst->next; @@ -207,9 +205,7 @@ cnfactlstReverse(struct cnfactlst *actlst) { struct cnfactlst *curr, *prev; - prev = actlst; - actlst = actlst->next; - prev->next = NULL; + prev = NULL; while(actlst != NULL) { curr = actlst; actlst = actlst->next; -- cgit v1.2.3 From bffa39ab9539c0e26dbbfb450f42de93638292e1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 15:31:09 +0200 Subject: milstone: top-level grammer now ready for integration (but script detail still missing) --- grammar/debian.conf | 10 ++++++++ grammar/rscript.l | 13 +++++----- grammar/rscript.y | 73 +++++++++++++++++++++++++---------------------------- grammar/utils.c | 42 ++++++++++++++++++++++++++---- grammar/utils.h | 30 ++++++++++++++++++++++ 5 files changed, 118 insertions(+), 50 deletions(-) diff --git a/grammar/debian.conf b/grammar/debian.conf index 166cde52..ff7708c5 100644 --- a/grammar/debian.conf +++ b/grammar/debian.conf @@ -118,5 +118,15 @@ daemon.*;mail.*;\ news.err;\ *.=debug;*.=info;\ *.=notice;*.=warn |/dev/xconsole +$cfs 21 +$cfs 22 +$cfs 23 # samples added to get full "flavor" of what we need to support... :msg, contains, "error" /var/log/somelog +$cfs 11 +$cfs 12 +$cfs 13 +module() +$cfs 1 +$cfs 2 +$cfs 3 diff --git a/grammar/rscript.l b/grammar/rscript.l index 6472ca13..68f4d406 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -94,8 +94,7 @@ char *currfn; /* name of currently processed file */ * to tell us the real source line. */ "preprocfilelinenumber(" { BEGIN LINENO; } -[0-9]+ { printf("linno was %d, set to %d\n", yylineno, atoi(yytext) -1); - yylineno = atoi(yytext) - 1; } +[0-9]+ { yylineno = atoi(yytext) - 1; } ")" { BEGIN INITIAL; } .|\n /* $IncludeConfig must be detected as part of CFSYSLINE, because this is @@ -116,18 +115,18 @@ char *currfn; /* name of currently processed file */ BEGIN INOBJ; return BEGINOBJ; } "action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { - printf("PROP-FILT: '%s'\n", yytext); - return PROPFILT; - } + yylval.s = strdup(yytext); return PROPFILT; } -^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("token prifilt '%s'\n", yytext); yylval.s = strdup(yytext); return PRIFILT; } +^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } "*" | \-\/[^*][^\n]* | \/[^*][^\n]* | :[a-z0-9]+:[^\n]* | [\|\.\-\@~][^\n]+ | -[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); printf("LEGA ACT: '%s'\n", yytext);return LEGACY_ACTION; } +[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); + // printf("lex: LEGA ACT: '%s'\n", yytext); + return LEGACY_ACTION; } ")" { BEGIN INITIAL; return ENDOBJ; } [a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); return NAME; } diff --git a/grammar/rscript.y b/grammar/rscript.y index 8dc00620..aaf133eb 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -16,6 +16,7 @@ extern int yylineno; struct nvlst *nvlst; struct cnfactlst *actlst; struct cnfexpr *expr; + struct cnfrule *rule; } %token NAME @@ -55,6 +56,8 @@ extern int yylineno; %type cfsysline %type block %type expr +%type rule +%type scriptfilt %left AND OR %left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT CMP_CONTAINS CMP_CONTAINSI CMP_STARTSWITH CMP_STARTSWITHI @@ -73,60 +76,54 @@ extern int yylineno; * were exactly these conflicts exits. */ %% +/* note: we use left recursion below, because that saves stack space AND + * offers the right sequence so that we can submit the top-layer objects + * one by one. + */ conf: /* empty (to end recursion) */ - | obj conf - | rule conf { printf("RULE processed, back in main\n"); } - | cfsysline conf { printf("cfsysline: %s\n", $1); } - | BSD_TAG_SELECTOR conf { printf("BSD tag '%s'\n", $1); } - | BSD_HOST_SELECTOR conf { printf("BSD host '%s'\n", $1); } - -obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); - cnfobjPrint($$); - cnfobjDestruct($$); - } - | BEGIN_ACTION nvlst ENDOBJ { struct cnfobj *t = cnfobjNew(CNFOBJ_ACTION, $2); - cnfobjPrint(t); - cnfobjDestruct(t); - printf("XXXX: this is an new-style action!\n"); - } -cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1);$$ = $1 } + | conf obj { printf("global:config: "); + cnfobjPrint($2); cnfobjDestruct($2); } + | conf rule { printf("global:rule processed\n"); + cnfrulePrint($2); } + | conf cfsysline { printf("global:cfsysline: %s\n", $2); } + | conf BSD_TAG_SELECTOR { printf("global:BSD tag '%s'\n", $2); } + | conf BSD_HOST_SELECTOR { printf("global:BSD host '%s'\n", $2); } + +obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } + | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } +cfsysline: CFSYSLINE { $$ = $1 } nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } -rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); - $2 = cnfactlstReverse($2); - cnfactlstPrint($2); } - | PROPFILT actlst { printf("PROPFILT: %s\n", $1); free($1); - $2 = cnfactlstReverse($2); - cnfactlstPrint($2); } - | scriptfilt - -scriptfilt: IF expr THEN actlst { printf("if filter detected, expr:\n"); cnfexprPrint($2,0); - struct exprret r; - cnfexprEval($2, &r); - printf("eval result: %lld\n", r.d.n); +rule: PRIFILT actlst { $$ = cnfruleNew(CNFFILT_PRI, $2); $$->filt.s = $1; } + | PROPFILT actlst { $$ = cnfruleNew(CNFFILT_PROP, $2); $$->filt.s = $1; } + | scriptfilt { $$ = $1; } + +scriptfilt: IF expr THEN actlst { $$ = cnfruleNew(CNFFILT_SCRIPT, $4); + $$->filt.expr = $2; + //struct exprret r; + //cnfexprEval($2, &r); + // printf("eval result: %lld\n", r.d.n); } /* note: we can do some limited block-structuring with the v6 engine. In that case, * we must not support additonal filters inside the blocks, so they must consist of * "act", only. We can implement that via the "&" actlist logic. */ -block: actlst - | block actlst +block: actlst { $$ = $1; } + | block actlst { $2->next = $1; $$ = $2; } /* v7: | actlst v7: | block rule */ -actlst: act { printf("action (end actlst)\n");$$=$1; } - | actlst '&' act { printf("in actionlist \n"); - $3->next = $1; $$ = $3; } - | actlst cfsysline { printf("in actionlist/CFSYSLINE: %s\n", $2); - $$ = cnfactlstAddSysline($1, $2); } +actlst: act { $$=$1; } + | actlst '&' act { $3->next = $1; $$ = $3; } + | actlst cfsysline { $$ = cnfactlstAddSysline($1, $2); } | '{' block '}' { $$ = $2; } act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } - | LEGACY_ACTION { printf("legacy action: '%s'\n", $1); + | LEGACY_ACTION { //printf("legacy action: '%s'\n", $1); $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } @@ -147,8 +144,8 @@ expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | expr '*' expr { $$ = cnfexprNew('*', $1, $3); } | expr '/' expr { $$ = cnfexprNew('/', $1, $3); } | expr '%' expr { $$ = cnfexprNew('%', $1, $3); } - | '(' expr ')' { $$ = $2; printf("( expr)\n"); } - | '-' expr %prec UMINUS { printf("uminus\n"); $$ = cnfexprNew('M', NULL, $2); } + | '(' expr ')' { $$ = $2; } + | '-' expr %prec UMINUS { $$ = cnfexprNew('M', NULL, $2); } | NUMBER { $$ = (struct cnfexpr*) cnfnumvalNew($1); } | STRING { $$ = (struct cnfexpr*) cnfstringvalNew($1); } | VAR { printf("variables not yet implemented!\n"); } diff --git a/grammar/utils.c b/grammar/utils.c index f25977d5..b04274c1 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -187,7 +187,6 @@ static inline struct cnfcfsyslinelst* cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) { struct cnfcfsyslinelst *curr, *prev; -printf("syslinerevers on %p\n", lst); if(lst == NULL) return NULL; prev = NULL; @@ -207,6 +206,7 @@ cnfactlstReverse(struct cnfactlst *actlst) prev = NULL; while(actlst != NULL) { + //printf("reversing: %s\n", actlst->data.legActLine); curr = actlst; actlst = actlst->next; curr->syslines = cnfcfsyslinelstReverse(curr->syslines); @@ -221,8 +221,8 @@ cnfactlstPrint(struct cnfactlst *actlst) { struct cnfcfsyslinelst *cflst; - printf("---------- cnfactlst %p:\n", actlst); while(actlst != NULL) { + printf("aclst %p: ", actlst); if(actlst->actType == CNFACT_V2) { printf("V2 action type: "); nvlstPrint(actlst->data.lst); @@ -232,11 +232,10 @@ cnfactlstPrint(struct cnfactlst *actlst) } for( cflst = actlst->syslines ; cflst != NULL ; cflst = cflst->next) { - printf("cfsysline: '%s'\n", cflst->line); + printf("action:cfsysline: '%s'\n", cflst->line); } actlst = actlst->next; } - printf("----------\n"); } struct cnfexpr* @@ -305,7 +304,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) { struct exprret r, l; /* memory for subexpression results */ - printf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + //printf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: COMP_NUM_BINOP(==); @@ -523,6 +522,39 @@ cnfstringvalNew(es_str_t *estr) return strval; } +struct cnfrule * +cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) +{ + struct cnfrule* cnfrule; + if((cnfrule = malloc(sizeof(struct cnfrule))) != NULL) { + cnfrule->nodetype = 'R'; + cnfrule->filttype = filttype; + cnfrule->actlst = cnfactlstReverse(actlst); + } + return cnfrule; +} + +void +cnfrulePrint(struct cnfrule *rule) +{ + printf("------ start rule %p:\n", rule); + printf("%s: ", cnfFiltType2str(rule->filttype)); + switch(rule->filttype) { + case CNFFILT_NONE: + break; + case CNFFILT_PRI: + case CNFFILT_PROP: + printf("%s\n", rule->filt.s); + break; + case CNFFILT_SCRIPT: + printf("\n"); + cnfexprPrint(rule->filt.expr, 0); + break; + } + cnfactlstPrint(rule->actlst); + printf("------ end rule %p\n", rule); +} + /* debug helper */ void cstrPrint(char *text, es_str_t *estr) diff --git a/grammar/utils.h b/grammar/utils.h index f52bc1e0..9dfac5b1 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -61,6 +61,34 @@ struct cnfactlst { /* the following structures support expressions, and may (very much later * be the sole foundation for the AST. */ +enum cnfFiltType { CNFFILT_NONE, CNFFILT_PRI, CNFFILT_PROP, CNFFILT_SCRIPT }; +static inline char* +cnfFiltType2str(enum cnfFiltType filttype) +{ + switch(filttype) { + case CNFFILT_NONE: + return("filter:none"); + case CNFFILT_PRI: + return("filter:pri"); + case CNFFILT_PROP: + return("filter:prop"); + case CNFFILT_SCRIPT: + return("filter:script"); + } + return("error:invalid_filter_type"); /* should never be reached */ +} + + +struct cnfrule { + unsigned nodetype; + enum cnfFiltType filttype; + union { + char *s; + struct cnfexpr *expr; + } filt; + struct cnfactlst *actlst; +}; + struct cnfexpr { unsigned nodetype; struct cnfexpr *l; @@ -110,6 +138,8 @@ void cnfexprPrint(struct cnfexpr *expr, int indent); void cnfexprEval(struct cnfexpr *expr, struct exprret *ret); struct cnfnumval* cnfnumvalNew(long long val); struct cnfstringval* cnfstringvalNew(es_str_t *estr); +struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst); +void cnfrulePrint(struct cnfrule *rule); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); -- cgit v1.2.3 From 460010068b1d46c23829e7106380ffb8527df949 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 16:00:26 +0200 Subject: milestone: strings and vars are now stored correctly in in-memory representation --- grammar/debian.new | 6 +++--- grammar/rscript.l | 7 +++++-- grammar/rscript.y | 15 +++------------ grammar/utils.c | 20 ++++++++++++++++++++ grammar/utils.h | 12 ++++++++++++ 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/grammar/debian.new b/grammar/debian.new index e995a2e8..6cf9b5e5 100644 --- a/grammar/debian.new +++ b/grammar/debian.new @@ -47,7 +47,7 @@ $Umask 0022 # # Include all config files in /etc/rsyslog.d/ # -$IncludeConfig /etc/rsyslog.d/*.conf +#$IncludeConfig /etc/rsyslog.d/*.conf ############### @@ -102,7 +102,7 @@ daemon.*;mail.*;\ global (dnscache="yes" arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") # samples added to get full "flavor" of what we need to support... :msg, contains, "error" /var/log/somelog -action(type=omfile target=/var/log/mail/log) +action(type="omfile" target="/var/log/mail/log") *.* /* comment */ * # test *.info :ommysql:, tra, la , la # comment (comment to be part of old style line!) @@ -134,7 +134,7 @@ then /dev/tty10 & |/dev/xconsole *.* rger # write to user (ugly...) -ruleset name +#ruleset name # FEDORA, a bit more complex config # ### begin forwarding rule ### diff --git a/grammar/rscript.l b/grammar/rscript.l index 68f4d406..37f08f66 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -82,8 +82,11 @@ char *currfn; /* name of currently processed file */ 0[0-7]+ | /* octal number */ 0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ ([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } -\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); return VAR; } -\'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); return STRING; } +\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } +\'([^'\\]|\\['])*\' { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return STRING; } +\"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return STRING; } [ \t\n] . { printf("invalid char in expr: %s\n", yytext); } "&" { return '&'; } diff --git a/grammar/rscript.y b/grammar/rscript.y index aaf133eb..281a1775 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -35,7 +35,7 @@ extern int yylineno; %token OR %token AND %token NOT -%token VAR +%token VAR %token STRING %token NUMBER %token CMP_EQ @@ -148,19 +148,10 @@ expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | '-' expr %prec UMINUS { $$ = cnfexprNew('M', NULL, $2); } | NUMBER { $$ = (struct cnfexpr*) cnfnumvalNew($1); } | STRING { $$ = (struct cnfexpr*) cnfstringvalNew($1); } - | VAR { printf("variables not yet implemented!\n"); } + | VAR { $$ = (struct cnfexpr*) cnfvarNew($1); } %% int yyerror(char *s) { - printf("yyerror called: %s\n", s); + printf("parse failure on or before line %d: %s\n", yylineno, s); } - -/* -int main() -{ - yydebug = 0; - return yyparse(); -} - -*/ diff --git a/grammar/utils.c b/grammar/utils.c index b04274c1..791a8967 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -481,6 +481,15 @@ cnfexprPrint(struct cnfexpr *expr, int indent) doIndent(indent); printf("%lld\n", ((struct cnfnumval*)expr)->val); break; + case 'V': + doIndent(indent); + printf("var '%s'\n", ((struct cnfvar*)expr)->name); + break; + case 'S': + doIndent(indent); + cstrPrint("string '", ((struct cnfstringval*)expr)->estr); + printf("'\n"); + break; case '+': case '-': case '*': @@ -522,6 +531,17 @@ cnfstringvalNew(es_str_t *estr) return strval; } +struct cnfvar* +cnfvarNew(char *name) +{ + struct cnfvar *var; + if((var = malloc(sizeof(struct cnfvar))) != NULL) { + var->nodetype = 'V'; + var->name = name; + } + return var; +} + struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) { diff --git a/grammar/utils.h b/grammar/utils.h index 9dfac5b1..fb1462a3 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -60,6 +60,12 @@ struct cnfactlst { /* the following structures support expressions, and may (very much later * be the sole foundation for the AST. + * + * nodetypes (list not yet complete) + * S - string + * N - number + * V - var + * R - rule */ enum cnfFiltType { CNFFILT_NONE, CNFFILT_PRI, CNFFILT_PROP, CNFFILT_SCRIPT }; static inline char* @@ -105,6 +111,11 @@ struct cnfstringval { es_str_t *estr; }; +struct cnfvar { + unsigned nodetype; + char *name; +}; + /* future extensions struct x { int nodetype; @@ -140,6 +151,7 @@ struct cnfnumval* cnfnumvalNew(long long val); struct cnfstringval* cnfstringvalNew(es_str_t *estr); struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst); void cnfrulePrint(struct cnfrule *rule); +struct cnfvar* cnfvarNew(char *name); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); -- cgit v1.2.3 From 3d08f4e0f2dcc0f2216e11104ec43507eab22078 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 16:06:50 +0200 Subject: cleanup --- grammar/rscript.l | 13 ++----------- grammar/rscript.y | 37 ++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/grammar/rscript.l b/grammar/rscript.l index 37f08f66..a0ed3b0c 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -1,4 +1,4 @@ - /* lex file for rsyslog config format v2. + /* Lex file for rsyslog config format v2 (RainerScript). * Please note: this file introduces the new config format, but maintains * backward compatibility. In order to do so, the grammar is not 100% clean, * but IMHO still sufficiently easy both to understand for programmers @@ -106,10 +106,7 @@ char *currfn; /* name of currently processed file */ .|\n [^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) yyterminate(); - BEGIN INITIAL; - } - - + BEGIN INITIAL; } "global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; BEGIN INOBJ; return BEGINOBJ; } "input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; @@ -119,9 +116,7 @@ char *currfn; /* name of currently processed file */ "action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { yylval.s = strdup(yytext); return PROPFILT; } - ^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } - "*" | \-\/[^*][^\n]* | \/[^*][^\n]* | @@ -141,11 +136,9 @@ char *currfn; /* name of currently processed file */ "/*" { preCommentState = YY_START; BEGIN COMMENT; } "*/" { BEGIN preCommentState; } ([^*]|\n)+|. - #.*$ /* skip comments in input */ [ \n\t] . { printf("INOBJ: invalid char '%s'\n", yytext); } - \$[a-z]+.*$ { /* see common on $IncludeConfig above */ if(!strncasecmp(yytext, "$includeconfig ", 14)) { yyless(14); @@ -159,12 +152,10 @@ char *currfn; /* name of currently processed file */ [+-]\*[ \t\n]*#.*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } [+-]\*[ \t\n]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } ^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } - \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ . { printf("invalid char: %s\n", yytext); } - <> { if(popfile() != 0) yyterminate(); } %% diff --git a/grammar/rscript.y b/grammar/rscript.y index 281a1775..75fce49d 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -1,3 +1,17 @@ + /* Bison file for rsyslog config format v2 (RainerScript). + * Please note: this file introduces the new config format, but maintains + * backward compatibility. In order to do so, the grammar is not 100% clean, + * but IMHO still sufficiently easy both to understand for programmers + * maitaining the code as well as users writing the config file. Users are, + * of course, encouraged to use new constructs only. But it needs to be noted + * that some of the legacy constructs (specifically the in-front-of-action + * PRI filter) are very hard to beat in ease of use, at least for simpler + * cases. So while we hope that cfsysline support can be dropped some time in + * the future, we will probably keep these useful constructs. + * + * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH + * Released under the GNU GPL v3. For details see LICENSE file. + */ %{ #include @@ -92,40 +106,25 @@ conf: /* empty (to end recursion) */ obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } cfsysline: CFSYSLINE { $$ = $1 } - nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } -nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } - +nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } rule: PRIFILT actlst { $$ = cnfruleNew(CNFFILT_PRI, $2); $$->filt.s = $1; } | PROPFILT actlst { $$ = cnfruleNew(CNFFILT_PROP, $2); $$->filt.s = $1; } | scriptfilt { $$ = $1; } scriptfilt: IF expr THEN actlst { $$ = cnfruleNew(CNFFILT_SCRIPT, $4); - $$->filt.expr = $2; - //struct exprret r; - //cnfexprEval($2, &r); - // printf("eval result: %lld\n", r.d.n); - } - -/* note: we can do some limited block-structuring with the v6 engine. In that case, - * we must not support additonal filters inside the blocks, so they must consist of - * "act", only. We can implement that via the "&" actlist logic. - */ + $$->filt.expr = $2; } block: actlst { $$ = $1; } | block actlst { $2->next = $1; $$ = $2; } /* v7: | actlst - v7: | block rule */ - + v7: | block rule */ /* v7 extensions require new rule engine capabilities! */ actlst: act { $$=$1; } | actlst '&' act { $3->next = $1; $$ = $3; } | actlst cfsysline { $$ = cnfactlstAddSysline($1, $2); } | '{' block '}' { $$ = $2; } - act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } - | LEGACY_ACTION { //printf("legacy action: '%s'\n", $1); - $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } - + | LEGACY_ACTION { $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | expr OR expr { $$ = cnfexprNew(OR, $1, $3); } | NOT expr { $$ = cnfexprNew(NOT, NULL, $2); } -- cgit v1.2.3 From 183641a091a3d7b5eabe4419db4ebd2b6f84934e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 18:25:17 +0200 Subject: milestone: added functions to grammar --- grammar/mini.samp | 1 + grammar/rscript.l | 3 +++ grammar/rscript.y | 8 ++++++++ grammar/utils.c | 39 +++++++++++++++++++++++++++++++++++++-- grammar/utils.h | 20 ++++++++++++++++++-- 5 files changed, 67 insertions(+), 4 deletions(-) diff --git a/grammar/mini.samp b/grammar/mini.samp index 71cfbb69..505ae67a 100644 --- a/grammar/mini.samp +++ b/grammar/mini.samp @@ -30,3 +30,4 @@ if not (1==0) and 2*4/-5--(10-3)>7/*pri("*.*")*/ then { action(type="omfwd" taget="10.0.0.1" port="514") action(type="omwusr" taget="rger") } +if getenv("user") == "test" then /var/log/testlog diff --git a/grammar/rscript.l b/grammar/rscript.l index a0ed3b0c..a7410b15 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -61,6 +61,7 @@ char *currfn; /* name of currently processed file */ "or" { return OR; } "and" { return AND; } "not" { return NOT; } +"," | "*" | "/" | "%" | @@ -88,6 +89,8 @@ char *currfn; /* name of currently processed file */ \"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); return STRING; } [ \t\n] +[a-z][a-z0-9_]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); + return FUNC; } . { printf("invalid char in expr: %s\n", yytext); } "&" { return '&'; } "{" { return '{'; } diff --git a/grammar/rscript.y b/grammar/rscript.y index 75fce49d..b24b7db7 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -31,10 +31,13 @@ extern int yylineno; struct cnfactlst *actlst; struct cnfexpr *expr; struct cnfrule *rule; + struct cnffunc *func; + struct cnffparamlst *fparams; } %token NAME %token VALUE +%token FUNC %token BEGINOBJ %token ENDOBJ %token CFSYSLINE @@ -72,6 +75,7 @@ extern int yylineno; %type expr %type rule %type scriptfilt +%type fparams %left AND OR %left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT CMP_CONTAINS CMP_CONTAINSI CMP_STARTSWITH CMP_STARTSWITHI @@ -145,9 +149,13 @@ expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | expr '%' expr { $$ = cnfexprNew('%', $1, $3); } | '(' expr ')' { $$ = $2; } | '-' expr %prec UMINUS { $$ = cnfexprNew('M', NULL, $2); } + | FUNC '(' ')' { $$ = (struct cnfexpr*) cnffuncNew($1, NULL); } + | FUNC '(' fparams ')' { $$ = (struct cnfexpr*) cnffuncNew($1, $3); } | NUMBER { $$ = (struct cnfexpr*) cnfnumvalNew($1); } | STRING { $$ = (struct cnfexpr*) cnfstringvalNew($1); } | VAR { $$ = (struct cnfexpr*) cnfvarNew($1); } +fparams: expr { $$ = cnffparamlstNew($1, NULL); } + | expr ',' fparams { $$ = cnffparamlstNew($1, $3); } %% int yyerror(char *s) diff --git a/grammar/utils.c b/grammar/utils.c index 791a8967..16cad201 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -398,6 +398,7 @@ doIndent(indent) void cnfexprPrint(struct cnfexpr *expr, int indent) { + struct cnffparamlst *param; //printf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: @@ -477,6 +478,11 @@ cnfexprPrint(struct cnfexpr *expr, int indent) printf("NOT\n"); cnfexprPrint(expr->r, indent+1); break; + case 'S': + doIndent(indent); + cstrPrint("string '", ((struct cnfstringval*)expr)->estr); + printf("'\n"); + break; case 'N': doIndent(indent); printf("%lld\n", ((struct cnfnumval*)expr)->val); @@ -485,10 +491,15 @@ cnfexprPrint(struct cnfexpr *expr, int indent) doIndent(indent); printf("var '%s'\n", ((struct cnfvar*)expr)->name); break; - case 'S': + case 'F': doIndent(indent); - cstrPrint("string '", ((struct cnfstringval*)expr)->estr); + cstrPrint("function '", ((struct cnffunc*)expr)->fname); printf("'\n"); + for( param = ((struct cnffunc*)expr)->paramlst + ; param != NULL + ; param = param->next) { + cnfexprPrint(param->expr, indent+1); + } break; case '+': case '-': @@ -575,6 +586,30 @@ cnfrulePrint(struct cnfrule *rule) printf("------ end rule %p\n", rule); } +struct cnffparamlst * +cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) +{ + struct cnffparamlst* lst; + if((lst = malloc(sizeof(struct cnffparamlst))) != NULL) { + lst->nodetype = 'P'; + lst->expr = expr; + lst->next = next; + } + return lst; +} + +struct cnffunc * +cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) +{ + struct cnffunc* func; + if((func = malloc(sizeof(struct cnffunc))) != NULL) { + func->nodetype = 'F'; + func->fname = fname; + func->paramlst = paramlst; + } + return func; +} + /* debug helper */ void cstrPrint(char *text, es_str_t *estr) diff --git a/grammar/utils.h b/grammar/utils.h index fb1462a3..e75105da 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -62,10 +62,12 @@ struct cnfactlst { * be the sole foundation for the AST. * * nodetypes (list not yet complete) - * S - string + * F - function * N - number - * V - var + * P - fparamlst * R - rule + * S - string + * V - var */ enum cnfFiltType { CNFFILT_NONE, CNFFILT_PRI, CNFFILT_PROP, CNFFILT_SCRIPT }; static inline char* @@ -116,6 +118,18 @@ struct cnfvar { char *name; }; +struct cnffparamlst { + unsigned nodetype; /* P */ + struct cnffparamlst *next; + struct cnfexpr *expr; +}; + +struct cnffunc { + unsigned nodetype; + es_str_t *fname; + struct cnffparamlst *paramlst; +}; + /* future extensions struct x { int nodetype; @@ -152,6 +166,8 @@ struct cnfstringval* cnfstringvalNew(es_str_t *estr); struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst); void cnfrulePrint(struct cnfrule *rule); struct cnfvar* cnfvarNew(char *name); +struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst); +struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); -- cgit v1.2.3 From 641e383b8ad13ad6ee7fd9241214e24e6a983500 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 5 Jul 2011 08:21:04 +0200 Subject: milestone: grammar integrated in rsyslog build system --- Makefile.am | 2 +- configure.ac | 6 +- grammar/Makefile.am | 7 ++ grammar/makefile | 14 --- grammar/makefile.stand-alone | 14 +++ grammar/rscript-lex.l | 241 +++++++++++++++++++++++++++++++++++++++++++ grammar/rscript.l | 233 ----------------------------------------- grammar/utils.c | 4 +- tools/Makefile.am | 2 +- 9 files changed, 272 insertions(+), 251 deletions(-) create mode 100644 grammar/Makefile.am delete mode 100644 grammar/makefile create mode 100644 grammar/makefile.stand-alone create mode 100644 grammar/rscript-lex.l delete mode 100644 grammar/rscript.l diff --git a/Makefile.am b/Makefile.am index d689b9ee..7bf9dd0e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -66,7 +66,7 @@ EXTRA_DIST = \ contrib/gnutls/key.pem \ rsyslog.service.in -SUBDIRS = doc runtime . plugins/immark plugins/imuxsock plugins/imtcp plugins/imudp plugins/omtesting +SUBDIRS = doc runtime grammar . plugins/immark plugins/imuxsock plugins/imtcp plugins/imudp plugins/omtesting if ENABLE_RSYSLOGD SUBDIRS += tools diff --git a/configure.ac b/configure.ac index b0e71c20..1a239ca4 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,8 @@ if test x"$HAVE_JAVAC" = x""; then fi # Checks for programs. +AC_PROG_LEX +AC_PROG_YACC AC_PROG_CC AM_PROG_CC_C_O if test "$GCC" = "yes" @@ -707,6 +709,7 @@ AC_ARG_ENABLE(rsyslogrt, if test "x$enable_rsyslogrt" = "xyes"; then RSRT_CFLAGS="-I\$(top_srcdir)/runtime -I\$(top_srcdir)" RSRT_LIBS="\$(top_builddir)/runtime/librsyslog.la" + CNF_LIBS="\$(top_builddir)/grammar/libgrammar.la" fi AM_CONDITIONAL(ENABLE_RSYSLOGRT, test x$enable_rsyslogrt = xyes) AC_SUBST(RSRT_CFLAGS) @@ -779,7 +782,7 @@ AM_CONDITIONAL(ENABLE_MAIL, test x$enable_mail = xyes) # would complicate things if we first needed to tell them how to enable imdiag. # rgerhards, 2008-07-25 AC_ARG_ENABLE(imdiag, - [AS_HELP_STRING([--enable-imdiag],[Enable imdiag @<:@default=yes@:>@])], + [AS_HELP_STRING([--enable-imdiag],[Enable imdiag @<:@default=no@:>@])], [case "${enableval}" in yes) enable_imdiag="yes" ;; no) enable_imdiag="no" ;; @@ -1224,6 +1227,7 @@ AM_CONDITIONAL(ENABLE_OMMONGODB, test x$enable_ommongodb = xyes) AC_CONFIG_FILES([Makefile \ runtime/Makefile \ + grammar/Makefile \ tools/Makefile \ doc/Makefile \ plugins/imudp/Makefile \ diff --git a/grammar/Makefile.am b/grammar/Makefile.am new file mode 100644 index 00000000..b2bd3430 --- /dev/null +++ b/grammar/Makefile.am @@ -0,0 +1,7 @@ +noinst_LTLIBRARIES = libgrammar.la + +libgrammar_la_SOURCES = \ + utils.c \ + utils.h \ + rscript-lex.l \ + rscript.y diff --git a/grammar/makefile b/grammar/makefile deleted file mode 100644 index eb6c9522..00000000 --- a/grammar/makefile +++ /dev/null @@ -1,14 +0,0 @@ -rscript: lex.yy.c utils.o rscript.tab.h utils.h - gcc -g -o rscript lex.yy.c rscript.tab.c utils.o -lestr - -lex.yy.c: rscript.l rscript.tab.h - flex rscript.l - -rscript.tab.h: rscript.y - bison -d rscript.y - -utils.o: utils.c utils.h - gcc -g -Wall -c utils.c - -clean: - rm *.o diff --git a/grammar/makefile.stand-alone b/grammar/makefile.stand-alone new file mode 100644 index 00000000..b998a39d --- /dev/null +++ b/grammar/makefile.stand-alone @@ -0,0 +1,14 @@ +rscript: lex.yy.c utils.o rscript.tab.h utils.h + gcc -DSTAND_ALONE -g -o rscript lex.yy.c rscript.tab.c utils.o -lestr + +lex.yy.c: rscript.l rscript.tab.h + flex rscript.l + +rscript.tab.h: rscript.y + bison -d rscript.y + +utils.o: utils.c utils.h + gcc -g -DSTAND_ALONE -Wall -c utils.c + +clean: + rm *.o diff --git a/grammar/rscript-lex.l b/grammar/rscript-lex.l new file mode 100644 index 00000000..1c7b963e --- /dev/null +++ b/grammar/rscript-lex.l @@ -0,0 +1,241 @@ + /* Lex file for rsyslog config format v2 (RainerScript). + * Please note: this file introduces the new config format, but maintains + * backward compatibility. In order to do so, the grammar is not 100% clean, + * but IMHO still sufficiently easy both to understand for programmers + * maitaining the code as well as users writing the config file. Users are, + * of course, encouraged to use new constructs only. But it needs to be noted + * that some of the legacy constructs (specifically the in-front-of-action + * PRI filter) are very hard to beat in ease of use, at least for simpler + * cases. So while we hope that cfsysline support can be dropped some time in + * the future, we will probably keep these useful constructs. + * + * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH + * Released under the GNU GPL v3. For details see LICENSE file. + */ + +%option noyywrap nodefault case-insensitive yylineno + /*%option noyywrap nodefault case-insensitive */ + +/* avoid compiler warning: `yyunput' defined but not used */ +%option nounput noinput + + +%x INOBJ + /* INOBJ is selected if we are inside an object (name/value pairs!) */ +%x COMMENT + /* COMMENT is "the usual trick" to handle C-style comments */ +%x INCL + /* INCL is in $IncludeConfig processing (skip to include file) */ +%x LINENO + /* LINENO: support for setting the linenumber */ +%x EXPR + /* EXPR is a bit ugly, but we need it to support pre v6-syntax. The problem + * is that cfsysline statement start with $..., the same like variables in + * an expression. However, cfsysline statements can never appear inside an + * expression. So we create a specific expr mode, which is turned on after + * we lexed a keyword that needs to be followed by an expression (using + * knowledge from the upper layer...). In expr mode, we strictly do + * expression-based parsing. Expr mode is stopped when we reach a token + * that can not be part of an expression (currently only "then"). As I + * wrote this ugly, but the price needed to pay in order to remain + * compatible to the previous format. + */ +%{ +#include +#include +#include "utils.h" +#include "rscript.tab.h" +static int preCommentState; /* save for lex state before a comment */ + +struct bufstack { + struct bufstack *prev; + YY_BUFFER_STATE bs; + int lineno; + char *fn; +} *currbs = NULL; + +char *currfn; /* name of currently processed file */ + +int popfile(void); +int cnfSetLexFile(char *fname); +%} + +%% + + /* keywords */ +"if" { BEGIN EXPR; return IF; } +"then" { BEGIN INITIAL; return THEN; } +"or" { return OR; } +"and" { return AND; } +"not" { return NOT; } +"," | +"*" | +"/" | +"%" | +"+" | +"-" | +"(" | +")" { return yytext[0]; } +"==" { return CMP_EQ; } +"<=" { return CMP_LE; } +">=" { return CMP_GE; } +"!=" | +"<>" { return CMP_NE; } +"<" { return CMP_LT; } +">" { return CMP_GT; } +"contains" { return CMP_CONTAINS; } +"contains_i" { return CMP_CONTAINSI; } +"startswith" { return CMP_STARTSWITH; } +"startswith_i" { return CMP_STARTSWITHI; } +0[0-7]+ | /* octal number */ +0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ +([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } +\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } +\'([^'\\]|\\['])*\' { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return STRING; } +\"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return STRING; } +[ \t\n] +[a-z][a-z0-9_]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); + return FUNC; } +. { printf("invalid char in expr: %s\n", yytext); } +"&" { return '&'; } +"{" { return '{'; } +"}" { return '}'; } +"ruleset" { printf("RULESET\n"); } + /* line number support because the "preprocessor" combines lines and so needs + * to tell us the real source line. + */ +"preprocfilelinenumber(" { BEGIN LINENO; } +[0-9]+ { yylineno = atoi(yytext) - 1; } +")" { BEGIN INITIAL; } +.|\n + /* $IncludeConfig must be detected as part of CFSYSLINE, because this is + * always the longest match :-( + */ +.|\n +[^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) + yyterminate(); + BEGIN INITIAL; } +"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; + BEGIN INOBJ; return BEGINOBJ; } +"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; + BEGIN INOBJ; return BEGINOBJ; } +"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; + BEGIN INOBJ; return BEGINOBJ; } +"action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } +^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { + yylval.s = strdup(yytext); return PROPFILT; } +^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } +"*" | +\-\/[^*][^\n]* | +\/[^*][^\n]* | +:[a-z0-9]+:[^\n]* | +[\|\.\-\@~][^\n]+ | +[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); + // printf("lex: LEGA ACT: '%s'\n", yytext); + return LEGACY_ACTION; } +")" { BEGIN INITIAL; return ENDOBJ; } +[a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); + return NAME; } +"=" { return(yytext[0]); } +\"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { + yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return VALUE; } +"/*" { preCommentState = YY_START; BEGIN COMMENT; } +"/*" { preCommentState = YY_START; BEGIN COMMENT; } +"*/" { BEGIN preCommentState; } +([^*]|\n)+|. +#.*$ /* skip comments in input */ +[ \n\t] +. { printf("INOBJ: invalid char '%s'\n", yytext); } +\$[a-z]+.*$ { /* see common on $IncludeConfig above */ + if(!strncasecmp(yytext, "$includeconfig ", 14)) { + yyless(14); + BEGIN INCL; + } else { + yylval.s = strdup(yytext); + return CFSYSLINE; + } + } +![^ \t\n]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } +[+-]\*[ \t\n]*#.*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +[+-]\*[ \t\n]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +\#.*\n /* skip comments in input */ +[\n\t ] /* drop whitespace */ +. { printf("invalid char: %s\n", yytext); + } +<> { if(popfile() != 0) yyterminate(); } + +%% +/* set a new buffers. Returns 0 on success, something else otherwise. */ +int +cnfSetLexFile(char *fname) +{ + es_str_t *str = NULL; + FILE *fp; + int r = 0; + struct bufstack *bs; + + if(fname == NULL) { + fp = stdin; + } else { + if((fp = fopen(fname, "r")) == NULL) { + r = 1; + goto done; + } + } + readConfFile(fp, &str); + if(fp != stdin) + fclose(fp); + + /* maintain stack */ + if((bs = malloc(sizeof(struct bufstack))) == NULL) { + r = 1; + goto done; + } + + if(currbs != NULL) + currbs->lineno = yylineno; + bs->prev = currbs; + bs->fn = strdup(fname); + bs->bs = yy_scan_buffer((char*)es_getBufAddr(str), es_strlen(str)); + currbs = bs; + currfn = bs->fn; + yylineno = 1; + +done: + if(r != 0) { + if(str != NULL) + es_deleteStr(str); + } + return r; +} + + +/* returns 0 on success, something else otherwise */ +int +popfile(void) +{ + struct bufstack *bs = currbs; + + if(bs == NULL) + return 1; + + /* delte current entry */ + yy_delete_buffer(bs->bs); + free(bs->fn); + + /* switch back to previous */ + currbs = bs->prev; + free(bs); + + if(currbs == NULL) + return 1; /* all processed */ + + yy_switch_to_buffer(currbs->bs); + yylineno = currbs->lineno; + currfn = currbs->fn; + return 0; +} diff --git a/grammar/rscript.l b/grammar/rscript.l deleted file mode 100644 index a7410b15..00000000 --- a/grammar/rscript.l +++ /dev/null @@ -1,233 +0,0 @@ - /* Lex file for rsyslog config format v2 (RainerScript). - * Please note: this file introduces the new config format, but maintains - * backward compatibility. In order to do so, the grammar is not 100% clean, - * but IMHO still sufficiently easy both to understand for programmers - * maitaining the code as well as users writing the config file. Users are, - * of course, encouraged to use new constructs only. But it needs to be noted - * that some of the legacy constructs (specifically the in-front-of-action - * PRI filter) are very hard to beat in ease of use, at least for simpler - * cases. So while we hope that cfsysline support can be dropped some time in - * the future, we will probably keep these useful constructs. - * - * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH - * Released under the GNU GPL v3. For details see LICENSE file. - */ - -%option noyywrap nodefault case-insensitive yylineno - /*%option noyywrap nodefault case-insensitive */ - -%x INOBJ - /* INOBJ is selected if we are inside an object (name/value pairs!) */ -%x COMMENT - /* COMMENT is "the usual trick" to handle C-style comments */ -%x INCL - /* INCL is in $IncludeConfig processing (skip to include file) */ -%x LINENO - /* LINENO: support for setting the linenumber */ -%x EXPR - /* EXPR is a bit ugly, but we need it to support pre v6-syntax. The problem - * is that cfsysline statement start with $..., the same like variables in - * an expression. However, cfsysline statements can never appear inside an - * expression. So we create a specific expr mode, which is turned on after - * we lexed a keyword that needs to be followed by an expression (using - * knowledge from the upper layer...). In expr mode, we strictly do - * expression-based parsing. Expr mode is stopped when we reach a token - * that can not be part of an expression (currently only "then"). As I - * wrote this ugly, but the price needed to pay in order to remain - * compatible to the previous format. - */ -%{ -#include -#include -#include "utils.h" -#include "rscript.tab.h" -static int preCommentState; /* save for lex state before a comment */ - -struct bufstack { - struct bufstack *prev; - YY_BUFFER_STATE bs; - int lineno; - char *fn; -} *currbs = NULL; - -char *currfn; /* name of currently processed file */ -%} - -%% - - /* keywords */ -"if" { BEGIN EXPR; return IF; } -"then" { BEGIN INITIAL; return THEN; } -"or" { return OR; } -"and" { return AND; } -"not" { return NOT; } -"," | -"*" | -"/" | -"%" | -"+" | -"-" | -"(" | -")" { return yytext[0]; } -"==" { return CMP_EQ; } -"<=" { return CMP_LE; } -">=" { return CMP_GE; } -"!=" | -"<>" { return CMP_NE; } -"<" { return CMP_LT; } -">" { return CMP_GT; } -"contains" { return CMP_CONTAINS; } -"contains_i" { return CMP_CONTAINSI; } -"startswith" { return CMP_STARTSWITH; } -"startswith_i" { return CMP_STARTSWITHI; } -0[0-7]+ | /* octal number */ -0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ -([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } -\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } -\'([^'\\]|\\['])*\' { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); - return STRING; } -\"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); - return STRING; } -[ \t\n] -[a-z][a-z0-9_]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); - return FUNC; } -. { printf("invalid char in expr: %s\n", yytext); } -"&" { return '&'; } -"{" { return '{'; } -"}" { return '}'; } -"ruleset" { printf("RULESET\n"); } - /* line number support because the "preprocessor" combines lines and so needs - * to tell us the real source line. - */ -"preprocfilelinenumber(" { BEGIN LINENO; } -[0-9]+ { yylineno = atoi(yytext) - 1; } -")" { BEGIN INITIAL; } -.|\n - /* $IncludeConfig must be detected as part of CFSYSLINE, because this is - * always the longest match :-( - */ -.|\n -[^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) - yyterminate(); - BEGIN INITIAL; } -"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; - BEGIN INOBJ; return BEGINOBJ; } -"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; - BEGIN INOBJ; return BEGINOBJ; } -"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; - BEGIN INOBJ; return BEGINOBJ; } -"action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } -^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { - yylval.s = strdup(yytext); return PROPFILT; } -^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } -"*" | -\-\/[^*][^\n]* | -\/[^*][^\n]* | -:[a-z0-9]+:[^\n]* | -[\|\.\-\@~][^\n]+ | -[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); - // printf("lex: LEGA ACT: '%s'\n", yytext); - return LEGACY_ACTION; } -")" { BEGIN INITIAL; return ENDOBJ; } -[a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); - return NAME; } -"=" { return(yytext[0]); } -\"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { - yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); - return VALUE; } -"/*" { preCommentState = YY_START; BEGIN COMMENT; } -"/*" { preCommentState = YY_START; BEGIN COMMENT; } -"*/" { BEGIN preCommentState; } -([^*]|\n)+|. -#.*$ /* skip comments in input */ -[ \n\t] -. { printf("INOBJ: invalid char '%s'\n", yytext); } -\$[a-z]+.*$ { /* see common on $IncludeConfig above */ - if(!strncasecmp(yytext, "$includeconfig ", 14)) { - yyless(14); - BEGIN INCL; - } else { - yylval.s = strdup(yytext); - return CFSYSLINE; - } - } -![^ \t\n]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } -[+-]\*[ \t\n]*#.*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -[+-]\*[ \t\n]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -\#.*\n /* skip comments in input */ -[\n\t ] /* drop whitespace */ -. { printf("invalid char: %s\n", yytext); - } -<> { if(popfile() != 0) yyterminate(); } - -%% -/* set a new buffers. Returns 0 on success, something else otherwise. */ -int cnfSetLexFile(char *fname) -{ - es_str_t *str = NULL; - FILE *fp; - int r = 0; - struct bufstack *bs; - - if(fname == NULL) { - fp = stdin; - } else { - if((fp = fopen(fname, "r")) == NULL) { - r = 1; - goto done; - } - } - readConfFile(fp, &str); - if(fp != stdin) - fclose(fp); - - /* maintain stack */ - if((bs = malloc(sizeof(struct bufstack))) == NULL) { - r = 1; - goto done; - } - - if(currbs != NULL) - currbs->lineno = yylineno; - bs->prev = currbs; - bs->fn = strdup(fname); - bs->bs = yy_scan_buffer(es_getBufAddr(str), es_strlen(str)); - currbs = bs; - currfn = bs->fn; - yylineno = 1; - -done: - if(r != 0) { - if(str != NULL) - es_deleteStr(str); - } - return r; -} - - -/* returns 0 on success, something else otherwise */ -int -popfile(void) -{ - struct bufstack *bs = currbs; - - if(bs == NULL) - return 1; - - /* delte current entry */ - yy_delete_buffer(bs->bs); - free(bs->fn); - - /* switch back to previous */ - currbs = bs->prev; - free(bs); - - if(currbs == NULL) - return 1; /* all processed */ - - yy_switch_to_buffer(currbs->bs); - yylineno = currbs->lineno; - currfn = currbs->fn; - return 0; -} diff --git a/grammar/utils.c b/grammar/utils.c index 16cad201..e488ebda 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -389,7 +389,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) } inline static void -doIndent(indent) +doIndent(int indent) { int i; for(i = 0 ; i < indent ; ++i) @@ -611,6 +611,7 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) } /* debug helper */ +#ifdef STAND_ALONE void cstrPrint(char *text, es_str_t *estr) { @@ -632,4 +633,5 @@ main(int argc, char *argv[]) printf("yyparse() returned %d\n", r); return r; } +#endif /* #ifdef STAND_ALONE */ diff --git a/tools/Makefile.am b/tools/Makefile.am index 5c3f7a40..f3b176f2 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -35,7 +35,7 @@ rsyslogd_SOURCES = \ pidfile.h \ \ ../dirty.h -rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) +rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) $(CNF_LIBS) rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) rsyslogd_LDFLAGS = -export-dynamic -- cgit v1.2.3 From 6175ce90b59d742976aa5a8b2603902761e540ae Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 5 Jul 2011 11:04:47 +0200 Subject: milestone: improved build system ... still had quite some glitches, as usual. This time it hopefully works under all circumstances (well, let's hope for "usual cir..." ;)). --- grammar/Makefile.am | 13 ++- grammar/grammar.y | 169 +++++++++++++++++++++++++++++++++ grammar/lexer.l | 251 ++++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rscript-lex.l | 241 ------------------------------------------------ grammar/rscript.y | 164 --------------------------------- grammar/testdriver.c | 50 ++++++++++ grammar/utils.c | 28 +----- 7 files changed, 482 insertions(+), 434 deletions(-) create mode 100644 grammar/grammar.y create mode 100644 grammar/lexer.l delete mode 100644 grammar/rscript-lex.l delete mode 100644 grammar/rscript.y create mode 100644 grammar/testdriver.c diff --git a/grammar/Makefile.am b/grammar/Makefile.am index b2bd3430..b482c99e 100644 --- a/grammar/Makefile.am +++ b/grammar/Makefile.am @@ -1,7 +1,16 @@ +BUILT_SOURCES = grammar.h +CLEANFILES = grammar.h grammar.c +AM_YFLAGS = -d noinst_LTLIBRARIES = libgrammar.la +bin_PROGRAMS = testdriver # TODO: make this conditional libgrammar_la_SOURCES = \ + grammar.y \ + lexer.l \ utils.c \ utils.h \ - rscript-lex.l \ - rscript.y + grammar.h + +testdriver_SOURCES = testdriver.c libgrammar.la +testdriver_LDADD = libgrammar.la +testdriver_LDFLAGS = -lestr diff --git a/grammar/grammar.y b/grammar/grammar.y new file mode 100644 index 00000000..76881fd1 --- /dev/null +++ b/grammar/grammar.y @@ -0,0 +1,169 @@ + /* Bison file for rsyslog config format v2 (RainerScript). + * Please note: this file introduces the new config format, but maintains + * backward compatibility. In order to do so, the grammar is not 100% clean, + * but IMHO still sufficiently easy both to understand for programmers + * maitaining the code as well as users writing the config file. Users are, + * of course, encouraged to use new constructs only. But it needs to be noted + * that some of the legacy constructs (specifically the in-front-of-action + * PRI filter) are very hard to beat in ease of use, at least for simpler + * cases. So while we hope that cfsysline support can be dropped some time in + * the future, we will probably keep these useful constructs. + * + * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH + * Released under the GNU GPL v3. For details see LICENSE file. + */ + +%{ +#include +#include +#include "utils.h" +#define YYDEBUG 1 +extern int yylineno; + +/* keep compile rule cleam of errors */ +extern int yylex(void); +extern int yyerror(char*); +%} + +%union { + char *s; + long long n; + es_str_t *estr; + enum cnfobjType objType; + struct cnfobj *obj; + struct nvlst *nvlst; + struct cnfactlst *actlst; + struct cnfexpr *expr; + struct cnfrule *rule; + struct cnffunc *func; + struct cnffparamlst *fparams; +} + +%token NAME +%token VALUE +%token FUNC +%token BEGINOBJ +%token ENDOBJ +%token CFSYSLINE +%token BEGIN_ACTION +%token LEGACY_ACTION +%token PRIFILT +%token PROPFILT +%token BSD_TAG_SELECTOR +%token BSD_HOST_SELECTOR +%token IF +%token THEN +%token OR +%token AND +%token NOT +%token VAR +%token STRING +%token NUMBER +%token CMP_EQ +%token CMP_NE +%token CMP_LE +%token CMP_GE +%token CMP_LT +%token CMP_GT +%token CMP_CONTAINS +%token CMP_CONTAINSI +%token CMP_STARTSWITH +%token CMP_STARTSWITHI + +%type nv nvlst +%type obj +%type actlst +%type act +%type cfsysline +%type block +%type expr +%type rule +%type scriptfilt +%type fparams + +%left AND OR +%left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT CMP_CONTAINS CMP_CONTAINSI CMP_STARTSWITH CMP_STARTSWITHI +%left '+' '-' +%left '*' '/' '%' +%nonassoc UMINUS NOT + +%expect 3 +/* these shift/reduce conflicts are created by the CFSYSLINE construct, which we + * unfortunately can not avoid. The problem is that CFSYSLINE can occur both in + * global context as well as within an action. It's not permitted somewhere else, + * but this is suficient for conflicts. The "dangling else" built-in resolution + * works well to solve this issue, so we accept it (it's a wonder that our + * old style grammar doesn't work at all, so we better do not complain...). + * Use "bison -v rscript.y" if more conflicts arise and check rscript.out for + * were exactly these conflicts exits. + */ +%% +/* note: we use left recursion below, because that saves stack space AND + * offers the right sequence so that we can submit the top-layer objects + * one by one. + */ +conf: /* empty (to end recursion) */ + | conf obj { printf("global:config: "); + cnfobjPrint($2); cnfobjDestruct($2); } + | conf rule { printf("global:rule processed\n"); + cnfrulePrint($2); } + | conf cfsysline { printf("global:cfsysline: %s\n", $2); } + | conf BSD_TAG_SELECTOR { printf("global:BSD tag '%s'\n", $2); } + | conf BSD_HOST_SELECTOR { printf("global:BSD host '%s'\n", $2); } + +obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } + | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } +cfsysline: CFSYSLINE { $$ = $1; } +nvlst: { $$ = NULL; } + | nvlst nv { $2->next = $1; $$ = $2; } +nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } +rule: PRIFILT actlst { $$ = cnfruleNew(CNFFILT_PRI, $2); $$->filt.s = $1; } + | PROPFILT actlst { $$ = cnfruleNew(CNFFILT_PROP, $2); $$->filt.s = $1; } + | scriptfilt { $$ = $1; } + +scriptfilt: IF expr THEN actlst { $$ = cnfruleNew(CNFFILT_SCRIPT, $4); + $$->filt.expr = $2; } +block: actlst { $$ = $1; } + | block actlst { $2->next = $1; $$ = $2; } + /* v7: | actlst + v7: | block rule */ /* v7 extensions require new rule engine capabilities! */ +actlst: act { $$=$1; } + | actlst '&' act { $3->next = $1; $$ = $3; } + | actlst cfsysline { $$ = cnfactlstAddSysline($1, $2); } + | '{' block '}' { $$ = $2; } +act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } + | LEGACY_ACTION { $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } +expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } + | expr OR expr { $$ = cnfexprNew(OR, $1, $3); } + | NOT expr { $$ = cnfexprNew(NOT, NULL, $2); } + | expr CMP_EQ expr { $$ = cnfexprNew(CMP_EQ, $1, $3); } + | expr CMP_NE expr { $$ = cnfexprNew(CMP_NE, $1, $3); } + | expr CMP_LE expr { $$ = cnfexprNew(CMP_LE, $1, $3); } + | expr CMP_GE expr { $$ = cnfexprNew(CMP_GE, $1, $3); } + | expr CMP_LT expr { $$ = cnfexprNew(CMP_LT, $1, $3); } + | expr CMP_GT expr { $$ = cnfexprNew(CMP_GT, $1, $3); } + | expr CMP_CONTAINS expr { $$ = cnfexprNew(CMP_CONTAINS, $1, $3); } + | expr CMP_CONTAINSI expr { $$ = cnfexprNew(CMP_CONTAINSI, $1, $3); } + | expr CMP_STARTSWITH expr { $$ = cnfexprNew(CMP_STARTSWITH, $1, $3); } + | expr CMP_STARTSWITHI expr { $$ = cnfexprNew(CMP_STARTSWITHI, $1, $3); } + | expr '+' expr { $$ = cnfexprNew('+', $1, $3); } + | expr '-' expr { $$ = cnfexprNew('-', $1, $3); } + | expr '*' expr { $$ = cnfexprNew('*', $1, $3); } + | expr '/' expr { $$ = cnfexprNew('/', $1, $3); } + | expr '%' expr { $$ = cnfexprNew('%', $1, $3); } + | '(' expr ')' { $$ = $2; } + | '-' expr %prec UMINUS { $$ = cnfexprNew('M', NULL, $2); } + | FUNC '(' ')' { $$ = (struct cnfexpr*) cnffuncNew($1, NULL); } + | FUNC '(' fparams ')' { $$ = (struct cnfexpr*) cnffuncNew($1, $3); } + | NUMBER { $$ = (struct cnfexpr*) cnfnumvalNew($1); } + | STRING { $$ = (struct cnfexpr*) cnfstringvalNew($1); } + | VAR { $$ = (struct cnfexpr*) cnfvarNew($1); } +fparams: expr { $$ = cnffparamlstNew($1, NULL); } + | expr ',' fparams { $$ = cnffparamlstNew($1, $3); } + +%% +int yyerror(char *s) +{ + printf("parse failure on or before line %d: %s\n", yylineno, s); + return 0; +} diff --git a/grammar/lexer.l b/grammar/lexer.l new file mode 100644 index 00000000..2411be6f --- /dev/null +++ b/grammar/lexer.l @@ -0,0 +1,251 @@ + /* Lex file for rsyslog config format v2 (RainerScript). + * Please note: this file introduces the new config format, but maintains + * backward compatibility. In order to do so, the grammar is not 100% clean, + * but IMHO still sufficiently easy both to understand for programmers + * maitaining the code as well as users writing the config file. Users are, + * of course, encouraged to use new constructs only. But it needs to be noted + * that some of the legacy constructs (specifically the in-front-of-action + * PRI filter) are very hard to beat in ease of use, at least for simpler + * cases. So while we hope that cfsysline support can be dropped some time in + * the future, we will probably keep these useful constructs. + * + * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH + * Released under the GNU GPL v3. For details see LICENSE file. + */ + +%option noyywrap nodefault case-insensitive yylineno + /*%option noyywrap nodefault case-insensitive */ + +/* avoid compiler warning: `yyunput' defined but not used */ +%option nounput noinput + + +%x INOBJ + /* INOBJ is selected if we are inside an object (name/value pairs!) */ +%x COMMENT + /* COMMENT is "the usual trick" to handle C-style comments */ +%x INCL + /* INCL is in $IncludeConfig processing (skip to include file) */ +%x LINENO + /* LINENO: support for setting the linenumber */ +%x EXPR + /* EXPR is a bit ugly, but we need it to support pre v6-syntax. The problem + * is that cfsysline statement start with $..., the same like variables in + * an expression. However, cfsysline statements can never appear inside an + * expression. So we create a specific expr mode, which is turned on after + * we lexed a keyword that needs to be followed by an expression (using + * knowledge from the upper layer...). In expr mode, we strictly do + * expression-based parsing. Expr mode is stopped when we reach a token + * that can not be part of an expression (currently only "then"). As I + * wrote this ugly, but the price needed to pay in order to remain + * compatible to the previous format. + */ +%{ +#include +#include +#include +#include +#include +#include "utils.h" +#include "grammar.h" +static int preCommentState; /* save for lex state before a comment */ + +struct bufstack { + struct bufstack *prev; + YY_BUFFER_STATE bs; + int lineno; + char *fn; +} *currbs = NULL; + +char *currfn; /* name of currently processed file */ + +int popfile(void); +int cnfSetLexFile(char *fname); + +/* somehow, I need these prototype even though the headers are + * included. I guess that's some autotools magic I don't understand... + */ +char *strdup(char*); +int fileno(FILE *stream); + +%} + +%% + + /* keywords */ +"if" { BEGIN EXPR; return IF; } +"then" { BEGIN INITIAL; return THEN; } +"or" { return OR; } +"and" { return AND; } +"not" { return NOT; } +"," | +"*" | +"/" | +"%" | +"+" | +"-" | +"(" | +")" { return yytext[0]; } +"==" { return CMP_EQ; } +"<=" { return CMP_LE; } +">=" { return CMP_GE; } +"!=" | +"<>" { return CMP_NE; } +"<" { return CMP_LT; } +">" { return CMP_GT; } +"contains" { return CMP_CONTAINS; } +"contains_i" { return CMP_CONTAINSI; } +"startswith" { return CMP_STARTSWITH; } +"startswith_i" { return CMP_STARTSWITHI; } +0[0-7]+ | /* octal number */ +0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ +([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } +\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } +\'([^'\\]|\\['])*\' { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return STRING; } +\"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return STRING; } +[ \t\n] +[a-z][a-z0-9_]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); + return FUNC; } +. { printf("invalid char in expr: %s\n", yytext); } +"&" { return '&'; } +"{" { return '{'; } +"}" { return '}'; } +"ruleset" { printf("RULESET\n"); } + /* line number support because the "preprocessor" combines lines and so needs + * to tell us the real source line. + */ +"preprocfilelinenumber(" { BEGIN LINENO; } +[0-9]+ { yylineno = atoi(yytext) - 1; } +")" { BEGIN INITIAL; } +.|\n + /* $IncludeConfig must be detected as part of CFSYSLINE, because this is + * always the longest match :-( + */ +.|\n +[^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) + yyterminate(); + BEGIN INITIAL; } +"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; + BEGIN INOBJ; return BEGINOBJ; } +"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; + BEGIN INOBJ; return BEGINOBJ; } +"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; + BEGIN INOBJ; return BEGINOBJ; } +"action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } +^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { + yylval.s = strdup(yytext); return PROPFILT; } +^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } +"*" | +\-\/[^*][^\n]* | +\/[^*][^\n]* | +:[a-z0-9]+:[^\n]* | +[\|\.\-\@~][^\n]+ | +[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); + // printf("lex: LEGA ACT: '%s'\n", yytext); + return LEGACY_ACTION; } +")" { BEGIN INITIAL; return ENDOBJ; } +[a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); + return NAME; } +"=" { return(yytext[0]); } +\"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { + yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return VALUE; } +"/*" { preCommentState = YY_START; BEGIN COMMENT; } +"/*" { preCommentState = YY_START; BEGIN COMMENT; } +"*/" { BEGIN preCommentState; } +([^*]|\n)+|. +#.*$ /* skip comments in input */ +[ \n\t] +. { printf("INOBJ: invalid char '%s'\n", yytext); } +\$[a-z]+.*$ { /* see common on $IncludeConfig above */ + if(!strncasecmp(yytext, "$includeconfig ", 14)) { + yyless(14); + BEGIN INCL; + } else { + yylval.s = strdup(yytext); + return CFSYSLINE; + } + } +![^ \t\n]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } +[+-]\*[ \t\n]*#.*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +[+-]\*[ \t\n]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +\#.*\n /* skip comments in input */ +[\n\t ] /* drop whitespace */ +. { printf("invalid char: %s\n", yytext); + } +<> { if(popfile() != 0) yyterminate(); } + +%% +/* set a new buffers. Returns 0 on success, something else otherwise. */ +int +cnfSetLexFile(char *fname) +{ + es_str_t *str = NULL; + FILE *fp; + int r = 0; + struct bufstack *bs; + + if(fname == NULL) { + fp = stdin; + } else { + if((fp = fopen(fname, "r")) == NULL) { + r = 1; + goto done; + } + } + readConfFile(fp, &str); + if(fp != stdin) + fclose(fp); + + /* maintain stack */ + if((bs = malloc(sizeof(struct bufstack))) == NULL) { + r = 1; + goto done; + } + + if(currbs != NULL) + currbs->lineno = yylineno; + bs->prev = currbs; + bs->fn = strdup(fname); + bs->bs = yy_scan_buffer((char*)es_getBufAddr(str), es_strlen(str)); + currbs = bs; + currfn = bs->fn; + yylineno = 1; + +done: + if(r != 0) { + if(str != NULL) + es_deleteStr(str); + } + return r; +} + + +/* returns 0 on success, something else otherwise */ +int +popfile(void) +{ + struct bufstack *bs = currbs; + + if(bs == NULL) + return 1; + + /* delte current entry */ + yy_delete_buffer(bs->bs); + free(bs->fn); + + /* switch back to previous */ + currbs = bs->prev; + free(bs); + + if(currbs == NULL) + return 1; /* all processed */ + + yy_switch_to_buffer(currbs->bs); + yylineno = currbs->lineno; + currfn = currbs->fn; + return 0; +} diff --git a/grammar/rscript-lex.l b/grammar/rscript-lex.l deleted file mode 100644 index 1c7b963e..00000000 --- a/grammar/rscript-lex.l +++ /dev/null @@ -1,241 +0,0 @@ - /* Lex file for rsyslog config format v2 (RainerScript). - * Please note: this file introduces the new config format, but maintains - * backward compatibility. In order to do so, the grammar is not 100% clean, - * but IMHO still sufficiently easy both to understand for programmers - * maitaining the code as well as users writing the config file. Users are, - * of course, encouraged to use new constructs only. But it needs to be noted - * that some of the legacy constructs (specifically the in-front-of-action - * PRI filter) are very hard to beat in ease of use, at least for simpler - * cases. So while we hope that cfsysline support can be dropped some time in - * the future, we will probably keep these useful constructs. - * - * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH - * Released under the GNU GPL v3. For details see LICENSE file. - */ - -%option noyywrap nodefault case-insensitive yylineno - /*%option noyywrap nodefault case-insensitive */ - -/* avoid compiler warning: `yyunput' defined but not used */ -%option nounput noinput - - -%x INOBJ - /* INOBJ is selected if we are inside an object (name/value pairs!) */ -%x COMMENT - /* COMMENT is "the usual trick" to handle C-style comments */ -%x INCL - /* INCL is in $IncludeConfig processing (skip to include file) */ -%x LINENO - /* LINENO: support for setting the linenumber */ -%x EXPR - /* EXPR is a bit ugly, but we need it to support pre v6-syntax. The problem - * is that cfsysline statement start with $..., the same like variables in - * an expression. However, cfsysline statements can never appear inside an - * expression. So we create a specific expr mode, which is turned on after - * we lexed a keyword that needs to be followed by an expression (using - * knowledge from the upper layer...). In expr mode, we strictly do - * expression-based parsing. Expr mode is stopped when we reach a token - * that can not be part of an expression (currently only "then"). As I - * wrote this ugly, but the price needed to pay in order to remain - * compatible to the previous format. - */ -%{ -#include -#include -#include "utils.h" -#include "rscript.tab.h" -static int preCommentState; /* save for lex state before a comment */ - -struct bufstack { - struct bufstack *prev; - YY_BUFFER_STATE bs; - int lineno; - char *fn; -} *currbs = NULL; - -char *currfn; /* name of currently processed file */ - -int popfile(void); -int cnfSetLexFile(char *fname); -%} - -%% - - /* keywords */ -"if" { BEGIN EXPR; return IF; } -"then" { BEGIN INITIAL; return THEN; } -"or" { return OR; } -"and" { return AND; } -"not" { return NOT; } -"," | -"*" | -"/" | -"%" | -"+" | -"-" | -"(" | -")" { return yytext[0]; } -"==" { return CMP_EQ; } -"<=" { return CMP_LE; } -">=" { return CMP_GE; } -"!=" | -"<>" { return CMP_NE; } -"<" { return CMP_LT; } -">" { return CMP_GT; } -"contains" { return CMP_CONTAINS; } -"contains_i" { return CMP_CONTAINSI; } -"startswith" { return CMP_STARTSWITH; } -"startswith_i" { return CMP_STARTSWITHI; } -0[0-7]+ | /* octal number */ -0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ -([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } -\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } -\'([^'\\]|\\['])*\' { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); - return STRING; } -\"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); - return STRING; } -[ \t\n] -[a-z][a-z0-9_]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); - return FUNC; } -. { printf("invalid char in expr: %s\n", yytext); } -"&" { return '&'; } -"{" { return '{'; } -"}" { return '}'; } -"ruleset" { printf("RULESET\n"); } - /* line number support because the "preprocessor" combines lines and so needs - * to tell us the real source line. - */ -"preprocfilelinenumber(" { BEGIN LINENO; } -[0-9]+ { yylineno = atoi(yytext) - 1; } -")" { BEGIN INITIAL; } -.|\n - /* $IncludeConfig must be detected as part of CFSYSLINE, because this is - * always the longest match :-( - */ -.|\n -[^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) - yyterminate(); - BEGIN INITIAL; } -"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; - BEGIN INOBJ; return BEGINOBJ; } -"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; - BEGIN INOBJ; return BEGINOBJ; } -"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; - BEGIN INOBJ; return BEGINOBJ; } -"action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } -^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { - yylval.s = strdup(yytext); return PROPFILT; } -^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } -"*" | -\-\/[^*][^\n]* | -\/[^*][^\n]* | -:[a-z0-9]+:[^\n]* | -[\|\.\-\@~][^\n]+ | -[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); - // printf("lex: LEGA ACT: '%s'\n", yytext); - return LEGACY_ACTION; } -")" { BEGIN INITIAL; return ENDOBJ; } -[a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); - return NAME; } -"=" { return(yytext[0]); } -\"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { - yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); - return VALUE; } -"/*" { preCommentState = YY_START; BEGIN COMMENT; } -"/*" { preCommentState = YY_START; BEGIN COMMENT; } -"*/" { BEGIN preCommentState; } -([^*]|\n)+|. -#.*$ /* skip comments in input */ -[ \n\t] -. { printf("INOBJ: invalid char '%s'\n", yytext); } -\$[a-z]+.*$ { /* see common on $IncludeConfig above */ - if(!strncasecmp(yytext, "$includeconfig ", 14)) { - yyless(14); - BEGIN INCL; - } else { - yylval.s = strdup(yytext); - return CFSYSLINE; - } - } -![^ \t\n]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } -[+-]\*[ \t\n]*#.*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -[+-]\*[ \t\n]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -\#.*\n /* skip comments in input */ -[\n\t ] /* drop whitespace */ -. { printf("invalid char: %s\n", yytext); - } -<> { if(popfile() != 0) yyterminate(); } - -%% -/* set a new buffers. Returns 0 on success, something else otherwise. */ -int -cnfSetLexFile(char *fname) -{ - es_str_t *str = NULL; - FILE *fp; - int r = 0; - struct bufstack *bs; - - if(fname == NULL) { - fp = stdin; - } else { - if((fp = fopen(fname, "r")) == NULL) { - r = 1; - goto done; - } - } - readConfFile(fp, &str); - if(fp != stdin) - fclose(fp); - - /* maintain stack */ - if((bs = malloc(sizeof(struct bufstack))) == NULL) { - r = 1; - goto done; - } - - if(currbs != NULL) - currbs->lineno = yylineno; - bs->prev = currbs; - bs->fn = strdup(fname); - bs->bs = yy_scan_buffer((char*)es_getBufAddr(str), es_strlen(str)); - currbs = bs; - currfn = bs->fn; - yylineno = 1; - -done: - if(r != 0) { - if(str != NULL) - es_deleteStr(str); - } - return r; -} - - -/* returns 0 on success, something else otherwise */ -int -popfile(void) -{ - struct bufstack *bs = currbs; - - if(bs == NULL) - return 1; - - /* delte current entry */ - yy_delete_buffer(bs->bs); - free(bs->fn); - - /* switch back to previous */ - currbs = bs->prev; - free(bs); - - if(currbs == NULL) - return 1; /* all processed */ - - yy_switch_to_buffer(currbs->bs); - yylineno = currbs->lineno; - currfn = currbs->fn; - return 0; -} diff --git a/grammar/rscript.y b/grammar/rscript.y deleted file mode 100644 index b24b7db7..00000000 --- a/grammar/rscript.y +++ /dev/null @@ -1,164 +0,0 @@ - /* Bison file for rsyslog config format v2 (RainerScript). - * Please note: this file introduces the new config format, but maintains - * backward compatibility. In order to do so, the grammar is not 100% clean, - * but IMHO still sufficiently easy both to understand for programmers - * maitaining the code as well as users writing the config file. Users are, - * of course, encouraged to use new constructs only. But it needs to be noted - * that some of the legacy constructs (specifically the in-front-of-action - * PRI filter) are very hard to beat in ease of use, at least for simpler - * cases. So while we hope that cfsysline support can be dropped some time in - * the future, we will probably keep these useful constructs. - * - * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH - * Released under the GNU GPL v3. For details see LICENSE file. - */ - -%{ -#include -#include -#include "utils.h" -#define YYDEBUG 1 -extern int yylineno; -%} - -%union { - char *s; - long long n; - es_str_t *estr; - enum cnfobjType objType; - struct cnfobj *obj; - struct nvlst *nvlst; - struct cnfactlst *actlst; - struct cnfexpr *expr; - struct cnfrule *rule; - struct cnffunc *func; - struct cnffparamlst *fparams; -} - -%token NAME -%token VALUE -%token FUNC -%token BEGINOBJ -%token ENDOBJ -%token CFSYSLINE -%token BEGIN_ACTION -%token LEGACY_ACTION -%token PRIFILT -%token PROPFILT -%token BSD_TAG_SELECTOR -%token BSD_HOST_SELECTOR -%token IF -%token THEN -%token OR -%token AND -%token NOT -%token VAR -%token STRING -%token NUMBER -%token CMP_EQ -%token CMP_NE -%token CMP_LE -%token CMP_GE -%token CMP_LT -%token CMP_GT -%token CMP_CONTAINS -%token CMP_CONTAINSI -%token CMP_STARTSWITH -%token CMP_STARTSWITHI - -%type nv nvlst -%type obj -%type actlst -%type act -%type cfsysline -%type block -%type expr -%type rule -%type scriptfilt -%type fparams - -%left AND OR -%left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT CMP_CONTAINS CMP_CONTAINSI CMP_STARTSWITH CMP_STARTSWITHI -%left '+' '-' -%left '*' '/' '%' -%nonassoc UMINUS NOT - -%expect 3 -/* these shift/reduce conflicts are created by the CFSYSLINE construct, which we - * unfortunately can not avoid. The problem is that CFSYSLINE can occur both in - * global context as well as within an action. It's not permitted somewhere else, - * but this is suficient for conflicts. The "dangling else" built-in resolution - * works well to solve this issue, so we accept it (it's a wonder that our - * old style grammar doesn't work at all, so we better do not complain...). - * Use "bison -v rscript.y" if more conflicts arise and check rscript.out for - * were exactly these conflicts exits. - */ -%% -/* note: we use left recursion below, because that saves stack space AND - * offers the right sequence so that we can submit the top-layer objects - * one by one. - */ -conf: /* empty (to end recursion) */ - | conf obj { printf("global:config: "); - cnfobjPrint($2); cnfobjDestruct($2); } - | conf rule { printf("global:rule processed\n"); - cnfrulePrint($2); } - | conf cfsysline { printf("global:cfsysline: %s\n", $2); } - | conf BSD_TAG_SELECTOR { printf("global:BSD tag '%s'\n", $2); } - | conf BSD_HOST_SELECTOR { printf("global:BSD host '%s'\n", $2); } - -obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } - | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } -cfsysline: CFSYSLINE { $$ = $1 } -nvlst: { $$ = NULL; } - | nvlst nv { $2->next = $1; $$ = $2; } -nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } -rule: PRIFILT actlst { $$ = cnfruleNew(CNFFILT_PRI, $2); $$->filt.s = $1; } - | PROPFILT actlst { $$ = cnfruleNew(CNFFILT_PROP, $2); $$->filt.s = $1; } - | scriptfilt { $$ = $1; } - -scriptfilt: IF expr THEN actlst { $$ = cnfruleNew(CNFFILT_SCRIPT, $4); - $$->filt.expr = $2; } -block: actlst { $$ = $1; } - | block actlst { $2->next = $1; $$ = $2; } - /* v7: | actlst - v7: | block rule */ /* v7 extensions require new rule engine capabilities! */ -actlst: act { $$=$1; } - | actlst '&' act { $3->next = $1; $$ = $3; } - | actlst cfsysline { $$ = cnfactlstAddSysline($1, $2); } - | '{' block '}' { $$ = $2; } -act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } - | LEGACY_ACTION { $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } -expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } - | expr OR expr { $$ = cnfexprNew(OR, $1, $3); } - | NOT expr { $$ = cnfexprNew(NOT, NULL, $2); } - | expr CMP_EQ expr { $$ = cnfexprNew(CMP_EQ, $1, $3); } - | expr CMP_NE expr { $$ = cnfexprNew(CMP_NE, $1, $3); } - | expr CMP_LE expr { $$ = cnfexprNew(CMP_LE, $1, $3); } - | expr CMP_GE expr { $$ = cnfexprNew(CMP_GE, $1, $3); } - | expr CMP_LT expr { $$ = cnfexprNew(CMP_LT, $1, $3); } - | expr CMP_GT expr { $$ = cnfexprNew(CMP_GT, $1, $3); } - | expr CMP_CONTAINS expr { $$ = cnfexprNew(CMP_CONTAINS, $1, $3); } - | expr CMP_CONTAINSI expr { $$ = cnfexprNew(CMP_CONTAINSI, $1, $3); } - | expr CMP_STARTSWITH expr { $$ = cnfexprNew(CMP_STARTSWITH, $1, $3); } - | expr CMP_STARTSWITHI expr { $$ = cnfexprNew(CMP_STARTSWITHI, $1, $3); } - | expr '+' expr { $$ = cnfexprNew('+', $1, $3); } - | expr '-' expr { $$ = cnfexprNew('-', $1, $3); } - | expr '*' expr { $$ = cnfexprNew('*', $1, $3); } - | expr '/' expr { $$ = cnfexprNew('/', $1, $3); } - | expr '%' expr { $$ = cnfexprNew('%', $1, $3); } - | '(' expr ')' { $$ = $2; } - | '-' expr %prec UMINUS { $$ = cnfexprNew('M', NULL, $2); } - | FUNC '(' ')' { $$ = (struct cnfexpr*) cnffuncNew($1, NULL); } - | FUNC '(' fparams ')' { $$ = (struct cnfexpr*) cnffuncNew($1, $3); } - | NUMBER { $$ = (struct cnfexpr*) cnfnumvalNew($1); } - | STRING { $$ = (struct cnfexpr*) cnfstringvalNew($1); } - | VAR { $$ = (struct cnfexpr*) cnfvarNew($1); } -fparams: expr { $$ = cnffparamlstNew($1, NULL); } - | expr ',' fparams { $$ = cnffparamlstNew($1, $3); } - -%% -int yyerror(char *s) -{ - printf("parse failure on or before line %d: %s\n", yylineno, s); -} diff --git a/grammar/testdriver.c b/grammar/testdriver.c new file mode 100644 index 00000000..e1623829 --- /dev/null +++ b/grammar/testdriver.c @@ -0,0 +1,50 @@ +/* This is a stand-alone test driver for grammar processing. We try to + * keep this separate as it simplyfies grammer development. + * + * Copyright 2011 by Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime 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 3 of the License, or + * (at your option) any later version. + * + * The rsyslog runtime 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ +#include "config.h" +#include +#include +#include +#include "parserif.h" + +void +cstrPrint(char *text, es_str_t *estr) +{ + char *str; + str = es_str2cstr(estr, NULL); + printf("%s%s", text, str); + free(str); +} + + +int +main(int argc, char *argv[]) +{ + int r; + + cnfSetLexFile(argc == 1 ? NULL : argv[1]); + yydebug = 0; + r = yyparse(); + printf("yyparse() returned %d\n", r); + return r; +} diff --git a/grammar/utils.c b/grammar/utils.c index e488ebda..d9bf67aa 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -5,7 +5,7 @@ #include #include "utils.h" #include "parserif.h" -#include "rscript.tab.h" +#include "grammar.h" void readConfFile(FILE *fp, es_str_t **str) @@ -609,29 +609,3 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) } return func; } - -/* debug helper */ -#ifdef STAND_ALONE -void -cstrPrint(char *text, es_str_t *estr) -{ - char *str; - str = es_str2cstr(estr, NULL); - printf("%s%s", text, str); - free(str); -} - - -int -main(int argc, char *argv[]) -{ - int r; - - cnfSetLexFile(argc == 1 ? NULL : argv[1]); - yydebug = 0; - r = yyparse(); - printf("yyparse() returned %d\n", r); - return r; -} -#endif /* #ifdef STAND_ALONE */ - -- cgit v1.2.3 From f8e7c7e3656085bee11b1667f32828dfb4e3df06 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 5 Jul 2011 12:33:48 +0200 Subject: milestone: some plumbing for rsyslog/stand alone parsing --- grammar/grammar.y | 13 +++++---- grammar/lexer.l | 4 +-- grammar/parserif.h | 8 +++--- grammar/testdriver.c | 30 +++++++++++++++++++++ grammar/utils.c | 76 ++++++++++++++++++++++++++-------------------------- 5 files changed, 83 insertions(+), 48 deletions(-) diff --git a/grammar/grammar.y b/grammar/grammar.y index 76881fd1..43e0289a 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -17,6 +17,7 @@ #include #include #include "utils.h" +#include "parserif.h" #define YYDEBUG 1 extern int yylineno; @@ -103,13 +104,13 @@ extern int yyerror(char*); * one by one. */ conf: /* empty (to end recursion) */ - | conf obj { printf("global:config: "); + | conf obj { dbgprintf("global:config: "); cnfobjPrint($2); cnfobjDestruct($2); } - | conf rule { printf("global:rule processed\n"); + | conf rule { dbgprintf("global:rule processed\n"); cnfrulePrint($2); } - | conf cfsysline { printf("global:cfsysline: %s\n", $2); } - | conf BSD_TAG_SELECTOR { printf("global:BSD tag '%s'\n", $2); } - | conf BSD_HOST_SELECTOR { printf("global:BSD host '%s'\n", $2); } + | conf cfsysline { dbgprintf("global:cfsysline: %s\n", $2); } + | conf BSD_TAG_SELECTOR { dbgprintf("global:BSD tag '%s'\n", $2); } + | conf BSD_HOST_SELECTOR { dbgprintf("global:BSD host '%s'\n", $2); } obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } @@ -162,8 +163,10 @@ fparams: expr { $$ = cnffparamlstNew($1, NULL); } | expr ',' fparams { $$ = cnffparamlstNew($1, $3); } %% +/* int yyerror(char *s) { printf("parse failure on or before line %d: %s\n", yylineno, s); return 0; } +*/ diff --git a/grammar/lexer.l b/grammar/lexer.l index 2411be6f..ba432b2e 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -65,7 +65,7 @@ int cnfSetLexFile(char *fname); /* somehow, I need these prototype even though the headers are * included. I guess that's some autotools magic I don't understand... */ -char *strdup(char*); +//char *strdup(char*); int fileno(FILE *stream); %} @@ -209,7 +209,7 @@ cnfSetLexFile(char *fname) if(currbs != NULL) currbs->lineno = yylineno; bs->prev = currbs; - bs->fn = strdup(fname); + bs->fn = strdup(fname == NULL ? "stdin" : fname); bs->bs = yy_scan_buffer((char*)es_getBufAddr(str), es_strlen(str)); currbs = bs; currfn = bs->fn; diff --git a/grammar/parserif.h b/grammar/parserif.h index e22b7d34..b6986dd8 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -1,6 +1,8 @@ #ifndef PARSERIF_H_DEFINED #define PARSERIF_H_DEFINED -extern int cnfSetLexFile(char*); -extern int yyparse(); -extern int yydebug; +int cnfSetLexFile(char*); +int yyparse(); +int yydebug; +void dbgprintf(char *fmt, ...) __attribute__((format(printf, 1, 2))); +void parser_errmsg(char *fmt, ...) __attribute__((format(printf, 1, 2))); #endif diff --git a/grammar/testdriver.c b/grammar/testdriver.c index e1623829..915b5942 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -24,9 +24,39 @@ #include "config.h" #include #include +#include #include #include "parserif.h" +extern int yylineno; + +void +parser_errmsg(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + printf("error on or before line %d: ", yylineno); + vprintf(fmt, ap); + printf("\n"); + va_end(ap); +} + +int +yyerror(char *s) +{ + parser_errmsg("%s", s); + return 0; +} + +void +dbgprintf(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); + va_end(ap); +} + void cstrPrint(char *text, es_str_t *estr) { diff --git a/grammar/utils.c b/grammar/utils.c index d9bf67aa..0812fa6b 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -90,11 +90,11 @@ void nvlstPrint(struct nvlst *lst) { char *name, *value; - printf("nvlst %p:\n", lst); + dbgprintf("nvlst %p:\n", lst); while(lst != NULL) { name = es_str2cstr(lst->name, NULL); value = es_str2cstr(lst->value, NULL); - printf("\tname: '%s', value '%s'\n", name, value); + dbgprintf("\tname: '%s', value '%s'\n", name, value); free(name); free(value); lst = lst->next; @@ -126,7 +126,7 @@ cnfobjDestruct(struct cnfobj *o) void cnfobjPrint(struct cnfobj *o) { - printf("obj: '%s'\n", cnfobjType2str(o->objType)); + dbgprintf("obj: '%s'\n", cnfobjType2str(o->objType)); nvlstPrint(o->nvlst); } @@ -206,7 +206,7 @@ cnfactlstReverse(struct cnfactlst *actlst) prev = NULL; while(actlst != NULL) { - //printf("reversing: %s\n", actlst->data.legActLine); + //dbgprintf("reversing: %s\n", actlst->data.legActLine); curr = actlst; actlst = actlst->next; curr->syslines = cnfcfsyslinelstReverse(curr->syslines); @@ -222,17 +222,17 @@ cnfactlstPrint(struct cnfactlst *actlst) struct cnfcfsyslinelst *cflst; while(actlst != NULL) { - printf("aclst %p: ", actlst); + dbgprintf("aclst %p: ", actlst); if(actlst->actType == CNFACT_V2) { - printf("V2 action type: "); + dbgprintf("V2 action type: "); nvlstPrint(actlst->data.lst); } else { - printf("legacy action line: '%s'\n", + dbgprintf("legacy action line: '%s'\n", actlst->data.legActLine); } for( cflst = actlst->syslines ; cflst != NULL ; cflst = cflst->next) { - printf("action:cfsysline: '%s'\n", cflst->line); + dbgprintf("action:cfsysline: '%s'\n", cflst->line); } actlst = actlst->next; } @@ -266,7 +266,7 @@ static inline long long exprret2Number(struct exprret *r) { if(r->datatype == 'S') { - printf("toNumber CONVERSION MISSING\n"); abort(); + dbgprintf("toNumber CONVERSION MISSING\n"); abort(); } return r->d.n; } @@ -278,7 +278,7 @@ static inline es_str_t * exprret2String(struct exprret *r) { if(r->datatype == 'N') { - printf("toString CONVERSION MISSING\n"); abort(); + dbgprintf("toString CONVERSION MISSING\n"); abort(); } return r->d.estr; } @@ -304,7 +304,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) { struct exprret r, l; /* memory for subexpression results */ - //printf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: COMP_NUM_BINOP(==); @@ -382,7 +382,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) default: ret->datatype = 'N'; ret->d.n = 0ll; - printf("eval error: unknown nodetype %u\n", + dbgprintf("eval error: unknown nodetype %u\n", (unsigned) expr->nodetype); break; } @@ -393,108 +393,108 @@ doIndent(int indent) { int i; for(i = 0 ; i < indent ; ++i) - printf(" "); + dbgprintf(" "); } void cnfexprPrint(struct cnfexpr *expr, int indent) { struct cnffparamlst *param; - //printf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); + //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("==\n"); + dbgprintf("==\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_NE: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("!=\n"); + dbgprintf("!=\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_LE: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("<=\n"); + dbgprintf("<=\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_GE: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf(">=\n"); + dbgprintf(">=\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_LT: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("<\n"); + dbgprintf("<\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_GT: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf(">\n"); + dbgprintf(">\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_CONTAINS: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("CONTAINS\n"); + dbgprintf("CONTAINS\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_CONTAINSI: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("CONTAINS_I\n"); + dbgprintf("CONTAINS_I\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_STARTSWITH: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("STARTSWITH\n"); + dbgprintf("STARTSWITH\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_STARTSWITHI: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("STARTSWITH_I\n"); + dbgprintf("STARTSWITH_I\n"); cnfexprPrint(expr->r, indent+1); break; case OR: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("OR\n"); + dbgprintf("OR\n"); cnfexprPrint(expr->r, indent+1); break; case AND: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("AND\n"); + dbgprintf("AND\n"); cnfexprPrint(expr->r, indent+1); break; case NOT: doIndent(indent); - printf("NOT\n"); + dbgprintf("NOT\n"); cnfexprPrint(expr->r, indent+1); break; case 'S': doIndent(indent); cstrPrint("string '", ((struct cnfstringval*)expr)->estr); - printf("'\n"); + dbgprintf("'\n"); break; case 'N': doIndent(indent); - printf("%lld\n", ((struct cnfnumval*)expr)->val); + dbgprintf("%lld\n", ((struct cnfnumval*)expr)->val); break; case 'V': doIndent(indent); - printf("var '%s'\n", ((struct cnfvar*)expr)->name); + dbgprintf("var '%s'\n", ((struct cnfvar*)expr)->name); break; case 'F': doIndent(indent); cstrPrint("function '", ((struct cnffunc*)expr)->fname); - printf("'\n"); + dbgprintf("'\n"); for( param = ((struct cnffunc*)expr)->paramlst ; param != NULL ; param = param->next) { @@ -510,11 +510,11 @@ cnfexprPrint(struct cnfexpr *expr, int indent) if(expr->l != NULL) cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("%c\n", (char) expr->nodetype); + dbgprintf("%c\n", (char) expr->nodetype); cnfexprPrint(expr->r, indent+1); break; default: - printf("error: unknown nodetype %u\n", + dbgprintf("error: unknown nodetype %u\n", (unsigned) expr->nodetype); break; } @@ -568,22 +568,22 @@ cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) void cnfrulePrint(struct cnfrule *rule) { - printf("------ start rule %p:\n", rule); - printf("%s: ", cnfFiltType2str(rule->filttype)); + dbgprintf("------ start rule %p:\n", rule); + dbgprintf("%s: ", cnfFiltType2str(rule->filttype)); switch(rule->filttype) { case CNFFILT_NONE: break; case CNFFILT_PRI: case CNFFILT_PROP: - printf("%s\n", rule->filt.s); + dbgprintf("%s\n", rule->filt.s); break; case CNFFILT_SCRIPT: - printf("\n"); + dbgprintf("\n"); cnfexprPrint(rule->filt.expr, 0); break; } cnfactlstPrint(rule->actlst); - printf("------ end rule %p\n", rule); + dbgprintf("------ end rule %p\n", rule); } struct cnffparamlst * -- cgit v1.2.3 From 2081c264a3b3219ed4756e548ec9b122fae9328c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 6 Jul 2011 10:05:29 +0200 Subject: milestone: abstracted parser interface ... so that both testdriver and other callers (rsyslog!) can use it without changing the parser (this simplifies development). --- grammar/grammar.y | 13 +++++-------- grammar/parserif.h | 10 ++++++++++ grammar/testdriver.c | 30 +++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/grammar/grammar.y b/grammar/grammar.y index 43e0289a..428011c5 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -104,14 +104,11 @@ extern int yyerror(char*); * one by one. */ conf: /* empty (to end recursion) */ - | conf obj { dbgprintf("global:config: "); - cnfobjPrint($2); cnfobjDestruct($2); } - | conf rule { dbgprintf("global:rule processed\n"); - cnfrulePrint($2); } - | conf cfsysline { dbgprintf("global:cfsysline: %s\n", $2); } - | conf BSD_TAG_SELECTOR { dbgprintf("global:BSD tag '%s'\n", $2); } - | conf BSD_HOST_SELECTOR { dbgprintf("global:BSD host '%s'\n", $2); } - + | conf obj { cnfDoObj($2); } + | conf rule { cnfDoRule($2); } + | conf cfsysline { cnfDoCfsysline($2); } + | conf BSD_TAG_SELECTOR { cnfDoBSDTag($2); } + | conf BSD_HOST_SELECTOR { cnfDoBSDHost($2); } obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } cfsysline: CFSYSLINE { $$ = $1; } diff --git a/grammar/parserif.h b/grammar/parserif.h index b6986dd8..c88114c9 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -5,4 +5,14 @@ int yyparse(); int yydebug; void dbgprintf(char *fmt, ...) __attribute__((format(printf, 1, 2))); void parser_errmsg(char *fmt, ...) __attribute__((format(printf, 1, 2))); + +/* entry points to be called after the parser has processed the + * element in question. Actual processing must than be done inside + * these functions. + */ +void cnfDoObj(struct cnfobj *o); +void cnfDoRule(struct cnfrule *rule); +void cnfDoCfsysline(char *ln); +void cnfDoBSDTag(char *ln); +void cnfDoBSDHost(char *ln); #endif diff --git a/grammar/testdriver.c b/grammar/testdriver.c index 915b5942..9899dbd1 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -26,6 +26,7 @@ #include #include #include +#include "utils.h" #include "parserif.h" extern int yylineno; @@ -57,6 +58,34 @@ dbgprintf(char *fmt, ...) va_end(ap); } +void cnfDoObj(struct cnfobj *o) +{ + dbgprintf("global:obj: "); + cnfobjPrint(o); + cnfobjDestruct(o); +} + +void cnfDoRule(struct cnfrule *rule) +{ + dbgprintf("global:rule processed\n"); + cnfrulePrint(rule); +} + +void cnfDoCfsysline(char *ln) +{ + dbgprintf("global:cfsysline: %s\n", ln); +} + +void cnfDoBSDTag(char *ln) +{ + dbgprintf("global:BSD tag: %s\n", ln); +} + +void cnfDoBSDHost(char *ln) +{ + dbgprintf("global:BSD host: %s\n", ln); +} + void cstrPrint(char *text, es_str_t *estr) { @@ -66,7 +95,6 @@ cstrPrint(char *text, es_str_t *estr) free(str); } - int main(int argc, char *argv[]) { -- cgit v1.2.3 From 4fcfea31e3c46d27c5a54a8d1d9925e59550f82c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 6 Jul 2011 11:32:54 +0200 Subject: milestone/[NONWORKING]: first integration of new parser, rules are not yet handled --- configure.ac | 4 +- grammar/parserif.h | 1 + grammar/testdriver.c | 9 ----- grammar/utils.c | 9 +++++ runtime/Makefile.am | 2 +- runtime/rsconf.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++ tools/Makefile.am | 2 +- 7 files changed, 120 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index 1a239ca4..4f9113bd 100644 --- a/configure.ac +++ b/configure.ac @@ -707,9 +707,9 @@ AC_ARG_ENABLE(rsyslogrt, [enable_rsyslogrt=yes] ) if test "x$enable_rsyslogrt" = "xyes"; then - RSRT_CFLAGS="-I\$(top_srcdir)/runtime -I\$(top_srcdir)" + RSRT_CFLAGS="-I\$(top_srcdir)/runtime -I\$(top_srcdir) -I\$(top_srcdir)/grammar" RSRT_LIBS="\$(top_builddir)/runtime/librsyslog.la" - CNF_LIBS="\$(top_builddir)/grammar/libgrammar.la" + #??CNF_LIBS="\$(top_builddir)/grammar/libgrammar.la" fi AM_CONDITIONAL(ENABLE_RSYSLOGRT, test x$enable_rsyslogrt = xyes) AC_SUBST(RSRT_CFLAGS) diff --git a/grammar/parserif.h b/grammar/parserif.h index c88114c9..0a6434d3 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -1,5 +1,6 @@ #ifndef PARSERIF_H_DEFINED #define PARSERIF_H_DEFINED +#include "utils.h" int cnfSetLexFile(char*); int yyparse(); int yydebug; diff --git a/grammar/testdriver.c b/grammar/testdriver.c index 9899dbd1..43f3bd3f 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -86,15 +86,6 @@ void cnfDoBSDHost(char *ln) dbgprintf("global:BSD host: %s\n", ln); } -void -cstrPrint(char *text, es_str_t *estr) -{ - char *str; - str = es_str2cstr(estr, NULL); - printf("%s%s", text, str); - free(str); -} - int main(int argc, char *argv[]) { diff --git a/grammar/utils.c b/grammar/utils.c index 0812fa6b..f49af9b0 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -609,3 +609,12 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) } return func; } + +void +cstrPrint(char *text, es_str_t *estr) +{ + char *str; + str = es_str2cstr(estr, NULL); + dbgprintf("%s%s", text, str); + free(str); +} diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 232d8f03..7c3d18ef 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -117,7 +117,7 @@ librsyslog_la_SOURCES = \ if WITH_MODDIRS librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools else -librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools +librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools -I\$(top_srcdir)/grammar endif #librsyslog_la_LDFLAGS = -module -avoid-version librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS) $(LIBEE_LIBS) diff --git a/runtime/rsconf.c b/runtime/rsconf.c index cb76e6da..446a9c8b 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ #include "parser.h" #include "outchannel.h" #include "threads.h" +#include "parserif.h" #include "dirty.h" /* static data */ @@ -92,6 +94,7 @@ static uchar template_StdPgSQLFmt[] = "\"insert into SystemEvents (Message, Faci static uchar template_spoofadr[] = "\"%fromhost-ip%\""; /* end templates */ +void cnfDoCfsysline(char *ln); /* Standard-Constructor */ @@ -212,6 +215,102 @@ CODESTARTobjDebugPrint(rsconf) ENDobjDebugPrint(rsconf) +rsRetVal +cnfDoActlst(struct cnfactlst *actlst) +{ + struct cnfcfsyslinelst *cflst; + rsRetVal localRet; + DEFiRet; + + while(actlst != NULL) { + dbgprintf("aclst %p: ", actlst); + if(actlst->actType == CNFACT_V2) { + dbgprintf("V2 action type not yet handled\n"); + } else { + dbgprintf("legacy action line not yet handled:%s\n", + actlst->data.legActLine); + } + for( cflst = actlst->syslines + ; cflst != NULL ; cflst = cflst->next) { + cnfDoCfsysline(cflst->line); + } + actlst = actlst->next; + } + RETiRet; +} + + +/*------------------------------ interface to flex/bison parser ------------------------------*/ +extern int yylineno; + +void +parser_errmsg(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + // TODO: create useful code ;) 2011-07-06 + dbgprintf("error on or before line %d: ", yylineno); + vprintf(fmt, ap); + printf("\n"); + va_end(ap); +} + +int +yyerror(char *s) +{ + parser_errmsg("%s", s); + return 0; +} +void cnfDoObj(struct cnfobj *o) +{ + dbgprintf("cnf:global:obj: "); + cnfobjPrint(o); + cnfobjDestruct(o); +} + +void cnfDoRule(struct cnfrule *rule) +{ + dbgprintf("cnf:global:rule\n"); + cnfrulePrint(rule); + + switch(rule->filttype) { + case CNFFILT_NONE: + break; + case CNFFILT_PRI: + case CNFFILT_PROP: + dbgprintf("%s\n", rule->filt.s); + break; + case CNFFILT_SCRIPT: + dbgprintf("\n"); + cnfexprPrint(rule->filt.expr, 0); + break; + } + cnfDoActlst(rule->actlst); +} + +void cnfDoCfsysline(char *ln) +{ + dbgprintf("cnf:global:cfsysline: %s\n", ln); + /* the legacy system needs the "$" stripped */ + conf.cfsysline(loadConf, (uchar*) ln+1); + dbgprintf("cnf:cfsysline call done\n"); +} + +void cnfDoBSDTag(char *ln) +{ + dbgprintf("cnf:global:BSD tag: %s\n", ln); + cflineProcessTagSelector(conf, &line); +} + +void cnfDoBSDHost(char *ln) +{ + dbgprintf("cnf:global:BSD host: %s\n", ln); + cflineProcessHostSelector(conf, &line); +} +/*------------------------------ end interface to flex/bison parser ------------------------------*/ + + + /* drop to specified group * if something goes wrong, the function never returns * Note that such an abort can cause damage to on-disk structures, so we should @@ -994,6 +1093,7 @@ load(rsconf_t **cnf, uchar *confFile) int iNbrActions; int bHadConfigErr = 0; char cbuf[BUFSIZ]; + int r; DEFiRet; CHKiRet(rsconfConstruct(&loadConf)); @@ -1003,6 +1103,12 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! CHKiRet(initLegacyConf()); /* open the configuration file */ + dbgprintf("ZZZZZ: calling cnfSetLexFile(%s)\n", confFile); + r = cnfSetLexFile((char*)confFile); + dbgprintf("ZZZZZ: cnfSetLexFile returns %d, calling yyparse()\n", r); + r = yyparse(); + dbgprintf("ZZZZZ: yyparse returns %d\n", r); + exit(1); localRet = conf.processConfFile(loadConf, confFile); CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions)); diff --git a/tools/Makefile.am b/tools/Makefile.am index f3b176f2..1bed5ae8 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -36,7 +36,7 @@ rsyslogd_SOURCES = \ \ ../dirty.h rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) $(CNF_LIBS) -rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) +rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) $(CNF_LIBS) ../grammar/libgrammar.la rsyslogd_LDFLAGS = -export-dynamic if ENABLE_DIAGTOOLS -- cgit v1.2.3 From 30f2b5b094d282af6f601aa4e8fa88c1baf187f4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 6 Jul 2011 12:26:52 +0200 Subject: milestone:/[PARTWORK]: config is processed using new parser, except... ... for "if" filters (more work to come, probably lots of more work... ;)) --- runtime/conf.c | 31 ++++++++++++------------- runtime/conf.h | 13 +++++++++-- runtime/rsconf.c | 70 ++++++++++++++++++++++++++++++++++++++++++++------------ tools/syslogd.c | 2 +- 4 files changed, 82 insertions(+), 34 deletions(-) diff --git a/runtime/conf.c b/runtime/conf.c index 6a2e57fa..5eb1aae2 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -354,7 +354,7 @@ finalize_it: * 2004-11-17 rgerhards */ rsRetVal -cfsysline(rsconf_t *conf, uchar *p) +cfsysline(uchar *p) { DEFiRet; uchar szCmd[64]; @@ -602,7 +602,7 @@ cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int * rgerhards 2005-09-15 */ /* GPLv3 - stems back to sysklogd */ -static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) +rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) { uchar *p; register uchar *q; @@ -619,7 +619,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule ASSERT(*pline != NULL); ISOBJ_TYPE_assert(pRule, rule); - dbgprintf(" - traditional PRI filter\n"); + dbgprintf(" - traditional PRI filter '%s'\n", *pline); errno = 0; /* keep strerror_r() stuff out of logerror messages */ pRule->f_filter_type = FILTER_PRI; @@ -632,7 +632,6 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule /* scan through the list of selectors */ for (p = *pline; *p && *p != '\t' && *p != ' ';) { - /* find the end of this facility name list */ for (q = p; *q && *q != '\t' && *q++ != '.'; ) continue; @@ -643,8 +642,10 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule *bp = '\0'; /* skip cruft */ - while (strchr(",;", *q)) - q++; + if(*q) { + while (strchr(",;", *q)) + q++; + } /* decode priority name */ if ( *buf == '!' ) { @@ -836,7 +837,7 @@ finalize_it: * of the action part. A pointer to that beginnig is passed back to the caller. * rgerhards 2005-09-15 */ -static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) +rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) { rsParsObj *pPars; cstr_t *pCSCompOp; @@ -848,7 +849,7 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) ASSERT(*pline != NULL); ASSERT(f != NULL); - dbgprintf(" - property-based filter\n"); + dbgprintf(" - property-based filter '%s'\n", *pline); errno = 0; /* keep strerror_r() stuff out of logerror messages */ f->f_filter_type = FILTER_PROP; @@ -908,7 +909,6 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) iOffset = 0; } -dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSCompOp)); if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) { f->f_filterData.prop.operation = FIOP_CONTAINS; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) { @@ -927,7 +927,6 @@ dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSC } rsCStrDestruct(&pCSCompOp); /* no longer needed */ -dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); if(f->f_filterData.prop.operation != FIOP_ISEMPTY) { /* read compare value */ iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue); @@ -958,7 +957,7 @@ dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); * from the config file ("+/-hostname"). It stores it for further reference. * rgerhards 2005-10-19 */ -static rsRetVal cflineProcessHostSelector(rsconf_t *conf, uchar **pline) +rsRetVal cflineProcessHostSelector(uchar **pline) { DEFiRet; @@ -1008,7 +1007,7 @@ finalize_it: * from the config file ("!tagname"). It stores it for further reference. * rgerhards 2005-10-18 */ -static rsRetVal cflineProcessTagSelector(rsconf_t *conf, uchar **pline) +rsRetVal cflineProcessTagSelector(uchar **pline) { DEFiRet; @@ -1093,7 +1092,7 @@ finalize_it: /* process the action part of a selector line * rgerhards, 2007-08-01 */ -static rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) +rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) { modInfo_t *pMod; cfgmodules_etry_t *node; @@ -1214,15 +1213,15 @@ cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr) /* check type of line and call respective processing */ switch(*line) { case '!': - iRet = cflineProcessTagSelector(conf, &line); + iRet = cflineProcessTagSelector(&line); break; case '+': case '-': - iRet = cflineProcessHostSelector(conf, &line); + iRet = cflineProcessHostSelector(&line); break; case '$': ++line; /* eat '$' */ - iRet = cfsysline(conf, line); + iRet = cfsysline(line); break; default: iRet = cflineClassic(conf, line, pfCurr); diff --git a/runtime/conf.h b/runtime/conf.h index 096af630..28ccdde1 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -21,6 +21,7 @@ */ #ifndef INCLUDED_CONF_H #define INCLUDED_CONF_H +#include "action.h" /* definitions used for doNameLine to differentiate between different command types * (with otherwise identical code). This is a left-over from the previous config @@ -34,7 +35,7 @@ extern int bConfStrictScoping; /* force strict scoping during config processing? /* interfaces */ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ rsRetVal (*doNameLine)(uchar **pp, void* pVal); - rsRetVal (*cfsysline)(rsconf_t *conf, uchar *p); + rsRetVal (*cfsysline)(uchar *p); rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); rsRetVal (*doIncludeLine)(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal); rsRetVal (*cfline)(rsconf_t *conf, uchar *line, rule_t **pfCurr); @@ -48,8 +49,10 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ */ /* version 5 -- 2011-04-19 rgerhards */ /* complete revamp, we now use the rsconf object */ + /* version 6 -- 2011-07-06 rgerhards */ + /* again a complete revamp, using flex/bison based parser now */ ENDinterface(conf) -#define confCURR_IF_VERSION 5 /* increment whenever you change the interface structure! */ +#define confCURR_IF_VERSION 6 /* increment whenever you change the interface structure! */ /* in Version 3, entry point "ReInitConf()" was removed, as we do not longer need * to support restart-type HUP -- rgerhards, 2009-07-15 */ @@ -63,5 +66,11 @@ PROTOTYPEObj(conf); rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName); rsRetVal cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *pszTpl); +/* more dirt to cover the new config interface (will go away...) */ +rsRetVal cflineProcessTagSelector(uchar **pline); +rsRetVal cflineProcessHostSelector(uchar **pline); +rsRetVal cflineProcessTradPRIFilter(uchar **pline, rule_t *pRule); +rsRetVal cflineProcessPropFilter(uchar **pline, rule_t *f); +rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction); #endif /* #ifndef INCLUDED_CONF_H */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 446a9c8b..17332464 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -39,6 +39,7 @@ #include "rsyslog.h" #include "obj.h" #include "srUtils.h" +#include "rule.h" #include "ruleset.h" #include "modules.h" #include "conf.h" @@ -69,6 +70,7 @@ /* static data */ DEFobjStaticHelpers +DEFobjCurrIf(rule) DEFobjCurrIf(ruleset) DEFobjCurrIf(module) DEFobjCurrIf(conf) @@ -216,10 +218,12 @@ ENDobjDebugPrint(rsconf) rsRetVal -cnfDoActlst(struct cnfactlst *actlst) +cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) { struct cnfcfsyslinelst *cflst; + action_t *pAction; rsRetVal localRet; + uchar *str; DEFiRet; while(actlst != NULL) { @@ -227,8 +231,10 @@ cnfDoActlst(struct cnfactlst *actlst) if(actlst->actType == CNFACT_V2) { dbgprintf("V2 action type not yet handled\n"); } else { - dbgprintf("legacy action line not yet handled:%s\n", - actlst->data.legActLine); + dbgprintf("legacy action line:%s\n", actlst->data.legActLine); + str = (uchar*) actlst->data.legActLine; + iRet = cflineDoAction(loadConf, &str, &pAction); + iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction); } for( cflst = actlst->syslines ; cflst != NULL ; cflst = cflst->next) { @@ -268,44 +274,77 @@ void cnfDoObj(struct cnfobj *o) cnfobjDestruct(o); } -void cnfDoRule(struct cnfrule *rule) +void cnfDoRule(struct cnfrule *cnfrule) { + rule_t *pRule; + uchar *str; + DEFiRet; + dbgprintf("cnf:global:rule\n"); - cnfrulePrint(rule); + cnfrulePrint(cnfrule); - switch(rule->filttype) { + CHKiRet(rule.Construct(&pRule)); /* create "fresh" selector */ + CHKiRet(rule.SetAssRuleset(pRule, ruleset.GetCurrent(loadConf))); /* create "fresh" selector */ + CHKiRet(rule.ConstructFinalize(pRule)); /* create "fresh" selector */ + + switch(cnfrule->filttype) { case CNFFILT_NONE: break; case CNFFILT_PRI: + str = (uchar*) cnfrule->filt.s; + iRet = cflineProcessTradPRIFilter(&str, pRule); + break; case CNFFILT_PROP: - dbgprintf("%s\n", rule->filt.s); + dbgprintf("%s\n", cnfrule->filt.s); + str = (uchar*) cnfrule->filt.s; + iRet = cflineProcessPropFilter(&str, pRule); break; case CNFFILT_SCRIPT: - dbgprintf("\n"); - cnfexprPrint(rule->filt.expr, 0); + dbgprintf("TODO: script filter implementation missing\n"); + cnfexprPrint(cnfrule->filt.expr, 0); break; } - cnfDoActlst(rule->actlst); + /* we now check if there are some global (BSD-style) filter conditions + * and, if so, we copy them over. rgerhards, 2005-10-18 + */ +#if 0 // TODO: add LATER! + if(pDfltProgNameCmp != NULL) { + CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp)); + } + + if(eDfltHostnameCmpMode != HN_NO_COMP) { + f->eHostnameCmpMode = eDfltHostnameCmpMode; + CHKiRet(rsCStrConstructFromCStr(&(f->pCSHostnameComp), pDfltHostnameCmp)); + } +#endif + + cnfDoActlst(cnfrule->actlst, pRule); + + CHKiRet(ruleset.AddRule(loadConf, rule.GetAssRuleset(pRule), &pRule)); + +finalize_it: + //TODO: do something with error states + ; } void cnfDoCfsysline(char *ln) { dbgprintf("cnf:global:cfsysline: %s\n", ln); /* the legacy system needs the "$" stripped */ - conf.cfsysline(loadConf, (uchar*) ln+1); + conf.cfsysline((uchar*) ln+1); dbgprintf("cnf:cfsysline call done\n"); } void cnfDoBSDTag(char *ln) { dbgprintf("cnf:global:BSD tag: %s\n", ln); - cflineProcessTagSelector(conf, &line); + cflineProcessTagSelector((uchar**)&ln); } void cnfDoBSDHost(char *ln) { dbgprintf("cnf:global:BSD host: %s\n", ln); - cflineProcessHostSelector(conf, &line); + cflineProcessHostSelector((uchar**)&ln); } /*------------------------------ end interface to flex/bison parser ------------------------------*/ @@ -1108,8 +1147,7 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! dbgprintf("ZZZZZ: cnfSetLexFile returns %d, calling yyparse()\n", r); r = yyparse(); dbgprintf("ZZZZZ: yyparse returns %d\n", r); - exit(1); - localRet = conf.processConfFile(loadConf, confFile); + //localRet = conf.processConfFile(loadConf, confFile); CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions)); if(localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) { @@ -1208,6 +1246,7 @@ ENDobjQueryInterface(rsconf) BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ CHKiRet(objUse(ruleset, CORE_COMPONENT)); + CHKiRet(objUse(rule, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); CHKiRet(objUse(conf, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); @@ -1223,6 +1262,7 @@ ENDObjClassInit(rsconf) /* De-initialize the rsconf class. */ BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */ + objRelease(rule, CORE_COMPONENT); objRelease(ruleset, CORE_COMPONENT); objRelease(module, CORE_COMPONENT); objRelease(conf, CORE_COMPONENT); diff --git a/tools/syslogd.c b/tools/syslogd.c index 6dbd4be5..79bf0c8a 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -802,7 +802,7 @@ void legacyOptsHook(void) errno = 0; errmsg.LogError(0, NO_ERRCODE, "Warning: backward compatibility layer added to following " "directive to rsyslog.conf: %s", pThis->line); - conf.cfsysline(ourConf, pThis->line); + conf.cfsysline(pThis->line); } pThis = pThis->next; } -- cgit v1.2.3 From 5710b413963d2fde9d062127ed72672b8a58a07e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 7 Jul 2011 08:22:40 +0200 Subject: milestone/[PARTWORK]: integrted script filter, but var access is missing --- grammar/Makefile.am | 4 +- grammar/grammar.y | 24 +- grammar/lexer.l | 23 +- grammar/parserif.h | 2 +- grammar/rainerscript.c | 658 +++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rainerscript.h | 176 +++++++++++++ grammar/testdriver.c | 2 +- grammar/utils.c | 620 ---------------------------------------------- grammar/utils.h | 174 ------------- runtime/conf.c | 10 +- runtime/conf.h | 3 + runtime/rsconf.c | 20 +- runtime/rule.c | 8 +- runtime/rule.h | 6 +- 14 files changed, 909 insertions(+), 821 deletions(-) create mode 100644 grammar/rainerscript.c create mode 100644 grammar/rainerscript.h delete mode 100644 grammar/utils.c delete mode 100644 grammar/utils.h diff --git a/grammar/Makefile.am b/grammar/Makefile.am index b482c99e..2b149abe 100644 --- a/grammar/Makefile.am +++ b/grammar/Makefile.am @@ -7,8 +7,8 @@ bin_PROGRAMS = testdriver # TODO: make this conditional libgrammar_la_SOURCES = \ grammar.y \ lexer.l \ - utils.c \ - utils.h \ + rainerscript.c \ + rainerscript.h \ grammar.h testdriver_SOURCES = testdriver.c libgrammar.la diff --git a/grammar/grammar.y b/grammar/grammar.y index 428011c5..b8790411 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -9,14 +9,30 @@ * cases. So while we hope that cfsysline support can be dropped some time in * the future, we will probably keep these useful constructs. * - * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH - * Released under the GNU GPL v3. For details see LICENSE file. + * Copyright 2011 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime 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 3 of the License, or + * (at your option) any later version. + * + * The rsyslog runtime 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. */ - %{ #include #include -#include "utils.h" +#include "rainerscript.h" #include "parserif.h" #define YYDEBUG 1 extern int yylineno; diff --git a/grammar/lexer.l b/grammar/lexer.l index ba432b2e..d761003a 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -9,8 +9,25 @@ * cases. So while we hope that cfsysline support can be dropped some time in * the future, we will probably keep these useful constructs. * - * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH - * Released under the GNU GPL v3. For details see LICENSE file. + * Copyright 2011 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime 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 3 of the License, or + * (at your option) any later version. + * + * The rsyslog runtime 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. */ %option noyywrap nodefault case-insensitive yylineno @@ -46,7 +63,7 @@ #include #include #include -#include "utils.h" +#include "rainerscript.h" #include "grammar.h" static int preCommentState; /* save for lex state before a comment */ diff --git a/grammar/parserif.h b/grammar/parserif.h index 0a6434d3..a04abb0c 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -1,6 +1,6 @@ #ifndef PARSERIF_H_DEFINED #define PARSERIF_H_DEFINED -#include "utils.h" +#include "rainerscript.h" int cnfSetLexFile(char*); int yyparse(); int yydebug; diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c new file mode 100644 index 00000000..801a52b2 --- /dev/null +++ b/grammar/rainerscript.c @@ -0,0 +1,658 @@ +/* rainerscript.c - routines to support RainerScript config language + * + * Module begun 2011-07-01 by Rainer Gerhards + * + * Copyright 2011 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime 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 3 of the License, or + * (at your option) any later version. + * + * The rsyslog runtime 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include "rainerscript.h" +#include "parserif.h" +#include "grammar.h" + +void +readConfFile(FILE *fp, es_str_t **str) +{ + char ln[10240]; + char buf[512]; + int lenBuf; + int bWriteLineno = 0; + int len, i; + int start; /* start index of to be submitted text */ + int bContLine = 0; + int lineno = 0; + + *str = es_newStr(4096); + + while(fgets(ln, sizeof(ln), fp) != NULL) { + ++lineno; + if(bWriteLineno) { + bWriteLineno = 0; + lenBuf = sprintf(buf, "PreprocFileLineNumber(%d)\n", lineno); + es_addBuf(str, buf, lenBuf); + } + len = strlen(ln); + /* if we are continuation line, we need to drop leading WS */ + if(bContLine) { + for(start = 0 ; start < len && isspace(ln[start]) ; ++start) + /* JUST SCAN */; + } else { + start = 0; + } + for(i = len - 1 ; i >= start && isspace(ln[i]) ; --i) + /* JUST SCAN */; + if(i >= 0) { + if(ln[i] == '\\') { + --i; + bContLine = 1; + } else { + if(bContLine) /* write line number if we had cont line */ + bWriteLineno = 1; + bContLine = 0; + } + /* add relevant data to buffer */ + es_addBuf(str, ln+start, i+1 - start); + } + if(!bContLine) + es_addChar(str, '\n'); + } + /* indicate end of buffer to flex */ + es_addChar(str, '\0'); + es_addChar(str, '\0'); +} + +struct nvlst* +nvlstNew(es_str_t *name, es_str_t *value) +{ + struct nvlst *lst; + + if((lst = malloc(sizeof(struct nvlst))) != NULL) { + lst->next = NULL; + lst->name = name; + lst->value = value; + } + + return lst; +} + +void +nvlstDestruct(struct nvlst *lst) +{ + struct nvlst *toDel; + + while(lst != NULL) { + toDel = lst; + lst = lst->next; + es_deleteStr(toDel->name); + es_deleteStr(toDel->value); + free(toDel); + } +} + +void +nvlstPrint(struct nvlst *lst) +{ + char *name, *value; + dbgprintf("nvlst %p:\n", lst); + while(lst != NULL) { + name = es_str2cstr(lst->name, NULL); + value = es_str2cstr(lst->value, NULL); + dbgprintf("\tname: '%s', value '%s'\n", name, value); + free(name); + free(value); + lst = lst->next; + } +} + +struct cnfobj* +cnfobjNew(enum cnfobjType objType, struct nvlst *lst) +{ + struct cnfobj *o; + + if((o = malloc(sizeof(struct nvlst))) != NULL) { + o->objType = objType; + o->nvlst = lst; + } + + return o; +} + +void +cnfobjDestruct(struct cnfobj *o) +{ + if(o != NULL) { + nvlstDestruct(o->nvlst); + free(o); + } +} + +void +cnfobjPrint(struct cnfobj *o) +{ + dbgprintf("obj: '%s'\n", cnfobjType2str(o->objType)); + nvlstPrint(o->nvlst); +} + + +struct cnfactlst* +cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine) +{ + struct cnfactlst *actlst; + + if((actlst = malloc(sizeof(struct cnfactlst))) != NULL) { + actlst->next = NULL; + actlst->syslines = NULL; + actlst->actType = actType; + if(actType == CNFACT_V2) + actlst->data.lst = lst; + else + actlst->data.legActLine = actLine; + } + return actlst; +} + +struct cnfactlst* +cnfactlstAddSysline(struct cnfactlst* actlst, char *line) +{ + struct cnfcfsyslinelst *cflst; + + if((cflst = malloc(sizeof(struct cnfcfsyslinelst))) != NULL) { + cflst->next = NULL; + cflst->line = line; + if(actlst->syslines == NULL) { + actlst->syslines = cflst; + } else { + cflst->next = actlst->syslines; + actlst->syslines = cflst; + } + } + return actlst; +} + +void +cnfactlstDestruct(struct cnfactlst *actlst) +{ + struct cnfactlst *toDel; + + while(actlst != NULL) { + toDel = actlst; + actlst = actlst->next; + if(toDel->actType == CNFACT_V2) + nvlstDestruct(toDel->data.lst); + else + free(toDel->data.legActLine); + free(toDel); + } + +} + +static inline struct cnfcfsyslinelst* +cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) +{ + struct cnfcfsyslinelst *curr, *prev; + if(lst == NULL) + return NULL; + prev = NULL; + while(lst != NULL) { + curr = lst; + lst = lst->next; + curr->next = prev; + prev = curr; + } + return prev; +} + +struct cnfactlst* +cnfactlstReverse(struct cnfactlst *actlst) +{ + struct cnfactlst *curr, *prev; + + prev = NULL; + while(actlst != NULL) { + //dbgprintf("reversing: %s\n", actlst->data.legActLine); + curr = actlst; + actlst = actlst->next; + curr->syslines = cnfcfsyslinelstReverse(curr->syslines); + curr->next = prev; + prev = curr; + } + return prev; +} + +void +cnfactlstPrint(struct cnfactlst *actlst) +{ + struct cnfcfsyslinelst *cflst; + + while(actlst != NULL) { + dbgprintf("aclst %p: ", actlst); + if(actlst->actType == CNFACT_V2) { + dbgprintf("V2 action type: "); + nvlstPrint(actlst->data.lst); + } else { + dbgprintf("legacy action line: '%s'\n", + actlst->data.legActLine); + } + for( cflst = actlst->syslines + ; cflst != NULL ; cflst = cflst->next) { + dbgprintf("action:cfsysline: '%s'\n", cflst->line); + } + actlst = actlst->next; + } +} + +struct cnfexpr* +cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r) +{ + struct cnfexpr *expr; + + /* optimize some constructs during parsing */ + if(nodetype == 'M' && r->nodetype == 'N') { + ((struct cnfnumval*)r)->val *= -1; + expr = r; + goto done; + } + + if((expr = malloc(sizeof(struct cnfexpr))) != NULL) { + expr->nodetype = nodetype; + expr->l = l; + expr->r = r; + } +done: + return expr; +} + +/* ensure that retval is a number; if string is no number, + * emit error message and set number to 0. + */ +static inline long long +exprret2Number(struct exprret *r) +{ + if(r->datatype == 'S') { + dbgprintf("toNumber CONVERSION MISSING\n"); abort(); + } + return r->d.n; +} + +/* ensure that retval is a string; if string is no number, + * emit error message and set number to 0. + */ +static inline es_str_t * +exprret2String(struct exprret *r) +{ + if(r->datatype == 'N') { + dbgprintf("toString CONVERSION MISSING\n"); abort(); + } + return r->d.estr; +} + +#define COMP_NUM_BINOP(x) \ + cnfexprEval(expr->l, &l); \ + cnfexprEval(expr->r, &r); \ + ret->datatype = 'N'; \ + ret->d.n = exprret2Number(&l) x exprret2Number(&r) + +/* evaluate an expression. + * Note that we try to avoid malloc whenever possible (because on + * the large overhead it has, especially on highly threaded programs). + * As such, the each caller level must provide buffer space for the + * result on its stack during recursion. This permits the callee to store + * the return value without malloc. As the value is a somewhat larger + * struct, we could otherwise not return it without malloc. + * Note that we implement boolean shortcut operations. For our needs, there + * simply is no case where full evaluation would make any sense at all. + */ +void +cnfexprEval(struct cnfexpr *expr, struct exprret *ret) +{ + struct exprret r, l; /* memory for subexpression results */ + + //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + switch(expr->nodetype) { + case CMP_EQ: + COMP_NUM_BINOP(==); + break; + case CMP_NE: + COMP_NUM_BINOP(!=); + break; + case CMP_LE: + COMP_NUM_BINOP(<=); + break; + case CMP_GE: + COMP_NUM_BINOP(>=); + break; + case CMP_LT: + COMP_NUM_BINOP(<); + break; + case CMP_GT: + COMP_NUM_BINOP(>); + break; + case OR: + cnfexprEval(expr->l, &l); + ret->datatype = 'N'; + if(exprret2Number(&l)) { + ret->d.n = 1ll; + } else { + cnfexprEval(expr->r, &r); + if(exprret2Number(&r)) + ret->d.n = 1ll; + else + ret->d.n = 0ll; + } + break; + case AND: + cnfexprEval(expr->l, &l); + ret->datatype = 'N'; + if(exprret2Number(&l)) { + cnfexprEval(expr->r, &r); + if(exprret2Number(&r)) + ret->d.n = 1ll; + else + ret->d.n = 0ll; + } else { + ret->d.n = 0ll; + } + break; + case NOT: + cnfexprEval(expr->r, &r); + ret->datatype = 'N'; + ret->d.n = !exprret2Number(&r); + break; + case 'N': + ret->datatype = 'N'; + ret->d.n = ((struct cnfnumval*)expr)->val; + break; + case '+': + COMP_NUM_BINOP(+); + break; + case '-': + COMP_NUM_BINOP(-); + break; + case '*': + COMP_NUM_BINOP(*); + break; + case '/': + COMP_NUM_BINOP(/); + break; + case '%': + COMP_NUM_BINOP(%); + break; + case 'M': + cnfexprEval(expr->r, &r); + ret->datatype = 'N'; + ret->d.n = -exprret2Number(&r); + break; + default: + ret->datatype = 'N'; + ret->d.n = 0ll; + dbgprintf("eval error: unknown nodetype %u\n", + (unsigned) expr->nodetype); + break; + } +} + +/* Evaluate an expression as a bool. This is added because expressions are + * mostly used inside filters, and so this function is quite common and + * important. + */ +int +cnfexprEvalBool(struct cnfexpr *expr) +{ + struct exprret ret; + cnfexprEval(expr, &ret); + return exprret2Number(&ret); +} + +inline static void +doIndent(int indent) +{ + int i; + for(i = 0 ; i < indent ; ++i) + dbgprintf(" "); +} +void +cnfexprPrint(struct cnfexpr *expr, int indent) +{ + struct cnffparamlst *param; + //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); + switch(expr->nodetype) { + case CMP_EQ: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("==\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_NE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("!=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_LE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("<=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_GE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf(">=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_LT: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("<\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_GT: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf(">\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_CONTAINS: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("CONTAINS\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_CONTAINSI: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("CONTAINS_I\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_STARTSWITH: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("STARTSWITH\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_STARTSWITHI: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("STARTSWITH_I\n"); + cnfexprPrint(expr->r, indent+1); + break; + case OR: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("OR\n"); + cnfexprPrint(expr->r, indent+1); + break; + case AND: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("AND\n"); + cnfexprPrint(expr->r, indent+1); + break; + case NOT: + doIndent(indent); + dbgprintf("NOT\n"); + cnfexprPrint(expr->r, indent+1); + break; + case 'S': + doIndent(indent); + cstrPrint("string '", ((struct cnfstringval*)expr)->estr); + dbgprintf("'\n"); + break; + case 'N': + doIndent(indent); + dbgprintf("%lld\n", ((struct cnfnumval*)expr)->val); + break; + case 'V': + doIndent(indent); + dbgprintf("var '%s'\n", ((struct cnfvar*)expr)->name); + break; + case 'F': + doIndent(indent); + cstrPrint("function '", ((struct cnffunc*)expr)->fname); + dbgprintf("'\n"); + for( param = ((struct cnffunc*)expr)->paramlst + ; param != NULL + ; param = param->next) { + cnfexprPrint(param->expr, indent+1); + } + break; + case '+': + case '-': + case '*': + case '/': + case '%': + case 'M': + if(expr->l != NULL) + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("%c\n", (char) expr->nodetype); + cnfexprPrint(expr->r, indent+1); + break; + default: + dbgprintf("error: unknown nodetype %u\n", + (unsigned) expr->nodetype); + break; + } +} + +struct cnfnumval* +cnfnumvalNew(long long val) +{ + struct cnfnumval *numval; + if((numval = malloc(sizeof(struct cnfnumval))) != NULL) { + numval->nodetype = 'N'; + numval->val = val; + } + return numval; +} + +struct cnfstringval* +cnfstringvalNew(es_str_t *estr) +{ + struct cnfstringval *strval; + if((strval = malloc(sizeof(struct cnfstringval))) != NULL) { + strval->nodetype = 'S'; + strval->estr = estr; + } + return strval; +} + +struct cnfvar* +cnfvarNew(char *name) +{ + struct cnfvar *var; + if((var = malloc(sizeof(struct cnfvar))) != NULL) { + var->nodetype = 'V'; + var->name = name; + } + return var; +} + +struct cnfrule * +cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) +{ + struct cnfrule* cnfrule; + if((cnfrule = malloc(sizeof(struct cnfrule))) != NULL) { + cnfrule->nodetype = 'R'; + cnfrule->filttype = filttype; + cnfrule->actlst = cnfactlstReverse(actlst); + } + return cnfrule; +} + +void +cnfrulePrint(struct cnfrule *rule) +{ + dbgprintf("------ start rule %p:\n", rule); + dbgprintf("%s: ", cnfFiltType2str(rule->filttype)); + switch(rule->filttype) { + case CNFFILT_NONE: + break; + case CNFFILT_PRI: + case CNFFILT_PROP: + dbgprintf("%s\n", rule->filt.s); + break; + case CNFFILT_SCRIPT: + dbgprintf("\n"); + cnfexprPrint(rule->filt.expr, 0); + break; + } + cnfactlstPrint(rule->actlst); + dbgprintf("------ end rule %p\n", rule); +} + +struct cnffparamlst * +cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) +{ + struct cnffparamlst* lst; + if((lst = malloc(sizeof(struct cnffparamlst))) != NULL) { + lst->nodetype = 'P'; + lst->expr = expr; + lst->next = next; + } + return lst; +} + +struct cnffunc * +cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) +{ + struct cnffunc* func; + if((func = malloc(sizeof(struct cnffunc))) != NULL) { + func->nodetype = 'F'; + func->fname = fname; + func->paramlst = paramlst; + } + return func; +} + +void +cstrPrint(char *text, es_str_t *estr) +{ + char *str; + str = es_str2cstr(estr, NULL); + dbgprintf("%s%s", text, str); + free(str); +} diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h new file mode 100644 index 00000000..bab7e602 --- /dev/null +++ b/grammar/rainerscript.h @@ -0,0 +1,176 @@ +#ifndef INC_UTILS_H +#define INC_UTILS_H +#include +#include + +enum cnfobjType { + CNFOBJ_ACTION, + CNFOBJ_GLOBAL, + CNFOBJ_INPUT, + CNFOBJ_MODULE, + CNFOBJ_INVALID = 0 +}; + +static inline char* +cnfobjType2str(enum cnfobjType ot) +{ + switch(ot) { + case CNFOBJ_ACTION: + return "action"; + break; + case CNFOBJ_GLOBAL: + return "global"; + break; + case CNFOBJ_INPUT: + return "input"; + break; + case CNFOBJ_MODULE: + return "module"; + break; + default:return "error: invalid cnfobjType"; + } +} + +enum cnfactType { CNFACT_V2, CNFACT_LEGACY }; + +struct cnfobj { + enum cnfobjType objType; + struct nvlst *nvlst; +}; + +struct nvlst { + struct nvlst *next; + es_str_t *name; + es_str_t *value; +}; + +struct cnfcfsyslinelst { + struct cnfcfsyslinelst *next; + char *line; +}; + +struct cnfactlst { + struct cnfactlst *next; + struct cnfcfsyslinelst *syslines; + enum cnfactType actType; + union { + struct nvlst *lst; + char *legActLine; + } data; +}; + +/* the following structures support expressions, and may (very much later + * be the sole foundation for the AST. + * + * nodetypes (list not yet complete) + * F - function + * N - number + * P - fparamlst + * R - rule + * S - string + * V - var + */ +enum cnfFiltType { CNFFILT_NONE, CNFFILT_PRI, CNFFILT_PROP, CNFFILT_SCRIPT }; +static inline char* +cnfFiltType2str(enum cnfFiltType filttype) +{ + switch(filttype) { + case CNFFILT_NONE: + return("filter:none"); + case CNFFILT_PRI: + return("filter:pri"); + case CNFFILT_PROP: + return("filter:prop"); + case CNFFILT_SCRIPT: + return("filter:script"); + } + return("error:invalid_filter_type"); /* should never be reached */ +} + + +struct cnfrule { + unsigned nodetype; + enum cnfFiltType filttype; + union { + char *s; + struct cnfexpr *expr; + } filt; + struct cnfactlst *actlst; +}; + +struct cnfexpr { + unsigned nodetype; + struct cnfexpr *l; + struct cnfexpr *r; +}; + +struct cnfnumval { + unsigned nodetype; + long long val; +}; + +struct cnfstringval { + unsigned nodetype; + es_str_t *estr; +}; + +struct cnfvar { + unsigned nodetype; + char *name; +}; + +struct cnffparamlst { + unsigned nodetype; /* P */ + struct cnffparamlst *next; + struct cnfexpr *expr; +}; + +struct cnffunc { + unsigned nodetype; + es_str_t *fname; + struct cnffparamlst *paramlst; +}; + +/* future extensions +struct x { + int nodetype; +}; +*/ + +/* the return value of an expresion evaluation */ +struct exprret { + union { + es_str_t *estr; + long long n; + } d; + char datatype; /* 'N' - number, 'S' - string */ +}; + + +void readConfFile(FILE *fp, es_str_t **str); +struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); +void nvlstDestruct(struct nvlst *lst); +void nvlstPrint(struct nvlst *lst); +struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst); +void cnfobjDestruct(struct cnfobj *o); +void cnfobjPrint(struct cnfobj *o); +struct cnfactlst* cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine); +void cnfactlstDestruct(struct cnfactlst *actlst); +void cnfactlstPrint(struct cnfactlst *actlst); +struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); +struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); +struct cnfexpr* cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r); +void cnfexprPrint(struct cnfexpr *expr, int indent); +void cnfexprEval(struct cnfexpr *expr, struct exprret *ret); +int cnfexprEvalBool(struct cnfexpr *expr); +struct cnfnumval* cnfnumvalNew(long long val); +struct cnfstringval* cnfstringvalNew(es_str_t *estr); +struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst); +void cnfrulePrint(struct cnfrule *rule); +struct cnfvar* cnfvarNew(char *name); +struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst); +struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next); + +/* debug helper */ +void cstrPrint(char *text, es_str_t *estr); +#endif diff --git a/grammar/testdriver.c b/grammar/testdriver.c index 43f3bd3f..52d2d0c7 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -26,7 +26,7 @@ #include #include #include -#include "utils.h" +#include "rainerscript.h" #include "parserif.h" extern int yylineno; diff --git a/grammar/utils.c b/grammar/utils.c deleted file mode 100644 index f49af9b0..00000000 --- a/grammar/utils.c +++ /dev/null @@ -1,620 +0,0 @@ -#include -#include -#include -#include -#include -#include "utils.h" -#include "parserif.h" -#include "grammar.h" - -void -readConfFile(FILE *fp, es_str_t **str) -{ - char ln[10240]; - char buf[512]; - int lenBuf; - int bWriteLineno = 0; - int len, i; - int start; /* start index of to be submitted text */ - int bContLine = 0; - int lineno = 0; - - *str = es_newStr(4096); - - while(fgets(ln, sizeof(ln), fp) != NULL) { - ++lineno; - if(bWriteLineno) { - bWriteLineno = 0; - lenBuf = sprintf(buf, "PreprocFileLineNumber(%d)\n", lineno); - es_addBuf(str, buf, lenBuf); - } - len = strlen(ln); - /* if we are continuation line, we need to drop leading WS */ - if(bContLine) { - for(start = 0 ; start < len && isspace(ln[start]) ; ++start) - /* JUST SCAN */; - } else { - start = 0; - } - for(i = len - 1 ; i >= start && isspace(ln[i]) ; --i) - /* JUST SCAN */; - if(i >= 0) { - if(ln[i] == '\\') { - --i; - bContLine = 1; - } else { - if(bContLine) /* write line number if we had cont line */ - bWriteLineno = 1; - bContLine = 0; - } - /* add relevant data to buffer */ - es_addBuf(str, ln+start, i+1 - start); - } - if(!bContLine) - es_addChar(str, '\n'); - } - /* indicate end of buffer to flex */ - es_addChar(str, '\0'); - es_addChar(str, '\0'); -} - -struct nvlst* -nvlstNew(es_str_t *name, es_str_t *value) -{ - struct nvlst *lst; - - if((lst = malloc(sizeof(struct nvlst))) != NULL) { - lst->next = NULL; - lst->name = name; - lst->value = value; - } - - return lst; -} - -void -nvlstDestruct(struct nvlst *lst) -{ - struct nvlst *toDel; - - while(lst != NULL) { - toDel = lst; - lst = lst->next; - es_deleteStr(toDel->name); - es_deleteStr(toDel->value); - free(toDel); - } -} - -void -nvlstPrint(struct nvlst *lst) -{ - char *name, *value; - dbgprintf("nvlst %p:\n", lst); - while(lst != NULL) { - name = es_str2cstr(lst->name, NULL); - value = es_str2cstr(lst->value, NULL); - dbgprintf("\tname: '%s', value '%s'\n", name, value); - free(name); - free(value); - lst = lst->next; - } -} - -struct cnfobj* -cnfobjNew(enum cnfobjType objType, struct nvlst *lst) -{ - struct cnfobj *o; - - if((o = malloc(sizeof(struct nvlst))) != NULL) { - o->objType = objType; - o->nvlst = lst; - } - - return o; -} - -void -cnfobjDestruct(struct cnfobj *o) -{ - if(o != NULL) { - nvlstDestruct(o->nvlst); - free(o); - } -} - -void -cnfobjPrint(struct cnfobj *o) -{ - dbgprintf("obj: '%s'\n", cnfobjType2str(o->objType)); - nvlstPrint(o->nvlst); -} - - -struct cnfactlst* -cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine) -{ - struct cnfactlst *actlst; - - if((actlst = malloc(sizeof(struct cnfactlst))) != NULL) { - actlst->next = NULL; - actlst->syslines = NULL; - actlst->actType = actType; - if(actType == CNFACT_V2) - actlst->data.lst = lst; - else - actlst->data.legActLine = actLine; - } - return actlst; -} - -struct cnfactlst* -cnfactlstAddSysline(struct cnfactlst* actlst, char *line) -{ - struct cnfcfsyslinelst *cflst; - - if((cflst = malloc(sizeof(struct cnfcfsyslinelst))) != NULL) { - cflst->next = NULL; - cflst->line = line; - if(actlst->syslines == NULL) { - actlst->syslines = cflst; - } else { - cflst->next = actlst->syslines; - actlst->syslines = cflst; - } - } - return actlst; -} - -void -cnfactlstDestruct(struct cnfactlst *actlst) -{ - struct cnfactlst *toDel; - - while(actlst != NULL) { - toDel = actlst; - actlst = actlst->next; - if(toDel->actType == CNFACT_V2) - nvlstDestruct(toDel->data.lst); - else - free(toDel->data.legActLine); - free(toDel); - } - -} - -static inline struct cnfcfsyslinelst* -cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) -{ - struct cnfcfsyslinelst *curr, *prev; - if(lst == NULL) - return NULL; - prev = NULL; - while(lst != NULL) { - curr = lst; - lst = lst->next; - curr->next = prev; - prev = curr; - } - return prev; -} - -struct cnfactlst* -cnfactlstReverse(struct cnfactlst *actlst) -{ - struct cnfactlst *curr, *prev; - - prev = NULL; - while(actlst != NULL) { - //dbgprintf("reversing: %s\n", actlst->data.legActLine); - curr = actlst; - actlst = actlst->next; - curr->syslines = cnfcfsyslinelstReverse(curr->syslines); - curr->next = prev; - prev = curr; - } - return prev; -} - -void -cnfactlstPrint(struct cnfactlst *actlst) -{ - struct cnfcfsyslinelst *cflst; - - while(actlst != NULL) { - dbgprintf("aclst %p: ", actlst); - if(actlst->actType == CNFACT_V2) { - dbgprintf("V2 action type: "); - nvlstPrint(actlst->data.lst); - } else { - dbgprintf("legacy action line: '%s'\n", - actlst->data.legActLine); - } - for( cflst = actlst->syslines - ; cflst != NULL ; cflst = cflst->next) { - dbgprintf("action:cfsysline: '%s'\n", cflst->line); - } - actlst = actlst->next; - } -} - -struct cnfexpr* -cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r) -{ - struct cnfexpr *expr; - - /* optimize some constructs during parsing */ - if(nodetype == 'M' && r->nodetype == 'N') { - ((struct cnfnumval*)r)->val *= -1; - expr = r; - goto done; - } - - if((expr = malloc(sizeof(struct cnfexpr))) != NULL) { - expr->nodetype = nodetype; - expr->l = l; - expr->r = r; - } -done: - return expr; -} - -/* ensure that retval is a number; if string is no number, - * emit error message and set number to 0. - */ -static inline long long -exprret2Number(struct exprret *r) -{ - if(r->datatype == 'S') { - dbgprintf("toNumber CONVERSION MISSING\n"); abort(); - } - return r->d.n; -} - -/* ensure that retval is a string; if string is no number, - * emit error message and set number to 0. - */ -static inline es_str_t * -exprret2String(struct exprret *r) -{ - if(r->datatype == 'N') { - dbgprintf("toString CONVERSION MISSING\n"); abort(); - } - return r->d.estr; -} - -#define COMP_NUM_BINOP(x) \ - cnfexprEval(expr->l, &l); \ - cnfexprEval(expr->r, &r); \ - ret->datatype = 'N'; \ - ret->d.n = exprret2Number(&l) x exprret2Number(&r) - -/* evaluate an expression. - * Note that we try to avoid malloc whenever possible (because on - * the large overhead it has, especially on highly threaded programs). - * As such, the each caller level must provide buffer space for the - * result on its stack during recursion. This permits the callee to store - * the return value without malloc. As the value is a somewhat larger - * struct, we could otherwise not return it without malloc. - * Note that we implement boolean shortcut operations. For our needs, there - * simply is no case where full evaluation would make any sense at all. - */ -void -cnfexprEval(struct cnfexpr *expr, struct exprret *ret) -{ - struct exprret r, l; /* memory for subexpression results */ - - //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); - switch(expr->nodetype) { - case CMP_EQ: - COMP_NUM_BINOP(==); - break; - case CMP_NE: - COMP_NUM_BINOP(!=); - break; - case CMP_LE: - COMP_NUM_BINOP(<=); - break; - case CMP_GE: - COMP_NUM_BINOP(>=); - break; - case CMP_LT: - COMP_NUM_BINOP(<); - break; - case CMP_GT: - COMP_NUM_BINOP(>); - break; - case OR: - cnfexprEval(expr->l, &l); - ret->datatype = 'N'; - if(exprret2Number(&l)) { - ret->d.n = 1ll; - } else { - cnfexprEval(expr->r, &r); - if(exprret2Number(&r)) - ret->d.n = 1ll; - else - ret->d.n = 0ll; - } - break; - case AND: - cnfexprEval(expr->l, &l); - ret->datatype = 'N'; - if(exprret2Number(&l)) { - cnfexprEval(expr->r, &r); - if(exprret2Number(&r)) - ret->d.n = 1ll; - else - ret->d.n = 0ll; - } else { - ret->d.n = 0ll; - } - break; - case NOT: - cnfexprEval(expr->r, &r); - ret->datatype = 'N'; - ret->d.n = !exprret2Number(&r); - break; - case 'N': - ret->datatype = 'N'; - ret->d.n = ((struct cnfnumval*)expr)->val; - break; - case '+': - COMP_NUM_BINOP(+); - break; - case '-': - COMP_NUM_BINOP(-); - break; - case '*': - COMP_NUM_BINOP(*); - break; - case '/': - COMP_NUM_BINOP(/); - break; - case '%': - COMP_NUM_BINOP(%); - break; - case 'M': - cnfexprEval(expr->r, &r); - ret->datatype = 'N'; - ret->d.n = -exprret2Number(&r); - break; - default: - ret->datatype = 'N'; - ret->d.n = 0ll; - dbgprintf("eval error: unknown nodetype %u\n", - (unsigned) expr->nodetype); - break; - } -} - -inline static void -doIndent(int indent) -{ - int i; - for(i = 0 ; i < indent ; ++i) - dbgprintf(" "); -} -void -cnfexprPrint(struct cnfexpr *expr, int indent) -{ - struct cnffparamlst *param; - //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); - switch(expr->nodetype) { - case CMP_EQ: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("==\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_NE: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("!=\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_LE: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("<=\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_GE: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf(">=\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_LT: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("<\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_GT: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf(">\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_CONTAINS: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("CONTAINS\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_CONTAINSI: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("CONTAINS_I\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_STARTSWITH: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("STARTSWITH\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_STARTSWITHI: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("STARTSWITH_I\n"); - cnfexprPrint(expr->r, indent+1); - break; - case OR: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("OR\n"); - cnfexprPrint(expr->r, indent+1); - break; - case AND: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("AND\n"); - cnfexprPrint(expr->r, indent+1); - break; - case NOT: - doIndent(indent); - dbgprintf("NOT\n"); - cnfexprPrint(expr->r, indent+1); - break; - case 'S': - doIndent(indent); - cstrPrint("string '", ((struct cnfstringval*)expr)->estr); - dbgprintf("'\n"); - break; - case 'N': - doIndent(indent); - dbgprintf("%lld\n", ((struct cnfnumval*)expr)->val); - break; - case 'V': - doIndent(indent); - dbgprintf("var '%s'\n", ((struct cnfvar*)expr)->name); - break; - case 'F': - doIndent(indent); - cstrPrint("function '", ((struct cnffunc*)expr)->fname); - dbgprintf("'\n"); - for( param = ((struct cnffunc*)expr)->paramlst - ; param != NULL - ; param = param->next) { - cnfexprPrint(param->expr, indent+1); - } - break; - case '+': - case '-': - case '*': - case '/': - case '%': - case 'M': - if(expr->l != NULL) - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("%c\n", (char) expr->nodetype); - cnfexprPrint(expr->r, indent+1); - break; - default: - dbgprintf("error: unknown nodetype %u\n", - (unsigned) expr->nodetype); - break; - } -} - -struct cnfnumval* -cnfnumvalNew(long long val) -{ - struct cnfnumval *numval; - if((numval = malloc(sizeof(struct cnfnumval))) != NULL) { - numval->nodetype = 'N'; - numval->val = val; - } - return numval; -} - -struct cnfstringval* -cnfstringvalNew(es_str_t *estr) -{ - struct cnfstringval *strval; - if((strval = malloc(sizeof(struct cnfstringval))) != NULL) { - strval->nodetype = 'S'; - strval->estr = estr; - } - return strval; -} - -struct cnfvar* -cnfvarNew(char *name) -{ - struct cnfvar *var; - if((var = malloc(sizeof(struct cnfvar))) != NULL) { - var->nodetype = 'V'; - var->name = name; - } - return var; -} - -struct cnfrule * -cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) -{ - struct cnfrule* cnfrule; - if((cnfrule = malloc(sizeof(struct cnfrule))) != NULL) { - cnfrule->nodetype = 'R'; - cnfrule->filttype = filttype; - cnfrule->actlst = cnfactlstReverse(actlst); - } - return cnfrule; -} - -void -cnfrulePrint(struct cnfrule *rule) -{ - dbgprintf("------ start rule %p:\n", rule); - dbgprintf("%s: ", cnfFiltType2str(rule->filttype)); - switch(rule->filttype) { - case CNFFILT_NONE: - break; - case CNFFILT_PRI: - case CNFFILT_PROP: - dbgprintf("%s\n", rule->filt.s); - break; - case CNFFILT_SCRIPT: - dbgprintf("\n"); - cnfexprPrint(rule->filt.expr, 0); - break; - } - cnfactlstPrint(rule->actlst); - dbgprintf("------ end rule %p\n", rule); -} - -struct cnffparamlst * -cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) -{ - struct cnffparamlst* lst; - if((lst = malloc(sizeof(struct cnffparamlst))) != NULL) { - lst->nodetype = 'P'; - lst->expr = expr; - lst->next = next; - } - return lst; -} - -struct cnffunc * -cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) -{ - struct cnffunc* func; - if((func = malloc(sizeof(struct cnffunc))) != NULL) { - func->nodetype = 'F'; - func->fname = fname; - func->paramlst = paramlst; - } - return func; -} - -void -cstrPrint(char *text, es_str_t *estr) -{ - char *str; - str = es_str2cstr(estr, NULL); - dbgprintf("%s%s", text, str); - free(str); -} diff --git a/grammar/utils.h b/grammar/utils.h deleted file mode 100644 index e75105da..00000000 --- a/grammar/utils.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef INC_UTILS_H -#define INC_UTILS_H -#include - -enum cnfobjType { - CNFOBJ_ACTION, - CNFOBJ_GLOBAL, - CNFOBJ_INPUT, - CNFOBJ_MODULE, - CNFOBJ_INVALID = 0 -}; - -static inline char* -cnfobjType2str(enum cnfobjType ot) -{ - switch(ot) { - case CNFOBJ_ACTION: - return "action"; - break; - case CNFOBJ_GLOBAL: - return "global"; - break; - case CNFOBJ_INPUT: - return "input"; - break; - case CNFOBJ_MODULE: - return "module"; - break; - default:return "error: invalid cnfobjType"; - } -} - -enum cnfactType { CNFACT_V2, CNFACT_LEGACY }; - -struct cnfobj { - enum cnfobjType objType; - struct nvlst *nvlst; -}; - -struct nvlst { - struct nvlst *next; - es_str_t *name; - es_str_t *value; -}; - -struct cnfcfsyslinelst { - struct cnfcfsyslinelst *next; - char *line; -}; - -struct cnfactlst { - struct cnfactlst *next; - struct cnfcfsyslinelst *syslines; - enum cnfactType actType; - union { - struct nvlst *lst; - char *legActLine; - } data; -}; - -/* the following structures support expressions, and may (very much later - * be the sole foundation for the AST. - * - * nodetypes (list not yet complete) - * F - function - * N - number - * P - fparamlst - * R - rule - * S - string - * V - var - */ -enum cnfFiltType { CNFFILT_NONE, CNFFILT_PRI, CNFFILT_PROP, CNFFILT_SCRIPT }; -static inline char* -cnfFiltType2str(enum cnfFiltType filttype) -{ - switch(filttype) { - case CNFFILT_NONE: - return("filter:none"); - case CNFFILT_PRI: - return("filter:pri"); - case CNFFILT_PROP: - return("filter:prop"); - case CNFFILT_SCRIPT: - return("filter:script"); - } - return("error:invalid_filter_type"); /* should never be reached */ -} - - -struct cnfrule { - unsigned nodetype; - enum cnfFiltType filttype; - union { - char *s; - struct cnfexpr *expr; - } filt; - struct cnfactlst *actlst; -}; - -struct cnfexpr { - unsigned nodetype; - struct cnfexpr *l; - struct cnfexpr *r; -}; - -struct cnfnumval { - unsigned nodetype; - long long val; -}; - -struct cnfstringval { - unsigned nodetype; - es_str_t *estr; -}; - -struct cnfvar { - unsigned nodetype; - char *name; -}; - -struct cnffparamlst { - unsigned nodetype; /* P */ - struct cnffparamlst *next; - struct cnfexpr *expr; -}; - -struct cnffunc { - unsigned nodetype; - es_str_t *fname; - struct cnffparamlst *paramlst; -}; - -/* future extensions -struct x { - int nodetype; -}; -*/ - -/* the return value of an expresion evaluation */ -struct exprret { - union { - es_str_t *estr; - long long n; - } d; - char datatype; /* 'N' - number, 'S' - string */ -}; - - -void readConfFile(FILE *fp, es_str_t **str); -struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); -void nvlstDestruct(struct nvlst *lst); -void nvlstPrint(struct nvlst *lst); -struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst); -void cnfobjDestruct(struct cnfobj *o); -void cnfobjPrint(struct cnfobj *o); -struct cnfactlst* cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine); -void cnfactlstDestruct(struct cnfactlst *actlst); -void cnfactlstPrint(struct cnfactlst *actlst); -struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); -struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); -struct cnfexpr* cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r); -void cnfexprPrint(struct cnfexpr *expr, int indent); -void cnfexprEval(struct cnfexpr *expr, struct exprret *ret); -struct cnfnumval* cnfnumvalNew(long long val); -struct cnfstringval* cnfstringvalNew(es_str_t *estr); -struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst); -void cnfrulePrint(struct cnfrule *rule); -struct cnfvar* cnfvarNew(char *name); -struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst); -struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next); - -/* debug helper */ -void cstrPrint(char *text, es_str_t *estr); -#endif diff --git a/runtime/conf.c b/runtime/conf.c index 5eb1aae2..51cf39e1 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -104,9 +104,9 @@ int bConfStrictScoping = 0; /* force strict scoping during config processing? */ * be run in a single thread anyways. So there can be no race conditions. * rgerhards 2005-10-18 */ -static EHostnameCmpMode eDfltHostnameCmpMode = HN_NO_COMP; -static cstr_t *pDfltHostnameCmp = NULL; -static cstr_t *pDfltProgNameCmp = NULL; +EHostnameCmpMode eDfltHostnameCmpMode = HN_NO_COMP; +cstr_t *pDfltHostnameCmp = NULL; +cstr_t *pDfltProgNameCmp = NULL; /* process a directory and include all of its files into @@ -763,6 +763,7 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) } +#if 0 /* Helper to cfline(). This function processes an "if" type of filter, * what essentially means it parses an expression. As usual, * It processes the line up to the beginning of the action part. @@ -830,6 +831,7 @@ finalize_it: RETiRet; } +#endif /* Helper to cfline(). This function takes the filter part of a property @@ -1061,12 +1063,14 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) case ':': CHKiRet(cflineProcessPropFilter(pp, f)); break; +#if 0 case 'i': /* "if" filter? */ if(*(*pp+1) && (*(*pp+1) == 'f') && isspace(*(*pp+2))) { CHKiRet(cflineProcessIfFilter(pp, f)); break; } /*FALLTHROUGH*/ +#endif default: CHKiRet(cflineProcessTradPRIFilter(pp, f)); break; diff --git a/runtime/conf.h b/runtime/conf.h index 28ccdde1..aa57c8fc 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -72,5 +72,8 @@ rsRetVal cflineProcessHostSelector(uchar **pline); rsRetVal cflineProcessTradPRIFilter(uchar **pline, rule_t *pRule); rsRetVal cflineProcessPropFilter(uchar **pline, rule_t *f); rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction); +extern EHostnameCmpMode eDfltHostnameCmpMode; +extern cstr_t *pDfltHostnameCmp; +extern cstr_t *pDfltProgNameCmp; #endif /* #ifndef INCLUDED_CONF_H */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 17332464..cb8eac50 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -255,7 +255,9 @@ parser_errmsg(char *fmt, ...) va_list ap; va_start(ap, fmt); // TODO: create useful code ;) 2011-07-06 - dbgprintf("error on or before line %d: ", yylineno); + errmsg.LogError(0, NO_ERRCODE, "error during parsing on or before line %d", + yylineno); +dbgprintf("error on or before line %d: ", yylineno); vprintf(fmt, ap); printf("\n"); va_end(ap); @@ -284,8 +286,8 @@ void cnfDoRule(struct cnfrule *cnfrule) cnfrulePrint(cnfrule); CHKiRet(rule.Construct(&pRule)); /* create "fresh" selector */ - CHKiRet(rule.SetAssRuleset(pRule, ruleset.GetCurrent(loadConf))); /* create "fresh" selector */ - CHKiRet(rule.ConstructFinalize(pRule)); /* create "fresh" selector */ + CHKiRet(rule.SetAssRuleset(pRule, ruleset.GetCurrent(loadConf))); + CHKiRet(rule.ConstructFinalize(pRule)); switch(cnfrule->filttype) { case CNFFILT_NONE: @@ -300,23 +302,21 @@ void cnfDoRule(struct cnfrule *cnfrule) iRet = cflineProcessPropFilter(&str, pRule); break; case CNFFILT_SCRIPT: - dbgprintf("TODO: script filter implementation missing\n"); - cnfexprPrint(cnfrule->filt.expr, 0); + pRule->f_filter_type = FILTER_EXPR; + pRule->f_filterData.f_expr = cnfrule->filt.expr; break; } /* we now check if there are some global (BSD-style) filter conditions * and, if so, we copy them over. rgerhards, 2005-10-18 */ -#if 0 // TODO: add LATER! if(pDfltProgNameCmp != NULL) { - CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp)); + CHKiRet(rsCStrConstructFromCStr(&(pRule->pCSProgNameComp), pDfltProgNameCmp)); } if(eDfltHostnameCmpMode != HN_NO_COMP) { - f->eHostnameCmpMode = eDfltHostnameCmpMode; - CHKiRet(rsCStrConstructFromCStr(&(f->pCSHostnameComp), pDfltHostnameCmp)); + pRule->eHostnameCmpMode = eDfltHostnameCmpMode; + CHKiRet(rsCStrConstructFromCStr(&(pRule->pCSHostnameComp), pDfltHostnameCmp)); } -#endif cnfDoActlst(cnfrule->actlst, pRule); diff --git a/runtime/rule.c b/runtime/rule.c index 3dcee877..8976c898 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -40,6 +40,7 @@ #include "var.h" #include "srUtils.h" #include "batch.h" +#include "parserif.h" #include "unicode-helper.h" /* static data */ @@ -186,14 +187,17 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) else bRet = 1; } else if(pRule->f_filter_type == FILTER_EXPR) { +#if 0 CHKiRet(vm.Construct(&pVM)); CHKiRet(vm.ConstructFinalize(pVM)); CHKiRet(vm.SetMsg(pVM, pMsg)); CHKiRet(vm.ExecProg(pVM, pRule->f_filterData.f_expr->pVmprg)); CHKiRet(vm.PopBoolFromStack(pVM, &pResult)); - dbgprintf("result of rainerscript filter evaluation: %lld\n", pResult->val.num); /* VM is destructed on function exit */ bRet = (pResult->val.num) ? 1 : 0; +#endif + bRet = cnfexprEvalBool(pRule->f_filterData.expr); + dbgprintf("result of rainerscript filter evaluation: %d\n", bRet); } else { assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */ pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID, @@ -356,9 +360,11 @@ CODESTARTobjDestruct(rule) rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache); if(pThis->f_filterData.prop.propName != NULL) es_deleteStr(pThis->f_filterData.prop.propName); +#if 0 } else if(pThis->f_filter_type == FILTER_EXPR) { if(pThis->f_filterData.f_expr != NULL) expr.Destruct(&pThis->f_filterData.f_expr); +#endif } llDestroy(&pThis->llActList); diff --git a/runtime/rule.h b/runtime/rule.h index 3b34e11a..f346c764 100644 --- a/runtime/rule.h +++ b/runtime/rule.h @@ -2,7 +2,7 @@ * * This implements rules within rsyslog. * - * Copyright 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2009-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -28,7 +28,8 @@ #include "libestr.h" #include "linkedlist.h" #include "regexp.h" -#include "expr.h" +#include "expr.h" // TODO: remove #if 0 +#include "rainerscript.h" /* the rule object */ struct rule_s { @@ -52,6 +53,7 @@ struct rule_s { propid_t propID; /* ID of the requested property */ es_str_t *propName; /* name of property for CEE-based filters */ } prop; + struct cnfexpr *expr; /* expression object */ expr_t *f_expr; /* expression object */ } f_filterData; -- cgit v1.2.3 From 8a9e0cc68e3314b02065dcd3424201f25f176dfb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 7 Jul 2011 16:35:51 +0200 Subject: milestone/[PARTWORK]: obtaining msg vars integrated, "==" works for strings --- configure.ac | 2 +- grammar/parserif.h | 1 + grammar/rainerscript.c | 68 +++++++++++++++++++++++++++++++++++++------------- grammar/rainerscript.h | 4 +-- grammar/testdriver.c | 8 ++++++ runtime/msg.c | 55 ++++++++++++++++++++++++++++++++++------ runtime/msg.h | 1 + runtime/rsconf.c | 14 +++++++++-- runtime/rule.c | 2 +- 9 files changed, 124 insertions(+), 31 deletions(-) diff --git a/configure.ac b/configure.ac index 4f9113bd..5612b1b2 100644 --- a/configure.ac +++ b/configure.ac @@ -38,7 +38,7 @@ AC_CANONICAL_HOST PKG_PROG_PKG_CONFIG # modules we require -PKG_CHECK_MODULES(LIBESTR, libestr >= 0.1.0) +PKG_CHECK_MODULES(LIBESTR, libestr >= 0.1.1) PKG_CHECK_MODULES(LIBEE, libee >= 0.3.1) case "${host}" in diff --git a/grammar/parserif.h b/grammar/parserif.h index a04abb0c..bebb1dfb 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -16,4 +16,5 @@ void cnfDoRule(struct cnfrule *rule); void cnfDoCfsysline(char *ln); void cnfDoBSDTag(char *ln); void cnfDoBSDHost(char *ln); +es_str_t *cnfGetVar(char *name, void *usrptr); #endif diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 801a52b2..ea23dc1a 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -291,8 +291,9 @@ done: static inline long long exprret2Number(struct exprret *r) { + long long n; if(r->datatype == 'S') { - dbgprintf("toNumber CONVERSION MISSING\n"); abort(); + n = es_str2num(r->d.estr); } return r->d.n; } @@ -301,22 +302,24 @@ exprret2Number(struct exprret *r) * emit error message and set number to 0. */ static inline es_str_t * -exprret2String(struct exprret *r) +exprret2String(struct exprret *r, int *bMustFree) { if(r->datatype == 'N') { - dbgprintf("toString CONVERSION MISSING\n"); abort(); + *bMustFree = 1; + return es_newStrFromNumber(r->d.n); } + *bMustFree = 0; return r->d.estr; } #define COMP_NUM_BINOP(x) \ - cnfexprEval(expr->l, &l); \ - cnfexprEval(expr->r, &r); \ + cnfexprEval(expr->l, &l, usrptr); \ + cnfexprEval(expr->r, &r, usrptr); \ ret->datatype = 'N'; \ ret->d.n = exprret2Number(&l) x exprret2Number(&r) /* evaluate an expression. - * Note that we try to avoid malloc whenever possible (because on + * Note that we try to avoid malloc whenever possible (because of * the large overhead it has, especially on highly threaded programs). * As such, the each caller level must provide buffer space for the * result on its stack during recursion. This permits the callee to store @@ -326,14 +329,35 @@ exprret2String(struct exprret *r) * simply is no case where full evaluation would make any sense at all. */ void -cnfexprEval(struct cnfexpr *expr, struct exprret *ret) +cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) { struct exprret r, l; /* memory for subexpression results */ + es_str_t *estr; + int bMustFree; //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: - COMP_NUM_BINOP(==); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = !es_strcmp(l.d.estr, r.d.estr); + } else { + estr = exprret2String(&r, &bMustFree); + ret->d.n = !es_strcmp(l.d.estr, estr); + if(bMustFree) es_deleteStr(estr); + } + } else { + if(r.datatype == 'S') { + estr = exprret2String(&l, &bMustFree); + ret->d.n = !es_strcmp(r.d.estr, estr); + if(bMustFree) es_deleteStr(estr); + } else { + ret->d.n = (l.d.n == r.d.n); + } + } break; case CMP_NE: COMP_NUM_BINOP(!=); @@ -351,12 +375,12 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) COMP_NUM_BINOP(>); break; case OR: - cnfexprEval(expr->l, &l); + cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; if(exprret2Number(&l)) { ret->d.n = 1ll; } else { - cnfexprEval(expr->r, &r); + cnfexprEval(expr->r, &r, usrptr); if(exprret2Number(&r)) ret->d.n = 1ll; else @@ -364,10 +388,10 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) } break; case AND: - cnfexprEval(expr->l, &l); + cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; if(exprret2Number(&l)) { - cnfexprEval(expr->r, &r); + cnfexprEval(expr->r, &r, usrptr); if(exprret2Number(&r)) ret->d.n = 1ll; else @@ -377,7 +401,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) } break; case NOT: - cnfexprEval(expr->r, &r); + cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; ret->d.n = !exprret2Number(&r); break; @@ -385,6 +409,14 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) ret->datatype = 'N'; ret->d.n = ((struct cnfnumval*)expr)->val; break; + case 'S': + ret->datatype = 'S'; + ret->d.estr = es_strdup(((struct cnfstringval*)expr)->estr); + break; + case 'V': + ret->datatype = 'S'; + ret->d.estr = cnfGetVar(((struct cnfvar*)expr)->name, usrptr); + break; case '+': COMP_NUM_BINOP(+); break; @@ -401,15 +433,15 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) COMP_NUM_BINOP(%); break; case 'M': - cnfexprEval(expr->r, &r); + cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; ret->d.n = -exprret2Number(&r); break; default: ret->datatype = 'N'; ret->d.n = 0ll; - dbgprintf("eval error: unknown nodetype %u\n", - (unsigned) expr->nodetype); + dbgprintf("eval error: unknown nodetype %u['%c']\n", + (unsigned) expr->nodetype, (char) expr->nodetype); break; } } @@ -419,10 +451,10 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) * important. */ int -cnfexprEvalBool(struct cnfexpr *expr) +cnfexprEvalBool(struct cnfexpr *expr, void *usrptr) { struct exprret ret; - cnfexprEval(expr, &ret); + cnfexprEval(expr, &ret, usrptr); return exprret2Number(&ret); } diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index bab7e602..8b5c36de 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -161,8 +161,8 @@ struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); struct cnfexpr* cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r); void cnfexprPrint(struct cnfexpr *expr, int indent); -void cnfexprEval(struct cnfexpr *expr, struct exprret *ret); -int cnfexprEvalBool(struct cnfexpr *expr); +void cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void *pusr); +int cnfexprEvalBool(struct cnfexpr *expr, void *usrptr); struct cnfnumval* cnfnumvalNew(long long val); struct cnfstringval* cnfstringvalNew(es_str_t *estr); struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst); diff --git a/grammar/testdriver.c b/grammar/testdriver.c index 52d2d0c7..3e161d38 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -86,6 +86,14 @@ void cnfDoBSDHost(char *ln) dbgprintf("global:BSD host: %s\n", ln); } +es_str_t* +cnfGetVar(char *name, void *usrptr) +{ + es_str_t *estr; + estr = es_newStrFromCStr("", 1); + return estr; +} + int main(int argc, char *argv[]) { diff --git a/runtime/msg.c b/runtime/msg.c index c5cbb5c8..96fe1b2c 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #if HAVE_MALLOC_H # include @@ -480,16 +481,13 @@ getRcvFromIP(msg_t *pM) } - -/* map a property name (string) to a property ID */ -rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID) +/* map a property name (C string) to a property ID */ +rsRetVal +propNameStrToID(uchar *pName, propid_t *pPropID) { - uchar *pName; DEFiRet; - assert(pCSPropName != NULL); - assert(pPropID != NULL); - pName = rsCStrGetSzStrNoNULL(pCSPropName); + assert(pName != NULL); /* sometimes there are aliases to the original MonitoWare * property names. These come after || in the ifs below. */ @@ -577,6 +575,21 @@ rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID) } +/* map a property name (string) to a property ID */ +rsRetVal +propNameToID(cstr_t *pCSPropName, propid_t *pPropID) +{ + uchar *pName; + DEFiRet; + + assert(pCSPropName != NULL); + assert(pPropID != NULL); + pName = rsCStrGetSzStrNoNULL(pCSPropName); + iRet = propNameStrToID(pName, pPropID); + RETiRet; +} + + /* map a property ID to a name string (useful for displaying) */ uchar *propIDToName(propid_t propID) { @@ -3190,6 +3203,34 @@ finalize_it: } + +/* Return an es_str_t for given message property. + */ +es_str_t* +msgGetMsgVarNew(msg_t *pThis, uchar *name) +{ + size_t propLen; + uchar *pszProp = NULL; + propid_t propid; + unsigned short bMustBeFreed = 0; + es_str_t *estr; + + ISOBJ_TYPE_assert(pThis, msg); + + /* always call MsgGetProp() without a template specifier */ + /* TODO: optimize propNameToID() call -- rgerhards, 2009-06-26 */ + propNameStrToID(name, &propid); + pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, NULL, &propLen, &bMustBeFreed); + +dbgprintf("ZZZZ: var %s returns '%s'\n", name, pszProp); + estr = es_newStrFromCStr((char*)pszProp, propLen); + if(bMustBeFreed) + free(pszProp); + + return estr; +} + + /* This function can be used as a generic way to set properties. * We have to handle a lot of legacy, so our return value is not always * 100% correct (called functions do not always provide one, should diff --git a/runtime/msg.h b/runtime/msg.h index 01a1e059..19debb03 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -170,6 +170,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, size_t *pPropLen, unsigned short *pbMustBeFreed); char *textpri(char *pRes, size_t pResLen, int pri); rsRetVal msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar); +es_str_t* msgGetMsgVarNew(msg_t *pThis, uchar *name); rsRetVal MsgEnableThreadSafety(void); uchar *getRcvFrom(msg_t *pM); void getTAG(msg_t *pM, uchar **ppBuf, int *piLen); diff --git a/runtime/rsconf.c b/runtime/rsconf.c index cb8eac50..459c9a17 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -222,7 +222,6 @@ cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) { struct cnfcfsyslinelst *cflst; action_t *pAction; - rsRetVal localRet; uchar *str; DEFiRet; @@ -280,7 +279,7 @@ void cnfDoRule(struct cnfrule *cnfrule) { rule_t *pRule; uchar *str; - DEFiRet; + rsRetVal iRet = RS_RET_OK; //DEFiRet; dbgprintf("cnf:global:rule\n"); cnfrulePrint(cnfrule); @@ -346,6 +345,17 @@ void cnfDoBSDHost(char *ln) dbgprintf("cnf:global:BSD host: %s\n", ln); cflineProcessHostSelector((uchar**)&ln); } + +es_str_t* +cnfGetVar(char *name, void *usrptr) +{ + es_str_t *estr; + dbgprintf("ZZZZ: var '%s' requested", name); + if(name[0] == '$') { + estr = msgGetMsgVarNew((msg_t*) usrptr, (uchar*)name+1); + } + return estr; +} /*------------------------------ end interface to flex/bison parser ------------------------------*/ diff --git a/runtime/rule.c b/runtime/rule.c index 8976c898..67ef8650 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -196,7 +196,7 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) /* VM is destructed on function exit */ bRet = (pResult->val.num) ? 1 : 0; #endif - bRet = cnfexprEvalBool(pRule->f_filterData.expr); + bRet = cnfexprEvalBool(pRule->f_filterData.expr, pMsg); dbgprintf("result of rainerscript filter evaluation: %d\n", bRet); } else { assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */ -- cgit v1.2.3 From 834fe024b4e53f65d9622a176116f232e212e326 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 07:13:56 +0200 Subject: milestone/[PARTWORK]: implemented "CONTAINS" --- grammar/rainerscript.c | 26 +++++++++++++++++++------- runtime/rsconf.c | 2 +- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index ea23dc1a..bcc73af0 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -332,8 +332,9 @@ void cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) { struct exprret r, l; /* memory for subexpression results */ - es_str_t *estr; + es_str_t *estr_r, *estr_l; int bMustFree; + int bMustFree2; //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { @@ -345,15 +346,15 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = !es_strcmp(l.d.estr, r.d.estr); } else { - estr = exprret2String(&r, &bMustFree); - ret->d.n = !es_strcmp(l.d.estr, estr); - if(bMustFree) es_deleteStr(estr); + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = !es_strcmp(l.d.estr, estr_r); + if(bMustFree) es_deleteStr(estr_r); } } else { if(r.datatype == 'S') { - estr = exprret2String(&l, &bMustFree); - ret->d.n = !es_strcmp(r.d.estr, estr); - if(bMustFree) es_deleteStr(estr); + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = !es_strcmp(r.d.estr, estr_l); + if(bMustFree) es_deleteStr(estr_l); } else { ret->d.n = (l.d.n == r.d.n); } @@ -374,6 +375,17 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) case CMP_GT: COMP_NUM_BINOP(>); break; + case CMP_CONTAINS: + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + estr_r = exprret2String(&r, &bMustFree); + estr_l = exprret2String(&l, &bMustFree2); + ret->datatype = 'N'; +dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); + ret->d.n = es_strContains(estr_l, estr_r) != -1; + if(bMustFree) es_deleteStr(estr_r); + if(bMustFree2) es_deleteStr(estr_l); + break; case OR: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 459c9a17..0d3c940a 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -350,7 +350,7 @@ es_str_t* cnfGetVar(char *name, void *usrptr) { es_str_t *estr; - dbgprintf("ZZZZ: var '%s' requested", name); + dbgprintf("ZZZZ: var '%s' requested\n", name); if(name[0] == '$') { estr = msgGetMsgVarNew((msg_t*) usrptr, (uchar*)name+1); } -- cgit v1.2.3 From d9ea755214ab75afa039a4df89f828d4b8b30ef0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 09:13:39 +0200 Subject: milestone/[PARTWORK]: implemented comparison operations --- grammar/lexer.l | 3 + grammar/rainerscript.c | 252 ++++++++++++++++++++++++++++++++++++++++++------- runtime/Makefile.am | 20 ++-- runtime/rsconf.c | 3 - runtime/rsyslog.c | 4 + runtime/rule.c | 11 --- tools/syslogd.c | 1 - 7 files changed, 236 insertions(+), 58 deletions(-) diff --git a/grammar/lexer.l b/grammar/lexer.l index d761003a..347a2a7a 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -72,6 +72,7 @@ struct bufstack { YY_BUFFER_STATE bs; int lineno; char *fn; + es_str_t *estr; } *currbs = NULL; char *currfn; /* name of currently processed file */ @@ -228,6 +229,7 @@ cnfSetLexFile(char *fname) bs->prev = currbs; bs->fn = strdup(fname == NULL ? "stdin" : fname); bs->bs = yy_scan_buffer((char*)es_getBufAddr(str), es_strlen(str)); + bs->estr = str; /* needed so we can free it later */ currbs = bs; currfn = bs->fn; yylineno = 1; @@ -253,6 +255,7 @@ popfile(void) /* delte current entry */ yy_delete_buffer(bs->bs); free(bs->fn); + free(bs->estr); /* switch back to previous */ currbs = bs->prev; diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index bcc73af0..0def9653 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -286,14 +286,17 @@ done: } /* ensure that retval is a number; if string is no number, - * emit error message and set number to 0. + * try to convert it to one. The semantics from es_str2num() + * are used (bSuccess tells if the conversion went well or not). */ static inline long long -exprret2Number(struct exprret *r) +exprret2Number(struct exprret *r, int *bSuccess) { long long n; if(r->datatype == 'S') { - n = es_str2num(r->d.estr); + n = es_str2num(r->d.estr, bSuccess); + } else { + *bSuccess = 1; } return r->d.n; } @@ -316,7 +319,17 @@ exprret2String(struct exprret *r, int *bMustFree) cnfexprEval(expr->l, &l, usrptr); \ cnfexprEval(expr->r, &r, usrptr); \ ret->datatype = 'N'; \ - ret->d.n = exprret2Number(&l) x exprret2Number(&r) + ret->d.n = exprret2Number(&l, &convok_l) x exprret2Number(&r, &convok_r) + +#define PREP_TWO_STRINGS \ + cnfexprEval(expr->l, &l, usrptr); \ + cnfexprEval(expr->r, &r, usrptr); \ + estr_r = exprret2String(&r, &bMustFree); \ + estr_l = exprret2String(&l, &bMustFree2) + +#define FREE_TWO_STRINGS \ + if(bMustFree) es_deleteStr(estr_r); \ + if(bMustFree2) es_deleteStr(estr_l) /* evaluate an expression. * Note that we try to avoid malloc whenever possible (because of @@ -333,67 +346,239 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) { struct exprret r, l; /* memory for subexpression results */ es_str_t *estr_r, *estr_l; - int bMustFree; - int bMustFree2; + int convok_r, convok_l; + int bMustFree, bMustFree2; + long long n_r, n_l; //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { + /* note: comparison operations are extremely similar. The code can be copyied, only + * places flagged with "CMP" need to be changed. + */ case CMP_EQ: cnfexprEval(expr->l, &l, usrptr); cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; if(l.datatype == 'S') { if(r.datatype == 'S') { - ret->d.n = !es_strcmp(l.d.estr, r.d.estr); + ret->d.n = !es_strcmp(l.d.estr, r.d.estr); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); - ret->d.n = !es_strcmp(l.d.estr, estr_r); - if(bMustFree) es_deleteStr(estr_r); + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l == r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = !es_strcmp(l.d.estr, estr_r); /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } } } else { if(r.datatype == 'S') { - estr_l = exprret2String(&l, &bMustFree); - ret->d.n = !es_strcmp(r.d.estr, estr_l); - if(bMustFree) es_deleteStr(estr_l); + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n == n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = !es_strcmp(r.d.estr, estr_l); /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } } else { - ret->d.n = (l.d.n == r.d.n); + ret->d.n = (l.d.n == r.d.n); /*CMP*/ } } break; case CMP_NE: - COMP_NUM_BINOP(!=); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr); /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l != r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r); /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n != n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l); /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n != r.d.n); /*CMP*/ + } + } break; case CMP_LE: - COMP_NUM_BINOP(<=); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr) <= 0; /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l <= r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r) <= 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n <= n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l) <= 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n <= r.d.n); /*CMP*/ + } + } break; case CMP_GE: - COMP_NUM_BINOP(>=); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr) >= 0; /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l >= r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r) >= 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n >= n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l) >= 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n >= r.d.n); /*CMP*/ + } + } break; case CMP_LT: - COMP_NUM_BINOP(<); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr) < 0; /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l < r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r) < 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n < n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l) < 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n < r.d.n); /*CMP*/ + } + } break; case CMP_GT: - COMP_NUM_BINOP(>); - break; - case CMP_CONTAINS: cnfexprEval(expr->l, &l, usrptr); cnfexprEval(expr->r, &r, usrptr); - estr_r = exprret2String(&r, &bMustFree); - estr_l = exprret2String(&l, &bMustFree2); ret->datatype = 'N'; -dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr) > 0; /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l > r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r) > 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n > n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l) > 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n > r.d.n); /*CMP*/ + } + } + break; + case CMP_STARTSWITH: + PREP_TWO_STRINGS; + ret->datatype = 'N'; + ret->d.n = es_strncmp(estr_l, estr_r, estr_r->lenStr) == 0; + FREE_TWO_STRINGS; + break; + case CMP_STARTSWITHI: + PREP_TWO_STRINGS; + ret->datatype = 'N'; + ret->d.n = es_strncasecmp(estr_l, estr_r, estr_r->lenStr) == 0; + FREE_TWO_STRINGS; + break; + case CMP_CONTAINS: + PREP_TWO_STRINGS; + ret->datatype = 'N'; ret->d.n = es_strContains(estr_l, estr_r) != -1; - if(bMustFree) es_deleteStr(estr_r); - if(bMustFree2) es_deleteStr(estr_l); + FREE_TWO_STRINGS; + break; + case CMP_CONTAINSI: + PREP_TWO_STRINGS; + ret->datatype = 'N'; + ret->d.n = es_strCaseContains(estr_l, estr_r) != -1; + FREE_TWO_STRINGS; break; case OR: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; - if(exprret2Number(&l)) { + if(exprret2Number(&l, &convok_l)) { ret->d.n = 1ll; } else { cnfexprEval(expr->r, &r, usrptr); - if(exprret2Number(&r)) + if(exprret2Number(&r, &convok_r)) ret->d.n = 1ll; else ret->d.n = 0ll; @@ -402,9 +587,9 @@ dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); case AND: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; - if(exprret2Number(&l)) { + if(exprret2Number(&l, &convok_l)) { cnfexprEval(expr->r, &r, usrptr); - if(exprret2Number(&r)) + if(exprret2Number(&r, &convok_r)) ret->d.n = 1ll; else ret->d.n = 0ll; @@ -415,7 +600,7 @@ dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); case NOT: cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; - ret->d.n = !exprret2Number(&r); + ret->d.n = !exprret2Number(&r, &convok_r); break; case 'N': ret->datatype = 'N'; @@ -447,7 +632,7 @@ dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); case 'M': cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; - ret->d.n = -exprret2Number(&r); + ret->d.n = -exprret2Number(&r, &convok_r); break; default: ret->datatype = 'N'; @@ -465,9 +650,10 @@ dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); int cnfexprEvalBool(struct cnfexpr *expr, void *usrptr) { + int convok; struct exprret ret; cnfexprEval(expr, &ret, usrptr); - return exprret2Number(&ret); + return exprret2Number(&ret, &convok); } inline static void diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 7c3d18ef..c6c860ea 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -5,6 +5,16 @@ pkglib_LTLIBRARIES = #pkglib_LTLIBRARIES = librsyslog.la librsyslog_la_SOURCES = \ + expr.c \ + expr.h \ + vm.c \ + vm.h \ + vmstk.c \ + vmstk.h \ + vmprg.c \ + vmprg.h \ + vmop.c \ + vmop.h \ rsyslog.c \ rsyslog.h \ typedefs.h \ @@ -55,8 +65,6 @@ librsyslog_la_SOURCES = \ statsobj.h \ sync.c \ sync.h \ - expr.c \ - expr.h \ ctok.c \ ctok.h \ ctok_token.c \ @@ -71,14 +79,6 @@ librsyslog_la_SOURCES = \ wti.h \ sysvar.c \ sysvar.h \ - vm.c \ - vm.h \ - vmstk.c \ - vmstk.h \ - vmprg.c \ - vmprg.h \ - vmop.c \ - vmop.h \ queue.c \ queue.h \ ruleset.c \ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 0d3c940a..c1bc3b72 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -1152,11 +1152,8 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! CHKiRet(initLegacyConf()); /* open the configuration file */ - dbgprintf("ZZZZZ: calling cnfSetLexFile(%s)\n", confFile); r = cnfSetLexFile((char*)confFile); - dbgprintf("ZZZZZ: cnfSetLexFile returns %d, calling yyparse()\n", r); r = yyparse(); - dbgprintf("ZZZZZ: yyparse returns %d\n", r); //localRet = conf.processConfFile(loadConf, confFile); CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions)); diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index 2b8f2b64..d71fe88a 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -182,10 +182,13 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(ctok_tokenClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "ctok"; CHKiRet(ctokClassInit(NULL)); +#if 1 if(ppErrObj != NULL) *ppErrObj = "vmstk"; CHKiRet(vmstkClassInit(NULL)); +#endif if(ppErrObj != NULL) *ppErrObj = "sysvar"; CHKiRet(sysvarClassInit(NULL)); +#if 1 if(ppErrObj != NULL) *ppErrObj = "vm"; CHKiRet(vmClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "vmop"; @@ -194,6 +197,7 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(vmprgClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "expr"; CHKiRet(exprClassInit(NULL)); +#endif if(ppErrObj != NULL) *ppErrObj = "rule"; CHKiRet(ruleClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "ruleset"; diff --git a/runtime/rule.c b/runtime/rule.c index 67ef8650..0b4b48a2 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -36,7 +36,6 @@ #include "action.h" #include "rule.h" #include "errmsg.h" -#include "vm.h" #include "var.h" #include "srUtils.h" #include "batch.h" @@ -46,9 +45,7 @@ /* static data */ DEFobjStaticHelpers DEFobjCurrIf(errmsg) -DEFobjCurrIf(expr) DEFobjCurrIf(var) -DEFobjCurrIf(vm) /* support for simple textual representation of FIOP names @@ -124,7 +121,6 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) uchar *pszPropVal; int bRet = 0; size_t propLen; - vm_t *pVM = NULL; var_t *pResult = NULL; ISOBJ_TYPE_assert(pRule, rule); @@ -276,9 +272,6 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) finalize_it: /* destruct in any case, not just on error, but it makes error handling much easier */ - if(pVM != NULL) - vm.Destruct(&pVM); - if(pResult != NULL) var.Destruct(&pResult); @@ -482,9 +475,7 @@ ENDobjQueryInterface(rule) */ BEGINObjClassExit(rule, OBJ_IS_CORE_MODULE) /* class, version */ objRelease(errmsg, CORE_COMPONENT); - objRelease(expr, CORE_COMPONENT); objRelease(var, CORE_COMPONENT); - objRelease(vm, CORE_COMPONENT); ENDObjClassExit(rule) @@ -495,9 +486,7 @@ ENDObjClassExit(rule) BEGINObjClassInit(rule, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ CHKiRet(objUse(errmsg, CORE_COMPONENT)); - CHKiRet(objUse(expr, CORE_COMPONENT)); CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(vm, CORE_COMPONENT)); /* set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, ruleDebugPrint); diff --git a/tools/syslogd.c b/tools/syslogd.c index 79bf0c8a..f623b398 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -1602,7 +1602,6 @@ GlobalClassExit(void) objRelease(ruleset, CORE_COMPONENT); objRelease(rule, CORE_COMPONENT); objRelease(expr, CORE_COMPONENT); - vmClassExit(); /* this is hack, currently core_modules do not get this automatically called */ parserClassExit(); /* this is hack, currently core_modules do not get this automatically called */ rsconfClassExit(); /* this is hack, currently core_modules do not get this automatically called */ objRelease(datetime, CORE_COMPONENT); -- cgit v1.2.3 From 379bd30a5481056c2e5e71443149fb6b3b2295fc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 14:50:35 +0200 Subject: milestone/[PARTWORK]: integrated all variable types (msg/sys/cee) --- grammar/rainerscript.c | 24 ++++++++++-- runtime/msg.c | 42 +++++++++++++++++++++ runtime/msg.h | 1 + runtime/rsconf.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 161 insertions(+), 5 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 0def9653..91e71e97 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -285,6 +285,7 @@ done: return expr; } + /* ensure that retval is a number; if string is no number, * try to convert it to one. The semantics from es_str2num() * are used (bSuccess tells if the conversion went well or not). @@ -315,21 +316,28 @@ exprret2String(struct exprret *r, int *bMustFree) return r->d.estr; } +#define FREE_BOTH_RET \ + if(r.datatype == 'S') es_deleteStr(r.d.estr); \ + if(l.datatype == 'S') es_deleteStr(l.d.estr) + #define COMP_NUM_BINOP(x) \ cnfexprEval(expr->l, &l, usrptr); \ cnfexprEval(expr->r, &r, usrptr); \ ret->datatype = 'N'; \ - ret->d.n = exprret2Number(&l, &convok_l) x exprret2Number(&r, &convok_r) + ret->d.n = exprret2Number(&l, &convok_l) x exprret2Number(&r, &convok_r); \ + FREE_BOTH_RET #define PREP_TWO_STRINGS \ cnfexprEval(expr->l, &l, usrptr); \ cnfexprEval(expr->r, &r, usrptr); \ estr_r = exprret2String(&r, &bMustFree); \ - estr_l = exprret2String(&l, &bMustFree2) + estr_l = exprret2String(&l, &bMustFree2); \ + FREE_BOTH_RET #define FREE_TWO_STRINGS \ if(bMustFree) es_deleteStr(estr_r); \ - if(bMustFree2) es_deleteStr(estr_l) + if(bMustFree2) es_deleteStr(estr_l); \ + FREE_BOTH_RET /* evaluate an expression. * Note that we try to avoid malloc whenever possible (because of @@ -386,6 +394,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n == r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_NE: cnfexprEval(expr->l, &l, usrptr); @@ -418,6 +427,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n != r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_LE: cnfexprEval(expr->l, &l, usrptr); @@ -450,6 +460,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n <= r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_GE: cnfexprEval(expr->l, &l, usrptr); @@ -482,6 +493,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n >= r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_LT: cnfexprEval(expr->l, &l, usrptr); @@ -514,6 +526,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n < r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_GT: cnfexprEval(expr->l, &l, usrptr); @@ -546,6 +559,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n > r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_STARTSWITH: PREP_TWO_STRINGS; @@ -583,6 +597,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) else ret->d.n = 0ll; } + FREE_BOTH_RET; break; case AND: cnfexprEval(expr->l, &l, usrptr); @@ -596,11 +611,13 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) } else { ret->d.n = 0ll; } + FREE_BOTH_RET; break; case NOT: cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; ret->d.n = !exprret2Number(&r, &convok_r); + if(r.datatype == 'S') es_deleteStr(r.d.estr); break; case 'N': ret->datatype = 'N'; @@ -633,6 +650,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; ret->d.n = -exprret2Number(&r, &convok_r); + if(r.datatype == 'S') es_deleteStr(r.d.estr); break; default: ret->datatype = 'N'; diff --git a/runtime/msg.c b/runtime/msg.c index 96fe1b2c..4e96a02f 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -3116,9 +3116,51 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, * to rewrite the script engine as well! * rgerhards, 2010-12-03 */ +es_str_t* +msgGetCEEVarNew(msg_t *pMsg, char *name) +{ + es_str_t *estr = NULL; + es_str_t *epropName = NULL; + struct ee_field *field; + + ISOBJ_TYPE_assert(pMsg, msg); + + if(pMsg->event == NULL) { + estr = es_newStr(1); + goto done; + } + + epropName = es_newStrFromCStr(name, strlen(name)); // TODO: optimize (in grammar!) +dbgprintf("ZZZZ: pmsg->event %p\n", pMsg->event); + field = ee_getEventField(pMsg->event, epropName); + if(field != NULL) { + estr = ee_getFieldValueAsStr(field, 0); + } + if(estr == NULL) { + DBGPRINTF("msgGetCEEVar: error obtaining var (field=%p, var='%s')\n", + field, name); + estr = es_newStrFromCStr("*ERROR*", sizeof("*ERROR*") - 1); + } + es_deleteStr(epropName); + +done: + return estr; +} + + +/* The function returns a cee variable suitable for use with RainerScript. Most importantly, this means + * that the value is returned in a var_t object. The var_t is constructed inside this function and + * MUST be freed by the caller. + * Note that we need to do a lot of conversions between es_str_t and cstr -- this will go away once + * we have moved larger parts of rsyslog to es_str_t. Acceptable for the moment, especially as we intend + * to rewrite the script engine as well! + * rgerhards, 2010-12-03 + * + */ rsRetVal msgGetCEEVar(msg_t *pMsg, cstr_t *propName, var_t **ppVar) { +#warning remove as part of cleanup DEFiRet; var_t *pVar; cstr_t *pstrProp; diff --git a/runtime/msg.h b/runtime/msg.h index 19debb03..55d2dfc0 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -178,6 +178,7 @@ char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt); char *getPRI(msg_t *pMsg); void getRawMsg(msg_t *pM, uchar **pBuf, int *piLen); rsRetVal msgGetCEEVar(msg_t *pThis, cstr_t *propName, var_t **ppVar); +es_str_t* msgGetCEEVarNew(msg_t *pMsg, char *name); /* TODO: remove these five (so far used in action.c) */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index c1bc3b72..d12a258b 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -65,6 +65,7 @@ #include "parser.h" #include "outchannel.h" #include "threads.h" +#include "datetime.h" #include "parserif.h" #include "dirty.h" @@ -77,6 +78,7 @@ DEFobjCurrIf(conf) DEFobjCurrIf(errmsg) DEFobjCurrIf(glbl) DEFobjCurrIf(parser) +DEFobjCurrIf(datetime) /* exported static data */ rsconf_t *runConf = NULL;/* the currently running config */ @@ -244,6 +246,87 @@ cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) RETiRet; } +/* This function returns the current date in different + * variants. It is used to construct the $NOW series of + * system properties. The returned buffer must be freed + * by the caller when no longer needed. If the function + * can not allocate memory, it returns a NULL pointer. + * TODO: this was taken from msg.c and we should consolidate it with the code + * there. This is especially important when we increase the number of system + * variables (what we definitely want to do). + */ +typedef enum ENOWType { NOW_NOW, NOW_YEAR, NOW_MONTH, NOW_DAY, NOW_HOUR, NOW_MINUTE } eNOWType; +static rsRetVal +getNOW(eNOWType eNow, es_str_t **estr) +{ + DEFiRet; + uchar szBuf[16]; + struct syslogTime t; + es_size_t len; + + datetime.getCurrTime(&t, NULL); + switch(eNow) { + case NOW_NOW: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), + "%4.4d-%2.2d-%2.2d", t.year, t.month, t.day); + break; + case NOW_YEAR: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%4.4d", t.year); + break; + case NOW_MONTH: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.month); + break; + case NOW_DAY: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.day); + break; + case NOW_HOUR: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.hour); + break; + case NOW_MINUTE: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.minute); + break; + } + + /* now create a string object out of it and hand that over to the var */ + *estr = es_newStrFromCStr((char*)szBuf, len); + + RETiRet; +} + + + +static inline es_str_t * +getSysVar(char *name) +{ + es_str_t *estr = NULL; + rsRetVal iRet = RS_RET_OK; + + if(!strcmp(name, "now")) { + CHKiRet(getNOW(NOW_NOW, &estr)); + } else if(!strcmp(name, "year")) { + CHKiRet(getNOW(NOW_YEAR, &estr)); + } else if(!strcmp(name, "month")) { + CHKiRet(getNOW(NOW_MONTH, &estr)); + } else if(!strcmp(name, "day")) { + CHKiRet(getNOW(NOW_DAY, &estr)); + } else if(!strcmp(name, "hour")) { + CHKiRet(getNOW(NOW_HOUR, &estr)); + } else if(!strcmp(name, "minute")) { + CHKiRet(getNOW(NOW_MINUTE, &estr)); + } else if(!strcmp(name, "myhostname")) { + char *hn = (char*)glbl.GetLocalHostName(); + estr = es_newStrFromCStr(hn, strlen(hn)); + } else { + ABORT_FINALIZE(RS_RET_SYSVAR_NOT_FOUND); + } +finalize_it: + if(iRet != RS_RET_OK) { + dbgprintf("getSysVar error iRet %d\n", iRet); + if(estr == NULL) + estr = es_newStrFromCStr("*ERROR*", sizeof("*ERROR*") - 1); + } + return estr; +} /*------------------------------ interface to flex/bison parser ------------------------------*/ extern int yylineno; @@ -350,9 +433,19 @@ es_str_t* cnfGetVar(char *name, void *usrptr) { es_str_t *estr; - dbgprintf("ZZZZ: var '%s' requested\n", name); if(name[0] == '$') { - estr = msgGetMsgVarNew((msg_t*) usrptr, (uchar*)name+1); + if(name[1] == '$') + estr = getSysVar(name+2); + else if(name[1] == '!') + estr = msgGetCEEVarNew((msg_t*) usrptr, name+2); + else + estr = msgGetMsgVarNew((msg_t*) usrptr, (uchar*)name+1); + } + if(Debug) { + char *s; + s = es_str2cstr(estr, NULL); + dbgprintf("rainerscript: var '%s': '%s'\n", name, s); + free(s); } return estr; } @@ -1258,6 +1351,7 @@ BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */ CHKiRet(objUse(conf, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(parser, CORE_COMPONENT)); /* now set our own handlers */ @@ -1275,6 +1369,7 @@ BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */ objRelease(conf, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); + objRelease(datetime, CORE_COMPONENT); objRelease(parser, CORE_COMPONENT); ENDObjClassExit(rsconf) -- cgit v1.2.3 From d649820ee508a9de3bcf37a9e3b71ff11ca3a8ea Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 14:59:42 +0200 Subject: cosmetic updates --- runtime/msg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/runtime/msg.c b/runtime/msg.c index 4e96a02f..0de805a7 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -3108,9 +3108,8 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, } -/* The function returns a cee variable suitable for use with RainerScript. Most importantly, this means - * that the value is returned in a var_t object. The var_t is constructed inside this function and - * MUST be freed by the caller. +/* The function returns a cee variable suitable for use with RainerScript. + * Note: caller must free the returned string. * Note that we need to do a lot of conversions between es_str_t and cstr -- this will go away once * we have moved larger parts of rsyslog to es_str_t. Acceptable for the moment, especially as we intend * to rewrite the script engine as well! @@ -3131,7 +3130,6 @@ msgGetCEEVarNew(msg_t *pMsg, char *name) } epropName = es_newStrFromCStr(name, strlen(name)); // TODO: optimize (in grammar!) -dbgprintf("ZZZZ: pmsg->event %p\n", pMsg->event); field = ee_getEventField(pMsg->event, epropName); if(field != NULL) { estr = ee_getFieldValueAsStr(field, 0); -- cgit v1.2.3 From f2ef6cd10699ab9f91b9e3e53726512cd290ea68 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 19:00:23 +0200 Subject: optimized function representation --- grammar/rainerscript.c | 36 ++++++++++++++++++++++++++++-------- grammar/rainerscript.h | 4 +++- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 91e71e97..de15d5f3 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -685,6 +685,9 @@ void cnfexprPrint(struct cnfexpr *expr, int indent) { struct cnffparamlst *param; + struct cnffunc *func; + int i; + //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: @@ -779,12 +782,11 @@ cnfexprPrint(struct cnfexpr *expr, int indent) break; case 'F': doIndent(indent); - cstrPrint("function '", ((struct cnffunc*)expr)->fname); - dbgprintf("'\n"); - for( param = ((struct cnffunc*)expr)->paramlst - ; param != NULL - ; param = param->next) { - cnfexprPrint(param->expr, indent+1); + func = (struct cnffunc*) expr; + cstrPrint("function '", func->fname); + dbgprintf("' (%u params)\n", (unsigned) func->nParams); + for(i = 0 ; i < func->nParams ; ++i) { + cnfexprPrint(func->expr[i], indent+1); } break; case '+': @@ -888,10 +890,28 @@ struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) { struct cnffunc* func; - if((func = malloc(sizeof(struct cnffunc))) != NULL) { + struct cnffparamlst *param, *toDel; + unsigned short i; + unsigned short nParams; + + /* we first need to find out how many params we have */ + nParams = 0; + for(param = paramlst ; param != NULL ; param = param->next) + ++nParams; + if((func = malloc(sizeof(struct cnffunc) + (nParams * sizeof(struct cnfexp*)))) + != NULL) { func->nodetype = 'F'; func->fname = fname; - func->paramlst = paramlst; + func->nParams = nParams; + func->fID = 0; /* use name */ + /* shuffle params over to array (access speed!) */ + param = paramlst; + for(i = 0 ; i < nParams ; ++i) { + func->expr[i] = param->expr; + toDel = param; + param = param->next; + free(toDel); + } } return func; } diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 8b5c36de..b7abf153 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -128,7 +128,9 @@ struct cnffparamlst { struct cnffunc { unsigned nodetype; es_str_t *fname; - struct cnffparamlst *paramlst; + unsigned short nParams; + unsigned short *fID; /* function ID for built-ins, 0 means use name */ + struct cnfexpr *expr[]; }; /* future extensions -- cgit v1.2.3 From f5e0bbe2d9d1d9594a01fc869392374d1a44afbe Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 09:30:17 +0200 Subject: milestone/[PARTWORK]: implemented RainerScript functions --- grammar/rainerscript.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++--- grammar/rainerscript.h | 19 +++++++- grammar/testdriver.c | 1 + 3 files changed, 129 insertions(+), 7 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index de15d5f3..41107de5 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -316,6 +316,91 @@ exprret2String(struct exprret *r, int *bMustFree) return r->d.estr; } +/* Perform a function call. This has been moved out of cnfExprEval in order + * to keep the code small and easier to maintain. + */ +static inline void +doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) +{ + char *fname; + char *envvar; + int bMustFree; + es_str_t *estr; + char *str; + struct exprret r[CNFFUNC_MAX_ARGS]; + + dbgprintf("rainerscript: executing function id %d\n", func->fID); + switch(func->fID) { + case CNFFUNC_STRLEN: + if(func->expr[0]->nodetype == 'S') { + /* if we already have a string, we do not need to + * do one more recursive call. + */ + ret->d.n = es_strlen(((struct cnfstringval*) func->expr[0])->estr); + } else { + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = exprret2String(&r[0], &bMustFree); + ret->d.n = es_strlen(estr); + if(bMustFree) es_deleteStr(estr); + } + ret->datatype = 'N'; + break; + case CNFFUNC_GETENV: + /* note: the optimizer shall have replaced calls to getenv() + * with a constant argument to a single string (once obtained via + * getenv()). So we do NOT need to check if there is just a + * string following. + */ + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = exprret2String(&r[0], &bMustFree); + str = (char*) es_str2cstr(estr, NULL); + envvar = getenv(str); + ret->datatype = 'S'; + ret->d.estr = es_newStrFromCStr(envvar, strlen(envvar)); + if(bMustFree) es_deleteStr(estr); + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); + free(str); + break; + case CNFFUNC_TOLOWER: + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = exprret2String(&r[0], &bMustFree); + if(!bMustFree) /* let caller handle that M) */ + estr = es_strdup(estr); + es_tolower(estr); + ret->datatype = 'S'; + ret->d.estr = estr; + break; + case CNFFUNC_CSTR: + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = exprret2String(&r[0], &bMustFree); + if(!bMustFree) /* let caller handle that M) */ + estr = es_strdup(estr); + ret->datatype = 'S'; + ret->d.estr = estr; + break; + case CNFFUNC_CNUM: + if(func->expr[0]->nodetype == 'N') { + ret->d.n = ((struct cnfnumval*)func->expr[0])->val; + } else if(func->expr[0]->nodetype == 'S') { + ret->d.n = es_str2num(((struct cnfstringval*) func->expr[0])->estr, + NULL); + } else { + cnfexprEval(func->expr[0], &r[0], usrptr); + ret->d.n = exprret2Number(&r[0], NULL); + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); + } + ret->datatype = 'N'; + break; + default: + if(Debug) { + fname = es_str2cstr(func->fname, NULL); + dbgprintf("rainerscript: invalid function id %u (name '%s')\n", + (unsigned) func->fID, fname); + free(fname); + } + } +} + #define FREE_BOTH_RET \ if(r.datatype == 'S') es_deleteStr(r.d.estr); \ if(l.datatype == 'S') es_deleteStr(l.d.estr) @@ -329,10 +414,9 @@ exprret2String(struct exprret *r, int *bMustFree) #define PREP_TWO_STRINGS \ cnfexprEval(expr->l, &l, usrptr); \ - cnfexprEval(expr->r, &r, usrptr); \ - estr_r = exprret2String(&r, &bMustFree); \ estr_l = exprret2String(&l, &bMustFree2); \ - FREE_BOTH_RET + cnfexprEval(expr->r, &r, usrptr); \ + estr_r = exprret2String(&r, &bMustFree) #define FREE_TWO_STRINGS \ if(bMustFree) es_deleteStr(estr_r); \ @@ -652,6 +736,9 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = -exprret2Number(&r, &convok_r); if(r.datatype == 'S') es_deleteStr(r.d.estr); break; + case 'F': + doFuncCall((struct cnffunc*) expr, ret, usrptr); + break; default: ret->datatype = 'N'; ret->d.n = 0ll; @@ -684,7 +771,6 @@ doIndent(int indent) void cnfexprPrint(struct cnfexpr *expr, int indent) { - struct cnffparamlst *param; struct cnffunc *func; int i; @@ -784,7 +870,7 @@ cnfexprPrint(struct cnfexpr *expr, int indent) doIndent(indent); func = (struct cnffunc*) expr; cstrPrint("function '", func->fname); - dbgprintf("' (%u params)\n", (unsigned) func->nParams); + dbgprintf("' (id:%d, params:%hu)\n", func->fID, func->nParams); for(i = 0 ; i < func->nParams ; ++i) { cnfexprPrint(func->expr[i], indent+1); } @@ -886,6 +972,24 @@ cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) return lst; } +static inline enum cnffuncid +funcName2ID(es_str_t *fname) +{ + if(!es_strbufcmp(fname, (unsigned char*)"strlen", sizeof("strlen") - 1)) { + return CNFFUNC_STRLEN; + } else if(!es_strbufcmp(fname, (unsigned char*)"getenv", sizeof("getenv") - 1)) { + return CNFFUNC_GETENV; + } else if(!es_strbufcmp(fname, (unsigned char*)"tolower", sizeof("tolower") - 1)) { + return CNFFUNC_TOLOWER; + } else if(!es_strbufcmp(fname, (unsigned char*)"cstr", sizeof("cstr") - 1)) { + return CNFFUNC_CSTR; + } else if(!es_strbufcmp(fname, (unsigned char*)"cnum", sizeof("cnum") - 1)) { + return CNFFUNC_CNUM; + } else { + return CNFFUNC_INVALID; + } +} + struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) { @@ -903,7 +1007,7 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) func->nodetype = 'F'; func->fname = fname; func->nParams = nParams; - func->fID = 0; /* use name */ + func->fID = funcName2ID(fname); /* shuffle params over to array (access speed!) */ param = paramlst; for(i = 0 ; i < nParams ; ++i) { diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index b7abf153..5d9eff7f 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -3,6 +3,13 @@ #include #include +#define CNFFUNC_MAX_ARGS 32 + /**< maximum number of arguments that any function can have (among + * others, this is used to size data structures). + */ + +extern int Debug; /* 1 if in debug mode, 0 otherwise -- to be enhanced */ + enum cnfobjType { CNFOBJ_ACTION, CNFOBJ_GLOBAL, @@ -125,11 +132,21 @@ struct cnffparamlst { struct cnfexpr *expr; }; +enum cnffuncid { + CNFFUNC_INVALID = 0, /**< defunct entry, do not use (should normally not be present) */ + CNFFUNC_NAME = 1, /**< use name to call function (for future use) */ + CNFFUNC_STRLEN, + CNFFUNC_GETENV, + CNFFUNC_TOLOWER, + CNFFUNC_CSTR, + CNFFUNC_CNUM +}; + struct cnffunc { unsigned nodetype; es_str_t *fname; unsigned short nParams; - unsigned short *fID; /* function ID for built-ins, 0 means use name */ + enum cnffuncid fID; /* function ID for built-ins, 0 means use name */ struct cnfexpr *expr[]; }; diff --git a/grammar/testdriver.c b/grammar/testdriver.c index 3e161d38..784e286e 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -30,6 +30,7 @@ #include "parserif.h" extern int yylineno; +int Debug = 1; void parser_errmsg(char *fmt, ...) -- cgit v1.2.3 From 59f8ebdba75d693f7b462f51b7b50136b590dea7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 09:43:06 +0200 Subject: checking number of parameters provided to function --- grammar/rainerscript.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 41107de5..f8809e13 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -398,6 +398,8 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) (unsigned) func->fID, fname); free(fname); } + ret->datatype = 'N'; + ret->d.n = 0; } } @@ -972,18 +974,46 @@ cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) return lst; } +/* Obtain function id from name AND number of params. Issues the + * relevant error messages if errors are detected. + */ static inline enum cnffuncid -funcName2ID(es_str_t *fname) +funcName2ID(es_str_t *fname, unsigned short nParams) { if(!es_strbufcmp(fname, (unsigned char*)"strlen", sizeof("strlen") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for strlen() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_STRLEN; } else if(!es_strbufcmp(fname, (unsigned char*)"getenv", sizeof("getenv") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for getenv() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_GETENV; } else if(!es_strbufcmp(fname, (unsigned char*)"tolower", sizeof("tolower") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for tolower() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_TOLOWER; } else if(!es_strbufcmp(fname, (unsigned char*)"cstr", sizeof("cstr") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for cstr() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_CSTR; } else if(!es_strbufcmp(fname, (unsigned char*)"cnum", sizeof("cnum") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for cnum() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_CNUM; } else { return CNFFUNC_INVALID; @@ -1007,7 +1037,7 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) func->nodetype = 'F'; func->fname = fname; func->nParams = nParams; - func->fID = funcName2ID(fname); + func->fID = funcName2ID(fname, nParams); /* shuffle params over to array (access speed!) */ param = paramlst; for(i = 0 ; i < nParams ; ++i) { -- cgit v1.2.3 From da6489743cd31a7896f17f5500dbfd18e0560260 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 17:33:12 +0200 Subject: milestone/[PARTWORK]: made sure all legacy selectors work ... except for the not guaranteed $outchannel construct, which we could not fix without syntax change. Shouldn't hurt too many. --- doc/log_rotation_fix_size.html | 2 +- doc/rsyslog_conf_output.html | 2 +- grammar/grammar.y | 1 + grammar/lexer.l | 3 ++- tools/omfile.c | 8 ++++++++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/doc/log_rotation_fix_size.html b/doc/log_rotation_fix_size.html index 190b24cb..51edf033 100644 --- a/doc/log_rotation_fix_size.html +++ b/doc/log_rotation_fix_size.html @@ -34,7 +34,7 @@ Channels to achieve this. Putting the following directive

# outchannel definiation $outchannel log_rotation,/var/log/log_rotation.log, 52428800,/home/me/./log_rotation_script # activate the channel and log everything to it -*.* $log_rotation +*.* :omfile:$log_rotation # end log rotation via outchannel

diff --git a/doc/rsyslog_conf_output.html b/doc/rsyslog_conf_output.html index c52aaa5e..426f2f27 100644 --- a/doc/rsyslog_conf_output.html +++ b/doc/rsyslog_conf_output.html @@ -49,7 +49,7 @@ does not activate it. To do so, you must use a selector line (see below). That selector line includes the channel name plus an $ sign in front of it. A sample might be:

-*.* $mychannel
+*.* :omfile:$mychannel

In its current form, output channels primarily provide the ability to size-limit an output file. To do so, specify a maximum size. When this diff --git a/grammar/grammar.y b/grammar/grammar.y index b8790411..402b1a57 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -63,6 +63,7 @@ extern int yyerror(char*); %token ENDOBJ %token CFSYSLINE %token BEGIN_ACTION +%token STOP %token LEGACY_ACTION %token PRIFILT %token PROPFILT diff --git a/grammar/lexer.l b/grammar/lexer.l index 347a2a7a..802b2d89 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -134,6 +134,7 @@ int fileno(FILE *stream); /* line number support because the "preprocessor" combines lines and so needs * to tell us the real source line. */ +"stop" { dbgprintf("STOP\n"); return STOP; } "preprocfilelinenumber(" { BEGIN LINENO; } [0-9]+ { yylineno = atoi(yytext) - 1; } ")" { BEGIN INITIAL; } @@ -159,7 +160,7 @@ int fileno(FILE *stream); \-\/[^*][^\n]* | \/[^*][^\n]* | :[a-z0-9]+:[^\n]* | -[\|\.\-\@~][^\n]+ | +[\|\.\-\@\^?~>][^\n]+ | [a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); // printf("lex: LEGA ACT: '%s'\n", yytext); return LEGACY_ACTION; } diff --git a/tools/omfile.c b/tools/omfile.c index b50a36ab..8ecfc302 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -712,6 +712,14 @@ ENDdoAction BEGINparseSelectorAct CODESTARTparseSelectorAct + /* Note: the indicator sequence permits us to use '$' to signify + * outchannel, what otherwise is not possible due to truely + * unresolvable grammar conflicts (*this time no way around*). + * rgerhards, 2011-07-09 + */ + if(!strncmp((char*) p, ":omfile:", sizeof(":omfile:") - 1)) { + p += sizeof(":omfile:") - 1; + } if(!(*p == '$' || *p == '?' || *p == '/' || *p == '.' || *p == '-')) ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); -- cgit v1.2.3 From 6ebf9ada253ffd8c88cbe84a46fd5aa3bfd58367 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 18:00:29 +0200 Subject: milestone/[WORKS AGAIN!]: looks like the new conf format is integrated finally completed $IncludeConfig processing. --- grammar/lexer.l | 2 +- grammar/rainerscript.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rainerscript.h | 1 + 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/grammar/lexer.l b/grammar/lexer.l index 802b2d89..316b2a65 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -143,7 +143,7 @@ int fileno(FILE *stream); * always the longest match :-( */ .|\n -[^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) +[^ \t\n]+ { if(cnfDoInclude(yytext) != 0) yyterminate(); BEGIN INITIAL; } "global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index f8809e13..680f8775 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include #include "rainerscript.h" #include "parserif.h" @@ -1050,6 +1053,55 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) return func; } +int +cnfDoInclude(char *name) +{ + char *cfgFile; + unsigned i; + int result; + glob_t cfgFiles; + struct stat fileInfo; + + /* Use GLOB_MARK to append a trailing slash for directories. + * Required by doIncludeDirectory(). + */ + result = glob(name, GLOB_MARK, NULL, &cfgFiles); + if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { +#if 0 + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s", + pattern, errStr); + ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND); +#endif + dbgprintf("includeconfig glob error %d\n", errno); + return 1; + } + + for(i = 0; i < cfgFiles.gl_pathc; i++) { + cfgFile = cfgFiles.gl_pathv[i]; + + if(stat(cfgFile, &fileInfo) != 0) + continue; /* continue with the next file if we can't stat() the file */ + + if(S_ISREG(fileInfo.st_mode)) { /* config file */ + dbgprintf("requested to include config file '%s'\n", cfgFile); + cnfSetLexFile(cfgFile); + } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */ + if(strcmp(name, cfgFile)) { + /* do not include ourselves! */ + dbgprintf("requested to include directory '%s'\n", cfgFile); + cnfDoInclude(cfgFile); + } + } else { + dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile); + } + } + + globfree(&cfgFiles); + return 0; +} + void cstrPrint(char *text, es_str_t *estr) { diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 5d9eff7f..75bb782d 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -189,6 +189,7 @@ void cnfrulePrint(struct cnfrule *rule); struct cnfvar* cnfvarNew(char *name); struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst); struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next); +int cnfDoInclude(char *name); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); -- cgit v1.2.3 From 5e2b03a31c312e6cd6a7f4cb0bca1f062668dc52 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 18:31:50 +0200 Subject: cleaup & emergency config system reactivated --- grammar/lexer.l | 23 +++++ grammar/rainerscript.h | 1 + runtime/conf.c | 257 ------------------------------------------------- runtime/conf.h | 2 - runtime/rsconf.c | 56 ++++------- runtime/rule.c | 9 -- runtime/rule.h | 1 - tests/Makefile.am | 3 +- 8 files changed, 44 insertions(+), 308 deletions(-) diff --git a/grammar/lexer.l b/grammar/lexer.l index 316b2a65..64a804fa 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -198,6 +198,29 @@ int fileno(FILE *stream); <> { if(popfile() != 0) yyterminate(); } %% +int +cnfParseBuffer(char *buf, unsigned lenBuf) +{ + struct bufstack *bs; + int r = 0; + /* maintain stack */ + if((bs = malloc(sizeof(struct bufstack))) == NULL) { + r = 1; + goto done; + } + + if(currbs != NULL) + currbs->lineno = yylineno; + bs->prev = currbs; + bs->fn = strdup("*buffer*"); + bs->bs = yy_scan_buffer(buf, lenBuf); + bs->estr = NULL; + currbs = bs; + currfn = bs->fn; + yylineno = 1; +done: return r; +} + /* set a new buffers. Returns 0 on success, something else otherwise. */ int cnfSetLexFile(char *fname) diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 75bb782d..62c2aa50 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -166,6 +166,7 @@ struct exprret { }; +int cnfParseBuffer(char *buf, unsigned lenBuf); void readConfFile(FILE *fp, es_str_t **str); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); void nvlstDestruct(struct nvlst *lst); diff --git a/runtime/conf.c b/runtime/conf.c index 51cf39e1..4c8f2285 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -79,7 +79,6 @@ /* forward definitions */ static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); -static rsRetVal processConfFile(rsconf_t *conf, uchar *pConfFile); /* static data */ @@ -109,146 +108,6 @@ cstr_t *pDfltHostnameCmp = NULL; cstr_t *pDfltProgNameCmp = NULL; -/* process a directory and include all of its files into - * the current config file. There is no specific order of inclusion, - * files are included in the order they are read from the directory. - * The caller must have make sure that the provided parameter is - * indeed a directory. - * rgerhards, 2007-08-01 - */ -static rsRetVal doIncludeDirectory(rsconf_t *conf, uchar *pDirName) -{ - DEFiRet; - int iEntriesDone = 0; - DIR *pDir; - union { - struct dirent d; - char b[offsetof(struct dirent, d_name) + NAME_MAX + 1]; - } u; - struct dirent *res; - size_t iDirNameLen; - size_t iFileNameLen; - uchar szFullFileName[MAXFNAME]; - - ASSERT(pDirName != NULL); - - if((pDir = opendir((char*) pDirName)) == NULL) { - errmsg.LogError(errno, RS_RET_FOPEN_FAILURE, "error opening include directory"); - ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); - } - - /* prepare file name buffer */ - iDirNameLen = strlen((char*) pDirName); - memcpy(szFullFileName, pDirName, iDirNameLen); - - /* now read the directory */ - iEntriesDone = 0; - while(readdir_r(pDir, &u.d, &res) == 0) { - if(res == NULL) - break; /* this also indicates end of directory */ -# ifdef DT_REG - /* TODO: find an alternate way to checking for special files if this is - * not defined. This is currently a known problem on HP UX, but the work- - * around is simple: do not create special files in that directory. So - * fixing this is actually not the most important thing on earth... - * rgerhards, 2008-03-04 - */ - if(res->d_type != DT_REG) - continue; /* we are not interested in special files */ -# endif - if(res->d_name[0] == '.') - continue; /* these files we are also not interested in */ - ++iEntriesDone; - /* construct filename */ - iFileNameLen = strlen(res->d_name); - if (iFileNameLen > NAME_MAX) - iFileNameLen = NAME_MAX; - memcpy(szFullFileName + iDirNameLen, res->d_name, iFileNameLen); - *(szFullFileName + iDirNameLen + iFileNameLen) = '\0'; - dbgprintf("including file '%s'\n", szFullFileName); - processConfFile(conf, szFullFileName); - /* we deliberately ignore the iRet of processConfFile() - this is because - * failure to process one file does not mean all files will fail. By ignoring, - * we retry with the next file, which is the best thing we can do. -- rgerhards, 2007-08-01 - */ - } - - if(iEntriesDone == 0) { - /* I just make it a debug output, because I can think of a lot of cases where it - * makes sense not to have any files. E.g. a system maintainer may place a $Include - * into the config file just in case, when additional modules be installed. When none - * are installed, the directory will be empty, which is fine. -- rgerhards 2007-08-01 - */ - dbgprintf("warning: the include directory contained no files - this may be ok.\n"); - } - -finalize_it: - if(pDir != NULL) - closedir(pDir); - - RETiRet; -} - - -/* process a $include config line. That type of line requires - * inclusion of another file. - * rgerhards, 2007-08-01 - */ -rsRetVal -doIncludeLine(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal) -{ - DEFiRet; - char pattern[MAXFNAME]; - uchar *cfgFile; - glob_t cfgFiles; - int result; - size_t i = 0; - struct stat fileInfo; - - ASSERT(pp != NULL); - ASSERT(*pp != NULL); - - if(getSubString(pp, (char*) pattern, sizeof(pattern) / sizeof(char), ' ') != 0) { - errmsg.LogError(0, RS_RET_NOT_FOUND, "could not parse config file name"); - ABORT_FINALIZE(RS_RET_NOT_FOUND); - } - - /* Use GLOB_MARK to append a trailing slash for directories. - * Required by doIncludeDirectory(). - */ - result = glob(pattern, GLOB_MARK, NULL, &cfgFiles); - if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { - char errStr[1024]; - rs_strerror_r(errno, errStr, sizeof(errStr)); - errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s", - pattern, errStr); - ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND); - } - - for(i = 0; i < cfgFiles.gl_pathc; i++) { - cfgFile = (uchar*) cfgFiles.gl_pathv[i]; - - if(stat((char*) cfgFile, &fileInfo) != 0) - continue; /* continue with the next file if we can't stat() the file */ - - if(S_ISREG(fileInfo.st_mode)) { /* config file */ - dbgprintf("requested to include config file '%s'\n", cfgFile); - iRet = processConfFile(conf, cfgFile); - } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */ - dbgprintf("requested to include directory '%s'\n", cfgFile); - iRet = doIncludeDirectory(conf, cfgFile); - } else { /* TODO: shall we handle symlinks or not? */ - dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile); - } - } - - globfree(&cfgFiles); - -finalize_it: - RETiRet; -} - - /* process a $ModLoad config line. */ rsRetVal doModLoad(uchar **pp, __attribute__((unused)) void* pVal) @@ -389,120 +248,6 @@ finalize_it: } - - -/* process a configuration file - * started with code from init() by rgerhards on 2007-07-31 - */ -static rsRetVal -processConfFile(rsconf_t *conf, uchar *pConfFile) -{ - int iLnNbr = 0; - FILE *cf; - rule_t *pCurrRule = NULL; - uchar *p; - uchar cbuf[CFGLNSIZ]; - uchar *cline; - int i; - int bHadAnError = 0; - uchar *pszOrgLine = NULL; - size_t lenLine; - DEFiRet; - ASSERT(pConfFile != NULL); - - if((cf = fopen((char*)pConfFile, "r")) == NULL) { - ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); - } - - /* Now process the file. - */ - cline = cbuf; - while (fgets((char*)cline, sizeof(cbuf) - (cline - cbuf), cf) != NULL) { - ++iLnNbr; - /* drop LF - TODO: make it better, replace fgets(), but its clean as it is */ - lenLine = ustrlen(cline); - if(cline[lenLine-1] == '\n') { - cline[lenLine-1] = '\0'; - } - free(pszOrgLine); - pszOrgLine = ustrdup(cline); /* save if needed for errmsg, NULL ptr is OK */ - /* check for end-of-section, comments, strip off trailing - * spaces and newline character. - */ - p = cline; - skipWhiteSpace(&p); - if (*p == '\0' || *p == '#') - continue; - - /* we now need to copy the characters to the begin of line. As this overlaps, - * we can not use strcpy(). -- rgerhards, 2008-03-20 - * TODO: review the code at whole - this is highly suspect (but will go away - * once we do the rest of RainerScript). - */ - for( i = 0 ; p[i] != '\0' ; ++i) { - cline[i] = p[i]; - } - cline[i] = '\0'; - - for (p = (uchar*) strchr((char*)cline, '\0'); isspace((int) *--p);) - /*EMPTY*/; - if (*p == '\\') { - if ((p - cbuf) > CFGLNSIZ - 30) { - /* Oops the buffer is full - what now? */ - cline = cbuf; - } else { - *p = 0; - cline = p; - continue; - } - } else - cline = cbuf; - *++p = '\0'; /* TODO: check this */ - - /* we now have the complete line, and are positioned at the first non-whitespace - * character. So let's process it - */ - if(cfline(conf, cbuf, &pCurrRule) != RS_RET_OK) { - /* we log a message, but otherwise ignore the error. After all, the next - * line can be correct. -- rgerhards, 2007-08-02 - */ - uchar szErrLoc[MAXFNAME + 64]; - dbgprintf("config line NOT successfully processed\n"); - snprintf((char*)szErrLoc, sizeof(szErrLoc) / sizeof(uchar), - "%s, line %d", pConfFile, iLnNbr); - errmsg.LogError(0, NO_ERRCODE, "the last error occured in %s:\"%s\"", (char*)szErrLoc, (char*)pszOrgLine); - bHadAnError = 1; - } - } - - /* we probably have one selector left to be added - so let's do that now */ - if(pCurrRule != NULL) { - CHKiRet(ruleset.AddRule(conf, rule.GetAssRuleset(pCurrRule), &pCurrRule)); - } - - /* close the configuration file */ - fclose(cf); - -finalize_it: - if(iRet != RS_RET_OK) { - char errStr[1024]; - if(pCurrRule != NULL) - rule.Destruct(&pCurrRule); - - rs_strerror_r(errno, errStr, sizeof(errStr)); - dbgprintf("error %d processing config file '%s'; os error (if any): %s\n", - iRet, pConfFile, errStr); - } - - free(pszOrgLine); - - if(bHadAnError && (iRet == RS_RET_OK)) { /* a bit dirty, enhance in future releases */ - iRet = RS_RET_NONFATAL_CONFIG_ERR; - } - RETiRet; -} - - /* Helper to cfline() and its helpers. Parses a template name * from an "action" line. Must be called with the Line pointer * pointing to the first character after the semicolon. @@ -1266,9 +1011,7 @@ CODESTARTobjQueryInterface(conf) pIf->doNameLine = doNameLine; pIf->cfsysline = cfsysline; pIf->doModLoad = doModLoad; - pIf->doIncludeLine = doIncludeLine; pIf->cfline = cfline; - pIf->processConfFile = processConfFile; pIf->GetNbrActActions = GetNbrActActions; finalize_it: diff --git a/runtime/conf.h b/runtime/conf.h index aa57c8fc..a74b99c5 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -37,9 +37,7 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ rsRetVal (*doNameLine)(uchar **pp, void* pVal); rsRetVal (*cfsysline)(uchar *p); rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); - rsRetVal (*doIncludeLine)(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal); rsRetVal (*cfline)(rsconf_t *conf, uchar *line, rule_t **pfCurr); - rsRetVal (*processConfFile)(rsconf_t *conf, uchar *pConfFile); rsRetVal (*GetNbrActActions)(rsconf_t *conf, int *); /* version 4 -- 2010-07-23 rgerhards */ /* "just" added global variables diff --git a/runtime/rsconf.c b/runtime/rsconf.c index d12a258b..ac969286 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -385,7 +385,7 @@ void cnfDoRule(struct cnfrule *cnfrule) break; case CNFFILT_SCRIPT: pRule->f_filter_type = FILTER_EXPR; - pRule->f_filterData.f_expr = cnfrule->filt.expr; + pRule->f_filterData.expr = cnfrule->filt.expr; break; } /* we now check if there are some global (BSD-style) filter conditions @@ -790,19 +790,6 @@ static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int } -/* this method is needed to shuffle the current conf object down to the - * IncludeConfig handler. - */ -static rsRetVal -doIncludeLine(void *pVal, uchar *pNewVal) -{ - DEFiRet; - iRet = conf.doIncludeLine(ourConf, pVal, pNewVal); - free(pNewVal); - RETiRet; -} - - /* set the maximum message size */ static rsRetVal setMaxMsgSize(void __attribute__((unused)) *pVal, long iNewVal) { @@ -1081,8 +1068,6 @@ initLegacyConf(void) setActionResumeInterval, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, conf.doModLoad, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, - doIncludeLine, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, setMaxMsgSize, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, @@ -1236,6 +1221,7 @@ load(rsconf_t **cnf, uchar *confFile) int bHadConfigErr = 0; char cbuf[BUFSIZ]; int r; + char *emergConf; DEFiRet; CHKiRet(rsconfConstruct(&loadConf)); @@ -1246,11 +1232,12 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! /* open the configuration file */ r = cnfSetLexFile((char*)confFile); - r = yyparse(); - //localRet = conf.processConfFile(loadConf, confFile); - CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions)); + if(r == 0) { + r = yyparse(); + conf.GetNbrActActions(loadConf, &iNbrActions); + } - if(localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) { + if(r == 1) { errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", confFile); bHadConfigErr = 1; } else if(iNbrActions == 0) { @@ -1259,8 +1246,7 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! bHadConfigErr = 1; } - if((localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) || iNbrActions == 0) { - + if(r == 1 || iNbrActions == 0) { /* rgerhards: this code is executed to set defaults when the * config file could not be opened. We might think about * abandoning the run in this case - but this, too, is not @@ -1268,23 +1254,17 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! * We ignore any errors while doing this - we would be lost anyhow... */ errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!"); - - /* note: we previously used _POSIY_TTY_NAME_MAX+1, but this turned out to be - * too low on linux... :-S -- rgerhards, 2008-07-28 - */ - char szTTYNameBuf[128]; - rule_t *pRule = NULL; /* initialization to NULL is *vitally* important! */ - conf.cfline(loadConf, UCHAR_CONSTANT("*.ERR\t" _PATH_CONSOLE), &pRule); - conf.cfline(loadConf, UCHAR_CONSTANT("syslog.*\t" _PATH_CONSOLE), &pRule); - conf.cfline(loadConf, UCHAR_CONSTANT("*.PANIC\t*"), &pRule); - conf.cfline(loadConf, UCHAR_CONSTANT("syslog.*\troot"), &pRule); - if(ttyname_r(0, szTTYNameBuf, sizeof(szTTYNameBuf)) == 0) { - snprintf(cbuf,sizeof(cbuf), "*.*\t%s", szTTYNameBuf); - conf.cfline(loadConf, (uchar*)cbuf, &pRule); - } else { - DBGPRINTF("error %d obtaining controlling terminal, not using that emergency rule\n", errno); + emergConf = + "*.err " _PATH_CONSOLE "\n" + "syslog.*" _PATH_CONSOLE "\n" + "*.panic :omusrmsg:*" "\n" + "syslog.* :omusrmsg:root" "\n"; + cnfParseBuffer(emergConf, strlen(emergConf)); + r = yyparse(); + if(r != 0) { + fprintf(stderr, "rsyslogd: could not even activate emergency conf - terminating\n"); + exit(1); } - ruleset.AddRule(loadConf, ruleset.GetCurrent(loadConf), &pRule); } CHKiRet(validateConf()); diff --git a/runtime/rule.c b/runtime/rule.c index 0b4b48a2..e7f3522e 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -183,15 +183,6 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) else bRet = 1; } else if(pRule->f_filter_type == FILTER_EXPR) { -#if 0 - CHKiRet(vm.Construct(&pVM)); - CHKiRet(vm.ConstructFinalize(pVM)); - CHKiRet(vm.SetMsg(pVM, pMsg)); - CHKiRet(vm.ExecProg(pVM, pRule->f_filterData.f_expr->pVmprg)); - CHKiRet(vm.PopBoolFromStack(pVM, &pResult)); - /* VM is destructed on function exit */ - bRet = (pResult->val.num) ? 1 : 0; -#endif bRet = cnfexprEvalBool(pRule->f_filterData.expr, pMsg); dbgprintf("result of rainerscript filter evaluation: %d\n", bRet); } else { diff --git a/runtime/rule.h b/runtime/rule.h index f346c764..8c2f72c9 100644 --- a/runtime/rule.h +++ b/runtime/rule.h @@ -54,7 +54,6 @@ struct rule_s { es_str_t *propName; /* name of property for CEE-based filters */ } prop; struct cnfexpr *expr; /* expression object */ - expr_t *f_expr; /* expression object */ } f_filterData; ruleset_t *pRuleset; /* associated ruleset */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 3a514aa0..86e845cb 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,8 @@ if ENABLE_TESTBENCH # TODO: reenable TESTRUNS = rt_init rscript check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen diagtalker uxsockrcvr syslog_caller syslog_inject inputfilegen -TESTS = $(TESTRUNS) cfg.sh +TESTS = $(TESTRUNS) +#TESTS = $(TESTRUNS) cfg.sh if ENABLE_IMDIAG TESTS += \ -- cgit v1.2.3 From 84f217e87d6cd912a81564acc341d00515571f96 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 15:07:56 +0200 Subject: cleanup, removing now unused code --- runtime/Makefile.am | 10 - runtime/conf.c | 83 ----- runtime/expr.c | 482 ----------------------------- runtime/expr.h | 57 ---- runtime/rsyslog.c | 19 -- runtime/rule.c | 5 - runtime/rule.h | 1 - runtime/vm.c | 869 ---------------------------------------------------- runtime/vm.h | 68 ---- runtime/vmop.c | 307 ------------------- runtime/vmop.h | 129 -------- runtime/vmprg.c | 236 -------------- runtime/vmprg.h | 69 ----- runtime/vmstk.c | 234 -------------- runtime/vmstk.h | 56 ---- tools/syslogd.c | 5 - tools/syslogd.h | 1 - 17 files changed, 2631 deletions(-) delete mode 100644 runtime/expr.c delete mode 100644 runtime/expr.h delete mode 100644 runtime/vm.c delete mode 100644 runtime/vm.h delete mode 100644 runtime/vmop.c delete mode 100644 runtime/vmop.h delete mode 100644 runtime/vmprg.c delete mode 100644 runtime/vmprg.h delete mode 100644 runtime/vmstk.c delete mode 100644 runtime/vmstk.h diff --git a/runtime/Makefile.am b/runtime/Makefile.am index c6c860ea..7f7e55fd 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -5,16 +5,6 @@ pkglib_LTLIBRARIES = #pkglib_LTLIBRARIES = librsyslog.la librsyslog_la_SOURCES = \ - expr.c \ - expr.h \ - vm.c \ - vm.h \ - vmstk.c \ - vmstk.h \ - vmprg.c \ - vmprg.h \ - vmop.c \ - vmop.h \ rsyslog.c \ rsyslog.h \ typedefs.h \ diff --git a/runtime/conf.c b/runtime/conf.c index 4c8f2285..413d02bb 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -65,7 +65,6 @@ #include "srUtils.h" #include "errmsg.h" #include "net.h" -#include "expr.h" #include "ctok.h" #include "ctok_token.h" #include "rule.h" @@ -83,7 +82,6 @@ static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); /* static data */ DEFobjStaticHelpers -DEFobjCurrIf(expr) DEFobjCurrIf(ctok) DEFobjCurrIf(ctok_token) DEFobjCurrIf(module) @@ -508,77 +506,6 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) } -#if 0 -/* Helper to cfline(). This function processes an "if" type of filter, - * what essentially means it parses an expression. As usual, - * It processes the line up to the beginning of the action part. - * A pointer to that beginnig is passed back to the caller. - * rgerhards 2008-01-19 - */ -static rsRetVal cflineProcessIfFilter(uchar **pline, register rule_t *f) -{ - DEFiRet; - ctok_t *tok; - ctok_token_t *pToken; - - ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ASSERT(f != NULL); - - dbgprintf(" - general expression-based filter\n"); - errno = 0; /* keep strerror_r() stuff out of logerror messages */ - - f->f_filter_type = FILTER_EXPR; - - /* if we come to over here, pline starts with "if ". We just skip that part. */ - (*pline) += 3; - - /* we first need a tokenizer... */ - CHKiRet(ctok.Construct(&tok)); - CHKiRet(ctok.Setpp(tok, *pline)); - CHKiRet(ctok.ConstructFinalize(tok)); - - /* now construct our expression */ - CHKiRet(expr.Construct(&f->f_filterData.f_expr)); - CHKiRet(expr.ConstructFinalize(f->f_filterData.f_expr)); - - /* ready to go... */ - CHKiRet(expr.Parse(f->f_filterData.f_expr, tok)); - - /* we now need to parse off the "then" - and note an error if it is - * missing... - */ - CHKiRet(ctok.GetToken(tok, &pToken)); - if(pToken->tok != ctok_THEN) { - ctok_token.Destruct(&pToken); - ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); - } - - ctok_token.Destruct(&pToken); /* no longer needed */ - - /* we are done, so we now need to restore things */ - CHKiRet(ctok.Getpp(tok, pline)); - CHKiRet(ctok.Destruct(&tok)); - - /* debug support - print vmprg after construction (uncomment to use) */ - /* vmprgDebugPrint(f->f_filterData.f_expr->pVmprg); */ - - /* we now need to skip whitespace to the action part, else we confuse - * the legacy rsyslog conf parser. -- rgerhards, 2008-02-25 - */ - while(isspace(**pline)) - ++(*pline); - -finalize_it: - if(iRet == RS_RET_SYNTAX_ERROR) { - errmsg.LogError(0, RS_RET_SYNTAX_ERROR, "syntax error in expression"); - } - - RETiRet; -} -#endif - - /* Helper to cfline(). This function takes the filter part of a property * based filter and decodes it. It processes the line up to the beginning * of the action part. A pointer to that beginnig is passed back to the caller. @@ -808,14 +735,6 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) case ':': CHKiRet(cflineProcessPropFilter(pp, f)); break; -#if 0 - case 'i': /* "if" filter? */ - if(*(*pp+1) && (*(*pp+1) == 'f') && isspace(*(*pp+2))) { - CHKiRet(cflineProcessIfFilter(pp, f)); - break; - } - /*FALLTHROUGH*/ -#endif default: CHKiRet(cflineProcessTradPRIFilter(pp, f)); break; @@ -1163,7 +1082,6 @@ CODESTARTObjClassExit(conf) } /* release objects we no longer need */ - objRelease(expr, CORE_COMPONENT); objRelease(ctok, CORE_COMPONENT); objRelease(ctok_token, CORE_COMPONENT); objRelease(module, CORE_COMPONENT); @@ -1180,7 +1098,6 @@ ENDObjClassExit(conf) */ BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */ /* request objects we use */ - CHKiRet(objUse(expr, CORE_COMPONENT)); CHKiRet(objUse(ctok, CORE_COMPONENT)); CHKiRet(objUse(ctok_token, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); diff --git a/runtime/expr.c b/runtime/expr.c deleted file mode 100644 index 01431474..00000000 --- a/runtime/expr.c +++ /dev/null @@ -1,482 +0,0 @@ -/* expr.c - an expression class. - * This module contains all code needed to represent expressions. Most - * importantly, that means code to parse and execute them. Expressions - * heavily depend on (loadable) functions, so it works in conjunction - * with the function manager. - * - * Module begun 2007-11-30 by Rainer Gerhards - * - * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include - -#include "rsyslog.h" -#include "template.h" -#include "expr.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(vmprg) -DEFobjCurrIf(var) -DEFobjCurrIf(ctok_token) -DEFobjCurrIf(ctok) - - -/* ------------------------------ parser functions ------------------------------ */ -/* the following functions implement the parser. They are all static. For - * simplicity, the function names match their ABNF definition. The ABNF is defined - * in the doc set. See file expression.html for details. I do *not* reproduce it - * here in an effort to keep both files in sync. - * - * All functions receive the current expression object as parameter as well as the - * current tokenizer. - * - * rgerhards, 2008-02-19 - */ - -/* forward definition - thanks to recursive ABNF, we can not avoid at least one ;) */ -static rsRetVal expr(expr_t *pThis, ctok_t *tok); - - -static rsRetVal -function(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken = NULL; - int iNumArgs = 0; - var_t *pVar; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(ctok.GetToken(tok, &pToken)); - /* note: pToken is destructed in finalize_it */ - - if(pToken->tok == ctok_LPAREN) { - CHKiRet(ctok_token.Destruct(&pToken)); /* token processed, "eat" it */ - CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one */ - } else - ABORT_FINALIZE(RS_RET_FUNC_NO_LPAREN); - - /* we first push all the params on the stack. Then we call the function */ - while(pToken->tok != ctok_RPAREN) { - ++iNumArgs; - CHKiRet(ctok.UngetToken(tok, pToken)); /* not for us, so let others process it */ - CHKiRet(expr(pThis, tok)); - CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one, needed for while() check */ - if(pToken->tok == ctok_COMMA) { - CHKiRet(ctok_token.Destruct(&pToken)); /* token processed, "eat" it */ - CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one */ - if(pToken->tok == ctok_RPAREN) { - ABORT_FINALIZE(RS_RET_FUNC_MISSING_EXPR); - } - } - } - - - /* now push number of arguments - this must be on top of the stack */ - CHKiRet(var.Construct(&pVar)); - CHKiRet(var.ConstructFinalize(pVar)); - CHKiRet(var.SetNumber(pVar, iNumArgs)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, pVar)); /* add to program */ - - -finalize_it: - if(pToken != NULL) { - ctok_token.Destruct(&pToken); /* "eat" processed token */ - } - - RETiRet; -} - - -static rsRetVal -terminal(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken = NULL; - var_t *pVar; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(ctok.GetToken(tok, &pToken)); - /* note: pToken is destructed in finalize_it */ - - switch(pToken->tok) { - case ctok_SIMPSTR: - dbgoprint((obj_t*) pThis, "simpstr\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, pVar)); /* add to program */ - break; - case ctok_NUMBER: - dbgoprint((obj_t*) pThis, "number\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, pVar)); /* add to program */ - break; - case ctok_FUNCTION: - dbgoprint((obj_t*) pThis, "function\n"); - CHKiRet(function(pThis, tok)); /* this creates the stack call frame */ - /* ... but we place the call instruction onto the stack ourselfs (because - * we have all relevant information) - */ - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(var.ConvToString(pVar)); /* make sure we have a string */ - CHKiRet(vmprg.AddCallOperation(pThis->pVmprg, pVar->val.pStr)); /* add to program */ - CHKiRet(var.Destruct(&pVar)); - break; - case ctok_MSGVAR: - dbgoprint((obj_t*) pThis, "MSGVAR\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHMSGVAR, pVar)); /* add to program */ - break; - case ctok_CEEVAR: - dbgoprint((obj_t*) pThis, "SYSVAR\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCEEVAR, pVar)); /* add to program */ - break; - case ctok_SYSVAR: - dbgoprint((obj_t*) pThis, "SYSVAR\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHSYSVAR, pVar)); /* add to program */ - break; - case ctok_LPAREN: - dbgoprint((obj_t*) pThis, "expr\n"); - CHKiRet(ctok_token.Destruct(&pToken)); /* "eat" processed token */ - CHKiRet(expr(pThis, tok)); - CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one */ - if(pToken->tok != ctok_RPAREN) - ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); - break; - default: - dbgoprint((obj_t*) pThis, "invalid token %d\n", pToken->tok); - ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); - break; - } - -finalize_it: - if(pToken != NULL) { - ctok_token.Destruct(&pToken); /* "eat" processed token */ - } - - RETiRet; -} - -static rsRetVal -factor(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - int bWasNot; - int bWasUnaryMinus; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(ctok.GetToken(tok, &pToken)); - if(pToken->tok == ctok_NOT) { - dbgprintf("not\n"); - bWasNot = 1; - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); /* get new one for next check */ - } else { - bWasNot = 0; - } - - if(pToken->tok == ctok_MINUS) { - dbgprintf("unary minus\n"); - bWasUnaryMinus = 1; - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - } else { - bWasUnaryMinus = 0; - /* we could not process the token, so push it back */ - CHKiRet(ctok.UngetToken(tok, pToken)); - } - - CHKiRet(terminal(pThis, tok)); - - /* warning: the order if the two following ifs is important. Do not change them, this - * would change the semantics of the expression! - */ - if(bWasUnaryMinus) { - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_UNARY_MINUS, NULL)); /* add to program */ - } - - if(bWasNot == 1) { - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_NOT, NULL)); /* add to program */ - } - -finalize_it: - RETiRet; -} - - -static rsRetVal -term(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(factor(pThis, tok)); - - /* *(("*" / "/" / "%") factor) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - while(pToken->tok == ctok_TIMES || pToken->tok == ctok_DIV || pToken->tok == ctok_MOD) { - dbgoprint((obj_t*) pThis, "/,*,%%\n"); - CHKiRet(factor(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, (opcode_t) pToken->tok, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); - } - - /* unget the token that made us exit the loop - it's obviously not one - * we can process. - */ - CHKiRet(ctok.UngetToken(tok, pToken)); - -finalize_it: - RETiRet; -} - -static rsRetVal -val(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(term(pThis, tok)); - - /* *(("+" / "-") term) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - while(pToken->tok == ctok_PLUS || pToken->tok == ctok_MINUS || pToken->tok == ctok_STRADD) { - dbgoprint((obj_t*) pThis, "+/-/&\n"); - CHKiRet(term(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, (opcode_t) pToken->tok, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); - } - - /* unget the token that made us exit the loop - it's obviously not one - * we can process. - */ - CHKiRet(ctok.UngetToken(tok, pToken)); - -finalize_it: - RETiRet; -} - - -static rsRetVal -e_cmp(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(val(pThis, tok)); - - /* 0*1(cmp_op val) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - if(ctok_token.IsCmpOp(pToken)) { - dbgoprint((obj_t*) pThis, "cmp\n"); - CHKiRet(val(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, (opcode_t) pToken->tok, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - } else { - /* we could not process the token, so push it back */ - CHKiRet(ctok.UngetToken(tok, pToken)); - } - - -finalize_it: - RETiRet; -} - - -static rsRetVal -e_and(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(e_cmp(pThis, tok)); - - /* *("and" e_cmp) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - while(pToken->tok == ctok_AND) { - dbgoprint((obj_t*) pThis, "and\n"); - CHKiRet(e_cmp(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_AND, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); - } - - /* unget the token that made us exit the loop - it's obviously not one - * we can process. - */ - CHKiRet(ctok.UngetToken(tok, pToken)); - -finalize_it: - RETiRet; -} - - -static rsRetVal -expr(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(e_and(pThis, tok)); - - /* *("or" e_and) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - while(pToken->tok == ctok_OR) { - dbgoprint((obj_t*) pThis, "found OR\n"); - CHKiRet(e_and(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_OR, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); - } - - /* unget the token that made us exit the loop - it's obviously not one - * we can process. - */ - CHKiRet(ctok.UngetToken(tok, pToken)); - -finalize_it: - RETiRet; -} - - -/* ------------------------------ end parser functions ------------------------------ */ - - -/* ------------------------------ actual expr object functions ------------------------------ */ - -/* Standard-Constructor - * rgerhards, 2008-02-09 (a rainy Tenerife return flight day ;)) - */ -BEGINobjConstruct(expr) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(expr) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -rsRetVal exprConstructFinalize(expr_t __attribute__((unused)) *pThis) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, expr); - - RETiRet; -} - - -/* destructor for the expr object */ -BEGINobjDestruct(expr) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(expr) - if(pThis->pVmprg != NULL) - vmprg.Destruct(&pThis->pVmprg); -ENDobjDestruct(expr) - - -/* parse an expression object based on a given tokenizer - * rgerhards, 2008-02-19 - */ -rsRetVal -exprParse(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - /* first, we need to make sure we have a program where we can add to what we parse... */ - CHKiRet(vmprg.Construct(&pThis->pVmprg)); - CHKiRet(vmprg.ConstructFinalize(pThis->pVmprg)); - - /* happy parsing... */ - CHKiRet(expr(pThis, tok)); - dbgoprint((obj_t*) pThis, "successfully parsed/created expression\n"); - -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(expr) -CODESTARTobjQueryInterface(expr) - if(pIf->ifVersion != exprCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = exprConstruct; - pIf->ConstructFinalize = exprConstructFinalize; - pIf->Destruct = exprDestruct; - pIf->Parse = exprParse; -finalize_it: -ENDobjQueryInterface(expr) - - -/* Initialize the expr class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(expr, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(vmprg, CORE_COMPONENT)); - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(ctok_token, CORE_COMPONENT)); - CHKiRet(objUse(ctok, CORE_COMPONENT)); - - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, exprConstructFinalize); -ENDObjClassInit(expr) - -/* vi:set ai: - */ diff --git a/runtime/expr.h b/runtime/expr.h deleted file mode 100644 index 1afe1a1f..00000000 --- a/runtime/expr.h +++ /dev/null @@ -1,57 +0,0 @@ -/* The expr object. - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_EXPR_H -#define INCLUDED_EXPR_H - -#include "obj.h" -#include "ctok.h" -#include "vmprg.h" -#include "stringbuf.h" - -/* a node inside an expression tree */ -typedef struct exprNode_s { - char dummy; -} exprNode_t; - - -/* the expression object */ -typedef struct expr_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - vmprg_t *pVmprg; /* the expression in vmprg format - ready to execute */ -} expr_t; - - -/* interfaces */ -BEGINinterface(expr) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(expr); - rsRetVal (*Construct)(expr_t **ppThis); - rsRetVal (*ConstructFinalize)(expr_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(expr_t **ppThis); - rsRetVal (*Parse)(expr_t *pThis, ctok_t *ctok); -ENDinterface(expr) -#define exprCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - -/* prototypes */ -PROTOTYPEObj(expr); - -#endif /* #ifndef INCLUDED_EXPR_H */ diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index d71fe88a..c5abcb2a 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -62,16 +62,11 @@ #include "rsyslog.h" #include "obj.h" -#include "vm.h" #include "sysvar.h" #include "stringbuf.h" #include "wti.h" #include "wtp.h" -#include "expr.h" #include "ctok.h" -#include "vmop.h" -#include "vmstk.h" -#include "vmprg.h" #include "datetime.h" #include "queue.h" #include "conf.h" @@ -182,22 +177,8 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(ctok_tokenClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "ctok"; CHKiRet(ctokClassInit(NULL)); -#if 1 - if(ppErrObj != NULL) *ppErrObj = "vmstk"; - CHKiRet(vmstkClassInit(NULL)); -#endif if(ppErrObj != NULL) *ppErrObj = "sysvar"; CHKiRet(sysvarClassInit(NULL)); -#if 1 - if(ppErrObj != NULL) *ppErrObj = "vm"; - CHKiRet(vmClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "vmop"; - CHKiRet(vmopClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "vmprg"; - CHKiRet(vmprgClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "expr"; - CHKiRet(exprClassInit(NULL)); -#endif if(ppErrObj != NULL) *ppErrObj = "rule"; CHKiRet(ruleClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "ruleset"; diff --git a/runtime/rule.c b/runtime/rule.c index e7f3522e..1a430577 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -344,11 +344,6 @@ CODESTARTobjDestruct(rule) rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache); if(pThis->f_filterData.prop.propName != NULL) es_deleteStr(pThis->f_filterData.prop.propName); -#if 0 - } else if(pThis->f_filter_type == FILTER_EXPR) { - if(pThis->f_filterData.f_expr != NULL) - expr.Destruct(&pThis->f_filterData.f_expr); -#endif } llDestroy(&pThis->llActList); diff --git a/runtime/rule.h b/runtime/rule.h index 8c2f72c9..76ed5f0b 100644 --- a/runtime/rule.h +++ b/runtime/rule.h @@ -28,7 +28,6 @@ #include "libestr.h" #include "linkedlist.h" #include "regexp.h" -#include "expr.h" // TODO: remove #if 0 #include "rainerscript.h" /* the rule object */ diff --git a/runtime/vm.c b/runtime/vm.c deleted file mode 100644 index bbc8d346..00000000 --- a/runtime/vm.c +++ /dev/null @@ -1,869 +0,0 @@ -/* vm.c - the arithmetic stack of a virtual machine. - * - * Module begun 2008-02-22 by Rainer Gerhards - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include -#include - -#include "rsyslog.h" -#include "obj.h" -#include "vm.h" -#include "sysvar.h" -#include "stringbuf.h" -#include "unicode-helper.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(vmstk) -DEFobjCurrIf(var) -DEFobjCurrIf(sysvar) - -static pthread_mutex_t mutGetenv; /* we need to make this global because otherwise we can not guarantee proper init! */ - -/* ------------------------------ function registry code and structures ------------------------------ */ - -/* we maintain a registry of known functions */ -/* currently, this is a singly-linked list, this shall become a binary - * tree when we add the real call interface. So far, entries are added - * at the root, only. - */ -typedef struct s_rsf_entry { - cstr_t *pName; /* function name */ - prsf_t rsf; /* pointer to function code */ - struct s_rsf_entry *pNext; /* Pointer to next element or NULL */ -} rsf_entry_t; -rsf_entry_t *funcRegRoot = NULL; - - -/* add a function to the function registry. - * The handed-over cstr_t* object must no longer be used by the caller. - * A duplicate function name is an error. - * rgerhards, 2009-04-06 - */ -static rsRetVal -rsfrAddFunction(uchar *szName, prsf_t rsf) -{ - rsf_entry_t *pEntry; - size_t lenName; - DEFiRet; - - assert(szName != NULL); - assert(rsf != NULL); - - /* first check if we have a duplicate name, with the current approach this means - * we need to go through the whole list. - */ - lenName = strlen((char*)szName); - for(pEntry = funcRegRoot ; pEntry != NULL ; pEntry = pEntry->pNext) - if(!rsCStrSzStrCmp(pEntry->pName, szName, lenName)) - ABORT_FINALIZE(RS_RET_DUP_FUNC_NAME); - - /* unique name, so add to head of list */ - CHKmalloc(pEntry = calloc(1, sizeof(rsf_entry_t))); - CHKiRet(rsCStrConstructFromszStr(&pEntry->pName, szName)); - CHKiRet(cstrFinalize(pEntry->pName)); - pEntry->rsf = rsf; - pEntry->pNext = funcRegRoot; - funcRegRoot = pEntry; - -finalize_it: - if(iRet != RS_RET_OK && iRet != RS_RET_DUP_FUNC_NAME) - free(pEntry); - - RETiRet; -} - - -/* find a function inside the function registry - * The caller provides a cstr_t with the function name and receives - * a function pointer back. If no function is found, an RS_RET_UNKNW_FUNC - * error is returned. So if the function returns with RS_RET_OK, the caller - * can savely assume the function pointer is valid. - * rgerhards, 2009-04-06 - */ -static rsRetVal -findRSFunction(cstr_t *pcsName, prsf_t *prsf) -{ - rsf_entry_t *pEntry; - rsf_entry_t *pFound; - DEFiRet; - - assert(prsf != NULL); - - /* find function by list walkthrough. */ - pFound = NULL; - for(pEntry = funcRegRoot ; pEntry != NULL && pFound == NULL ; pEntry = pEntry->pNext) - if(!rsCStrCStrCmp(pEntry->pName, pcsName)) - pFound = pEntry; - - if(pFound == NULL) - ABORT_FINALIZE(RS_RET_UNKNW_FUNC); - - *prsf = pFound->rsf; - -finalize_it: - RETiRet; -} - - -/* find the name of a RainerScript function whom's function pointer - * is known. This function returns the cstr_t object, which MUST NOT - * be modified by the caller. - * rgerhards, 2009-04-06 - */ -static rsRetVal -findRSFunctionName(prsf_t rsf, cstr_t **ppcsName) -{ - rsf_entry_t *pEntry; - rsf_entry_t *pFound; - DEFiRet; - - assert(rsf != NULL); - assert(ppcsName != NULL); - - /* find function by list walkthrough. */ - pFound = NULL; - for(pEntry = funcRegRoot ; pEntry != NULL && pFound == NULL ; pEntry = pEntry->pNext) - if(pEntry->rsf == rsf) - pFound = pEntry; - - if(pFound == NULL) - ABORT_FINALIZE(RS_RET_UNKNW_FUNC); - - *ppcsName = pFound->pName; - -finalize_it: - RETiRet; -} - - -/* free the whole function registry - */ -static void -rsfrRemoveAll(void) -{ - rsf_entry_t *pEntry; - rsf_entry_t *pEntryDel; - - BEGINfunc - pEntry = funcRegRoot; - while(pEntry != NULL) { - pEntryDel = pEntry; - pEntry = pEntry->pNext; - cstrDestruct(&pEntryDel->pName); - free(pEntryDel); - } - funcRegRoot = NULL; - ENDfunc -} - - -/* ------------------------------ end function registry code and structures ------------------------------ */ - - -/* ------------------------------ instruction set implementation ------------------------------ * - * The following functions implement the VM's instruction set. - */ -#define BEGINop(instruction) \ - static rsRetVal op##instruction(vm_t *pThis, __attribute__((unused)) vmop_t *pOp) \ - { \ - DEFiRet; - -#define CODESTARTop(instruction) \ - ISOBJ_TYPE_assert(pThis, vm); - -#define PUSHRESULTop(operand, res) \ - /* we have a result, so let's push it */ \ - var.SetNumber(operand, res); \ - vmstk.Push(pThis->pStk, operand); /* result */ - -#define ENDop(instruction) \ - RETiRet; \ - } - -/* code generator for boolean operations */ -#define BOOLOP(name, OPERATION) \ -BEGINop(name) /* remember to set the instruction also in the ENDop macro! */ \ - var_t *operand1; \ - var_t *operand2; \ -CODESTARTop(name) \ - vmstk.PopBool(pThis->pStk, &operand1); \ - vmstk.PopBool(pThis->pStk, &operand2); \ - if(operand1->val.num OPERATION operand2->val.num) { \ - CHKiRet(var.SetNumber(operand1, 1)); \ - } else { \ - CHKiRet(var.SetNumber(operand1, 0)); \ - } \ - vmstk.Push(pThis->pStk, operand1); /* result */ \ - var.Destruct(&operand2); /* no longer needed */ \ -finalize_it: \ -ENDop(name) -BOOLOP(OR, ||) -BOOLOP(AND, &&) -#undef BOOLOP - - -/* code generator for numerical operations */ -#define NUMOP(name, OPERATION) \ -BEGINop(name) /* remember to set the instruction also in the ENDop macro! */ \ - var_t *operand1; \ - var_t *operand2; \ -CODESTARTop(name) \ - vmstk.PopNumber(pThis->pStk, &operand1); \ - vmstk.PopNumber(pThis->pStk, &operand2); \ - operand1->val.num = operand1->val.num OPERATION operand2->val.num; \ - vmstk.Push(pThis->pStk, operand1); /* result */ \ - var.Destruct(&operand2); /* no longer needed */ \ -ENDop(name) -NUMOP(PLUS, +) -NUMOP(MINUS, -) -NUMOP(TIMES, *) -NUMOP(DIV, /) -NUMOP(MOD, %) -#undef BOOLOP - - -/* code generator for compare operations */ -#define BEGINCMPOP(name) \ -BEGINop(name) \ - var_t *operand1; \ - var_t *operand2; \ - number_t bRes; \ -CODESTARTop(name) \ - CHKiRet(vmstk.Pop2CommOp(pThis->pStk, &operand1, &operand2)); \ - /* data types are equal (so we look only at operand1), but we must \ - * check which type we have to deal with... \ - */ \ - switch(operand1->varType) { -#define ENDCMPOP(name) \ - default: \ - bRes = 0; /* we do not abort just so that we have a value. TODO: reconsider */ \ - break; \ - } \ - \ - /* we have a result, so let's push it */ \ - var.SetNumber(operand1, bRes); \ - vmstk.Push(pThis->pStk, operand1); /* result */ \ - var.Destruct(&operand2); /* no longer needed */ \ -finalize_it: \ -ENDop(name) - -BEGINCMPOP(CMP_EQ) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num == operand2->val.num; - break; - case VARTYPE_STR: - bRes = !rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr); - break; -ENDCMPOP(CMP_EQ) - -BEGINCMPOP(CMP_NEQ) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num != operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr); - break; -ENDCMPOP(CMP_NEQ) - -BEGINCMPOP(CMP_LT) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num < operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr) < 0; - break; -ENDCMPOP(CMP_LT) - -BEGINCMPOP(CMP_GT) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num > operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr) > 0; - break; -ENDCMPOP(CMP_GT) - -BEGINCMPOP(CMP_LTEQ) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num <= operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr) <= 0; - break; -ENDCMPOP(CMP_LTEQ) - -BEGINCMPOP(CMP_GTEQ) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num >= operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr) >= 0; - break; -ENDCMPOP(CMP_GTEQ) - -#undef BEGINCMPOP -#undef ENDCMPOP -/* end regular compare operations */ - -/* comare operations that work on strings, only */ -BEGINop(CMP_CONTAINS) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; - number_t bRes; -CODESTARTop(CMP_CONTAINS) - /* operand2 is on top of stack, so needs to be popped first */ - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); - /* TODO: extend cstr class so that it supports location of cstr inside cstr */ - bRes = (rsCStrLocateInSzStr(operand2->val.pStr, rsCStrGetSzStr(operand1->val.pStr)) == -1) ? 0 : 1; - - /* we have a result, so let's push it */ - PUSHRESULTop(operand1, bRes); - var.Destruct(&operand2); /* no longer needed */ -ENDop(CMP_CONTAINS) - - -BEGINop(CMP_CONTAINSI) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; - number_t bRes; -CODESTARTop(CMP_CONTAINSI) - /* operand2 is on top of stack, so needs to be popped first */ - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); -var.DebugPrint(operand1); \ -var.DebugPrint(operand2); \ - /* TODO: extend cstr class so that it supports location of cstr inside cstr */ - bRes = (rsCStrCaseInsensitiveLocateInSzStr(operand2->val.pStr, rsCStrGetSzStr(operand1->val.pStr)) == -1) ? 0 : 1; - - /* we have a result, so let's push it */ - PUSHRESULTop(operand1, bRes); - var.Destruct(&operand2); /* no longer needed */ -ENDop(CMP_CONTAINSI) - - -BEGINop(CMP_STARTSWITH) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; - number_t bRes; -CODESTARTop(CMP_STARTSWITH) - /* operand2 is on top of stack, so needs to be popped first */ - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); - /* TODO: extend cstr class so that it supports location of cstr inside cstr */ - bRes = (rsCStrStartsWithSzStr(operand1->val.pStr, rsCStrGetSzStr(operand2->val.pStr), - rsCStrLen(operand2->val.pStr)) == 0) ? 1 : 0; - - /* we have a result, so let's push it */ - PUSHRESULTop(operand1, bRes); - var.Destruct(&operand2); /* no longer needed */ -ENDop(CMP_STARTSWITH) - - -BEGINop(CMP_STARTSWITHI) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; - number_t bRes; -CODESTARTop(CMP_STARTSWITHI) - /* operand2 is on top of stack, so needs to be popped first */ - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); - /* TODO: extend cstr class so that it supports location of cstr inside cstr */ - bRes = (rsCStrCaseInsensitveStartsWithSzStr(operand1->val.pStr, rsCStrGetSzStr(operand2->val.pStr), - rsCStrLen(operand2->val.pStr)) == 0) ? 1 : 0; - - /* we have a result, so let's push it */ - PUSHRESULTop(operand1, bRes); - var.Destruct(&operand2); /* no longer needed */ -ENDop(CMP_STARTSWITHI) - -/* end comare operations that work on strings, only */ - -BEGINop(STRADD) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; -CODESTARTop(STRADD) - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); - - CHKiRet(rsCStrAppendCStr(operand1->val.pStr, operand2->val.pStr)); - CHKiRet(cstrFinalize(operand1->val.pStr)); - - /* we have a result, so let's push it */ - vmstk.Push(pThis->pStk, operand1); - var.Destruct(&operand2); /* no longer needed */ -finalize_it: -ENDop(STRADD) - -BEGINop(NOT) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand; -CODESTARTop(NOT) - vmstk.PopBool(pThis->pStk, &operand); - PUSHRESULTop(operand, !operand->val.num); -ENDop(NOT) - -BEGINop(UNARY_MINUS) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand; -CODESTARTop(UNARY_MINUS) - vmstk.PopNumber(pThis->pStk, &operand); - PUSHRESULTop(operand, -operand->val.num); -ENDop(UNARY_MINUS) - - -BEGINop(PUSHCONSTANT) /* remember to set the instruction also in the ENDop macro! */ - var_t *pVarDup; /* we need to duplicate the var, as we need to hand it over */ -CODESTARTop(PUSHCONSTANT) - CHKiRet(var.Duplicate(pOp->operand.pVar, &pVarDup)); - vmstk.Push(pThis->pStk, pVarDup); -finalize_it: -ENDop(PUSHCONSTANT) - - -BEGINop(PUSHMSGVAR) /* remember to set the instruction also in the ENDop macro! */ - var_t *pVal; /* the value to push */ - cstr_t *pstrVal; -CODESTARTop(PUSHMSGVAR) -dbgprintf("XXX: pushMSGVAR, var '%s'\n", rsCStrGetSzStr(pOp->operand.pVar->val.pStr)); - if(pThis->pMsg == NULL) { - /* TODO: flag an error message! As a work-around, we permit - * execution to continue here with an empty string - */ - /* TODO: create a method in var to create a string var? */ - CHKiRet(var.Construct(&pVal)); - CHKiRet(var.ConstructFinalize(pVal)); - CHKiRet(rsCStrConstructFromszStr(&pstrVal, (uchar*)"")); - CHKiRet(var.SetString(pVal, pstrVal)); - } else { - /* we have a message, so pull value from there */ - CHKiRet(msgGetMsgVar(pThis->pMsg, pOp->operand.pVar->val.pStr, &pVal)); - } - - /* if we reach this point, we have a valid pVal and can push it */ - vmstk.Push(pThis->pStk, pVal); -finalize_it: -ENDop(PUSHMSGVAR) - - -BEGINop(PUSHCEEVAR) /* remember to set the instruction also in the ENDop macro! */ - var_t *pVal; /* the value to push */ - cstr_t *pstrVal; -CODESTARTop(PUSHCEEVAR) -dbgprintf("XXX: pushCEEVAR, var '%s'\n", rsCStrGetSzStr(pOp->operand.pVar->val.pStr)); - if(pThis->pMsg == NULL) { - /* TODO: flag an error message! As a work-around, we permit - * execution to continue here with an empty string - */ - CHKiRet(var.Construct(&pVal)); - CHKiRet(var.ConstructFinalize(pVal)); - CHKiRet(rsCStrConstructFromszStr(&pstrVal, (uchar*)"")); - CHKiRet(var.SetString(pVal, pstrVal)); - } else { - /* we have a message, so pull value from there */ - CHKiRet(msgGetCEEVar(pThis->pMsg, pOp->operand.pVar->val.pStr, &pVal)); - } - - /* if we reach this point, we have a valid pVal and can push it */ - vmstk.Push(pThis->pStk, pVal); -dbgprintf("XXX: pushCEEVAR, result '%s'\n", rsCStrGetSzStr(pVal->val.pStr)); -finalize_it: -ENDop(PUSHCEEVAR) - - -BEGINop(PUSHSYSVAR) /* remember to set the instruction also in the ENDop macro! */ - var_t *pVal; /* the value to push */ -CODESTARTop(PUSHSYSVAR) - CHKiRet(sysvar.GetVar(pOp->operand.pVar->val.pStr, &pVal)); - vmstk.Push(pThis->pStk, pVal); -finalize_it: - if(Debug && iRet != RS_RET_OK) { - if(iRet == RS_RET_SYSVAR_NOT_FOUND) { - DBGPRINTF("rainerscript: sysvar '%s' not found\n", - rsCStrGetSzStrNoNULL(pOp->operand.pVar->val.pStr)); - } else { - DBGPRINTF("rainerscript: error %d trying to obtain sysvar '%s'\n", - iRet, rsCStrGetSzStrNoNULL(pOp->operand.pVar->val.pStr)); - } - } -ENDop(PUSHSYSVAR) - -/* The function call operation is only very roughly implemented. While the plumbing - * to reach this instruction is fine, the instruction itself currently supports only - * functions with a single argument AND with a name that we know. - * TODO: later, we can add here the real logic, that involves looking up function - * names, loading them dynamically ... and all that... - * implementation begun 2009-03-10 by rgerhards - */ -BEGINop(FUNC_CALL) /* remember to set the instruction also in the ENDop macro! */ - var_t *numOperands; -CODESTARTop(FUNC_CALL) - vmstk.PopNumber(pThis->pStk, &numOperands); - CHKiRet((*pOp->operand.rsf)(pThis->pStk, numOperands->val.num)); - var.Destruct(&numOperands); /* no longer needed */ -finalize_it: -ENDop(FUNC_CALL) - - -/* ------------------------------ end instruction set implementation ------------------------------ */ - - -/* ------------------------------ begin built-in function implementation ------------------------------ */ -/* note: this shall probably be moved to a separate module, but for the time being we do it directly - * in here. This is on our way to get from a dirty to a clean solution via baby steps that are - * a bit less dirty each time... - * - * The advantage of doing it here is that we do not yet need to think about how to handle the - * exit case, where we must not unload function modules which functions are still referenced. - * - * CALLING INTERFACE: - * The function must pop its parameters off the stack and pop its result onto - * the stack when it is finished. The number of parameters the function was - * called with is provided to it. If the argument count is less then what the function - * expected, it may handle the situation with defaults (or return an error). If the - * argument count is greater than expected, returnung an error is highly - * recommended (use RS_RET_INVLD_NBR_ARGUMENTS for these cases). - * - * All function names are prefixed with "rsf_" (RainerScript Function) to have - * a separate "name space". - * - * rgerhards, 2009-04-06 - */ - - -/* The strlen function, also probably a prototype of how all functions should be - * implemented. - * rgerhards, 2009-04-06 - */ -static rsRetVal -rsf_strlen(vmstk_t *pStk, int numOperands) -{ - DEFiRet; - var_t *operand1; - int iStrlen; - - if(numOperands != 1) - ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS); - - /* pop args and do operaton (trivial case here...) */ - vmstk.PopString(pStk, &operand1); - iStrlen = strlen((char*) rsCStrGetSzStr(operand1->val.pStr)); - - /* Store result and cleanup */ - var.SetNumber(operand1, iStrlen); - vmstk.Push(pStk, operand1); -finalize_it: - RETiRet; -} - - -/* The getenv function. Note that we guard the OS call by a mutex, as that - * function is not guaranteed to be thread-safe. This implementation here is far from - * being optimal, at least we should cache the result. This is left TODO for - * a later revision. - * rgerhards, 2009-11-03 - */ -static rsRetVal -rsf_getenv(vmstk_t *pStk, int numOperands) -{ - DEFiRet; - var_t *operand1; - char *envResult; - cstr_t *pCstr; - - if(numOperands != 1) - ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS); - - /* pop args and do operaton (trivial case here...) */ - vmstk.PopString(pStk, &operand1); - d_pthread_mutex_lock(&mutGetenv); - envResult = getenv((char*) rsCStrGetSzStr(operand1->val.pStr)); - DBGPRINTF("rsf_getenv(): envvar '%s', return '%s'\n", rsCStrGetSzStr(operand1->val.pStr), - envResult == NULL ? "(NULL)" : envResult); - iRet = rsCStrConstructFromszStr(&pCstr, (envResult == NULL) ? UCHAR_CONSTANT("") : (uchar*)envResult); - d_pthread_mutex_unlock(&mutGetenv); - if(iRet != RS_RET_OK) - FINALIZE; /* need to do this after mutex is unlocked! */ - - /* Store result and cleanup */ - var.SetString(operand1, pCstr); - vmstk.Push(pStk, operand1); -finalize_it: - RETiRet; -} - - -/* The "tolower" function, which converts its sole argument to lower case. - * Quite honestly, currently this is primarily a test driver for me... - * rgerhards, 2009-04-06 - */ -static rsRetVal -rsf_tolower(vmstk_t *pStk, int numOperands) -{ - DEFiRet; - var_t *operand1; - uchar *pSrc; - cstr_t *pcstr; - int iStrlen; - - if(numOperands != 1) - ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS); - - /* pop args and do operaton */ - CHKiRet(cstrConstruct(&pcstr)); - vmstk.PopString(pStk, &operand1); - pSrc = cstrGetSzStr(operand1->val.pStr); - iStrlen = strlen((char*)pSrc); // TODO: use count from string! - while(iStrlen--) { - CHKiRet(cstrAppendChar(pcstr, tolower(*pSrc++))); - } - - /* Store result and cleanup */ - CHKiRet(cstrFinalize(pcstr)); - var.SetString(operand1, pcstr); - vmstk.Push(pStk, operand1); -finalize_it: - RETiRet; -} - - -/* Standard-Constructor - */ -BEGINobjConstruct(vm) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(vm) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -static rsRetVal -vmConstructFinalize(vm_t __attribute__((unused)) *pThis) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vm); - - CHKiRet(vmstk.Construct(&pThis->pStk)); - CHKiRet(vmstk.ConstructFinalize(pThis->pStk)); - -finalize_it: - RETiRet; -} - - -/* destructor for the vm object */ -BEGINobjDestruct(vm) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(vm) - if(pThis->pStk != NULL) - vmstk.Destruct(&pThis->pStk); - if(pThis->pMsg != NULL) - msgDestruct(&pThis->pMsg); -ENDobjDestruct(vm) - - -/* debugprint for the vm object */ -BEGINobjDebugPrint(vm) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDebugPrint(vm) - dbgoprint((obj_t*) pThis, "rsyslog virtual machine, currently no state info available\n"); -ENDobjDebugPrint(vm) - - -/* execute a program - */ -static rsRetVal -execProg(vm_t *pThis, vmprg_t *pProg) -{ - DEFiRet; - vmop_t *pCurrOp; /* virtual instruction pointer */ - - ISOBJ_TYPE_assert(pThis, vm); - ISOBJ_TYPE_assert(pProg, vmprg); - -#define doOP(OP) case opcode_##OP: DBGPRINTF("rainerscript: opcode %s\n", #OP); \ - CHKiRet(op##OP(pThis, pCurrOp)); break - pCurrOp = pProg->vmopRoot; /* TODO: do this via a method! */ - while(pCurrOp != NULL && pCurrOp->opcode != opcode_END_PROG) { - DBGPRINTF("rainerscript: executing step, opcode %d...\n", pCurrOp->opcode); - switch(pCurrOp->opcode) { - doOP(OR); - doOP(AND); - doOP(CMP_EQ); - doOP(CMP_NEQ); - doOP(CMP_LT); - doOP(CMP_GT); - doOP(CMP_LTEQ); - doOP(CMP_GTEQ); - doOP(CMP_CONTAINS); - doOP(CMP_CONTAINSI); - doOP(CMP_STARTSWITH); - doOP(CMP_STARTSWITHI); - doOP(NOT); - doOP(PUSHCONSTANT); - doOP(PUSHMSGVAR); - doOP(PUSHCEEVAR); - doOP(PUSHSYSVAR); - doOP(STRADD); - doOP(PLUS); - doOP(MINUS); - doOP(TIMES); - doOP(DIV); - doOP(MOD); - doOP(UNARY_MINUS); - doOP(FUNC_CALL); - default: - dbgoprint((obj_t*) pThis, "invalid instruction %d in vmprg\n", pCurrOp->opcode); - ABORT_FINALIZE(RS_RET_INVALID_VMOP); - break; - } - /* so far, we have plain sequential execution, so on to next... */ - pCurrOp = pCurrOp->pNext; - } -#undef doOP - - /* if we reach this point, our program has intintionally terminated - * (no error state). - */ - -finalize_it: - DBGPRINTF("rainerscript: script execution terminated with state %d\n", iRet); - RETiRet; -} - - -/* Set the current message object for the VM. It *is* valid to set a - * NULL message object, what simply means there is none. Message - * objects are properly reference counted. - */ -static rsRetVal -SetMsg(vm_t *pThis, msg_t *pMsg) -{ - DEFiRet; - if(pThis->pMsg != NULL) { - msgDestruct(&pThis->pMsg); - } - - if(pMsg != NULL) { - pThis->pMsg = MsgAddRef(pMsg); - } - - RETiRet; -} - - -/* Pop a var from the stack and return it to caller. The variable type is not - * changed, it is taken from the stack as is. This functionality is - * partly needed. We may (or may not ;)) be able to remove it once we have - * full RainerScript support. -- rgerhards, 2008-02-25 - */ -static rsRetVal -PopVarFromStack(vm_t *pThis, var_t **ppVar) -{ - DEFiRet; - CHKiRet(vmstk.Pop(pThis->pStk, ppVar)); -finalize_it: - RETiRet; -} - - -/* Pop a boolean from the stack and return it to caller. This functionality is - * partly needed. We may (or may not ;)) be able to remove it once we have - * full RainerScript support. -- rgerhards, 2008-02-25 - */ -static rsRetVal -PopBoolFromStack(vm_t *pThis, var_t **ppVar) -{ - DEFiRet; - CHKiRet(vmstk.PopBool(pThis->pStk, ppVar)); -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(vm) -CODESTARTobjQueryInterface(vm) - if(pIf->ifVersion != vmCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = vmConstruct; - pIf->ConstructFinalize = vmConstructFinalize; - pIf->Destruct = vmDestruct; - pIf->DebugPrint = vmDebugPrint; - pIf->ExecProg = execProg; - pIf->PopBoolFromStack = PopBoolFromStack; - pIf->PopVarFromStack = PopVarFromStack; - pIf->SetMsg = SetMsg; - pIf->FindRSFunction = findRSFunction; - pIf->FindRSFunctionName = findRSFunctionName; -finalize_it: -ENDobjQueryInterface(vm) - - -/* Exit the vm class. - * rgerhards, 2009-04-06 - */ -BEGINObjClassExit(vm, OBJ_IS_CORE_MODULE) /* class, version */ - rsfrRemoveAll(); - objRelease(sysvar, CORE_COMPONENT); - objRelease(var, CORE_COMPONENT); - objRelease(vmstk, CORE_COMPONENT); - - pthread_mutex_destroy(&mutGetenv); -ENDObjClassExit(vm) - - -/* Initialize the vm class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(vm, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(vmstk, CORE_COMPONENT)); - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(sysvar, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_DEBUGPRINT, vmDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmConstructFinalize); - - /* register built-in functions // TODO: move to its own module */ - CHKiRet(rsfrAddFunction((uchar*)"strlen", rsf_strlen)); - CHKiRet(rsfrAddFunction((uchar*)"tolower", rsf_tolower)); - CHKiRet(rsfrAddFunction((uchar*)"getenv", rsf_getenv)); - - pthread_mutex_init(&mutGetenv, NULL); - -ENDObjClassInit(vm) - -/* vi:set ai: - */ diff --git a/runtime/vm.h b/runtime/vm.h deleted file mode 100644 index cb3c69d0..00000000 --- a/runtime/vm.h +++ /dev/null @@ -1,68 +0,0 @@ -/* The vm object. - * - * This implements the rsyslog virtual machine. The initial implementation is - * done to support complex user-defined expressions, but it may evolve into a - * much more useful thing over time. - * - * The virtual machine uses rsyslog variables as its memory storage system. - * All computation is done on a stack (vmstk). The vm supports a given - * instruction set and executes programs of type vmprg, which consist of - * single operations defined in vmop (which hold the instruction and the - * data). - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_VM_H -#define INCLUDED_VM_H - -#include "msg.h" -#include "vmstk.h" -#include "vmprg.h" - -/* the vm object */ -typedef struct vm_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - vmstk_t *pStk; /* The stack */ - msg_t *pMsg; /* the current message (or NULL, if we have none) */ -} vm_t; - - -/* interfaces */ -BEGINinterface(vm) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(vm); - rsRetVal (*Construct)(vm_t **ppThis); - rsRetVal (*ConstructFinalize)(vm_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(vm_t **ppThis); - rsRetVal (*ExecProg)(vm_t *pThis, vmprg_t *pProg); - rsRetVal (*PopBoolFromStack)(vm_t *pThis, var_t **ppVar); /* there are a few cases where we need this... */ - rsRetVal (*PopVarFromStack)(vm_t *pThis, var_t **ppVar); /* there are a few cases where we need this... */ - rsRetVal (*SetMsg)(vm_t *pThis, msg_t *pMsg); /* there are a few cases where we need this... */ - /* v2 (4.1.7) */ - rsRetVal (*FindRSFunction)(cstr_t *pcsName, prsf_t *prsf); /* 2009-06-04 */ - rsRetVal (*FindRSFunctionName)(prsf_t rsf, cstr_t **ppcsName); /* 2009-06-04 */ -ENDinterface(vm) -#define vmCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(vm); - -#endif /* #ifndef INCLUDED_VM_H */ diff --git a/runtime/vmop.c b/runtime/vmop.c deleted file mode 100644 index ea627220..00000000 --- a/runtime/vmop.c +++ /dev/null @@ -1,307 +0,0 @@ -/* vmop.c - abstracts an operation (instructed) supported by the - * rsyslog virtual machine - * - * Module begun 2008-02-20 by Rainer Gerhards - * - * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include - -#include "rsyslog.h" -#include "obj.h" -#include "vmop.h" -#include "vm.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(var) -DEFobjCurrIf(vm) - - -/* forward definitions */ -static rsRetVal vmopOpcode2Str(vmop_t *pThis, uchar **ppName); - -/* Standard-Constructor - */ -BEGINobjConstruct(vmop) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(vmop) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -rsRetVal vmopConstructFinalize(vmop_t __attribute__((unused)) *pThis) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - RETiRet; -} - - -/* destructor for the vmop object */ -BEGINobjDestruct(vmop) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(vmop) - if(pThis->opcode != opcode_FUNC_CALL) { - if(pThis->operand.pVar != NULL) - var.Destruct(&pThis->operand.pVar); - } -ENDobjDestruct(vmop) - - -/* DebugPrint support for the vmop object */ -BEGINobjDebugPrint(vmop) /* be sure to specify the object type also in END and CODESTART macros! */ - uchar *pOpcodeName; - cstr_t *pStrVar; -CODESTARTobjDebugPrint(vmop) - vmopOpcode2Str(pThis, &pOpcodeName); - if(pThis->opcode == opcode_FUNC_CALL) { - CHKiRet(vm.FindRSFunctionName(pThis->operand.rsf, &pStrVar)); - assert(pStrVar != NULL); - } else { - CHKiRet(rsCStrConstruct(&pStrVar)); - if(pThis->operand.pVar != NULL) { - CHKiRet(var.Obj2Str(pThis->operand.pVar, pStrVar)); - } - } - CHKiRet(cstrFinalize(pStrVar)); - dbgoprint((obj_t*) pThis, "%.12s\t%s\n", pOpcodeName, rsCStrGetSzStrNoNULL(pStrVar)); - if(pThis->opcode != opcode_FUNC_CALL) - rsCStrDestruct(&pStrVar); -finalize_it: -ENDobjDebugPrint(vmop) - - -/* This function is similar to DebugPrint, but does not send its output to - * the debug log but instead to a caller-provided string. The idea here is that - * we can use this string to get a textual representation of an operation. - * Among others, this is useful for creating testbenches, our first use case for - * it. Here, it enables simple comparison of the resulting program to a - * reference program by simple string compare. - * Note that the caller must initialize the string object. We always add - * data to it. So, it can be easily combined into a chain of methods - * to generate the final string. - * rgerhards, 2008-07-04 - */ -static rsRetVal -Obj2Str(vmop_t *pThis, cstr_t *pstrPrg) -{ - uchar *pOpcodeName; - cstr_t *pcsFuncName; - uchar szBuf[2048]; - size_t lenBuf; - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmop); - assert(pstrPrg != NULL); - vmopOpcode2Str(pThis, &pOpcodeName); - lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%s\t", pOpcodeName); - CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szBuf, lenBuf)); - if(pThis->opcode == opcode_FUNC_CALL) { - CHKiRet(vm.FindRSFunctionName(pThis->operand.rsf, &pcsFuncName)); - CHKiRet(rsCStrAppendCStr(pstrPrg, pcsFuncName)); - } else { - if(pThis->operand.pVar != NULL) - CHKiRet(var.Obj2Str(pThis->operand.pVar, pstrPrg)); - } - CHKiRet(cstrAppendChar(pstrPrg, '\n')); - -finalize_it: - RETiRet; -} - - -/* set function - * rgerhards, 2009-04-06 - */ -static rsRetVal -vmopSetFunc(vmop_t *pThis, cstr_t *pcsFuncName) -{ - prsf_t rsf; /* pointer to function */ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - CHKiRet(vm.FindRSFunction(pcsFuncName, &rsf)); /* check if function exists and obtain pointer to it */ - assert(rsf != NULL); /* just double-check, would be very hard to find! */ - pThis->operand.rsf = rsf; -finalize_it: - RETiRet; -} - - -/* set operand (variant case) - * rgerhards, 2008-02-20 - */ -static rsRetVal -vmopSetVar(vmop_t *pThis, var_t *pVar) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - ISOBJ_TYPE_assert(pVar, var); - pThis->operand.pVar = pVar; - RETiRet; -} - - -/* set operation - * rgerhards, 2008-02-20 - */ -static rsRetVal -vmopSetOpcode(vmop_t *pThis, opcode_t opcode) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - pThis->opcode = opcode; - RETiRet; -} - - -/* a way to turn an opcode into a readable string - */ -static rsRetVal -vmopOpcode2Str(vmop_t *pThis, uchar **ppName) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - - switch(pThis->opcode) { - case opcode_OR: - *ppName = (uchar*) "or"; - break; - case opcode_AND: - *ppName = (uchar*) "and"; - break; - case opcode_PLUS: - *ppName = (uchar*) "add"; - break; - case opcode_MINUS: - *ppName = (uchar*) "sub"; - break; - case opcode_TIMES: - *ppName = (uchar*) "mul"; - break; - case opcode_DIV: - *ppName = (uchar*) "div"; - break; - case opcode_MOD: - *ppName = (uchar*) "mod"; - break; - case opcode_NOT: - *ppName = (uchar*) "not"; - break; - case opcode_CMP_EQ: - *ppName = (uchar*) "cmp_=="; - break; - case opcode_CMP_NEQ: - *ppName = (uchar*) "cmp_!="; - break; - case opcode_CMP_LT: - *ppName = (uchar*) "cmp_<"; - break; - case opcode_CMP_GT: - *ppName = (uchar*) "cmp_>"; - break; - case opcode_CMP_LTEQ: - *ppName = (uchar*) "cmp_<="; - break; - case opcode_CMP_CONTAINS: - *ppName = (uchar*) "contains"; - break; - case opcode_CMP_STARTSWITH: - *ppName = (uchar*) "startswith"; - break; - case opcode_CMP_GTEQ: - *ppName = (uchar*) "cmp_>="; - break; - case opcode_PUSHSYSVAR: - *ppName = (uchar*) "push_sysvar"; - break; - case opcode_PUSHMSGVAR: - *ppName = (uchar*) "push_msgvar"; - break; - case opcode_PUSHCONSTANT: - *ppName = (uchar*) "push_const"; - break; - case opcode_POP: - *ppName = (uchar*) "pop"; - break; - case opcode_UNARY_MINUS: - *ppName = (uchar*) "unary_minus"; - break; - case opcode_STRADD: - *ppName = (uchar*) "strconcat"; - break; - case opcode_FUNC_CALL: - *ppName = (uchar*) "func_call"; - break; - default: - *ppName = (uchar*) "!invalid_opcode!"; - break; - } - - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(vmop) -CODESTARTobjQueryInterface(vmop) - if(pIf->ifVersion != vmopCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = vmopConstruct; - pIf->ConstructFinalize = vmopConstructFinalize; - pIf->Destruct = vmopDestruct; - pIf->DebugPrint = vmopDebugPrint; - pIf->SetFunc = vmopSetFunc; - pIf->SetOpcode = vmopSetOpcode; - pIf->SetVar = vmopSetVar; - pIf->Opcode2Str = vmopOpcode2Str; - pIf->Obj2Str = Obj2Str; -finalize_it: -ENDobjQueryInterface(vmop) - - -/* Initialize the vmop class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(vmop, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(vm, CORE_COMPONENT)); - - OBJSetMethodHandler(objMethod_DEBUGPRINT, vmopDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmopConstructFinalize); -ENDObjClassInit(vmop) - -/* vi:set ai: - */ diff --git a/runtime/vmop.h b/runtime/vmop.h deleted file mode 100644 index c085a940..00000000 --- a/runtime/vmop.h +++ /dev/null @@ -1,129 +0,0 @@ -/* The vmop object. - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of rsyslog. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_VMOP_H -#define INCLUDED_VMOP_H - -#include "ctok_token.h" -#include "vmstk.h" -#include "stringbuf.h" - -/* machine instructions types */ -typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc() */ - opcode_INVALID = 0, - /* for simplicity of debugging and reading dumps, we use the same IDs - * that the tokenizer uses where this applicable. - */ - opcode_OR = ctok_OR, - opcode_AND = ctok_AND, - opcode_STRADD= ctok_STRADD, - opcode_PLUS = ctok_PLUS, - opcode_MINUS = ctok_MINUS, - opcode_TIMES = ctok_TIMES, /* "*" */ - opcode_DIV = ctok_DIV, - opcode_MOD = ctok_MOD, - opcode_NOT = ctok_NOT, - opcode_CMP_EQ = ctok_CMP_EQ, /* all compare operations must be in a row */ - opcode_CMP_NEQ = ctok_CMP_NEQ, - opcode_CMP_LT = ctok_CMP_LT, - opcode_CMP_GT = ctok_CMP_GT, - opcode_CMP_LTEQ = ctok_CMP_LTEQ, - opcode_CMP_CONTAINS = ctok_CMP_CONTAINS, - opcode_CMP_STARTSWITH = ctok_CMP_STARTSWITH, - opcode_CMP_CONTAINSI = ctok_CMP_CONTAINSI, - opcode_CMP_STARTSWITHI = ctok_CMP_STARTSWITHI, - opcode_CMP_GTEQ = ctok_CMP_GTEQ, /* end compare operations */ - /* here we start our own codes */ - opcode_POP = 1000, /* requires var operand to receive result */ - opcode_PUSHSYSVAR = 1001, /* requires var operand */ - opcode_PUSHMSGVAR = 1002, /* requires var operand */ - opcode_PUSHCONSTANT = 1003, /* requires var operand */ - opcode_PUSHCEEVAR = 1004, /* requires var operand */ - opcode_UNARY_MINUS = 1010, - opcode_FUNC_CALL = 1012, - opcode_END_PROG = 2000 -} opcode_t; - - -/* Additional doc, operation specific - - FUNC_CALL - All parameter passing is via the stack. Parameters are placed onto the stack in reverse order, - that means the last parameter is on top of the stack, the first at the bottom location. - At the actual top of the stack is the number of parameters. This permits functions to be - called with variable number of arguments. The function itself is responsible for poping - the right number of parameters of the stack and complaining if the number is incorrect. - On exit, a single return value must be pushed onto the stack. The FUNC_CALL operation - is generic. Its pVar argument contains the function name string (TODO: very slow, make - faster in later releases). - - Sample Function call: sampleFunc(p1, p2, p3) ; returns number 4711 (sample) - Stacklayout on entry (order is top to bottom): - 3 - p3 - p2 - p1 - ... other vars ... - - Stack on exit - 4711 - ... other vars ... - - */ - - -/* the vmop object */ -typedef struct vmop_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - opcode_t opcode; - union { - var_t *pVar; - prsf_t rsf; /* pointer to function for "call" instruction */ - } operand; - struct vmop_s *pNext; /* next operation or NULL, if end of program (logically this belongs to vmprg) */ -} vmop_t; - - -/* interfaces */ -BEGINinterface(vmop) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(vmop); - rsRetVal (*Construct)(vmop_t **ppThis); - rsRetVal (*ConstructFinalize)(vmop_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(vmop_t **ppThis); - rsRetVal (*SetOpcode)(vmop_t *pThis, opcode_t opcode); - rsRetVal (*SetVar)(vmop_t *pThis, var_t *pVar); - rsRetVal (*Opcode2Str)(vmop_t *pThis, uchar **ppName); - rsRetVal (*Obj2Str)(vmop_t *pThis, cstr_t *pstr); - /* v2 */ - rsRetVal (*SetFunc)(vmop_t *pThis, cstr_t *pcsFuncName); -ENDinterface(vmop) -#define vmopCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ -/* interface changes, v1 -> v2 - * added SetFuct after existing function pointers -- rgerhards, 2009-04-06 - */ - -/* the remaining prototypes */ -PROTOTYPEObj(vmop); - -#endif /* #ifndef INCLUDED_VMOP_H */ diff --git a/runtime/vmprg.c b/runtime/vmprg.c deleted file mode 100644 index 07757b98..00000000 --- a/runtime/vmprg.c +++ /dev/null @@ -1,236 +0,0 @@ -/* vmprg.c - abstracts a program (bytecode) for the rsyslog virtual machine - * - * Module begun 2008-02-20 by Rainer Gerhards - * - * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include - -#include "rsyslog.h" -#include "obj.h" -#include "vmprg.h" -#include "stringbuf.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(vmop) - - -/* Standard-Constructor - */ -BEGINobjConstruct(vmprg) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(vmprg) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -static rsRetVal -vmprgConstructFinalize(vmprg_t __attribute__((unused)) *pThis) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmprg); - RETiRet; -} - - -/* destructor for the vmprg object */ -BEGINobjDestruct(vmprg) /* be sure to specify the object type also in END and CODESTART macros! */ - vmop_t *pOp; - vmop_t *pTmp; -CODESTARTobjDestruct(vmprg) - /* we need to destruct the program elements! */ - for(pOp = pThis->vmopRoot ; pOp != NULL ; ) { - pTmp = pOp; - pOp = pOp->pNext; - vmop.Destruct(&pTmp); - } -ENDobjDestruct(vmprg) - - -/* destructor for the vmop object */ -BEGINobjDebugPrint(vmprg) /* be sure to specify the object type also in END and CODESTART macros! */ - vmop_t *pOp; -CODESTARTobjDebugPrint(vmprg) - dbgoprint((obj_t*) pThis, "VM Program:\n"); - for(pOp = pThis->vmopRoot ; pOp != NULL ; pOp = pOp->pNext) { - vmop.DebugPrint(pOp); - } -ENDobjDebugPrint(vmprg) - - -/* This function is similar to DebugPrint, but does not send its output to - * the debug log but instead to a caller-provided string. The idea here is that - * we can use this string to get a textual representation of a bytecode program. - * Among others, this is useful for creating testbenches, our first use case for - * it. Here, it enables simple comparison of the resulting program to a - * reference program by simple string compare. - * Note that the caller must initialize the string object. We always add - * data to it. So, it can be easily combined into a chain of methods - * to generate the final string. - * rgerhards, 2008-07-04 - */ -static rsRetVal -Obj2Str(vmprg_t *pThis, cstr_t *pstrPrg) -{ - uchar szAddr[12]; - vmop_t *pOp; - int i; - int lenAddr; - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmprg); - assert(pstrPrg != NULL); - i = 0; /* "program counter" */ - for(pOp = pThis->vmopRoot ; pOp != NULL ; pOp = pOp->pNext) { - lenAddr = snprintf((char*)szAddr, sizeof(szAddr), "%8.8d: ", i++); - CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szAddr, lenAddr)); - vmop.Obj2Str(pOp, pstrPrg); - } - -finalize_it: - RETiRet; -} - - -/* add an operation (instruction) to the end of the current program. This - * function is expected to be called while creating the program, but never - * again after this is done and it is being executed. Results are undefined if - * it is called after execution. - */ -static rsRetVal -vmprgAddOperation(vmprg_t *pThis, vmop_t *pOp) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmprg); - ISOBJ_TYPE_assert(pOp, vmop); - - if(pThis->vmopRoot == NULL) { - pThis->vmopRoot = pOp; - } else { - pThis->vmopLast->pNext = pOp; - } - pThis->vmopLast = pOp; - - RETiRet; -} - - -/* this is a shortcut for high-level callers. It creates a new vmop, sets its - * parameters and adds it to the program - all in one big step. If there is no - * var associated with this operation, the caller can simply supply NULL as - * pVar. - */ -static rsRetVal -vmprgAddVarOperation(vmprg_t *pThis, opcode_t opcode, var_t *pVar) -{ - DEFiRet; - vmop_t *pOp; - - ISOBJ_TYPE_assert(pThis, vmprg); - - /* construct and fill vmop */ - CHKiRet(vmop.Construct(&pOp)); - CHKiRet(vmop.ConstructFinalize(pOp)); - CHKiRet(vmop.SetOpcode(pOp, opcode)); - if(pVar != NULL) - CHKiRet(vmop.SetVar(pOp, pVar)); - - /* and add it to the program */ - CHKiRet(vmprgAddOperation(pThis, pOp)); - -finalize_it: - RETiRet; -} - - -/* this is another shortcut for high-level callers. It is similar to vmprgAddVarOperation - * but adds a call operation. Among others, this include a check if the function - * is known. - */ -static rsRetVal -vmprgAddCallOperation(vmprg_t *pThis, cstr_t *pcsName) -{ - DEFiRet; - vmop_t *pOp; - - ISOBJ_TYPE_assert(pThis, vmprg); - - /* construct and fill vmop */ - CHKiRet(vmop.Construct(&pOp)); - CHKiRet(vmop.ConstructFinalize(pOp)); - CHKiRet(vmop.SetFunc(pOp, pcsName)); - CHKiRet(vmop.SetOpcode(pOp, opcode_FUNC_CALL)); - - /* and add it to the program */ - CHKiRet(vmprgAddOperation(pThis, pOp)); - -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(vmprg) -CODESTARTobjQueryInterface(vmprg) - if(pIf->ifVersion != vmprgCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = vmprgConstruct; - pIf->ConstructFinalize = vmprgConstructFinalize; - pIf->Destruct = vmprgDestruct; - pIf->DebugPrint = vmprgDebugPrint; - pIf->Obj2Str = Obj2Str; - pIf->AddOperation = vmprgAddOperation; - pIf->AddVarOperation = vmprgAddVarOperation; - pIf->AddCallOperation = vmprgAddCallOperation; -finalize_it: -ENDobjQueryInterface(vmprg) - - -/* Initialize the vmprg class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(vmprg, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(vmop, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_DEBUGPRINT, vmprgDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmprgConstructFinalize); -ENDObjClassInit(vmprg) - -/* vi:set ai: - */ diff --git a/runtime/vmprg.h b/runtime/vmprg.h deleted file mode 100644 index 66f03913..00000000 --- a/runtime/vmprg.h +++ /dev/null @@ -1,69 +0,0 @@ -/* The vmprg object. - * - * The program is made up of vmop_t's, one after another. When we support - * branching (or user-defined functions) at some time, well do this via - * special branch opcodes. They will then contain the actual memory - * address of a logical program entry that we shall branch to. Other than - * that, all execution is serial - that is one opcode is executed after - * the other. This class implements a logical program store, modelled - * after real main memory. A linked list of opcodes is used to implement it. - * In the future, we may use linked lists of array's to enhance performance, - * but for the time being we have taken the simplistic approach (which also - * reduces risk of bugs during initial development). The necessary pointers - * for this are already implemented in vmop. Though this is not the 100% - * correct place, we have opted this time in favor of performance, which - * made them go there. - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_VMPRG_H -#define INCLUDED_VMPRG_H - -#include "vmop.h" -#include "stringbuf.h" - -/* the vmprg object */ -typedef struct vmprg_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - vmop_t *vmopRoot; /* start of program */ - vmop_t *vmopLast; /* last vmop of program (for adding new ones) */ -} vmprg_t; - - -/* interfaces */ -BEGINinterface(vmprg) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(vmprg); - rsRetVal (*Construct)(vmprg_t **ppThis); - rsRetVal (*ConstructFinalize)(vmprg_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(vmprg_t **ppThis); - rsRetVal (*AddOperation)(vmprg_t *pThis, vmop_t *pOp); - rsRetVal (*AddVarOperation)(vmprg_t *pThis, opcode_t opcode, var_t *pVar); - rsRetVal (*Obj2Str)(vmprg_t *pThis, cstr_t *pstr); - /* v2 (4.1.7) */ - rsRetVal (*AddCallOperation)(vmprg_t *pThis, cstr_t *pVar); /* added 2009-04-06 */ -ENDinterface(vmprg) -#define vmprgCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(vmprg); - -#endif /* #ifndef INCLUDED_VMPRG_H */ diff --git a/runtime/vmstk.c b/runtime/vmstk.c deleted file mode 100644 index 1ee3d485..00000000 --- a/runtime/vmstk.c +++ /dev/null @@ -1,234 +0,0 @@ -/* vmstk.c - the arithmetic stack of a virtual machine. - * - * Module begun 2008-02-21 by Rainer Gerhards - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include - -#include "rsyslog.h" -#include "obj.h" -#include "vmstk.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(var) - - -/* Standard-Constructor - */ -BEGINobjConstruct(vmstk) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(vmstk) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -static rsRetVal -vmstkConstructFinalize(vmstk_t __attribute__((unused)) *pThis) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmstk); - RETiRet; -} - - -/* destructor for the vmstk object */ -BEGINobjDestruct(vmstk) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(vmstk) -ENDobjDestruct(vmstk) - - -/* debugprint for the vmstk object */ -BEGINobjDebugPrint(vmstk) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDebugPrint(vmstk) - dbgoprint((obj_t*) pThis, "stack contents:\n"); -ENDobjDebugPrint(vmstk) - - -/* push a value on the stack. The provided pVar is now owned - * by the stack. If the user intends to continue use it, it - * must be duplicated. - */ -static rsRetVal -push(vmstk_t *pThis, var_t *pVar) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmstk); - ISOBJ_TYPE_assert(pVar, var); - - if(pThis->iStkPtr >= VMSTK_SIZE) - ABORT_FINALIZE(RS_RET_OUT_OF_STACKSPACE); - - pThis->vStk[pThis->iStkPtr++] = pVar; - -finalize_it: - RETiRet; -} - - -/* pop a value from the stack - * IMPORTANT: the stack pointer always points to the NEXT FREE entry. So in - * order to pop, we must access the element one below the stack pointer. - * The user is responsible for destructing the ppVar returned. - */ -static rsRetVal -pop(vmstk_t *pThis, var_t **ppVar) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmstk); - ASSERT(ppVar != NULL); - - if(pThis->iStkPtr == 0) - ABORT_FINALIZE(RS_RET_STACK_EMPTY); - - *ppVar = pThis->vStk[--pThis->iStkPtr]; - -finalize_it: - RETiRet; -} - - -/* pop a boolean value from the stack - * The user is responsible for destructing the ppVar returned. - */ -static rsRetVal -popBool(vmstk_t *pThis, var_t **ppVar) -{ - DEFiRet; - - /* assertions are done in pop(), we do not duplicate here */ - CHKiRet(pop(pThis, ppVar)); - CHKiRet(var.ConvToBool(*ppVar)); - -finalize_it: - RETiRet; -} - - -/* pop a number value from the stack - * The user is responsible for destructing the ppVar returned. - */ -static rsRetVal -popNumber(vmstk_t *pThis, var_t **ppVar) -{ - DEFiRet; - - /* assertions are done in pop(), we do not duplicate here */ - CHKiRet(pop(pThis, ppVar)); - CHKiRet(var.ConvToNumber(*ppVar)); - -finalize_it: - RETiRet; -} - - -/* pop a number value from the stack - * The user is responsible for destructing the ppVar returned. - */ -static rsRetVal -popString(vmstk_t *pThis, var_t **ppVar) -{ - DEFiRet; - - /* assertions are done in pop(), we do not duplicate here */ - CHKiRet(pop(pThis, ppVar)); - CHKiRet(var.ConvToString(*ppVar)); - -finalize_it: - RETiRet; -} - - -/* pop two variables for a common operation, e.g. a compare. When this - * functions returns, both variables have the same type, but the type - * is not set to anything specific. - * The user is responsible for destructing the ppVar's returned. - * A quick note on the name: it means pop 2 variable for a common - * opertion - just in case you wonder (I don't really like the name, - * but I didn't come up with a better one...). - * rgerhards, 2008-02-25 - */ -static rsRetVal -pop2CommOp(vmstk_t *pThis, var_t **ppVar1, var_t **ppVar2) -{ - DEFiRet; - - /* assertions are done in pop(), we do not duplicate here */ - /* operand two must be popped first, because it is at the top of stack */ - CHKiRet(pop(pThis, ppVar2)); - CHKiRet(pop(pThis, ppVar1)); - CHKiRet(var.ConvForOperation(*ppVar1, *ppVar2)); - -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(vmstk) -CODESTARTobjQueryInterface(vmstk) - if(pIf->ifVersion != vmstkCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = vmstkConstruct; - pIf->ConstructFinalize = vmstkConstructFinalize; - pIf->Destruct = vmstkDestruct; - pIf->DebugPrint = vmstkDebugPrint; - pIf->Push = push; - pIf->Pop = pop; - pIf->PopBool = popBool; - pIf->PopNumber = popNumber; - pIf->PopString = popString; - pIf->Pop2CommOp = pop2CommOp; - -finalize_it: -ENDobjQueryInterface(vmstk) - - -/* Initialize the vmstk class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(vmstk, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_DEBUGPRINT, vmstkDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmstkConstructFinalize); -ENDObjClassInit(vmstk) - -/* vi:set ai: - */ diff --git a/runtime/vmstk.h b/runtime/vmstk.h deleted file mode 100644 index 06657cf4..00000000 --- a/runtime/vmstk.h +++ /dev/null @@ -1,56 +0,0 @@ -/* The vmstk object. - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_VMSTK_H -#define INCLUDED_VMSTK_H - -/* The max size of the stack - TODO: make configurable */ -#define VMSTK_SIZE 256 - -/* the vmstk object */ -struct vmstk_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - var_t *vStk[VMSTK_SIZE];/* the actual stack */ - int iStkPtr; /* stack pointer, points to next free location, grows from 0 --> topend */ -}; - - -/* interfaces */ -BEGINinterface(vmstk) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(vmstk); - rsRetVal (*Construct)(vmstk_t **ppThis); - rsRetVal (*ConstructFinalize)(vmstk_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(vmstk_t **ppThis); - rsRetVal (*Push)(vmstk_t *pThis, var_t *pVar); - rsRetVal (*Pop)(vmstk_t *pThis, var_t **ppVar); - rsRetVal (*PopBool)(vmstk_t *pThis, var_t **ppVar); - rsRetVal (*PopNumber)(vmstk_t *pThis, var_t **ppVar); - rsRetVal (*PopString)(vmstk_t *pThis, var_t **ppVar); - rsRetVal (*Pop2CommOp)(vmstk_t *pThis, var_t **ppVar1, var_t **ppVar2); -ENDinterface(vmstk) -#define vmstkCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(vmstk); - -#endif /* #ifndef INCLUDED_VMSTK_H */ diff --git a/tools/syslogd.c b/tools/syslogd.c index f623b398..45abf1a7 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -121,7 +121,6 @@ #include "ruleset.h" #include "rule.h" #include "net.h" -#include "vm.h" #include "prop.h" #include "rsconf.h" #include "dnscache.h" @@ -132,7 +131,6 @@ DEFobjCurrIf(obj) DEFobjCurrIf(glbl) DEFobjCurrIf(datetime) /* TODO: make go away! */ DEFobjCurrIf(conf) -DEFobjCurrIf(expr) DEFobjCurrIf(module) DEFobjCurrIf(errmsg) DEFobjCurrIf(rule) @@ -1544,8 +1542,6 @@ InitGlobalClasses(void) CHKiRet(objUse(module, CORE_COMPONENT)); pErrObj = "datetime"; CHKiRet(objUse(datetime, CORE_COMPONENT)); - pErrObj = "expr"; - CHKiRet(objUse(expr, CORE_COMPONENT)); pErrObj = "rule"; CHKiRet(objUse(rule, CORE_COMPONENT)); pErrObj = "ruleset"; @@ -1601,7 +1597,6 @@ GlobalClassExit(void) objRelease(conf, CORE_COMPONENT); objRelease(ruleset, CORE_COMPONENT); objRelease(rule, CORE_COMPONENT); - objRelease(expr, CORE_COMPONENT); parserClassExit(); /* this is hack, currently core_modules do not get this automatically called */ rsconfClassExit(); /* this is hack, currently core_modules do not get this automatically called */ objRelease(datetime, CORE_COMPONENT); diff --git a/tools/syslogd.h b/tools/syslogd.h index c3b99f9d..7c5dde81 100644 --- a/tools/syslogd.h +++ b/tools/syslogd.h @@ -27,7 +27,6 @@ #include "template.h" #include "action.h" #include "linkedlist.h" -#include "expr.h" /* the following prototypes should go away once we have an input * module interface -- rgerhards, 2007-12-12 -- cgit v1.2.3 From c809f8d1d92307564cb1a4b071934b955211663a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 15:28:16 +0200 Subject: more cleanup --- runtime/Makefile.am | 4 - runtime/conf.c | 8 - runtime/ctok.c | 629 --------------------------------------------------- runtime/ctok.h | 56 ----- runtime/ctok_token.c | 129 ----------- runtime/ctok_token.h | 88 ------- runtime/rsyslog.c | 5 - 7 files changed, 919 deletions(-) delete mode 100644 runtime/ctok.c delete mode 100644 runtime/ctok.h delete mode 100644 runtime/ctok_token.c delete mode 100644 runtime/ctok_token.h diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 7f7e55fd..74ba2ab7 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -55,10 +55,6 @@ librsyslog_la_SOURCES = \ statsobj.h \ sync.c \ sync.h \ - ctok.c \ - ctok.h \ - ctok_token.c \ - ctok_token.h \ stream.c \ stream.h \ var.c \ diff --git a/runtime/conf.c b/runtime/conf.c index 413d02bb..8c7bc7b6 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -65,8 +65,6 @@ #include "srUtils.h" #include "errmsg.h" #include "net.h" -#include "ctok.h" -#include "ctok_token.h" #include "rule.h" #include "ruleset.h" #include "rsconf.h" @@ -82,8 +80,6 @@ static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); /* static data */ DEFobjStaticHelpers -DEFobjCurrIf(ctok) -DEFobjCurrIf(ctok_token) DEFobjCurrIf(module) DEFobjCurrIf(errmsg) DEFobjCurrIf(net) @@ -1082,8 +1078,6 @@ CODESTARTObjClassExit(conf) } /* release objects we no longer need */ - objRelease(ctok, CORE_COMPONENT); - objRelease(ctok_token, CORE_COMPONENT); objRelease(module, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); objRelease(net, LM_NET_FILENAME); @@ -1098,8 +1092,6 @@ ENDObjClassExit(conf) */ BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */ /* request objects we use */ - CHKiRet(objUse(ctok, CORE_COMPONENT)); - CHKiRet(objUse(ctok_token, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(net, LM_NET_FILENAME)); /* TODO: make this dependcy go away! */ diff --git a/runtime/ctok.c b/runtime/ctok.c deleted file mode 100644 index 19c9bd24..00000000 --- a/runtime/ctok.c +++ /dev/null @@ -1,629 +0,0 @@ -/* ctok.c - helper class to tokenize an input stream - which surprisingly - * currently does not work with streams but with string. But that will - * probably change over time ;) This class was originally written to support - * the expression module but may evolve when (if) the expression module is - * expanded (or aggregated) by a full-fledged ctoken based config parser. - * Obviously, this class is used together with config files and not any other - * parse function. - * - * Module begun 2008-02-19 by Rainer Gerhards - * - * Copyright (C) 2008 by Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include -#include - -#include "rsyslog.h" -#include "template.h" -#include "ctok.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(ctok_token) -DEFobjCurrIf(var) - - -/* Standard-Constructor - */ -BEGINobjConstruct(ctok) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(ctok) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -rsRetVal ctokConstructFinalize(ctok_t __attribute__((unused)) *pThis) -{ - DEFiRet; - RETiRet; -} - - -/* destructor for the ctok object */ -BEGINobjDestruct(ctok) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(ctok) - /* ... then free resources */ -ENDobjDestruct(ctok) - - -/* unget character from input stream. At most one character can be ungotten. - * This funtion is only permitted to be called after at least one character - * has been read from the stream. Right now, we handle the situation simply by - * moving the string "stream" pointer one position backwards. If we work with - * real streams (some time), the strm object will handle the functionality - * itself. -- rgerhards, 2008-02-19 - */ -static rsRetVal -ctokUngetCharFromStream(ctok_t *pThis, uchar __attribute__((unused)) c) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok); - --pThis->pp; - - RETiRet; -} - - -/* get the next character from the input "stream". Note that this version - * does NOT look for comment characters as end-of-stream, so it is suitable - * when building constant strings! -- rgerhards, 2010-03-01 - */ -static inline rsRetVal -ctokGetCharFromStreamNoComment(ctok_t *pThis, uchar *pc) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pc != NULL); - - /* end of string or begin of comment terminates the "stream" */ - if(*pThis->pp == '\0') { - ABORT_FINALIZE(RS_RET_EOS); - } else { - *pc = *pThis->pp; - ++pThis->pp; - } - -finalize_it: - RETiRet; -} - - -/* get the next character from the input "stream" (currently just a in-memory - * string...) -- rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetCharFromStream(ctok_t *pThis, uchar *pc) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pc != NULL); - - CHKiRet(ctokGetCharFromStreamNoComment(pThis, pc)); - /* begin of comment terminates the "stream"! */ - if(*pc == '#') { - ABORT_FINALIZE(RS_RET_EOS); - } - -finalize_it: - RETiRet; -} - - -/* skip whitespace in the input "stream". - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokSkipWhitespaceFromStream(ctok_t *pThis) -{ - DEFiRet; - uchar c; - - ISOBJ_TYPE_assert(pThis, ctok); - - CHKiRet(ctokGetCharFromStream(pThis, &c)); - while(isspace(c)) { - CHKiRet(ctokGetCharFromStream(pThis, &c)); - } - - /* we must unget the one non-whitespace we found */ - CHKiRet(ctokUngetCharFromStream(pThis, c)); - -dbgprintf("skipped whitespace, stream now '%s'\n", pThis->pp); -finalize_it: - RETiRet; -} - - -/* get the next word from the input "stream" (currently just a in-memory - * string...). A word is anything from the current location until the - * first non-alphanumeric character. If the word is longer - * than the provided memory buffer, parsing terminates when buffer length - * has been reached. A buffer of 128 bytes or more should always be by - * far sufficient. -- rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetWordFromStream(ctok_t *pThis, uchar *pWordBuf, size_t lenWordBuf) -{ - DEFiRet; - uchar c; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pWordBuf != NULL); - ASSERT(lenWordBuf > 0); - - CHKiRet(ctokSkipWhitespaceFromStream(pThis)); - - CHKiRet(ctokGetCharFromStream(pThis, &c)); - while((isalnum(c) || c == '_' || c == '-') && lenWordBuf > 1) { - *pWordBuf++ = c; - --lenWordBuf; - CHKiRet(ctokGetCharFromStream(pThis, &c)); - } - *pWordBuf = '\0'; /* there is always space for this - see while() */ - - /* push back the char that we have read too much */ - CHKiRet(ctokUngetCharFromStream(pThis, c)); - -finalize_it: - RETiRet; -} - - -/* read in a constant number - * This is the "number" ABNF element - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetNumber(ctok_t *pThis, ctok_token_t *pToken) -{ - DEFiRet; - number_t n; /* the parsed number */ - uchar c; - int valC; - int iBase; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pToken != NULL); - - pToken->tok = ctok_NUMBER; - - CHKiRet(ctokGetCharFromStream(pThis, &c)); - if(c == '0') { /* octal? */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); - if(c == 'x') { /* nope, hex! */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); - c = tolower(c); - iBase = 16; - } else { - iBase = 8; - } - } else { - iBase = 10; - } - - n = 0; - /* this loop is quite simple, a variable name is terminated by whitespace. */ - while(isdigit(c) || (c >= 'a' && c <= 'f')) { - if(isdigit(c)) { - valC = c - '0'; - } else { - valC = c - 'a' + 10; - } - - if(valC >= iBase) { - if(iBase == 8) { - ABORT_FINALIZE(RS_RET_INVALID_OCTAL_DIGIT); - } else { - ABORT_FINALIZE(RS_RET_INVALID_HEX_DIGIT); - } - } - /* we now have the next value and know it is right */ - n = n * iBase + valC; - CHKiRet(ctokGetCharFromStream(pThis, &c)); - c = tolower(c); - } - - /* we need to unget the character that made the loop terminate */ - CHKiRet(ctokUngetCharFromStream(pThis, c)); - - CHKiRet(var.SetNumber(pToken->pVar, n)); - -finalize_it: - RETiRet; -} - - -/* read in a variable - * This covers both msgvar and sysvar from the ABNF. - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetVar(ctok_t *pThis, ctok_token_t *pToken) -{ - DEFiRet; - uchar c; - cstr_t *pstrVal = NULL; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pToken != NULL); - - CHKiRet(ctokGetCharFromStream(pThis, &c)); - - if(c == '$') { /* second dollar, we have a system variable */ - pToken->tok = ctok_SYSVAR; - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */ - } else if(c == '!') { /* cee variable indicator */ - pToken->tok = ctok_CEEVAR; - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */ - } else { - pToken->tok = ctok_MSGVAR; - } - - CHKiRet(cstrConstruct(&pstrVal)); - /* this loop is quite simple, a variable name is terminated when a non-supported - * character is detected. Note that we currently permit a numerical digit as the - * first char, which is not permitted by ABNF. -- rgerhards, 2009-03-10 - */ - while(isalpha(c) || isdigit(c) || (c == '_') || (c == '-')) { - CHKiRet(cstrAppendChar(pstrVal, tolower(c))); - CHKiRet(ctokGetCharFromStream(pThis, &c)); - } - CHKiRet(ctokUngetCharFromStream(pThis, c)); /* put not processed char back */ - - CHKiRet(cstrFinalize(pstrVal)); - - CHKiRet(var.SetString(pToken->pVar, pstrVal)); - pstrVal = NULL; - -finalize_it: - if(iRet != RS_RET_OK) { - if(pstrVal != NULL) { - cstrDestruct(&pstrVal); - } - } - - RETiRet; -} - - -/* read in a simple string (simpstr in ABNF) - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetSimpStr(ctok_t *pThis, ctok_token_t *pToken) -{ - DEFiRet; - uchar c; - int bInEsc = 0; - cstr_t *pstrVal; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pToken != NULL); - - pToken->tok = ctok_SIMPSTR; - - CHKiRet(cstrConstruct(&pstrVal)); - CHKiRet(ctokGetCharFromStreamNoComment(pThis, &c)); - /* while we are in escape mode (had a backslash), no sequence - * terminates the loop. If outside, it is terminated by a single quote. - */ - while(bInEsc || c != '\'') { - if(bInEsc) { - CHKiRet(cstrAppendChar(pstrVal, c)); - bInEsc = 0; - } else { - if(c == '\\') { - bInEsc = 1; - } else { - CHKiRet(cstrAppendChar(pstrVal, c)); - } - } - CHKiRet(ctokGetCharFromStreamNoComment(pThis, &c)); - } - CHKiRet(cstrFinalize(pstrVal)); - - CHKiRet(var.SetString(pToken->pVar, pstrVal)); - pstrVal = NULL; - -finalize_it: - if(iRet != RS_RET_OK) { - if(pstrVal != NULL) { - cstrDestruct(&pstrVal); - } - } - - RETiRet; -} - - -/* Unget a token. The token ungotten will be returned the next time - * ctokGetToken() is called. Only one token can be ungotten at a time. - * If a second token is ungotten, the first is lost. This is considered - * a programming error. - * rgerhards, 2008-02-20 - */ -static rsRetVal -ctokUngetToken(ctok_t *pThis, ctok_token_t *pToken) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pToken != NULL); - ASSERT(pThis->pUngotToken == NULL); - - pThis->pUngotToken = pToken; - - RETiRet; -} - - -/* skip an inine comment (just like a C-comment) - * rgerhards, 2008-02-20 - */ -static rsRetVal -ctokSkipInlineComment(ctok_t *pThis) -{ - DEFiRet; - uchar c; - int bHadAsterisk = 0; - - ISOBJ_TYPE_assert(pThis, ctok); - - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */ - while(!(bHadAsterisk && c == '/')) { - bHadAsterisk = (c == '*') ? 1 : 0; - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read next */ - } - -finalize_it: - RETiRet; -} - - - -/* Get the *next* token from the input stream. This parses the next token and - * ignores any whitespace in between. End of stream is communicated via iRet. - * The returned token must either be destructed by the caller OR being passed - * back to ctokUngetToken(). - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetToken(ctok_t *pThis, ctok_token_t **ppToken) -{ - DEFiRet; - ctok_token_t *pToken; - uchar c; - uchar szWord[128]; - int bRetry = 0; /* retry parse? Only needed for inline comments... */ - cstr_t *pstrVal; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(ppToken != NULL); - - /* first check if we have an ungotten token and, if so, provide that - * one back (without any parsing). -- rgerhards, 2008-02-20 - */ - if(pThis->pUngotToken != NULL) { - *ppToken = pThis->pUngotToken; - pThis->pUngotToken = NULL; - FINALIZE; - } - - /* setup the stage - create our token */ - CHKiRet(ctok_token.Construct(&pToken)); - CHKiRet(ctok_token.ConstructFinalize(pToken)); - - /* find the next token. We may loop when we have inline comments */ - do { - bRetry = 0; - CHKiRet(ctokSkipWhitespaceFromStream(pThis)); - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */ - switch(c) { - case '=': /* == */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a character */ - pToken->tok = (c == '=')? ctok_CMP_EQ : ctok_INVALID; - break; - case '!': /* != */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a character */ - pToken->tok = (c == '=')? ctok_CMP_NEQ : ctok_INVALID; - break; - case '<': /* <, <=, <> */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a character */ - if(c == '=') { - pToken->tok = ctok_CMP_LTEQ; - } else if(c == '>') { - pToken->tok = ctok_CMP_NEQ; - } else { - pToken->tok = ctok_CMP_LT; - } - break; - case '>': /* >, >= */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a character */ - if(c == '=') { - pToken->tok = ctok_CMP_GTEQ; - } else { - pToken->tok = ctok_CMP_GT; - } - break; - case '+': - pToken->tok = ctok_PLUS; - break; - case '-': - pToken->tok = ctok_MINUS; - break; - case '*': - pToken->tok = ctok_TIMES; - break; - case '/': /* /, /.* ... *./ (comments, mungled here for obvious reasons...) */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */ - if(c == '*') { - /* we have a comment and need to skip it */ - ctokSkipInlineComment(pThis); - bRetry = 1; - } else { - CHKiRet(ctokUngetCharFromStream(pThis, c)); /* put back, not processed */ - } - pToken->tok = ctok_DIV; - break; - case '%': - pToken->tok = ctok_MOD; - break; - case '(': - pToken->tok = ctok_LPAREN; - break; - case ')': - pToken->tok = ctok_RPAREN; - break; - case ',': - pToken->tok = ctok_COMMA; - break; - case '&': - pToken->tok = ctok_STRADD; - break; - case '$': - CHKiRet(ctokGetVar(pThis, pToken)); - break; - case '\'': /* simple string, this is somewhat more elaborate */ - CHKiRet(ctokGetSimpStr(pThis, pToken)); - break; - case '"': - /* TODO: template string parser */ - ABORT_FINALIZE(RS_RET_NOT_IMPLEMENTED); - break; - default: - CHKiRet(ctokUngetCharFromStream(pThis, c)); /* push back, we need it in any case */ - if(isdigit(c)) { - CHKiRet(ctokGetNumber(pThis, pToken)); - } else { /* now we check if we have a multi-char sequence */ - CHKiRet(ctokGetWordFromStream(pThis, szWord, sizeof(szWord)/sizeof(uchar))); - if(!strcasecmp((char*)szWord, "and")) { - pToken->tok = ctok_AND; - } else if(!strcasecmp((char*)szWord, "or")) { - pToken->tok = ctok_OR; - } else if(!strcasecmp((char*)szWord, "not")) { - pToken->tok = ctok_NOT; - } else if(!strcasecmp((char*)szWord, "contains")) { - pToken->tok = ctok_CMP_CONTAINS; - } else if(!strcasecmp((char*)szWord, "contains_i")) { - pToken->tok = ctok_CMP_CONTAINSI; - } else if(!strcasecmp((char*)szWord, "startswith")) { - pToken->tok = ctok_CMP_STARTSWITH; - } else if(!strcasecmp((char*)szWord, "startswith_i")) { - pToken->tok = ctok_CMP_STARTSWITHI; - } else if(!strcasecmp((char*)szWord, "then")) { - pToken->tok = ctok_THEN; - } else { - /* finally, we check if it is a function */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */ - if(c == '(') { - /* push c back, higher level parser needs it */ - CHKiRet(ctokUngetCharFromStream(pThis, c)); - pToken->tok = ctok_FUNCTION; - /* fill function name */ - CHKiRet(cstrConstruct(&pstrVal)); - CHKiRet(rsCStrSetSzStr(pstrVal, szWord)); - CHKiRet(cstrFinalize(pstrVal)); - CHKiRet(var.SetString(pToken->pVar, pstrVal)); - } else { /* give up... */ - dbgprintf("parser has an invalid word (token) '%s'\n", szWord); - pToken->tok = ctok_INVALID; - } - } - } - break; - } - } while(bRetry); /* warning: do ... while()! */ - - *ppToken = pToken; - dbgoprint((obj_t*) pToken, "token: %d\n", pToken->tok); - -finalize_it: -/*dbgprintf("ctokGetToken, returns %d, returns token %d, addr %p\n", iRet, (*ppToken)->tok, &((*ppToken)->tok));*/ - if(iRet != RS_RET_OK) { - if(pToken != NULL) - ctok_token.Destruct(&pToken); - } - - RETiRet; -} - - -/* property set methods */ -/* simple ones first */ -DEFpropSetMeth(ctok, pp, uchar*) - -/* return the current position of pp - most important as currently we do only - * partial parsing, so the rest must know where to start from... - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetpp(ctok_t *pThis, uchar **pp) -{ - DEFiRet; - ASSERT(pp != NULL); - *pp = pThis->pp; - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(ctok) -CODESTARTobjQueryInterface(ctok) - if(pIf->ifVersion != ctokCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = ctokConstruct; - pIf->ConstructFinalize = ctokConstructFinalize; - pIf->Destruct = ctokDestruct; - pIf->Getpp = ctokGetpp; - pIf->GetToken = ctokGetToken; - pIf->UngetToken = ctokUngetToken; - pIf->Setpp = ctokSetpp; -finalize_it: -ENDobjQueryInterface(ctok) - - - -BEGINObjClassInit(ctok, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(ctok_token, CORE_COMPONENT)); - CHKiRet(objUse(var, CORE_COMPONENT)); - - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, ctokConstructFinalize); -ENDObjClassInit(ctok) - -/* vi:set ai: - */ diff --git a/runtime/ctok.h b/runtime/ctok.h deleted file mode 100644 index 591f0838..00000000 --- a/runtime/ctok.h +++ /dev/null @@ -1,56 +0,0 @@ -/* The ctok object (implements a config file tokenizer). - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_CTOK_H -#define INCLUDED_CTOK_H - -#include "obj.h" -#include "stringbuf.h" -#include "ctok_token.h" - -/* the ctokession object */ -typedef struct ctok_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - uchar *pp; /* this points to the next unread character, it is a reminescent of pp in - the config parser code ;) */ - ctok_token_t *pUngotToken; /* buffer for ctokUngetToken(), NULL if not set */ -} ctok_t; - - -/* interfaces */ -BEGINinterface(ctok) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(ctok); - INTERFACEpropSetMeth(ctok, pp, uchar*); - rsRetVal (*Construct)(ctok_t **ppThis); - rsRetVal (*ConstructFinalize)(ctok_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(ctok_t **ppThis); - rsRetVal (*Getpp)(ctok_t *pThis, uchar **pp); - rsRetVal (*GetToken)(ctok_t *pThis, ctok_token_t **ppToken); - rsRetVal (*UngetToken)(ctok_t *pThis, ctok_token_t *pToken); -ENDinterface(ctok) -#define ctokCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(ctok); - -#endif /* #ifndef INCLUDED_CTOK_H */ diff --git a/runtime/ctok_token.c b/runtime/ctok_token.c deleted file mode 100644 index 8c17f693..00000000 --- a/runtime/ctok_token.c +++ /dev/null @@ -1,129 +0,0 @@ -/* ctok_token - implements the token_t class. - * - * Module begun 2008-02-20 by Rainer Gerhards - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include -#include - -#include "rsyslog.h" -#include "template.h" -#include "ctok_token.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(var) - - -/* Standard-Constructor - */ -BEGINobjConstruct(ctok_token) /* be sure to specify the object type also in END macro! */ - /* TODO: we may optimize the code below and alloc var only if actually - * needed (but we need it quite often) - */ - CHKiRet(var.Construct(&pThis->pVar)); - CHKiRet(var.ConstructFinalize(pThis->pVar)); -finalize_it: -ENDobjConstruct(ctok_token) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -rsRetVal ctok_tokenConstructFinalize(ctok_token_t __attribute__((unused)) *pThis) -{ - DEFiRet; - RETiRet; -} - - -/* destructor for the ctok object */ -BEGINobjDestruct(ctok_token) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(ctok_token) - if(pThis->pVar != NULL) { - var.Destruct(&pThis->pVar); - } -ENDobjDestruct(ctok_token) - - -/* get the cstr_t from the token, but do not destruct it. This is meant to - * be used by a caller who passes on the string to some other function. The - * caller is responsible for destructing it. - * rgerhards, 2008-02-20 - */ -static rsRetVal -ctok_tokenUnlinkVar(ctok_token_t *pThis, var_t **ppVar) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok_token); - ASSERT(ppVar != NULL); - - *ppVar = pThis->pVar; - pThis->pVar = NULL; - - RETiRet; -} - - -/* tell the caller if the supplied token is a compare operation */ -static int ctok_tokenIsCmpOp(ctok_token_t *pThis) -{ - return(pThis->tok >= ctok_CMP_EQ && pThis->tok <= ctok_CMP_GTEQ); -} - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(ctok_token) -CODESTARTobjQueryInterface(ctok_token) - if(pIf->ifVersion != ctok_tokenCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = ctok_tokenConstruct; - pIf->ConstructFinalize = ctok_tokenConstructFinalize; - pIf->Destruct = ctok_tokenDestruct; - pIf->UnlinkVar = ctok_tokenUnlinkVar; - pIf->IsCmpOp = ctok_tokenIsCmpOp; -finalize_it: -ENDobjQueryInterface(ctok_token) - - -BEGINObjClassInit(ctok_token, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, ctok_tokenConstructFinalize); -ENDObjClassInit(ctok_token) - -/* vi:set ai: - */ diff --git a/runtime/ctok_token.h b/runtime/ctok_token.h deleted file mode 100644 index 1413c699..00000000 --- a/runtime/ctok_token.h +++ /dev/null @@ -1,88 +0,0 @@ -/* The ctok_token object - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_CTOK_TOKEN_H -#define INCLUDED_CTOK_TOKEN_H - -#include "obj.h" -#include "var.h" - -/* the tokens... I use numbers below so that the tokens can be easier - * identified in debug output. These ID's are also partly resused as opcodes. - * As such, they should be kept below 1,000 so that they do not interfer - * with the rest of the opcodes. - */ -typedef struct { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - enum { - ctok_INVALID = 0, - ctok_OR = 1, - ctok_AND = 2, - ctok_PLUS = 3, - ctok_MINUS = 4, - ctok_TIMES = 5, /* "*" */ - ctok_DIV = 6, - ctok_MOD = 7, - ctok_NOT = 8, - ctok_RPAREN = 9, - ctok_LPAREN = 10, - ctok_COMMA = 11, - ctok_SYSVAR = 12, - ctok_MSGVAR = 13, - ctok_SIMPSTR = 14, - ctok_TPLSTR = 15, - ctok_NUMBER = 16, - ctok_FUNCTION = 17, - ctok_THEN = 18, - ctok_STRADD = 19, - ctok_CEEVAR = 20, - ctok_CMP_EQ = 100, /* all compare operations must be in a row */ - ctok_CMP_NEQ = 101, - ctok_CMP_LT = 102, - ctok_CMP_GT = 103, - ctok_CMP_LTEQ = 104, - ctok_CMP_CONTAINS = 105, - ctok_CMP_STARTSWITH = 106, - ctok_CMP_CONTAINSI = 107, - ctok_CMP_STARTSWITHI = 108, - ctok_CMP_GTEQ = 109 /* end compare operations */ - } tok; - var_t *pVar; -} ctok_token_t; - - -/* interfaces */ -BEGINinterface(ctok_token) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(ctok_token); - rsRetVal (*Construct)(ctok_token_t **ppThis); - rsRetVal (*ConstructFinalize)(ctok_token_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(ctok_token_t **ppThis); - rsRetVal (*UnlinkVar)(ctok_token_t *pThis, var_t **ppVar); - int (*IsCmpOp)(ctok_token_t *pThis); -ENDinterface(ctok_token) -#define ctok_tokenCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(ctok_token); - -#endif /* #ifndef INCLUDED_CTOK_TOKEN_H */ diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index c5abcb2a..5d5fdda2 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -66,7 +66,6 @@ #include "stringbuf.h" #include "wti.h" #include "wtp.h" -#include "ctok.h" #include "datetime.h" #include "queue.h" #include "conf.h" @@ -173,10 +172,6 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(glblClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "msg"; CHKiRet(msgClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "ctok_token"; - CHKiRet(ctok_tokenClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "ctok"; - CHKiRet(ctokClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "sysvar"; CHKiRet(sysvarClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "rule"; -- cgit v1.2.3 From 31900e004bbfd6da025e64844e2a07247dc87e94 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 15:36:05 +0200 Subject: more cleanup... --- runtime/Makefile.am | 2 - runtime/datetime.c | 1 - runtime/errmsg.c | 1 - runtime/rsyslog.c | 3 - runtime/statsobj.c | 1 - runtime/sysvar.c | 204 ---------------------------------------------------- runtime/sysvar.h | 47 ------------ 7 files changed, 259 deletions(-) delete mode 100644 runtime/sysvar.c delete mode 100644 runtime/sysvar.h diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 74ba2ab7..ac4f4279 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -63,8 +63,6 @@ librsyslog_la_SOURCES = \ wtp.h \ wti.c \ wti.h \ - sysvar.c \ - sysvar.h \ queue.c \ queue.h \ ruleset.c \ diff --git a/runtime/datetime.c b/runtime/datetime.c index 89452f1c..753d2068 100644 --- a/runtime/datetime.c +++ b/runtime/datetime.c @@ -40,7 +40,6 @@ #include "obj.h" #include "modules.h" #include "datetime.h" -#include "sysvar.h" #include "srUtils.h" #include "stringbuf.h" #include "errmsg.h" diff --git a/runtime/errmsg.c b/runtime/errmsg.c index 3c3ee02c..d9062931 100644 --- a/runtime/errmsg.c +++ b/runtime/errmsg.c @@ -35,7 +35,6 @@ #include "rsyslog.h" #include "obj.h" #include "errmsg.h" -#include "sysvar.h" #include "srUtils.h" #include "stringbuf.h" diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index 5d5fdda2..cbab06b7 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -62,7 +62,6 @@ #include "rsyslog.h" #include "obj.h" -#include "sysvar.h" #include "stringbuf.h" #include "wti.h" #include "wtp.h" @@ -172,8 +171,6 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(glblClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "msg"; CHKiRet(msgClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "sysvar"; - CHKiRet(sysvarClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "rule"; CHKiRet(ruleClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "ruleset"; diff --git a/runtime/statsobj.c b/runtime/statsobj.c index e1a89cf4..d1213a34 100644 --- a/runtime/statsobj.c +++ b/runtime/statsobj.c @@ -36,7 +36,6 @@ #include "unicode-helper.h" #include "obj.h" #include "statsobj.h" -#include "sysvar.h" #include "srUtils.h" #include "stringbuf.h" diff --git a/runtime/sysvar.c b/runtime/sysvar.c deleted file mode 100644 index ecc31e2d..00000000 --- a/runtime/sysvar.c +++ /dev/null @@ -1,204 +0,0 @@ -/* sysvar.c - imlements rsyslog system variables - * - * At least for now, this class only has static functions and no - * instances. - * - * Module begun 2008-02-25 by Rainer Gerhards - * - * Copyright (C) 2008 by Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include - -#include "rsyslog.h" -#include "obj.h" -#include "stringbuf.h" -#include "sysvar.h" -#include "datetime.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(var) -DEFobjCurrIf(datetime) -DEFobjCurrIf(glbl) - - -/* Standard-Constructor - */ -BEGINobjConstruct(sysvar) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(sysvar) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -static rsRetVal -sysvarConstructFinalize(sysvar_t __attribute__((unused)) *pThis) -{ - DEFiRet; - RETiRet; -} - - -/* destructor for the sysvar object */ -BEGINobjDestruct(sysvar) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(sysvar) -ENDobjDestruct(sysvar) - - -/* This function returns the current date in different - * variants. It is used to construct the $NOW series of - * system properties. The returned buffer must be freed - * by the caller when no longer needed. If the function - * can not allocate memory, it returns a NULL pointer. - * Added 2007-07-10 rgerhards - * TODO: this was taken from msg.c and we should consolidate it with the code - * there. This is especially important when we increase the number of system - * variables (what we definitely want to do). - */ -typedef enum ENOWType { NOW_NOW, NOW_YEAR, NOW_MONTH, NOW_DAY, NOW_HOUR, NOW_MINUTE } eNOWType; -static rsRetVal -getNOW(eNOWType eNow, cstr_t **ppStr) -{ - DEFiRet; - uchar szBuf[16]; - struct syslogTime t; - - datetime.getCurrTime(&t, NULL); - switch(eNow) { - case NOW_NOW: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%4.4d-%2.2d-%2.2d", t.year, t.month, t.day); - break; - case NOW_YEAR: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%4.4d", t.year); - break; - case NOW_MONTH: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.month); - break; - case NOW_DAY: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.day); - break; - case NOW_HOUR: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.hour); - break; - case NOW_MINUTE: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.minute); - break; - } - - /* now create a string object out of it and hand that over to the var */ - CHKiRet(rsCStrConstructFromszStr(ppStr, szBuf)); - -finalize_it: - RETiRet; -} - - -/* The function returns a system variable suitable for use with RainerScript. Most importantly, this means - * that the value is returned in a var_t object. The var_t is constructed inside this function and - * MUST be freed by the caller. - * rgerhards, 2008-02-25 - */ -static rsRetVal -GetVar(cstr_t *pstrVarName, var_t **ppVar) -{ - DEFiRet; - var_t *pVar; - cstr_t *pstrProp; - - ASSERT(pstrVarName != NULL); - ASSERT(ppVar != NULL); - - /* make sure we have a var_t instance */ - CHKiRet(var.Construct(&pVar)); - CHKiRet(var.ConstructFinalize(pVar)); - - /* now begin the actual variable evaluation */ - if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"now", sizeof("now") - 1)) { - CHKiRet(getNOW(NOW_NOW, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"year", sizeof("year") - 1)) { - CHKiRet(getNOW(NOW_YEAR, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"month", sizeof("month") - 1)) { - CHKiRet(getNOW(NOW_MONTH, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"day", sizeof("day") - 1)) { - CHKiRet(getNOW(NOW_DAY, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"hour", sizeof("hour") - 1)) { - CHKiRet(getNOW(NOW_HOUR, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"minute", sizeof("minute") - 1)) { - CHKiRet(getNOW(NOW_MINUTE, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"myhostname", sizeof("myhostname") - 1)) { - CHKiRet(rsCStrConstructFromszStr(&pstrProp, glbl.GetLocalHostName())); - } else { - ABORT_FINALIZE(RS_RET_SYSVAR_NOT_FOUND); - } - - /* now hand the string over to the var object */ - CHKiRet(var.SetString(pVar, pstrProp)); - - /* finally store var */ - *ppVar = pVar; - -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(sysvar) -CODESTARTobjQueryInterface(sysvar) - if(pIf->ifVersion != sysvarCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = sysvarConstruct; - pIf->ConstructFinalize = sysvarConstructFinalize; - pIf->Destruct = sysvarDestruct; - pIf->GetVar = GetVar; -finalize_it: -ENDobjQueryInterface(sysvar) - - -/* Initialize the sysvar class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(sysvar, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(datetime, CORE_COMPONENT)); - CHKiRet(objUse(glbl, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, sysvarConstructFinalize); -ENDObjClassInit(sysvar) - -/* vi:set ai: - */ diff --git a/runtime/sysvar.h b/runtime/sysvar.h deleted file mode 100644 index 35051b64..00000000 --- a/runtime/sysvar.h +++ /dev/null @@ -1,47 +0,0 @@ -/* The sysvar object. So far, no instance can be defined (makes logically no - * sense). - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime 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 3 of the License, or - * (at your option) any later version. - * - * The rsyslog runtime 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_SYSVAR_H -#define INCLUDED_SYSVAR_H - -/* the sysvar object - not really used... */ -typedef struct sysvar_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ -} sysvar_t; - - -/* interfaces */ -BEGINinterface(sysvar) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(sysvar); - rsRetVal (*Construct)(sysvar_t **ppThis); - rsRetVal (*ConstructFinalize)(sysvar_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(sysvar_t **ppThis); - rsRetVal (*GetVar)(cstr_t *pstrPropName, var_t **ppVar); -ENDinterface(sysvar) -#define sysvarCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(sysvar); - -#endif /* #ifndef INCLUDED_SYSVAR_H */ -- cgit v1.2.3 From 05ff79aa1f928e42bf9883e946923353eb2925ac Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 15:44:04 +0200 Subject: even more cleanup ;) --- runtime/msg.c | 99 ---------------------------------------------------------- runtime/rule.c | 6 ---- 2 files changed, 105 deletions(-) diff --git a/runtime/msg.c b/runtime/msg.c index 0de805a7..b440d6ca 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -47,7 +47,6 @@ #include "stringbuf.h" #include "template.h" #include "msg.h" -#include "var.h" #include "datetime.h" #include "glbl.h" #include "regexp.h" @@ -3146,104 +3145,6 @@ done: } -/* The function returns a cee variable suitable for use with RainerScript. Most importantly, this means - * that the value is returned in a var_t object. The var_t is constructed inside this function and - * MUST be freed by the caller. - * Note that we need to do a lot of conversions between es_str_t and cstr -- this will go away once - * we have moved larger parts of rsyslog to es_str_t. Acceptable for the moment, especially as we intend - * to rewrite the script engine as well! - * rgerhards, 2010-12-03 - * - */ -rsRetVal -msgGetCEEVar(msg_t *pMsg, cstr_t *propName, var_t **ppVar) -{ -#warning remove as part of cleanup - DEFiRet; - var_t *pVar; - cstr_t *pstrProp; - es_str_t *str = NULL; - es_str_t *epropName = NULL; - int r; - - ISOBJ_TYPE_assert(pMsg, msg); - ASSERT(propName != NULL); - ASSERT(ppVar != NULL); - - /* make sure we have a var_t instance */ - CHKiRet(var.Construct(&pVar)); - CHKiRet(var.ConstructFinalize(pVar)); - - epropName = es_newStrFromBuf((char*)propName->pBuf, propName->iStrLen); - r = ee_getEventFieldAsString(pMsg->event, epropName, &str); - - if(r != EE_OK) { - DBGPRINTF("msgGtCEEVar: libee error %d during ee_getEventFieldAsString\n", r); - CHKiRet(cstrConstruct(&pstrProp)); - CHKiRet(cstrFinalize(pstrProp)); - } else { - CHKiRet(cstrConstructFromESStr(&pstrProp, str)); - } - - /* now create a string object out of it and hand that over to the var */ - CHKiRet(var.SetString(pVar, pstrProp)); - es_deleteStr(str); - - /* finally store var */ - *ppVar = pVar; - -finalize_it: - if(epropName != NULL) - es_deleteStr(epropName); - RETiRet; -} - - -/* The returns a message variable suitable for use with RainerScript. Most importantly, this means - * that the value is returned in a var_t object. The var_t is constructed inside this function and - * MUST be freed by the caller. - * rgerhards, 2008-02-25 - */ -rsRetVal -msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar) -{ - DEFiRet; - var_t *pVar; - size_t propLen; - uchar *pszProp = NULL; - cstr_t *pstrProp; - propid_t propid; - unsigned short bMustBeFreed = 0; - - ISOBJ_TYPE_assert(pThis, msg); - ASSERT(pstrPropName != NULL); - ASSERT(ppVar != NULL); - - /* make sure we have a var_t instance */ - CHKiRet(var.Construct(&pVar)); - CHKiRet(var.ConstructFinalize(pVar)); - - /* always call MsgGetProp() without a template specifier */ - /* TODO: optimize propNameToID() call -- rgerhards, 2009-06-26 */ - propNameToID(pstrPropName, &propid); - pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, NULL, &propLen, &bMustBeFreed); - - /* now create a string object out of it and hand that over to the var */ - CHKiRet(rsCStrConstructFromszStr(&pstrProp, pszProp)); - CHKiRet(var.SetString(pVar, pstrProp)); - - /* finally store var */ - *ppVar = pVar; - -finalize_it: - if(bMustBeFreed) - free(pszProp); - - RETiRet; -} - - - /* Return an es_str_t for given message property. */ es_str_t* diff --git a/runtime/rule.c b/runtime/rule.c index 1a430577..cbd2660d 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -36,7 +36,6 @@ #include "action.h" #include "rule.h" #include "errmsg.h" -#include "var.h" #include "srUtils.h" #include "batch.h" #include "parserif.h" @@ -121,7 +120,6 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) uchar *pszPropVal; int bRet = 0; size_t propLen; - var_t *pResult = NULL; ISOBJ_TYPE_assert(pRule, rule); assert(pMsg != NULL); @@ -262,10 +260,6 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) } finalize_it: - /* destruct in any case, not just on error, but it makes error handling much easier */ - if(pResult != NULL) - var.Destruct(&pResult); - *bProcessMsg = bRet; RETiRet; } -- cgit v1.2.3 From cefa1fac08d4d67a4139146016fef206d59d5ddc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 16:51:30 +0200 Subject: fixed lexer: facilities local0-local7 were not correctly handled --- grammar/lexer.l | 6 +++++- runtime/rsconf.c | 3 ++- tests/diag.sh | 4 ++-- tests/imtcp_conndrop.sh | 1 - tests/testsuites/imtcp_conndrop.conf | 1 - 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/grammar/lexer.l b/grammar/lexer.l index 64a804fa..d56b4fc2 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -80,6 +80,8 @@ char *currfn; /* name of currently processed file */ int popfile(void); int cnfSetLexFile(char *fname); +extern int yydebug; + /* somehow, I need these prototype even though the headers are * included. I guess that's some autotools magic I don't understand... */ @@ -155,7 +157,7 @@ int fileno(FILE *stream); "action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { yylval.s = strdup(yytext); return PROPFILT; } -^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } +^[ \t]*[a-z][,\*a-z]*[0-7]*\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } "*" | \-\/[^*][^\n]* | \/[^*][^\n]* | @@ -203,6 +205,8 @@ cnfParseBuffer(char *buf, unsigned lenBuf) { struct bufstack *bs; int r = 0; + yydebug = 1; + BEGIN INITIAL; /* maintain stack */ if((bs = malloc(sizeof(struct bufstack))) == NULL) { r = 1; diff --git a/runtime/rsconf.c b/runtime/rsconf.c index ac969286..d2cb9332 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -1256,9 +1256,10 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!"); emergConf = "*.err " _PATH_CONSOLE "\n" - "syslog.*" _PATH_CONSOLE "\n" + "syslog.* " _PATH_CONSOLE "\n" "*.panic :omusrmsg:*" "\n" "syslog.* :omusrmsg:root" "\n"; +dbgprintf("Emer Config '%s'\n",emergConf); cnfParseBuffer(emergConf, strlen(emergConf)); r = yyparse(); if(r != 0) { diff --git a/tests/diag.sh b/tests/diag.sh index 1f7de2cf..f2bcc4b8 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -10,8 +10,8 @@ #valgrind="valgrind --tool=helgrind --log-fd=1" #valgrind="valgrind --tool=exp-ptrcheck --log-fd=1" #set -o xtrace -#export RSYSLOG_DEBUG="debug nologfuncflow noprintmutexaction stdout" -#export RSYSLOG_DEBUGLOG="log" +export RSYSLOG_DEBUG="debug nologfuncflow noprintmutexaction stdout" +export RSYSLOG_DEBUGLOG="log" case $1 in 'init') $srcdir/killrsyslog.sh # kill rsyslogd if it runs for some reason cp $srcdir/testsuites/diag-common.conf diag-common.conf diff --git a/tests/imtcp_conndrop.sh b/tests/imtcp_conndrop.sh index 0bfcd99c..c5073924 100755 --- a/tests/imtcp_conndrop.sh +++ b/tests/imtcp_conndrop.sh @@ -4,7 +4,6 @@ # This file is part of the rsyslog project, released under GPLv3 echo ==================================================================================== echo TEST: \[imtcp_conndrop.sh\]: test imtcp with random connection drops -cat rsyslog.action.1.include source $srcdir/diag.sh init source $srcdir/diag.sh startup imtcp_conndrop.conf # 100 byte messages to gain more practical data use diff --git a/tests/testsuites/imtcp_conndrop.conf b/tests/testsuites/imtcp_conndrop.conf index b64f132b..de41bc43 100644 --- a/tests/testsuites/imtcp_conndrop.conf +++ b/tests/testsuites/imtcp_conndrop.conf @@ -12,5 +12,4 @@ $template dynfile,"rsyslog.out.log" # trick to use relative path names! $OMFileFlushOnTXEnd off $OMFileFlushInterval 2 $OMFileIOBufferSize 256k -$IncludeConfig rsyslog.action.1.include local0.* ?dynfile;outfmt -- cgit v1.2.3 From 80701b698802efe1bcecac09afcd393dd4bd3d5c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 17:32:26 +0200 Subject: more cleanup, working on emergency config system --- runtime/conf.c | 7 ++++-- runtime/conf.h | 1 - runtime/rsconf.c | 67 +++++++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/runtime/conf.c b/runtime/conf.c index 8c7bc7b6..425d6259 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -75,7 +75,7 @@ #endif /* forward definitions */ -static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); +//static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); /* static data */ @@ -715,6 +715,7 @@ finalize_it: } +#if 0 /* read the filter part of a configuration line and store the filter * in the supplied rule_t * rgerhards, 2007-08-01 @@ -751,6 +752,7 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) finalize_it: RETiRet; } +#endif /* process the action part of a selector line @@ -817,6 +819,7 @@ rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) } +#if 0 /* Process a configuration file line in traditional "filter selector" format * or one that builds upon this format. Note that ppRule may be a NULL pointer, * which is valid and happens if there is no previous line (right at the start @@ -894,6 +897,7 @@ cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr) RETiRet; } +#endif /* return the current number of active actions @@ -926,7 +930,6 @@ CODESTARTobjQueryInterface(conf) pIf->doNameLine = doNameLine; pIf->cfsysline = cfsysline; pIf->doModLoad = doModLoad; - pIf->cfline = cfline; pIf->GetNbrActActions = GetNbrActActions; finalize_it: diff --git a/runtime/conf.h b/runtime/conf.h index a74b99c5..9253e880 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -37,7 +37,6 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ rsRetVal (*doNameLine)(uchar **pp, void* pVal); rsRetVal (*cfsysline)(uchar *p); rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); - rsRetVal (*cfline)(rsconf_t *conf, uchar *line, rule_t **pfCurr); rsRetVal (*GetNbrActActions)(rsconf_t *conf, int *); /* version 4 -- 2010-07-23 rgerhards */ /* "just" added global variables diff --git a/runtime/rsconf.c b/runtime/rsconf.c index d2cb9332..2f0287c2 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -1206,6 +1206,56 @@ validateConf(void) } +#if 0 +/* create an emergency rule */ +static inline rsRetVal +createEmergRule(char *PRIFilt, char *legact) +{ + rule_t *pRule; + action_t *pAction; + DEFiRet; + + CHKiRet(rule.Construct(&pRule)); /* create "fresh" selector */ + CHKiRet(rule.SetAssRuleset(pRule, ruleset.GetCurrent(loadConf))); + CHKiRet(rule.ConstructFinalize(pRule)); + CHKiRet(cflineProcessTradPRIFilter((uchar**)&PRIFilt, pRule)); + iRet = cflineDoAction(loadConf, (uchar**)&legact, &pAction); + iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction); + CHKiRet(ruleset.AddRule(loadConf, rule.GetAssRuleset(pRule), &pRule)); + +finalize_it: + RETiRet; +} + + +/* start up an rsyslog emergency configuration. This is recovery if + * the config failed. + */ +static inline rsRetVal +createEmergConf(void) +{ + DEFiRet; + errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - " + "fix rsyslog config file!"); + /* + CHKiRet(rsconfConstruct(&loadConf)); +ourConf = loadConf; // TODO: remove, once ourConf is gone! + CHKiRet(loadBuildInModules()); + CHKiRet(initLegacyConf()); + */ + ruleset.SetDefaultRuleset(loadConf, (uchar*) "RSYSLOG_DefaultRuleset"); + + CHKiRet(createEmergRule("*.err", _PATH_CONSOLE)); + CHKiRet(createEmergRule("syslog.*", _PATH_CONSOLE)); + CHKiRet(createEmergRule("*.panic", ":omusrmsg:*")); + CHKiRet(createEmergRule("syslog.*", ":omusrmsg:root")); +CHKiRet(createEmergRule("*.*", "/tmp/emerg")); +finalize_it: + RETiRet; +} +#endif + + /* Load a configuration. This will do all necessary steps to create * the in-memory representation of the configuration, including support * for multiple configuration languages. @@ -1219,9 +1269,7 @@ load(rsconf_t **cnf, uchar *confFile) rsRetVal localRet; int iNbrActions; int bHadConfigErr = 0; - char cbuf[BUFSIZ]; int r; - char *emergConf; DEFiRet; CHKiRet(rsconfConstruct(&loadConf)); @@ -1253,17 +1301,10 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! * very clever... So we stick with what we have. * We ignore any errors while doing this - we would be lost anyhow... */ - errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!"); - emergConf = - "*.err " _PATH_CONSOLE "\n" - "syslog.* " _PATH_CONSOLE "\n" - "*.panic :omusrmsg:*" "\n" - "syslog.* :omusrmsg:root" "\n"; -dbgprintf("Emer Config '%s'\n",emergConf); - cnfParseBuffer(emergConf, strlen(emergConf)); - r = yyparse(); - if(r != 0) { - fprintf(stderr, "rsyslogd: could not even activate emergency conf - terminating\n"); + // TODO: think about this! iRet = createEmergConf(); + if(1) { //if(iRet != RS_RET_OK) { + fprintf(stderr, "rsyslogd: could not even activate emergency " + "conf - terminating\n"); exit(1); } } -- cgit v1.2.3 From a5bc2a8b4bdf8b7834326ae6410c3bc7285fa1e8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 12 Jul 2011 12:14:47 +0200 Subject: removed emergency config, do error reporting on fatal config file error --- grammar/lexer.l | 8 +-- grammar/parserif.h | 1 + runtime/rsconf.c | 101 ++++++----------------------------- runtime/rsyslog.h | 1 + tests/testsuites/imtcp_conndrop.conf | 2 +- tools/syslogd.c | 2 +- 6 files changed, 24 insertions(+), 91 deletions(-) diff --git a/grammar/lexer.l b/grammar/lexer.l index d56b4fc2..0c82a4af 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -75,7 +75,7 @@ struct bufstack { es_str_t *estr; } *currbs = NULL; -char *currfn; /* name of currently processed file */ +char *cnfcurrfn; /* name of currently processed file */ int popfile(void); int cnfSetLexFile(char *fname); @@ -220,7 +220,7 @@ cnfParseBuffer(char *buf, unsigned lenBuf) bs->bs = yy_scan_buffer(buf, lenBuf); bs->estr = NULL; currbs = bs; - currfn = bs->fn; + cnfcurrfn = bs->fn; yylineno = 1; done: return r; } @@ -259,7 +259,7 @@ cnfSetLexFile(char *fname) bs->bs = yy_scan_buffer((char*)es_getBufAddr(str), es_strlen(str)); bs->estr = str; /* needed so we can free it later */ currbs = bs; - currfn = bs->fn; + cnfcurrfn = bs->fn; yylineno = 1; done: @@ -294,6 +294,6 @@ popfile(void) yy_switch_to_buffer(currbs->bs); yylineno = currbs->lineno; - currfn = currbs->fn; + cnfcurrfn = currbs->fn; return 0; } diff --git a/grammar/parserif.h b/grammar/parserif.h index bebb1dfb..58b8fbdd 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -4,6 +4,7 @@ int cnfSetLexFile(char*); int yyparse(); int yydebug; +char *cnfcurrfn; void dbgprintf(char *fmt, ...) __attribute__((format(printf, 1, 2))); void parser_errmsg(char *fmt, ...) __attribute__((format(printf, 1, 2))); diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 2f0287c2..5df4c2c8 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -335,13 +335,14 @@ void parser_errmsg(char *fmt, ...) { va_list ap; + char errBuf[1024]; + va_start(ap, fmt); - // TODO: create useful code ;) 2011-07-06 - errmsg.LogError(0, NO_ERRCODE, "error during parsing on or before line %d", - yylineno); -dbgprintf("error on or before line %d: ", yylineno); - vprintf(fmt, ap); - printf("\n"); + if(vsnprintf(errBuf, sizeof(errBuf), fmt, ap) == sizeof(errBuf)) + errBuf[1024] = '\0'; + errmsg.LogError(0, RS_RET_CONF_PARSE_ERROR, + "error during parsing file %s, on or before line %d: %s", + cnfcurrfn, yylineno, errBuf); va_end(ap); } @@ -1206,56 +1207,6 @@ validateConf(void) } -#if 0 -/* create an emergency rule */ -static inline rsRetVal -createEmergRule(char *PRIFilt, char *legact) -{ - rule_t *pRule; - action_t *pAction; - DEFiRet; - - CHKiRet(rule.Construct(&pRule)); /* create "fresh" selector */ - CHKiRet(rule.SetAssRuleset(pRule, ruleset.GetCurrent(loadConf))); - CHKiRet(rule.ConstructFinalize(pRule)); - CHKiRet(cflineProcessTradPRIFilter((uchar**)&PRIFilt, pRule)); - iRet = cflineDoAction(loadConf, (uchar**)&legact, &pAction); - iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction); - CHKiRet(ruleset.AddRule(loadConf, rule.GetAssRuleset(pRule), &pRule)); - -finalize_it: - RETiRet; -} - - -/* start up an rsyslog emergency configuration. This is recovery if - * the config failed. - */ -static inline rsRetVal -createEmergConf(void) -{ - DEFiRet; - errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - " - "fix rsyslog config file!"); - /* - CHKiRet(rsconfConstruct(&loadConf)); -ourConf = loadConf; // TODO: remove, once ourConf is gone! - CHKiRet(loadBuildInModules()); - CHKiRet(initLegacyConf()); - */ - ruleset.SetDefaultRuleset(loadConf, (uchar*) "RSYSLOG_DefaultRuleset"); - - CHKiRet(createEmergRule("*.err", _PATH_CONSOLE)); - CHKiRet(createEmergRule("syslog.*", _PATH_CONSOLE)); - CHKiRet(createEmergRule("*.panic", ":omusrmsg:*")); - CHKiRet(createEmergRule("syslog.*", ":omusrmsg:root")); -CHKiRet(createEmergRule("*.*", "/tmp/emerg")); -finalize_it: - RETiRet; -} -#endif - - /* Load a configuration. This will do all necessary steps to create * the in-memory representation of the configuration, including support * for multiple configuration languages. @@ -1266,9 +1217,7 @@ finalize_it: rsRetVal load(rsconf_t **cnf, uchar *confFile) { - rsRetVal localRet; int iNbrActions; - int bHadConfigErr = 0; int r; DEFiRet; @@ -1286,37 +1235,19 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! } if(r == 1) { - errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", confFile); - bHadConfigErr = 1; + errmsg.LogError(0, RS_RET_CONF_PARSE_ERROR, + "CONFIG ERROR: could not interpret master " + "config file '%s'.", confFile); + ABORT_FINALIZE(RS_RET_CONF_PARSE_ERROR); } else if(iNbrActions == 0) { - errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no active actions configured. Inputs will " - "run, but no output whatsoever is created."); - bHadConfigErr = 1; - } - - if(r == 1 || iNbrActions == 0) { - /* rgerhards: this code is executed to set defaults when the - * config file could not be opened. We might think about - * abandoning the run in this case - but this, too, is not - * very clever... So we stick with what we have. - * We ignore any errors while doing this - we would be lost anyhow... - */ - // TODO: think about this! iRet = createEmergConf(); - if(1) { //if(iRet != RS_RET_OK) { - fprintf(stderr, "rsyslogd: could not even activate emergency " - "conf - terminating\n"); - exit(1); - } + errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no " + "active actions configured. Inputs will " + "run, but no output whatsoever is created."); + ABORT_FINALIZE(RS_RET_NO_ACTIONS); } CHKiRet(validateConf()); - - /* return warning state if we had some acceptable problems */ - if(bHadConfigErr) { - iRet = RS_RET_NONFATAL_CONFIG_ERR; - } - /* we are done checking the config - now validate if we should actually run or not. * If not, terminate. -- rgerhards, 2008-07-25 * TODO: iConfigVerify -- should it be pulled from the config, or leave as is (option)? @@ -1331,7 +1262,7 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! *cnf = loadConf; // TODO: enable this once all config code is moved to here! loadConf = NULL; - dbgprintf("rsyslog finished loading initial config %p\n", loadConf); + dbgprintf("rsyslog finished loading master config %p\n", loadConf); rsconfDebugPrint(loadConf); finalize_it: diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index d1290aeb..05f45565 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -359,6 +359,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_CMD_GONE_AWAY = -2204,/**< config directive existed, but no longer supported */ RS_RET_ERR_SCHED_PARAMS = -2205,/**< there is a problem with configured thread scheduling params */ RS_RET_SOCKNAME_MISSING = -2206,/**< no socket name configured where one is required */ + RS_RET_CONF_PARSE_ERROR = -2207,/**< (fatal) error parsing config file */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/tests/testsuites/imtcp_conndrop.conf b/tests/testsuites/imtcp_conndrop.conf index de41bc43..c1508525 100644 --- a/tests/testsuites/imtcp_conndrop.conf +++ b/tests/testsuites/imtcp_conndrop.conf @@ -12,4 +12,4 @@ $template dynfile,"rsyslog.out.log" # trick to use relative path names! $OMFileFlushOnTXEnd off $OMFileFlushInterval 2 $OMFileIOBufferSize 256k -local0.* ?dynfile;outfmt +0local0.* ?dynfile;outfmt diff --git a/tools/syslogd.c b/tools/syslogd.c index 45abf1a7..72c0bdb3 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -2243,7 +2243,7 @@ finalize_it: if(iRet == RS_RET_VALIDATION_RUN) { fprintf(stderr, "rsyslogd: End of config validation run. Bye.\n"); } else if(iRet != RS_RET_OK) { - fprintf(stderr, "rsyslogd run failed with error %d (see rsyslog.h " + fprintf(stderr, "rsyslogd: run failed with error %d (see rsyslog.h " "or try http://www.rsyslog.com/e/%d to learn what that number means)\n", iRet, iRet*-1); } -- cgit v1.2.3 From 20607ba1695b99838db7bdf809b22cf52bbdf5ce Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 12 Jul 2011 12:29:55 +0200 Subject: removed compatibility mode as we expect people have adjusted their confs by now --- ChangeLog | 4 + tools/syslogd.c | 247 +++----------------------------------------------------- 2 files changed, 17 insertions(+), 234 deletions(-) diff --git a/ChangeLog b/ChangeLog index 52d5e4dd..93c9edbb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ --------------------------------------------------------------------------- +Version 6.3.3 [DEVEL] (rgerhards), 2011-06-?? +- removed compatibility mode as we expect people have adjusted their + confs by now +--------------------------------------------------------------------------- Version 6.3.2 [DEVEL] (rgerhards), 2011-06-?? - added support for obtaining timestamp for kernel message from message If the kernel time-stamps messages, time is now take from that diff --git a/tools/syslogd.c b/tools/syslogd.c index 72c0bdb3..91df6469 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -215,12 +215,6 @@ int repeatinterval[2] = { 30, 60 }; /* # of secs before flush */ static pid_t ppid; /* This is a quick and dirty hack used for spliting main/startup thread */ -typedef struct legacyOptsLL_s { - uchar *line; - struct legacyOptsLL_s *next; -} legacyOptsLL_t; -legacyOptsLL_t *pLegacyOptsLL = NULL; - /* global variables for config file state */ int iCompatibilityMode = 0; /* version we should be compatible with; 0 means sysklogd. It is the default, so if no -c option is given, we make ourselvs @@ -754,132 +748,6 @@ static void debug_switch() } -void legacyOptsEnq(uchar *line) -{ - legacyOptsLL_t *pNew; - - pNew = MALLOC(sizeof(legacyOptsLL_t)); - if(line == NULL) - pNew->line = NULL; - else - pNew->line = (uchar *) strdup((char *) line); - pNew->next = NULL; - - if(pLegacyOptsLL == NULL) - pLegacyOptsLL = pNew; - else { - legacyOptsLL_t *pThis = pLegacyOptsLL; - - while(pThis->next != NULL) - pThis = pThis->next; - pThis->next = pNew; - } -} - - -void legacyOptsFree(void) -{ - legacyOptsLL_t *pThis = pLegacyOptsLL, *pNext; - - while(pThis != NULL) { - if(pThis->line != NULL) - free(pThis->line); - pNext = pThis->next; - free(pThis); - pThis = pNext; - } -} - - -void legacyOptsHook(void) -{ - legacyOptsLL_t *pThis = pLegacyOptsLL; - - while(pThis != NULL) { - if(pThis->line != NULL) { - errno = 0; - errmsg.LogError(0, NO_ERRCODE, "Warning: backward compatibility layer added to following " - "directive to rsyslog.conf: %s", pThis->line); - conf.cfsysline(pThis->line); - } - pThis = pThis->next; - } -} - - -void legacyOptsParseTCP(char ch, char *arg) -{ - register int i; - register char *pArg = arg; - static char conflict = '\0'; - - if((conflict == 'g' && ch == 't') || (conflict == 't' && ch == 'g')) { - fprintf(stderr, "rsyslogd: If you want to use both -g and -t, use directives instead, -%c ignored.\n", ch); - return; - } else - conflict = ch; - - /* extract port */ - i = 0; - while(isdigit((int) *pArg)) - i = i * 10 + *pArg++ - '0'; - - /* number of sessions */ - if(*pArg == '\0' || *pArg == ',') { - if(ch == 't') - legacyOptsEnq((uchar *) "ModLoad imtcp"); - else if(ch == 'g') - legacyOptsEnq((uchar *) "ModLoad imgssapi"); - - if(i >= 0 && i <= 65535) { - uchar line[30]; - - if(ch == 't') { - snprintf((char *) line, sizeof(line), "InputTCPServerRun %d", i); - } else if(ch == 'g') { - snprintf((char *) line, sizeof(line), "InputGSSServerRun %d", i); - } - legacyOptsEnq(line); - } else { - if(ch == 't') { - fprintf(stderr, "rsyslogd: Invalid TCP listen port %d - changed to 514.\n", i); - legacyOptsEnq((uchar *) "InputTCPServerRun 514"); - } else if(ch == 'g') { - fprintf(stderr, "rsyslogd: Invalid GSS listen port %d - changed to 514.\n", i); - legacyOptsEnq((uchar *) "InputGSSServerRun 514"); - } - } - - if(*pArg == ',') { - ++pArg; - while(isspace((int) *pArg)) - ++pArg; - i = 0; - while(isdigit((int) *pArg)) { - i = i * 10 + *pArg++ - '0'; - } - if(i > 0) { - uchar line[30]; - - snprintf((char *) line, sizeof(line), "InputTCPMaxSessions %d", i); - legacyOptsEnq(line); - } else { - if(ch == 't') { - fprintf(stderr, "rsyslogd: TCP session max configured " - "to %d [-t %s] - changing to 1.\n", i, arg); - legacyOptsEnq((uchar *) "InputTCPMaxSessions 1"); - } else if (ch == 'g') { - fprintf(stderr, "rsyslogd: GSS session max configured " - "to %d [-g %s] - changing to 1.\n", i, arg); - legacyOptsEnq((uchar *) "InputTCPMaxSessions 1"); - } - } - } - } else - fprintf(stderr, "rsyslogd: Invalid -t %s command line option.\n", arg); -} - - /* doDie() is a signal handler. If called, it sets the bFinished variable * to indicate the program should terminate. However, it does not terminate * it itself, because that causes issues with multi-threading. The actual @@ -1003,8 +871,6 @@ die(int sig) */ unregCfSysLineHdlrs(); - legacyOptsFree(); - /* destruct our global properties */ if(pInternalInputName != NULL) prop.Destruct(&pInternalInputName); @@ -1305,8 +1171,6 @@ init(void) struct sigaction sigAct; DEFiRet; - legacyOptsHook(); - memset(&sigAct, 0, sizeof (sigAct)); sigemptyset(&sigAct.sa_mask); sigAct.sa_handler = sighup_handler; @@ -1824,11 +1688,9 @@ int realMain(int argc, char **argv) extern int optind; extern char *optarg; int bEOptionWasGiven = 0; - int bImUxSockLoaded = 0; /* already generated a $ModLoad imuxsock? */ int iHelperUOpt; int bChDirRoot = 1; /* change the current working directory to "/"? */ char *arg; /* for command line option processing */ - uchar legacyConfLine[80]; uchar *LocalHostName; uchar *LocalDomain; uchar *LocalFQDNName; @@ -1871,6 +1733,9 @@ int realMain(int argc, char **argv) case 'u': /* misc user settings */ case 'w': /* disable disallowed host warnings */ case 'x': /* disable dns for remote messages */ + case 'g': /* enable tcp gssapi logging */ + case 'r': /* accept remote messages */ + case 't': /* enable tcp logging */ CHKiRet(bufOptAdd(ch, optarg)); break; case 'c': /* compatibility mode */ @@ -1881,37 +1746,15 @@ int realMain(int argc, char **argv) Debug = 1; break; case 'e': /* log every message (no repeat message supression) */ - fprintf(stderr, "note: -e option is no longer supported, every message is now logged by default\n"); bEOptionWasGiven = 1; break; - case 'g': /* enable tcp gssapi logging */ -#if defined(SYSLOG_INET) && defined(USE_GSSAPI) - CHKiRet(bufOptAdd('g', optarg)); -#else - fprintf(stderr, "rsyslogd: -g not valid - not compiled with gssapi support"); -#endif - break; case 'M': /* default module load path -- this MUST be carried out immediately! */ glblModPath = (uchar*) optarg; break; - case 'r': /* accept remote messages */ -#ifdef SYSLOG_INET - CHKiRet(bufOptAdd(ch, optarg)); -#else - fprintf(stderr, "rsyslogd: -r not valid - not compiled with network support\n"); -#endif - break; - case 't': /* enable tcp logging */ -#ifdef SYSLOG_INET - CHKiRet(bufOptAdd(ch, optarg)); -#else - fprintf(stderr, "rsyslogd: -t not valid - not compiled with network support\n"); -#endif - break; case 'v': /* MUST be carried out immediately! */ printVersion(); exit(0); /* exit for -v option - so this is a "good one" */ - case '?': + case '?': default: usage(); } @@ -2020,32 +1863,15 @@ int realMain(int argc, char **argv) send_to_all++; break; case 'a': - if(iCompatibilityMode < 3) { - if(!bImUxSockLoaded) { - legacyOptsEnq((uchar *) "ModLoad imuxsock"); - bImUxSockLoaded = 1; - } - snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "addunixlistensocket %s", arg); - legacyOptsEnq(legacyConfLine); - } else { - fprintf(stderr, "error -a is no longer supported, use module imuxsock instead"); - } + fprintf(stderr, "rsyslogd: error -a is no longer supported, use module imuxsock instead"); break; case 'f': /* configuration file */ ConfFile = (uchar*) arg; break; case 'g': /* enable tcp gssapi logging */ - if(iCompatibilityMode < 3) { - legacyOptsParseTCP(ch, arg); - } else - fprintf(stderr, "-g option only supported in compatibility modes 0 to 2 - ignored\n"); - break; + fprintf(stderr, "rsyslogd: -g option no longer supported - ignored\n"); case 'h': - if(iCompatibilityMode < 3) { - errmsg.LogError(0, NO_ERRCODE, "WARNING: -h option is no longer supported - ignored"); - } else { - usage(); /* for v3 and above, it simply is an error */ - } + fprintf(stderr, "rsyslogd: error -h is no longer supported - ignored"); break; case 'i': /* pid file name */ PidFile = arg; @@ -2058,11 +1884,7 @@ int realMain(int argc, char **argv) } break; case 'm': /* mark interval */ - if(iCompatibilityMode < 3) { - MarkInterval = atoi(arg) * 60; - } else - fprintf(stderr, - "-m option only supported in compatibility modes 0 to 2 - ignored\n"); + fprintf(stderr, "rsyslogd: error -m is no longer supported - use immark instead"); break; case 'n': /* don't fork */ NoFork = 1; @@ -2071,27 +1893,10 @@ int realMain(int argc, char **argv) iConfigVerify = atoi(arg); break; case 'o': - if(iCompatibilityMode < 3) { - if(!bImUxSockLoaded) { - legacyOptsEnq((uchar *) "ModLoad imuxsock"); - bImUxSockLoaded = 1; - } - legacyOptsEnq((uchar *) "OmitLocalLogging"); - } else { - fprintf(stderr, "error -o is no longer supported, use module imuxsock instead"); - } + fprintf(stderr, "error -o is no longer supported, use module imuxsock instead"); break; case 'p': - if(iCompatibilityMode < 3) { - if(!bImUxSockLoaded) { - legacyOptsEnq((uchar *) "ModLoad imuxsock"); - bImUxSockLoaded = 1; - } - snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "SystemLogSocketName %s", arg); - legacyOptsEnq(legacyConfLine); - } else { - fprintf(stderr, "error -p is no longer supported, use module imuxsock instead"); - } + fprintf(stderr, "error -p is no longer supported, use module imuxsock instead"); break; case 'q': /* add hostname if DNS resolving has failed */ *(net.pACLAddHostnameOnFail) = 1; @@ -2100,12 +1905,7 @@ int realMain(int argc, char **argv) *(net.pACLDontResolve) = 1; break; case 'r': /* accept remote messages */ - if(iCompatibilityMode < 3) { - legacyOptsEnq((uchar *) "ModLoad imudp"); - snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "UDPServerRun %s", arg); - legacyOptsEnq(legacyConfLine); - } else - fprintf(stderr, "-r option only supported in compatibility modes 0 to 2 - ignored\n"); + fprintf(stderr, "rsyslogd: error option -r is no longer supported - ignored"); break; case 's': if(glbl.GetStripDomains() != NULL) { @@ -2115,10 +1915,7 @@ int realMain(int argc, char **argv) } break; case 't': /* enable tcp logging */ - if(iCompatibilityMode < 3) { - legacyOptsParseTCP(ch, arg); - } else - fprintf(stderr, "-t option only supported in compatibility modes 0 to 2 - ignored\n"); + fprintf(stderr, "rsyslogd: error option -t is no longer supported - ignored"); break; case 'T':/* chroot() immediately at program startup, but only for testing, NOT security yet */ if(chroot(arg) != 0) { @@ -2176,25 +1973,7 @@ int realMain(int argc, char **argv) } /* process compatibility mode settings */ - if(iCompatibilityMode < 4) { - errmsg.LogError(0, NO_ERRCODE, "WARNING: rsyslogd is running in compatibility mode. Automatically " - "generated config directives may interfer with your rsyslog.conf settings. " - "We suggest upgrading your config and adding -c5 as the first " - "rsyslogd option."); - } - - if(iCompatibilityMode < 3) { - if(MarkInterval > 0) { - legacyOptsEnq((uchar *) "ModLoad immark"); - snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "MarkMessagePeriod %d", MarkInterval); - legacyOptsEnq(legacyConfLine); - } - if(!bImUxSockLoaded) { - legacyOptsEnq((uchar *) "ModLoad imuxsock"); - } - } - - if(bEOptionWasGiven && iCompatibilityMode < 3) { + if(bEOptionWasGiven) { errmsg.LogError(0, NO_ERRCODE, "WARNING: \"message repeated n times\" feature MUST be turned on in " "rsyslog.conf - CURRENTLY EVERY MESSAGE WILL BE LOGGED. Visit " "http://www.rsyslog.com/rptdmsgreduction to learn " -- cgit v1.2.3