summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--conf.c136
-rw-r--r--ctok.c87
-rw-r--r--ctok.h44
-rw-r--r--doc/Makefile.am3
-rw-r--r--expr.c54
-rw-r--r--obj-types.h5
-rw-r--r--syslogd.c7
-rw-r--r--syslogd.h5
9 files changed, 253 insertions, 90 deletions
diff --git a/Makefile.am b/Makefile.am
index 3971d7e6..d6e50d8f 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -43,6 +43,8 @@ rsyslogd_SOURCES = \
msg.h \
expr.c \
expr.h \
+ ctok.c \
+ ctok.h \
conf.c \
conf.h \
omshell.c \
diff --git a/conf.c b/conf.c
index d3892b3b..c8fa9ab6 100644
--- a/conf.c
+++ b/conf.c
@@ -91,7 +91,7 @@ static rsRetVal doIncludeDirectory(uchar *pDirName)
size_t iFileNameLen;
uchar szFullFileName[MAXFNAME];
- assert(pDirName != NULL);
+ ASSERT(pDirName != NULL);
if((pDir = opendir((char*) pDirName)) == NULL) {
logerror("error opening include directory");
@@ -157,8 +157,8 @@ doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal)
size_t i = 0;
struct stat fileInfo;
- assert(pp != NULL);
- assert(*pp != NULL);
+ ASSERT(pp != NULL);
+ ASSERT(*pp != NULL);
if(getSubString(pp, (char*) pattern, sizeof(pattern) / sizeof(char), ' ') != 0) {
logerror("could not extract group name");
@@ -215,8 +215,8 @@ doModLoad(uchar **pp, __attribute__((unused)) void* pVal)
uchar *pModName;
void *pModHdlr, *pModInit;
- assert(pp != NULL);
- assert(*pp != NULL);
+ ASSERT(pp != NULL);
+ ASSERT(*pp != NULL);
if(getSubString(pp, (char*) szName, sizeof(szName) / sizeof(uchar), ' ') != 0) {
logerror("could not extract module name");
@@ -286,9 +286,9 @@ doNameLine(uchar **pp, void* pVal)
enum eDirective eDir;
char szName[128];
- assert(pp != NULL);
+ ASSERT(pp != NULL);
p = *pp;
- assert(p != NULL);
+ ASSERT(p != NULL);
eDir = (enum eDirective) pVal; /* this time, it actually is NOT a pointer! */
@@ -344,7 +344,7 @@ cfsysline(uchar *p)
uchar szCmd[64];
uchar errMsg[128]; /* for dynamic error messages */
- assert(p != NULL);
+ ASSERT(p != NULL);
errno = 0;
if(getSubString(&p, (char*) szCmd, sizeof(szCmd) / sizeof(uchar), ' ') != 0) {
logerror("Invalid $-configline - could not extract command - line ignored\n");
@@ -391,7 +391,7 @@ processConfFile(uchar *pConfFile)
uchar *p;
uchar cbuf[BUFSIZ];
uchar *cline;
- assert(pConfFile != NULL);
+ ASSERT(pConfFile != NULL);
if((cf = fopen((char*)pConfFile, "r")) == NULL) {
ABORT_FINALIZE(RS_RET_FOPEN_FAILURE);
@@ -478,9 +478,9 @@ rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEn
DEFiRet;
rsCStrObj *pStrB;
- assert(pp != NULL);
- assert(*pp != NULL);
- assert(pOMSR != NULL);
+ ASSERT(pp != NULL);
+ ASSERT(*pp != NULL);
+ ASSERT(pOMSR != NULL);
p =*pp;
/* a template must follow - search it and complain, if not found
@@ -541,7 +541,7 @@ rsRetVal cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pO
int i;
DEFiRet;
- assert(pOMSR != NULL);
+ ASSERT(pOMSR != NULL);
pName = pFileName;
i = 1; /* we start at 1 so that we reseve space for the '\0'! */
@@ -576,9 +576,9 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
uchar buf[MAXLINE];
uchar xbuf[200];
- assert(pline != NULL);
- assert(*pline != NULL);
- assert(f != NULL);
+ ASSERT(pline != NULL);
+ ASSERT(*pline != NULL);
+ ASSERT(f != NULL);
dbgprintf(" - traditional PRI filter\n");
errno = 0; /* keep strerror_r() stuff out of logerror messages */
@@ -723,8 +723,54 @@ dbgPrintAllDebugInfo();
}
-/*
- * Helper to cfline(). This function takes the filter part of a property
+/* 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 selector_t *f)
+{
+ DEFiRet;
+ ctok_t *ctok;
+
+ 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 */
+
+dbgprintf("calling expression parser, pp %p ('%s')\n", *pline, *pline);
+ 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(ctokConstruct(&ctok));
+ CHKiRet(ctokSetpp(ctok, *pline));
+ CHKiRet(ctokConstructFinalize(ctok));
+
+ /* now construct our expression */
+ CHKiRet(exprConstruct(&f->f_filterData.f_expr));
+ CHKiRet(exprConstructFinalize(f->f_filterData.f_expr));
+
+ /* ready to go... */
+ CHKiRet(exprParse(f->f_filterData.f_expr, ctok));
+
+ /* we are back, so we now need to restore things */
+ CHKiRet(ctokGetpp(ctok, pline));
+
+ CHKiRet(ctokDestruct(&ctok));
+dbgprintf("end expression parser, pp %p ('%s')\n", *pline, *pline);
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* 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.
* rgerhards 2005-09-15
@@ -736,9 +782,9 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register selector_t *f)
rsRetVal iRet;
int iOffset; /* for compare operations */
- assert(pline != NULL);
- assert(*pline != NULL);
- assert(f != NULL);
+ ASSERT(pline != NULL);
+ ASSERT(*pline != NULL);
+ ASSERT(f != NULL);
dbgprintf(" - property-based filter\n");
errno = 0; /* keep strerror_r() stuff out of logerror messages */
@@ -831,9 +877,9 @@ static rsRetVal cflineProcessHostSelector(uchar **pline)
{
rsRetVal iRet;
- assert(pline != NULL);
- assert(*pline != NULL);
- assert(**pline == '-' || **pline == '+');
+ ASSERT(pline != NULL);
+ ASSERT(*pline != NULL);
+ ASSERT(**pline == '-' || **pline == '+');
dbgprintf(" - host selector line\n");
@@ -882,9 +928,9 @@ static rsRetVal cflineProcessTagSelector(uchar **pline)
{
rsRetVal iRet;
- assert(pline != NULL);
- assert(*pline != NULL);
- assert(**pline == '!');
+ ASSERT(pline != NULL);
+ ASSERT(*pline != NULL);
+ ASSERT(**pline == '!');
dbgprintf(" - programname selector line\n");
@@ -925,32 +971,38 @@ static rsRetVal cflineDoFilter(uchar **pp, selector_t *f)
{
DEFiRet;
- assert(pp != NULL);
- assert(f != NULL);
+ ASSERT(pp != NULL);
+ ASSERT(f != NULL);
/* check which filter we need to pull... */
switch(**pp) {
case ':':
- iRet = cflineProcessPropFilter(pp, f);
+ CHKiRet(cflineProcessPropFilter(pp, f));
break;
+ case 'i': /* "if" filter? */
+ if(*(*pp+1) && (*(*pp+1) == 'f') && isspace(*(*pp+2))) {
+ CHKiRet(cflineProcessIfFilter(pp, f));
+ break;
+ }
+ /*FALLTHROUGH*/
default:
- iRet = cflineProcessTradPRIFilter(pp, f);
+ CHKiRet(cflineProcessTradPRIFilter(pp, f));
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(pDfltProgNameCmp != NULL)
- if((iRet = rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp)) != RS_RET_OK)
- return(iRet);
+ if(pDfltProgNameCmp != NULL) {
+ CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp));
+ }
if(eDfltHostnameCmpMode != HN_NO_COMP) {
f->eHostnameCmpMode = eDfltHostnameCmpMode;
- if((iRet = rsCStrConstructFromCStr(&(f->pCSHostnameComp), pDfltHostnameCmp)) != RS_RET_OK)
- return(iRet);
+ CHKiRet(rsCStrConstructFromCStr(&(f->pCSHostnameComp), pDfltHostnameCmp));
}
+finalize_it:
RETiRet;
}
@@ -966,8 +1018,8 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
action_t *pAction;
void *pModData;
- assert(p != NULL);
- assert(ppAction != NULL);
+ ASSERT(p != NULL);
+ ASSERT(ppAction != NULL);
/* loop through all modules and see if one picks up the line */
pMod = modGetNxtType(NULL, eMOD_OUT);
@@ -1006,6 +1058,7 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
/* Process a configuration file line in traditional "filter selector" format
+ * or one that builds upon this format.
*/
static rsRetVal cflineClassic(uchar *p, selector_t **pfCurr)
{
@@ -1013,7 +1066,7 @@ static rsRetVal cflineClassic(uchar *p, selector_t **pfCurr)
action_t *pAction;
selector_t *fCurr;
- assert(pfCurr != NULL);
+ ASSERT(pfCurr != NULL);
fCurr = *pfCurr;
@@ -1024,7 +1077,8 @@ static rsRetVal cflineClassic(uchar *p, selector_t **pfCurr)
++p; /* eat '&' */
skipWhiteSpace(&p); /* on to command */
} else {
- /* we are finished with the current selector. So we now need to check
+ /* we are finished with the current selector (on previous line).
+ * So we now need to check
* if it has any actions associated and, if so, link it to the linked
* list. If it has nothing associated with it, we can simply discard
* it. In any case, we create a fresh selector for our new filter.
@@ -1055,7 +1109,7 @@ cfline(uchar *line, selector_t **pfCurr)
{
DEFiRet;
- assert(line != NULL);
+ ASSERT(line != NULL);
dbgprintf("cfline: '%s'\n", line);
diff --git a/ctok.c b/ctok.c
new file mode 100644
index 00000000..917b3175
--- /dev/null
+++ b/ctok.c
@@ -0,0 +1,87 @@
+/* cfgtok.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 2008 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+
+#include "config.h"
+#include <stdlib.h>
+#include <assert.h>
+
+#include "rsyslog.h"
+#include "template.h"
+#include "ctok.h"
+
+/* static data */
+DEFobjStaticHelpers
+
+
+/* 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 *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)
+
+/* 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
+ */
+rsRetVal
+ctokGetpp(ctok_t *pThis, uchar **pp)
+{
+ DEFiRet;
+ ASSERT(pp != NULL);
+ *pp = pThis->pp;
+ RETiRet;
+}
+
+BEGINObjClassInit(ctok, 1) /* class, version */
+ OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, ctokConstructFinalize);
+ENDObjClassInit(ctok)
+
+/* vi:set ai:
+ */
diff --git a/ctok.h b/ctok.h
new file mode 100644
index 00000000..ea8fa164
--- /dev/null
+++ b/ctok.h
@@ -0,0 +1,44 @@
+/* The ctok object (implements a config file tokenizer).
+ *
+ * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of rsyslog.
+ *
+ * Rsyslog is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Rsyslog 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * A copy of the GPL can be found in the file "COPYING" in this distribution.
+ */
+#ifndef INCLUDED_CTOK_H
+#define INCLUDED_CTOK_H
+
+#include "obj.h"
+#include "stringbuf.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_t;
+
+
+/* prototypes */
+rsRetVal ctokConstruct(ctok_t **ppThis);
+rsRetVal ctokConstructFinalize(ctok_t __attribute__((unused)) *pThis);
+rsRetVal ctokDestruct(ctok_t **ppThis);
+rsRetVal ctokGetpp(ctok_t *pThis, uchar **pp);
+PROTOTYPEObjClassInit(ctok);
+PROTOTYPEpropSetMeth(ctok, pp, uchar*);
+
+#endif /* #ifndef INCLUDED_CTOK_H */
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 49a689c6..901f1202 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -64,6 +64,7 @@ html_files = \
rsconf1_repeatedmsgreduction.html \
rsconf1_resetconfigvariables.html \
rsconf1_umask.html \
- v3compatibility.html
+ v3compatibility.html \
+ src/classes.dia
EXTRA_DIST = $(html_files)
diff --git a/expr.c b/expr.c
index dfdf5fc7..88098325 100644
--- a/expr.c
+++ b/expr.c
@@ -38,6 +38,8 @@
DEFobjStaticHelpers
+/* ------------------------------ actual expr object functions ------------------------------ */
+
/* Standard-Constructor
*/
BEGINobjConstruct(expr) /* be sure to specify the object type also in END macro! */
@@ -68,7 +70,7 @@ ENDobjDestruct(expr)
/* evaluate an expression and store the result. pMsg is optional, but if
* it is not given, no message-based variables can be accessed. The expression
* must previously have been created.
- * rgerhards, 2008-02-09
+ * rgerhards, 2008-02-09 (a rainy tenerife return flight day ;))
*/
rsRetVal
exprEval(expr_t *pThis, msg_t *pMsg)
@@ -89,7 +91,7 @@ exprEval(expr_t *pThis, msg_t *pMsg)
* Also, it is assumed that most callers will hold their private expression. If it
* is not shared, the caller can count on the string to remain stable as long as it
* does not reevaluate the expression (via exprEval or other means) or destruct it.
- * rgerhards, 2008-02-09
+ * rgerhards, 2008-02-09 (a rainy tenerife return flight day ;))
*/
rsRetVal
exprGetStr(expr_t *pThis, rsCStrObj **ppStr)
@@ -103,54 +105,18 @@ exprGetStr(expr_t *pThis, rsCStrObj **ppStr)
}
-/* parse an expression from a string. The string MUST include the full expression. The
- * expression object is only created if there is no error during parsing.
- * The string is a standard C string. It must NOT contain anything else but the
- * expression. Most importantly, it must not contain any comments after the
- * expression.
- * rgerhards, 2008-02-09 (a rainy tenerife return flight day ;))
+/* parse an expression object based on a given tokenizer
+ * rgerhards, 2008-02-19
*/
rsRetVal
-exprParseStr(expr_t **ppThis, uchar *p)
+exprParse(expr_t *pThis, ctok_t *ctok)
{
DEFiRet;
- expr_t *pThis = NULL;
-
- ASSERT(ppThis != NULL);
- ASSERT(p != NULL);
-
- CHKiRet(exprConstruct(&pThis));
-
- CHKiRet(rsCStrConstruct(&pThis->cstrConst));
- /* so far, we are a dummy - we just pull the first string and
- * ignore the rest...
- */
- while(*p && *p != '"')
- ++p; /* find begin of string */
- if(*p == '"')
- ++p; /* eat it */
-
- /* we got it, now copy over everything up until the end of the string */
- while(*p && *p != '"') {
- CHKiRet(rsCStrAppendChar(pThis->cstrConst, *p));
- ++p;
- }
-
- /* we are done with it... */
- CHKiRet(rsCStrFinish(pThis->cstrConst));
-
- CHKiRet(exprConstructFinalize(&pThis));
-
- /* we are successfully done, so store the result */
- *ppThis = pThis;
-
-finalize_it:
- if(iRet != RS_RET_OK) {
- if(pThis != NULL)
- exprDestruct(pThis);
- }
+ ISOBJ_TYPE_assert(pThis, expr);
+ ISOBJ_TYPE_assert(ctok, ctok);
+RUNLOG_STR("expr parser being called");
RETiRet;
}
diff --git a/obj-types.h b/obj-types.h
index 68f565dd..e301b7bc 100644
--- a/obj-types.h
+++ b/obj-types.h
@@ -62,9 +62,10 @@ typedef enum { /* IDs of known object "types/classes" */
OBJwtp = 3,
OBJwti = 4,
OBJqueue = 5,
- OBJexpr = 6 /* remeber to UPDATE OBJ_NUM_IDS (below) if you add one! */
+ OBJctok = 6,
+ OBJexpr = 7 /* remeber to UPDATE OBJ_NUM_IDS (below) if you add one! */
} objID_t;
-#define OBJ_NUM_IDS 7
+#define OBJ_NUM_IDS 8
typedef enum { /* IDs of base methods supported by all objects - used for jump table, so
* they must start at zero and be incremented. -- rgerahrds, 2008-01-04
diff --git a/syslogd.c b/syslogd.c
index 21975777..d3ad9fbd 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -168,6 +168,7 @@
#include "wti.h"
#include "wtp.h"
#include "expr.h"
+#include "ctok.h"
#include "conf.h"
/* We define our own set of syslog defintions so that we
@@ -997,6 +998,9 @@ selectorDestruct(void *pVal)
rsCStrDestruct(pThis->f_filterData.prop.pCSPropName);
if(pThis->f_filterData.prop.pCSCompValue != NULL)
rsCStrDestruct(pThis->f_filterData.prop.pCSCompValue);
+ } else if(pThis->f_filter_type == FILTER_EXPR) {
+ if(pThis->f_filterData.f_expr != NULL)
+ exprDestruct(&pThis->f_filterData.f_expr);
}
llDestroy(&pThis->llActList);
@@ -3408,12 +3412,13 @@ static rsRetVal InitGlobalClasses(void)
{
DEFiRet;
- CHKiRet(objClassInit()); /* *THIS* *MUST* always be the first class initilizere called! */
+ CHKiRet(objClassInit()); /* *THIS* *MUST* always be the first class initilizer being called! */
CHKiRet(msgClassInit());
CHKiRet(strmClassInit());
CHKiRet(wtiClassInit());
CHKiRet(wtpClassInit());
CHKiRet(queueClassInit());
+ CHKiRet(ctokClassInit());
CHKiRet(exprClassInit());
finalize_it:
diff --git a/syslogd.h b/syslogd.h
index 7887dc2c..d2dd37fe 100644
--- a/syslogd.h
+++ b/syslogd.h
@@ -27,6 +27,7 @@
#include "template.h"
#include "action.h"
#include "linkedlist.h"
+#include "expr.h"
#ifdef USE_NETZIP
/* config param: minimum message size to try compression. The smaller
@@ -72,7 +73,8 @@ struct filed {
/* filter properties */
enum {
FILTER_PRI = 0, /* traditional PRI based filer */
- FILTER_PROP = 1 /* extended filter, property based */
+ FILTER_PROP = 1, /* extended filter, property based */
+ FILTER_EXPR = 2 /* extended filter, expression based */
} f_filter_type;
EHostnameCmpMode eHostnameCmpMode;
rsCStrObj *pCSHostnameComp; /* hostname to check */
@@ -91,6 +93,7 @@ struct filed {
rsCStrObj *pCSCompValue; /* value to "compare" against */
char isNegated; /* actually a boolean ;) */
} prop;
+ expr_t *f_expr; /* expression object */
} f_filterData;
linkedList_t llActList; /* list of configured actions */