summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/Makefile.am1
-rw-r--r--doc/expression.html8
-rw-r--r--doc/rainerscript.html37
-rw-r--r--rsyslog.h4
-rwxr-xr-xstringbuf.c90
-rwxr-xr-xstringbuf.h3
-rw-r--r--var.c60
-rw-r--r--var.h2
8 files changed, 170 insertions, 35 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am
index f03c9120..31481a96 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -37,6 +37,7 @@ html_files = \
queueWorkerLogic.dia \
queueWorkerLogic.jpg \
queueWorkerLogic_small.jpg \
+ rainerscript.html \
rsconf1_actionexeconlywhenpreviousissuspended.html \
rsconf1_actionresumeinterval.html \
rsconf1_allowedsender.html \
diff --git a/doc/expression.html b/doc/expression.html
index 6d187413..e7eb7842 100644
--- a/doc/expression.html
+++ b/doc/expression.html
@@ -4,13 +4,7 @@
<body>
<h1>Expressions</h1>
<p>Rsyslog supports expressions at a growing number of places. So
-far, they are supported for filtering messages.</p><p>C-like comments (/* some comment */) are supported <span style="font-weight: bold;">inside</span> the expression, but not yet in the rest of the configuration file.</p>
-<p></p>
-<h2>Formal Definition</h2>
-
-<p>Below is the formal definition of expression format (in ABNF, RFC 2234):<br>
-</p><pre>; The stuff immediately below here is a quick shot at how the config<br>; file ABNF *at whole* may look like. That is not really related to<br>; expressions, but for the time being I put it here. It will later be<br>; moved to a more appropriate place. -- rgerhards, 2008-02-22<br>?line? := cfsysline / cfli<br>cfsysline:= BOL "$" *char EOL ; how to handle the first line? (no EOL in front!)<br>BOL := ; Begin of Line - implicitely set on file beginning and after each EOL<br>EOL := 0x0a ;LF<br>if_stmt := "if" expr "then"<br>old_filter:= BOL facility "." severity ; no whitespace allowed between BOL and facility!<br>facility := "*" / "auth" / "authpriv" / "cron" / "daemon" / "kern" / "lpr" / <br> "mail" / "mark" / "news" / "security" / "syslog" / "user" / "uucp" / <br> "local0" .. "local7" / "mark"<br> ; The keyword security should not be used anymore<br> ; mark is just internal<br>severity := TBD ; not really relevant in this context<br><br>; and now the actual expression<br>expr := e_and *("or" e_and)<br>e_and := e_cmp *("and" e_cmp)<br>e_cmp := val 0*1(cmp_op val)<br>val := term *(("+" / "-") term)<br>term := factor *(("*" / "/" / "%") factor)<br>factor := ["not"] ["-"] terminal<br>terminal := var / constant / function / ( "(" expr ")" )<br>function := name "(" *("," expr) ")"<br>var := "$" varname<br>varname := msgvar / sysvar<br>msgvar := name<br>sysvar := "$" name<br>name := alpha *(alnum)<br>constant := string / number<br>string := simpstr / tplstr ; tplstr will be implemented in next phase<br>simpstr := "'" *char "'" ; use your imagination for char ;)<br>tplstr := '"' template '"' ; not initially implemented<br>number := ["-"] 1*digit ; 0nn = octal, 0xnn = hex, nn = decimal<br>cmp_op := "==" / "!=" / "&lt;&gt;" / "&lt;" / "&gt;" / "&lt;=" / "&gt;=" / "contains" / "startswith"<br>digit := %x30-39<br>alpha := "a" ... "z" # all letters<br>alnum :* alpha / digit / "_"<br></pre>
-<p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
+far, they are supported for filtering messages.</p><p>Expression support is provided by RainerScript. For now, please see the formal expression definition in <a href="rainerscript.html">RainerScript ABNF</a>. It is the "expr" node.</p><p>C-like comments (/* some comment */) are supported <span style="font-weight: bold;">inside</span> the expression, but not yet in the rest of the configuration file.</p><p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
<p><font size="2">This documentation is part of the
<a href="http://www.rsyslog.com/">rsyslog</a>
diff --git a/doc/rainerscript.html b/doc/rainerscript.html
new file mode 100644
index 00000000..22415258
--- /dev/null
+++ b/doc/rainerscript.html
@@ -0,0 +1,37 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html><head>
+<meta http-equiv="Content-Language" content="en"><title>RainerScript ABNF</title>
+
+</head>
+<body>
+<h1>RainerScript ABNF</h1>
+<p>This is the formal definition of RainerScript, as supported by
+rsyslog configuration. Please note that this currently is working
+document and the actual implementation may be quite different.</p>
+<p>The
+first glimpse of RainerScript will be available as part of rsyslog
+3.12.0 expression support. However, the 3.12. series of rsyslog will
+have a partial script implementaiton, which will not necessariy be
+compatible with the later full implementation. So if you use it, be
+prepared for some config file changes as RainerScript evolves.</p>
+<p>C-like comments (/* some comment */) are supported in all pure
+RainerScript lines. However, legacy-mapped lines do not support them.
+All lines support the hash mark "#" as a comment initiator. Everything
+between the hash and the end of line is a comment (just like // in C++
+and many other languages).</p>
+<h2>Formal Definition</h2>
+<p>Below is the formal language definitionin ABNF (RFC 2234)
+format: <br>
+</p>
+<pre>; <span style="font-weight: bold;">all of this is a working document and may change!</span> -- rgerhards, 2008-02-24<br><br>script := *stmt<br>stmt := (if_stmt / block / vardef / run_s / load_s)<br>vardef := "var" ["scope" = ("global" / "event")] <br>block := "begin" stmt "end"<br>load_s := "load" constraint ("module") modpath params ; load mod only if expr is true<br>run_s := "run" constraint ("input") name<br>constraint:= "if" expr ; constrains some one-time commands<br>modpath := expr<br>params := ["params" *1param *("," param) "endparams"]<br>param := paramname) "=" expr<br>paramname := [*(obqualifier ".") name]<br>modpath:= ; path to module<br>?line? := cfsysline / cfli<br>cfsysline:= BOL "$" *char EOL ; how to handle the first line? (no EOL in front!)<br>BOL := ; Begin of Line - implicitely set on file beginning and after each EOL<br>EOL := 0x0a ;LF<br>if_stmt := "if" expr "then"<br>old_filter:= BOL facility "." severity ; no whitespace allowed between BOL and facility!<br>facility := "*" / "auth" / "authpriv" / "cron" / "daemon" / "kern" / "lpr" / <br> "mail" / "mark" / "news" / "security" / "syslog" / "user" / "uucp" / <br> "local0" .. "local7" / "mark"<br> ; The keyword security should not be used anymore<br> ; mark is just internal<br>severity := TBD ; not really relevant in this context<br><br>; and now the actual expression<br>expr := e_and *("or" e_and)<br>e_and := e_cmp *("and" e_cmp)<br>e_cmp := val 0*1(cmp_op val)<br>val := term *(("+" / "-") term)<br>term := factor *(("*" / "/" / "%") factor)<br>factor := ["not"] ["-"] terminal<br>terminal := var / constant / function / ( "(" expr ")" )<br>function := name "(" *("," expr) ")"<br>var := "$" varname<br>varname := msgvar / sysvar<br>msgvar := name<br>sysvar := "$" name<br>name := alpha *(alnum)<br>constant := string / number<br>string := simpstr / tplstr ; tplstr will be implemented in next phase<br>simpstr := "'" *char "'" ; use your imagination for char ;)<br>tplstr := '"' template '"' ; not initially implemented<br>number := ["-"] 1*digit ; 0nn = octal, 0xnn = hex, nn = decimal<br>cmp_op := "==" / "!=" / "&lt;&gt;" / "&lt;" / "&gt;" / "&lt;=" / "&gt;=" / "contains" / "startswith"<br>digit := %x30-39<br>alpha := "a" ... "z" # all letters<br>alnum :* alpha / digit / "_"<br></pre>
+<h2>Samples</h2>
+<p>Some samples of RainerScript:</p><p>define function IsLinux<br>begin<br>&nbsp; &nbsp; if $environ contains "linux" then return true else return false<br>end</p><p>load if IsLinux() 'imklog.so' params name='klog' endparams /* load klog under linux only */<br>run if IsLinux() input 'klog'<br>load 'ommysql.so'</p><p>if $message contains "error" then<br>&nbsp; action<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp; &nbsp; [?action.template='templatename'?] or [?action.sql='insert into table... values('+$facility+','+$severity+...?]<br>&nbsp; endaction<br><br>... or ...</p><p>define action writeMySQL<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp; &nbsp; [?action.template='templatename'?] or [?action.sql='insert into table... values('+$facility+','+$severity+...?]<br>&nbsp; &nbsp;endaction</p><p>if $message contains "error" then action writeMySQL</p><p>ALTERNATE APPROACH</p><p>define function IsLinux(<br>&nbsp; &nbsp; if $environ contains "linux" then return true else return false<br>)</p><p>load if IsLinux() 'imklog.so' params name='klog' endparams /* load klog under linux only */<br>run if IsLinux() input 'klog'<br>load 'ommysql.so'</p><p>if $message contains "error" then<br>&nbsp; action(<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp; &nbsp; [?action.template='templatename'?] or [?action.sql='insert into table... values('+$facility+','+$severity+...?]<br>&nbsp;&nbsp;)<br><br>... or ...</p><p>define action writeMySQL(<br>&nbsp;&nbsp;&nbsp; type='ommysql.so', queue.mode='disk', queue.highwatermark = 300,<br>&nbsp; &nbsp; action.dbname='events', action.dbuser='uid',<br>&nbsp; &nbsp; [?action.template='templatename'?] or [?action.sql='insert into table... values('+$facility+','+$severity+...?]<br>&nbsp; &nbsp;)</p><p>if $message contains "error" then action writeMySQL(action.dbname='differentDB')</p><p></p><p>[<a href="rsyslog_conf.html">rsyslog.conf overview</a>]
+[<a href="manual.html">manual index</a>] [<a href="http://www.rsyslog.com/">rsyslog site</a>]</p>
+<p><font size="2">This documentation is part of the
+<a href="http://www.rsyslog.com/">rsyslog</a>
+project.<br>
+Copyright © 2008 by <a href="http://www.gerhards.net/rainer">Rainer
+Gerhards</a> and
+<a href="http://www.adiscon.com/">Adiscon</a>.
+Released under the GNU GPL version 3 or higher.</font></p>
+</body></html> \ No newline at end of file
diff --git a/rsyslog.h b/rsyslog.h
index 1d0bb3ce..a64a13d9 100644
--- a/rsyslog.h
+++ b/rsyslog.h
@@ -47,6 +47,7 @@
/* some universal 64 bit define... */
typedef long long int64;
typedef long long unsigned uint64;
+typedef int64 number_t; /* type to use for numbers - TODO: maybe an autoconf option? */
/* The error codes below are orginally "borrowed" from
* liblogging. As such, we reserve values up to -2999
@@ -131,7 +132,8 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_OUT_OF_STACKSPACE = -2055, /**< a stack data structure is exhausted and can not be grown */
RS_RET_STACK_EMPTY = -2056, /**< a pop was requested on a stack, but the stack was already empty */
RS_RET_INVALID_VMOP = -2057, /**< invalid virtual machine instruction */
- RS_RET_INVALID_VAR = -2057, /**< a var_t or its content is unsuitable, eg. VARTYPE_NONE */
+ RS_RET_INVALID_VAR = -2058, /**< a var_t or its content is unsuitable, eg. VARTYPE_NONE */
+ RS_RET_NOT_A_NUMBER = -2059, /**< e.g. conversion impossible because the string is not a number */
RS_RET_OK_DELETE_LISTENTRY = 1, /**< operation successful, but callee requested the deletion of an entry (special state) */
RS_RET_TERMINATE_NOW = 2, /**< operation successful, function is requested to terminate (mostly used with threads) */
RS_RET_NO_RUN = 3, /**< operation successful, but function does not like to be executed */
diff --git a/stringbuf.c b/stringbuf.c
index d1e69abf..80f1bb97 100755
--- a/stringbuf.c
+++ b/stringbuf.c
@@ -718,34 +718,100 @@ int rsCStrOffsetSzStrCmp(cstr_t *pCS1, size_t iOffset, uchar *psz, size_t iLenSz
}
-/* check if the string can be converted to a number. Returns 1 if that's possible
- * and 0 otherwise.
+/* Converts a string to a number. If the string dos not contain a number,
+ * RS_RET_NOT_A_NUMBER is returned and the contents of pNumber is undefined.
+ * If all goes well, pNumber contains the number that the string was converted
+ * to.
*/
-int rsCStrCanConvertToNumber(cstr_t *pStr)
+rsRetVal
+rsCStrConvertToNumber(cstr_t *pStr, number_t *pNumber)
{
- int i;
- int ret = 1;
+ DEFiRet;
+ number_t n;
+ int bIsNegative;
+ size_t i;
+
+ ASSERT(pStr != NULL);
+ ASSERT(pNumber != NULL);
if(pStr->iStrLen == 0) {
/* can be converted to 0! (by convention) */
- goto finalize_it;
+ pNumber = 0;
+ FINALIZE;
+ }
+
+ /* first skip whitespace (if present) */
+ for(i = 0 ; i < pStr->iStrLen && isspace(pStr->pBuf[i]) ; ++i) {
+ /*DO NOTHING*/
}
/* we have a string, so let's check its syntax */
- if(pStr->pBuf[0] == '+' || pStr->pBuf[0] == '-') {
- i = 1; /* skip that char */
+ if(pStr->pBuf[i] == '+') {
+ ++i; /* skip that char */
+ bIsNegative = 0;
+ } else if(pStr->pBuf[0] == '-') {
+ ++i; /* skip that char */
+ bIsNegative = 1;
} else {
- i = 0; /* start from the beginning */
+ bIsNegative = 0;
}
- while(i < pStr->iStrLen && isdigit(pStr->pBuf[i]))
+ /* TODO: octal? hex? */
+ n = 0;
+ while(i < pStr->iStrLen && isdigit(pStr->pBuf[i])) {
+ n = n * 10 + pStr->pBuf[i] * 10;
++i;
+ }
if(i < pStr->iStrLen) /* non-digits before end of string? */
- ret = 0; /* than we can not convert */
+ ABORT_FINALIZE(RS_RET_NOT_A_NUMBER);
+
+ if(bIsNegative)
+ n *= -1;
+
+ /* we got it, so return the number */
+ *pNumber = n;
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* Converts a string to a boolen. First tries to convert to a number. If
+ * that succeeds, we are done (number is then used as boolean value). If
+ * that fails, we look if the string is "yes" or "true". If so, a value
+ * of 1 is returned. In all other cases, a value of 0 is returned. Please
+ * note that we do not have a specific boolean type, so we return a number.
+ * so, these are
+ * RS_RET_NOT_A_NUMBER is returned and the contents of pNumber is undefined.
+ * If all goes well, pNumber contains the number that the string was converted
+ * to.
+ */
+rsRetVal
+rsCStrConvertToBool(cstr_t *pStr, number_t *pBool)
+{
+ DEFiRet;
+
+ ASSERT(pStr != NULL);
+ ASSERT(pBool != NULL);
+
+ iRet = rsCStrConvertToNumber(pStr, pBool);
+
+ if(iRet != RS_RET_NOT_A_NUMBER) {
+ FINALIZE; /* in any case, we have nothing left to do */
+ }
+
+ /* TODO: maybe we can do better than strcasecmp ;) -- overhead! */
+ if(!strcasecmp((char*)rsCStrGetSzStr(pStr), "true")) {
+ *pBool = 1;
+ } else if(!strcasecmp((char*)rsCStrGetSzStr(pStr), "yes")) {
+ *pBool = 1;
+ } else {
+ *pBool = 0;
+ }
finalize_it:
- return ret;
+ RETiRet;
}
diff --git a/stringbuf.h b/stringbuf.h
index 02720c2a..d8e72999 100755
--- a/stringbuf.h
+++ b/stringbuf.h
@@ -138,7 +138,8 @@ int rsCStrLocateInSzStr(cstr_t *pThis, uchar *sz);
int rsCStrStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz);
int rsCStrSzStrStartsWithCStr(cstr_t *pCS1, uchar *psz, size_t iLenSz);
int rsCStrSzStrMatchRegex(cstr_t *pCS1, uchar *psz);
-int rsCStrCanConvertToNumber(cstr_t *pStr);
+rsRetVal rsCStrConvertToNumber(cstr_t *pStr, number_t *pNumber);
+rsRetVal rsCStrConvertToBool(cstr_t *pStr, number_t *pBool);
/* now come inline-like functions */
#ifdef NDEBUG
diff --git a/var.c b/var.c
index 1f4ed1cb..6910986e 100644
--- a/var.c
+++ b/var.c
@@ -148,23 +148,50 @@ finalize_it:
* conversion request on the unchanged object is guaranteed to succeed.
* rgerhards, 2008-02-22
*/
-int canConvToNumber(var_t *pThis)
+rsRetVal
+ConvToNumber(var_t *pThis)
{
- int ret = 0;
-
- BEGINfunc
+ DEFiRet;
+ number_t n;
if(pThis->varType == VARTYPE_NUMBER) {
- ret = 1;
+ FINALIZE;
} else if(pThis->varType == VARTYPE_STR) {
- ret = rsCStrCanConvertToNumber(pThis->val.pStr); // TODO: implement the same method in str_t object, then call that */
+ CHKiRet(rsCStrConvertToNumber(pThis->val.pStr, &n));
+ pThis->val.num = n;
+ pThis->varType = VARTYPE_NUMBER;
}
- ENDfunc
- return ret;
+finalize_it:
+ RETiRet;
}
+/* convert the provided var to type string. This is always possible
+ * (except, of course, for things like out of memory...)
+ * TODO: finish implementation!!!!!!!!!
+ * rgerhards, 2008-02-24
+ */
+rsRetVal
+ConvToString(var_t *pThis)
+{
+ DEFiRet;
+
+ if(pThis->varType == VARTYPE_STR) {
+ FINALIZE;
+ } else if(pThis->varType == VARTYPE_NUMBER) {
+ //CHKiRet(rsCStrConvertToNumber(pThis->val.pStr, &n));
+ //pThis->val.num = n;
+ // TODO: ADD CODE!!!!
+ pThis->varType = VARTYPE_STR;
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+
/* This function is used to prepare two var_t objects for a common operation,
* e.g before they are added, multiplied or compared. The function looks at
* the data types of both operands and finds the best data type suitable for
@@ -217,11 +244,16 @@ ConvForOperation(var_t *pThis, var_t *pOther)
ABORT_FINALIZE(RS_RET_INVALID_VAR);
break;
case VARTYPE_STR:
- commonType = VARTYPE_STR;
+ /* two strings, we are all set */
break;
case VARTYPE_NUMBER:
/* check if we can convert pThis to a number, if so use number format. */
- commonType = canConvToNumber(pThis) ? VARTYPE_NUMBER : VARTYPE_STR;
+ iRet = ConvToNumber(pThis);
+ if(iRet != RS_RET_NOT_A_NUMBER) {
+ CHKiRet(ConvToString(pOther));
+ } else {
+ FINALIZE; /* OK or error */
+ }
break;
case VARTYPE_SYSLOGTIME:
ABORT_FINALIZE(RS_RET_NOT_IMPLEMENTED);
@@ -234,8 +266,12 @@ ConvForOperation(var_t *pThis, var_t *pOther)
ABORT_FINALIZE(RS_RET_INVALID_VAR);
break;
case VARTYPE_STR:
- /* check if we can convert pOther to a number, if so use number format. */
- commonType = canConvToNumber(pOther) ? VARTYPE_NUMBER : VARTYPE_STR;
+ iRet = ConvToNumber(pOther);
+ if(iRet != RS_RET_NOT_A_NUMBER) {
+ CHKiRet(ConvToString(pThis));
+ } else {
+ FINALIZE; /* OK or error */
+ }
break;
case VARTYPE_NUMBER:
commonType = VARTYPE_NUMBER;
diff --git a/var.h b/var.h
index 40b33037..77ccb8c6 100644
--- a/var.h
+++ b/var.h
@@ -32,8 +32,6 @@ typedef enum {
VARTYPE_SYSLOGTIME = 3
} varType_t;
-typedef int64 number_t; /* type to use for numbers */
-
/* the var object */
typedef struct var_s {
BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */