summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dirty.h2
-rw-r--r--runtime/Makefile.am4
-rw-r--r--runtime/conf.c102
-rw-r--r--runtime/conf.h2
-rw-r--r--runtime/linkedlist.c2
-rw-r--r--runtime/obj-types.h5
-rw-r--r--runtime/obj.h2
-rw-r--r--runtime/rsyslog.c8
-rw-r--r--runtime/rsyslog.h19
-rw-r--r--runtime/rule.c431
-rw-r--r--runtime/rule.h74
-rw-r--r--runtime/ruleset.c369
-rw-r--r--runtime/ruleset.h56
-rw-r--r--runtime/stream.c3
-rwxr-xr-xtests/diskqueue-fsync.sh2
-rw-r--r--tests/ourtail.c2
-rw-r--r--tests/runtime-dummy.c4
-rwxr-xr-xtests/validation-run.sh7
-rw-r--r--tools/syslogd.c537
-rw-r--r--tools/syslogd.h56
20 files changed, 1093 insertions, 594 deletions
diff --git a/dirty.h b/dirty.h
index 6d585753..bab15485 100644
--- a/dirty.h
+++ b/dirty.h
@@ -33,6 +33,7 @@ rsRetVal parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len
int parseRFCSyslogMsg(msg_t *pMsg, int flags);
int parseLegacySyslogMsg(msg_t *pMsg, int flags);
rsRetVal diagGetMainMsgQSize(int *piSize); /* for imdiag */
+char* getFIOPName(unsigned iFIOP);
/* TODO: the following 2 need to go in conf obj interface... */
rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName);
@@ -56,6 +57,7 @@ extern int bReduceRepeatMsgs;
extern int bDropTrailingLF;
extern uchar cCCEscapeChar;
extern int bEscapeCCOnRcv;
+extern ruleset_t *pCurrRuleset;
#ifdef USE_NETZIP
/* config param: minimum message size to try compression. The smaller
* the message, the less likely is any compression gain. We check for
diff --git a/runtime/Makefile.am b/runtime/Makefile.am
index 81422d64..de0daac4 100644
--- a/runtime/Makefile.am
+++ b/runtime/Makefile.am
@@ -67,6 +67,10 @@ librsyslog_la_SOURCES = \
vmop.h \
queue.c \
queue.h \
+ ruleset.c \
+ ruleset.h \
+ rule.c \
+ rule.h \
cfsysline.c \
cfsysline.h \
\
diff --git a/runtime/conf.c b/runtime/conf.c
index 7cdcf5ec..e0ed3d6a 100644
--- a/runtime/conf.c
+++ b/runtime/conf.c
@@ -69,13 +69,15 @@
#include "expr.h"
#include "ctok.h"
#include "ctok_token.h"
+#include "rule.h"
+#include "ruleset.h"
#ifdef OS_SOLARIS
# define NAME_MAX MAXNAMELEN
#endif
/* forward definitions */
-static rsRetVal cfline(uchar *line, selector_t **pfCurr);
+static rsRetVal cfline(uchar *line, rule_t **pfCurr);
static rsRetVal processConfFile(uchar *pConfFile);
@@ -87,6 +89,8 @@ DEFobjCurrIf(ctok_token)
DEFobjCurrIf(module)
DEFobjCurrIf(errmsg)
DEFobjCurrIf(net)
+DEFobjCurrIf(rule)
+DEFobjCurrIf(ruleset)
static int iNbrActions; /* number of actions the running config has. Needs to be init on ReInitConf() */
@@ -395,7 +399,7 @@ processConfFile(uchar *pConfFile)
DEFiRet;
int iLnNbr = 0;
FILE *cf;
- selector_t *fCurr = NULL;
+ rule_t *pCurrRule = NULL;
uchar *p;
uchar cbuf[CFGLNSIZ];
uchar *cline;
@@ -429,7 +433,6 @@ processConfFile(uchar *pConfFile)
* TODO: review the code at whole - this is highly suspect (but will go away
* once we do the rest of RainerScript).
*/
- /* was: strcpy((char*)cline, (char*)p); */
for( i = 0 ; p[i] != '\0' ; ++i) {
cline[i] = p[i];
}
@@ -453,7 +456,7 @@ processConfFile(uchar *pConfFile)
/* we now have the complete line, and are positioned at the first non-whitespace
* character. So let's process it
*/
- if(cfline(cbuf, &fCurr) != RS_RET_OK) {
+ if(cfline(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
*/
@@ -467,16 +470,18 @@ processConfFile(uchar *pConfFile)
}
/* we probably have one selector left to be added - so let's do that now */
- CHKiRet(selectorAddList(fCurr));
+ if(pCurrRule != NULL) {
+ CHKiRet(ruleset.AddRule(pCurrRuleset, &pCurrRule));
+ }
/* close the configuration file */
- (void) fclose(cf);
+ fclose(cf);
finalize_it:
if(iRet != RS_RET_OK) {
char errStr[1024];
- if(fCurr != NULL)
- selectorDestruct(fCurr);
+ 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",
@@ -588,7 +593,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 selector_t *f)
+static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule)
{
uchar *p;
register uchar *q;
@@ -603,17 +608,17 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
ASSERT(pline != NULL);
ASSERT(*pline != NULL);
- ASSERT(f != NULL);
+ ISOBJ_TYPE_assert(pRule, rule);
dbgprintf(" - traditional PRI filter\n");
errno = 0; /* keep strerror_r() stuff out of logerror messages */
- f->f_filter_type = FILTER_PRI;
+ pRule->f_filter_type = FILTER_PRI;
/* Note: file structure is pre-initialized to zero because it was
* created with calloc()!
*/
for (i = 0; i <= LOG_NFACILITIES; i++) {
- f->f_filterData.f_pmask[i] = TABLE_NOPRI;
+ pRule->f_filterData.f_pmask[i] = TABLE_NOPRI;
}
/* scan through the list of selectors */
@@ -668,32 +673,32 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
for (i = 0; i <= LOG_NFACILITIES; i++) {
if ( pri == INTERNAL_NOPRI ) {
if ( ignorepri )
- f->f_filterData.f_pmask[i] = TABLE_ALLPRI;
+ pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI;
else
- f->f_filterData.f_pmask[i] = TABLE_NOPRI;
+ pRule->f_filterData.f_pmask[i] = TABLE_NOPRI;
}
else if ( singlpri ) {
if ( ignorepri )
- f->f_filterData.f_pmask[i] &= ~(1<<pri);
+ pRule->f_filterData.f_pmask[i] &= ~(1<<pri);
else
- f->f_filterData.f_pmask[i] |= (1<<pri);
+ pRule->f_filterData.f_pmask[i] |= (1<<pri);
}
else
{
if ( pri == TABLE_ALLPRI ) {
if ( ignorepri )
- f->f_filterData.f_pmask[i] = TABLE_NOPRI;
+ pRule->f_filterData.f_pmask[i] = TABLE_NOPRI;
else
- f->f_filterData.f_pmask[i] = TABLE_ALLPRI;
+ pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI;
}
else
{
if ( ignorepri )
for (i2= 0; i2 <= pri; ++i2)
- f->f_filterData.f_pmask[i] &= ~(1<<i2);
+ pRule->f_filterData.f_pmask[i] &= ~(1<<i2);
else
for (i2= 0; i2 <= pri; ++i2)
- f->f_filterData.f_pmask[i] |= (1<<i2);
+ pRule->f_filterData.f_pmask[i] |= (1<<i2);
}
}
}
@@ -708,27 +713,27 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
if ( pri == INTERNAL_NOPRI ) {
if ( ignorepri )
- f->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI;
+ pRule->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI;
else
- f->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI;
+ pRule->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI;
} else if ( singlpri ) {
if ( ignorepri )
- f->f_filterData.f_pmask[i >> 3] &= ~(1<<pri);
+ pRule->f_filterData.f_pmask[i >> 3] &= ~(1<<pri);
else
- f->f_filterData.f_pmask[i >> 3] |= (1<<pri);
+ pRule->f_filterData.f_pmask[i >> 3] |= (1<<pri);
} else {
if ( pri == TABLE_ALLPRI ) {
if ( ignorepri )
- f->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI;
+ pRule->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI;
else
- f->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI;
+ pRule->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI;
} else {
if ( ignorepri )
for (i2= 0; i2 <= pri; ++i2)
- f->f_filterData.f_pmask[i >> 3] &= ~(1<<i2);
+ pRule->f_filterData.f_pmask[i >> 3] &= ~(1<<i2);
else
for (i2= 0; i2 <= pri; ++i2)
- f->f_filterData.f_pmask[i >> 3] |= (1<<i2);
+ pRule->f_filterData.f_pmask[i >> 3] |= (1<<i2);
}
}
}
@@ -754,7 +759,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
* A pointer to that beginnig is passed back to the caller.
* rgerhards 2008-01-19
*/
-static rsRetVal cflineProcessIfFilter(uchar **pline, register selector_t *f)
+static rsRetVal cflineProcessIfFilter(uchar **pline, register rule_t *f)
{
DEFiRet;
ctok_t *tok;
@@ -767,7 +772,6 @@ static rsRetVal cflineProcessIfFilter(uchar **pline, register selector_t *f)
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. */
@@ -823,7 +827,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 selector_t *f)
+static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
{
rsParsObj *pPars;
cstr_t *pCSCompOp;
@@ -1014,10 +1018,10 @@ static rsRetVal cflineProcessTagSelector(uchar **pline)
/* read the filter part of a configuration line and store the filter
- * in the supplied selector_t
+ * in the supplied rule_t
* rgerhards, 2007-08-01
*/
-static rsRetVal cflineDoFilter(uchar **pp, selector_t *f)
+static rsRetVal cflineDoFilter(uchar **pp, rule_t *f)
{
DEFiRet;
@@ -1110,17 +1114,15 @@ 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.
+ * 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
+ * of the master config file!).
*/
-static rsRetVal cflineClassic(uchar *p, selector_t **pfCurr)
+static rsRetVal
+cflineClassic(uchar *p, rule_t **ppRule)
{
DEFiRet;
action_t *pAction;
- selector_t *fCurr;
-
- ASSERT(pfCurr != NULL);
-
- fCurr = *pfCurr;
/* lines starting with '&' have no new filters and just add
* new actions to the currently processed selector.
@@ -1138,16 +1140,18 @@ static rsRetVal cflineClassic(uchar *p, selector_t **pfCurr)
* selector is NULL, which means we do not need to care about it at
* all. -- rgerhards, 2007-08-01
*/
- CHKiRet(selectorAddList(fCurr));
- CHKiRet(selectorConstruct(&fCurr)); /* create "fresh" selector */
- CHKiRet(cflineDoFilter(&p, fCurr)); /* pull filters */
+ if(*ppRule != NULL) {
+ CHKiRet(ruleset.AddRule(pCurrRuleset, ppRule));
+ }
+ CHKiRet(rule.Construct(ppRule)); /* create "fresh" selector */
+ CHKiRet(rule.ConstructFinalize(*ppRule)); /* create "fresh" selector */
+ CHKiRet(cflineDoFilter(&p, *ppRule)); /* pull filters */
}
CHKiRet(cflineDoAction(&p, &pAction));
- CHKiRet(llAppend(&fCurr->llActList, NULL, (void*) pAction));
+ CHKiRet(llAppend(&(*ppRule)->llActList, NULL, (void*) pAction));
finalize_it:
- *pfCurr = fCurr;
RETiRet;
}
@@ -1157,11 +1161,12 @@ finalize_it:
* rgerhards, 2007-08-01
*/
static rsRetVal
-cfline(uchar *line, selector_t **pfCurr)
+cfline(uchar *line, rule_t **pfCurr)
{
DEFiRet;
ASSERT(line != NULL);
+if(*pfCurr != NULL){ ISOBJ_TYPE_assert(*pfCurr, rule);}
dbgprintf("cfline: '%s'\n", line);
@@ -1180,6 +1185,7 @@ cfline(uchar *line, selector_t **pfCurr)
break;
default:
iRet = cflineClassic(line, pfCurr);
+ISOBJ_TYPE_assert(*pfCurr, rule);
break;
}
@@ -1254,6 +1260,8 @@ CODESTARTObjClassExit(conf)
objRelease(module, CORE_COMPONENT);
objRelease(errmsg, CORE_COMPONENT);
objRelease(net, LM_NET_FILENAME);
+ objRelease(rule, CORE_COMPONENT);
+ objRelease(ruleset, CORE_COMPONENT);
ENDObjClassExit(conf)
@@ -1269,6 +1277,8 @@ BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANG
CHKiRet(objUse(module, CORE_COMPONENT));
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(net, LM_NET_FILENAME)); /* TODO: make this dependcy go away! */
+ CHKiRet(objUse(rule, CORE_COMPONENT));
+ CHKiRet(objUse(ruleset, CORE_COMPONENT));
ENDObjClassInit(conf)
/* vi:set ai:
diff --git a/runtime/conf.h b/runtime/conf.h
index 2494d4dc..f29de1ba 100644
--- a/runtime/conf.h
+++ b/runtime/conf.h
@@ -35,7 +35,7 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */
rsRetVal (*cfsysline)(uchar *p);
rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal);
rsRetVal (*doIncludeLine)(uchar **pp, __attribute__((unused)) void* pVal);
- rsRetVal (*cfline)(uchar *line, selector_t **pfCurr);
+ rsRetVal (*cfline)(uchar *line, rule_t **pfCurr);
rsRetVal (*processConfFile)(uchar *pConfFile);
rsRetVal (*ReInitConf)(void);
rsRetVal (*GetNbrActActions)(int *);
diff --git a/runtime/linkedlist.c b/runtime/linkedlist.c
index 8f842e43..cc095f6e 100644
--- a/runtime/linkedlist.c
+++ b/runtime/linkedlist.c
@@ -398,7 +398,7 @@ rsRetVal llExecFunc(linkedList_t *pThis, rsRetVal (*pFunc)(void*, void*), void*
*/
llCookie = llCookiePrev;
} else if (iRet != RS_RET_OK) {
- goto finalize_it;
+ FINALIZE;
}
llCookiePrev = llCookie;
}
diff --git a/runtime/obj-types.h b/runtime/obj-types.h
index 914c2f2c..23f74590 100644
--- a/runtime/obj-types.h
+++ b/runtime/obj-types.h
@@ -105,12 +105,13 @@ struct obj_s { /* the dummy struct that each derived class can be casted to */
# define ISOBJ_TYPE_assert(pObj, objType) \
do { \
ASSERT(pObj != NULL); \
- ASSERT((unsigned) ((obj_t*) (pObj))->iObjCooCKiE == (unsigned) 0xBADEFEE); \
if(strcmp((char*)(((obj_t*)pObj)->pObjInfo->pszID), #objType)) { \
dbgprintf("%s:%d ISOBJ assert failure: invalid object type, expected '%s' " \
- "actual '%s'\n", __FILE__, __LINE__, #objType, (((obj_t*)pObj)->pObjInfo->pszID)); \
+ "actual '%s', cookie: %X\n", __FILE__, __LINE__, #objType, \
+ (((obj_t*)pObj)->pObjInfo->pszID), ((obj_t*)(pObj))->iObjCooCKiE); \
assert(0); /* trigger assertion, messge we already have */ \
} \
+ ASSERT((unsigned) ((obj_t*)(pObj))->iObjCooCKiE == (unsigned) 0xBADEFEE); \
} while(0)
#else /* non-debug mode, no checks but much faster */
# define BEGINobjInstance obj_t objData
diff --git a/runtime/obj.h b/runtime/obj.h
index dc04203b..3973a16e 100644
--- a/runtime/obj.h
+++ b/runtime/obj.h
@@ -68,7 +68,7 @@
#define objSerializePTR(strm, propName, propType) \
CHKiRet(obj.SerializeProp(strm, (uchar*) #propName, PROPTYPE_##propType, (void*) pThis->propName));
#define DEFobjStaticHelpers \
- static objInfo_t *pObjInfoOBJ = NULL; \
+ static objInfo_t __attribute__((unused)) *pObjInfoOBJ = NULL; \
DEFobjCurrIf(obj)
diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c
index 81550f12..3496bb0d 100644
--- a/runtime/rsyslog.c
+++ b/runtime/rsyslog.c
@@ -77,6 +77,8 @@
#include "conf.h"
#include "glbl.h"
#include "errmsg.h"
+#include "rule.h"
+#include "ruleset.h"
/* forward definitions */
static rsRetVal dfltErrLogger(int, uchar *errMsg);
@@ -172,6 +174,10 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF)
CHKiRet(ctokClassInit(NULL));
if(ppErrObj != NULL) *ppErrObj = "expr";
CHKiRet(exprClassInit(NULL));
+ if(ppErrObj != NULL) *ppErrObj = "rule";
+ CHKiRet(ruleClassInit(NULL));
+ if(ppErrObj != NULL) *ppErrObj = "ruleset";
+ CHKiRet(rulesetClassInit(NULL));
if(ppErrObj != NULL) *ppErrObj = "conf";
CHKiRet(confClassInit(NULL));
@@ -204,6 +210,8 @@ rsrtExit(void)
/* do actual de-init only if we are the last runtime user */
confClassExit();
glblClassExit();
+ rulesetClassExit();
+ ruleClassExit();
objClassExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */
}
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index f93592b7..b587554e 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -62,7 +62,9 @@
typedef unsigned char uchar;/* get rid of the unhandy "unsigned char" */
typedef struct thrdInfo thrdInfo_t;
typedef struct obj_s obj_t;
-typedef struct filed selector_t;/* TODO: this so far resides in syslogd.c, think about modularization */
+typedef struct ruleset_s ruleset_t;
+typedef struct rule_s rule_t;
+//typedef struct filed selector_t;/* TODO: this so far resides in syslogd.c, think about modularization */
typedef struct NetAddr netAddr_t;
typedef struct netstrms_s netstrms_t;
typedef struct netstrm_s netstrm_t;
@@ -112,6 +114,16 @@ typedef enum {
eFLOWCTL_FULL_DELAY = 2 /**< delay possible for extended period of time */
} flowControl_t;
+/* filter operations */
+typedef enum {
+ FIOP_NOP = 0, /* do not use - No Operation */
+ FIOP_CONTAINS = 1, /* contains string? */
+ FIOP_ISEQUAL = 2, /* is (exactly) equal? */
+ FIOP_STARTSWITH = 3, /* starts with a string? */
+ FIOP_REGEX = 4, /* matches a (BRE) regular expression? */
+ FIOP_EREREGEX = 5 /* matches a ERE regular expression? */
+} fiop_t;
+
/* The error codes below are orginally "borrowed" from
* liblogging. As such, we reserve values up to -2999
@@ -367,6 +379,11 @@ typedef enum rsObjectID rsObjID;
# define O_CLOEXEC 0
#endif
+/* some constants */
+// TODO: do we really need them - if not, delete -- rgerhards, 2009-06-10
+#define IGNORE_ERROR_CODES 1
+#define ABORT_ON_ERROR 0
+
/* The following prototype is convenient, even though it may not be the 100% correct place.. -- rgerhards 2008-01-07 */
void dbgprintf(char *, ...) __attribute__((format(printf, 1, 2)));
diff --git a/runtime/rule.c b/runtime/rule.c
new file mode 100644
index 00000000..fa56dc3b
--- /dev/null
+++ b/runtime/rule.c
@@ -0,0 +1,431 @@
+/* rule.c - rsyslog's rule object
+ *
+ * See file comment in rule.c for the overall structure of rule processing.
+ *
+ * Module begun 2009-06-10 by Rainer Gerhards
+ *
+ * Copyright 2009 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "rsyslog.h"
+#include "obj.h"
+#include "action.h"
+#include "rule.h"
+#include "errmsg.h"
+#include "vm.h"
+#include "var.h"
+#include "srUtils.h"
+#include "dirty.h" /* for getFIOPName */
+
+/* static data */
+DEFobjStaticHelpers
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(expr)
+DEFobjCurrIf(var)
+DEFobjCurrIf(vm)
+
+/* iterate over all actions, this is often needed, for example when HUP processing
+ * must be done or a shutdown is pending.
+ */
+static rsRetVal
+iterateAllActions(rule_t *pThis, rsRetVal (*pFunc)(void*, void*), void* pParam)
+{
+ return llExecFunc(&pThis->llActList, pFunc, pParam);
+}
+
+
+
+/* helper to processMsg(), used to call the configured actions. It is
+ * executed from within llExecFunc() of the action list.
+ * rgerhards, 2007-08-02
+ */
+typedef struct processMsgDoActions_s {
+ int bPrevWasSuspended; /* was the previous action suspended? */
+ msg_t *pMsg;
+} processMsgDoActions_t;
+DEFFUNC_llExecFunc(processMsgDoActions)
+{
+ DEFiRet;
+ rsRetVal iRetMod; /* return value of module - we do not always pass that back */
+ action_t *pAction = (action_t*) pData;
+ processMsgDoActions_t *pDoActData = (processMsgDoActions_t*) pParam;
+
+ assert(pAction != NULL);
+
+ if((pAction->bExecWhenPrevSusp == 1) && (pDoActData->bPrevWasSuspended == 0)) {
+ dbgprintf("not calling action because the previous one is not suspended\n");
+ ABORT_FINALIZE(RS_RET_OK);
+ }
+
+ iRetMod = actionCallAction(pAction, pDoActData->pMsg);
+ if(iRetMod == RS_RET_DISCARDMSG) {
+ ABORT_FINALIZE(RS_RET_DISCARDMSG);
+ } else if(iRetMod == RS_RET_SUSPENDED) {
+ /* indicate suspension for next module to be called */
+ pDoActData->bPrevWasSuspended = 1;
+ } else {
+ pDoActData->bPrevWasSuspended = 0;
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* This functions looks at the given message and checks if it matches the
+ * provided filter condition.
+ */
+static rsRetVal
+shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, int *bProcessMsg)
+{
+ DEFiRet;
+ unsigned short pbMustBeFreed;
+ char *pszPropVal;
+ int bRet = 0;
+ vm_t *pVM = NULL;
+ var_t *pResult = NULL;
+
+ ISOBJ_TYPE_assert(pRule, rule);
+ assert(pMsg != NULL);
+
+ /* we first have a look at the global, BSD-style block filters (for tag
+ * and host). Only if they match, we evaluate the actual filter.
+ * rgerhards, 2005-10-18
+ */
+ if(pRule->eHostnameCmpMode == HN_NO_COMP) {
+ /* EMPTY BY INTENSION - we check this value first, because
+ * it is the one most often used, so this saves us time!
+ */
+ } else if(pRule->eHostnameCmpMode == HN_COMP_MATCH) {
+ if(rsCStrSzStrCmp(pRule->pCSHostnameComp, (uchar*) getHOSTNAME(pMsg), getHOSTNAMELen(pMsg))) {
+ /* not equal, so we are already done... */
+ dbgprintf("hostname filter '+%s' does not match '%s'\n",
+ rsCStrGetSzStrNoNULL(pRule->pCSHostnameComp), getHOSTNAME(pMsg));
+ FINALIZE;
+ }
+ } else { /* must be -hostname */
+ if(!rsCStrSzStrCmp(pRule->pCSHostnameComp, (uchar*) getHOSTNAME(pMsg), getHOSTNAMELen(pMsg))) {
+ /* not equal, so we are already done... */
+ dbgprintf("hostname filter '-%s' does not match '%s'\n",
+ rsCStrGetSzStrNoNULL(pRule->pCSHostnameComp), getHOSTNAME(pMsg));
+ FINALIZE;
+ }
+ }
+
+ if(pRule->pCSProgNameComp != NULL) {
+ int bInv = 0, bEqv = 0, offset = 0;
+ if(*(rsCStrGetSzStrNoNULL(pRule->pCSProgNameComp)) == '-') {
+ if(*(rsCStrGetSzStrNoNULL(pRule->pCSProgNameComp) + 1) == '-')
+ offset = 1;
+ else {
+ bInv = 1;
+ offset = 1;
+ }
+ }
+ if(!rsCStrOffsetSzStrCmp(pRule->pCSProgNameComp, offset, (uchar*) getProgramName(pMsg), getProgramNameLen(pMsg)))
+ bEqv = 1;
+
+ if((!bEqv && !bInv) || (bEqv && bInv)) {
+ /* not equal or inverted selection, so we are already done... */
+ dbgprintf("programname filter '%s' does not match '%s'\n",
+ rsCStrGetSzStrNoNULL(pRule->pCSProgNameComp), getProgramName(pMsg));
+ FINALIZE;
+ }
+ }
+
+ /* done with the BSD-style block filters */
+
+ if(pRule->f_filter_type == FILTER_PRI) {
+ /* skip messages that are incorrect priority */
+ if ( (pRule->f_filterData.f_pmask[pMsg->iFacility] == TABLE_NOPRI) || \
+ ((pRule->f_filterData.f_pmask[pMsg->iFacility] & (1<<pMsg->iSeverity)) == 0) )
+ bRet = 0;
+ else
+ bRet = 1;
+ } else if(pRule->f_filter_type == FILTER_EXPR) {
+ 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 expression evaluation: %lld\n", pResult->val.num);
+ /* VM is destructed on function exit */
+ bRet = (pResult->val.num) ? 1 : 0;
+ } else {
+ assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */
+ pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.pCSPropName, &pbMustBeFreed);
+
+ /* Now do the compares (short list currently ;)) */
+ switch(pRule->f_filterData.prop.operation ) {
+ case FIOP_CONTAINS:
+ if(rsCStrLocateInSzStr(pRule->f_filterData.prop.pCSCompValue, (uchar*) pszPropVal) != -1)
+ bRet = 1;
+ break;
+ case FIOP_ISEQUAL:
+ if(rsCStrSzStrCmp(pRule->f_filterData.prop.pCSCompValue,
+ (uchar*) pszPropVal, strlen(pszPropVal)) == 0)
+ bRet = 1; /* process message! */
+ break;
+ case FIOP_STARTSWITH:
+ if(rsCStrSzStrStartsWithCStr(pRule->f_filterData.prop.pCSCompValue,
+ (uchar*) pszPropVal, strlen(pszPropVal)) == 0)
+ bRet = 1; /* process message! */
+ break;
+ case FIOP_REGEX:
+ if(rsCStrSzStrMatchRegex(pRule->f_filterData.prop.pCSCompValue,
+ (unsigned char*) pszPropVal, 0, &pRule->f_filterData.prop.regex_cache) == RS_RET_OK)
+ bRet = 1;
+ break;
+ case FIOP_EREREGEX:
+ if(rsCStrSzStrMatchRegex(pRule->f_filterData.prop.pCSCompValue,
+ (unsigned char*) pszPropVal, 1, &pRule->f_filterData.prop.regex_cache) == RS_RET_OK)
+ bRet = 1;
+ break;
+ default:
+ /* here, it handles NOP (for performance reasons) */
+ assert(pRule->f_filterData.prop.operation == FIOP_NOP);
+ bRet = 1; /* as good as any other default ;) */
+ break;
+ }
+
+ /* now check if the value must be negated */
+ if(pRule->f_filterData.prop.isNegated)
+ bRet = (bRet == 1) ? 0 : 1;
+
+ if(Debug) {
+ dbgprintf("Filter: check for property '%s' (value '%s') ",
+ rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSPropName),
+ pszPropVal);
+ if(pRule->f_filterData.prop.isNegated)
+ dbgprintf("NOT ");
+ dbgprintf("%s '%s': %s\n",
+ getFIOPName(pRule->f_filterData.prop.operation),
+ rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSCompValue),
+ bRet ? "TRUE" : "FALSE");
+ }
+
+ /* cleanup */
+ if(pbMustBeFreed)
+ free(pszPropVal);
+ }
+
+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);
+
+ *bProcessMsg = bRet;
+ RETiRet;
+}
+
+
+
+/* Process (consume) a received message. Calls the actions configured.
+ * rgerhards, 2005-10-13
+ */
+static rsRetVal
+processMsg(rule_t *pThis, msg_t *pMsg)
+{
+ int bProcessMsg;
+ processMsgDoActions_t DoActData;
+ DEFiRet;
+
+ ISOBJ_TYPE_assert(pThis, rule);
+ assert(pMsg != NULL);
+
+ /* first check the filters... */
+ CHKiRet(shouldProcessThisMessage(pThis, pMsg, &bProcessMsg));
+ if(bProcessMsg) {
+ DoActData.pMsg = pMsg;
+ DoActData.bPrevWasSuspended = 0;
+ CHKiRet(llExecFunc(&pThis->llActList, processMsgDoActions, (void*)&DoActData));
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* Standard-Constructor
+ */
+BEGINobjConstruct(rule) /* be sure to specify the object type also in END macro! */
+ENDobjConstruct(rule)
+
+
+/* ConstructionFinalizer
+ * rgerhards, 2008-01-09
+ */
+static rsRetVal
+ruleConstructFinalize(rule_t *pThis)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, rule);
+
+ /* note: actionDestruct is from action.c API! */
+ CHKiRet(llInit(&pThis->llActList, actionDestruct, NULL, NULL));
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* destructor for the rule object */
+BEGINobjDestruct(rule) /* be sure to specify the object type also in END and CODESTART macros! */
+CODESTARTobjDestruct(rule)
+ if(pThis->pCSHostnameComp != NULL)
+ rsCStrDestruct(&pThis->pCSHostnameComp);
+ if(pThis->pCSProgNameComp != NULL)
+ rsCStrDestruct(&pThis->pCSProgNameComp);
+
+ if(pThis->f_filter_type == FILTER_PROP) {
+ if(pThis->f_filterData.prop.pCSPropName != NULL)
+ rsCStrDestruct(&pThis->f_filterData.prop.pCSPropName);
+ if(pThis->f_filterData.prop.pCSCompValue != NULL)
+ rsCStrDestruct(&pThis->f_filterData.prop.pCSCompValue);
+ if(pThis->f_filterData.prop.regex_cache != NULL)
+ rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache);
+ } else if(pThis->f_filter_type == FILTER_EXPR) {
+ if(pThis->f_filterData.f_expr != NULL)
+ expr.Destruct(&pThis->f_filterData.f_expr);
+ }
+
+ llDestroy(&pThis->llActList);
+ free(pThis);
+
+ return RS_RET_OK;
+ENDobjDestruct(rule)
+
+
+/* helper to DebugPrint, to print out all actions via
+ * the llExecFunc() facility.
+ */
+DEFFUNC_llExecFunc(dbgPrintInitInfoAction)
+{
+ DEFiRet;
+ iRet = actionDbgPrint((action_t*) pData);
+ dbgprintf("\n");
+ RETiRet;
+}
+
+
+/* debugprint for the rule object */
+BEGINobjDebugPrint(rule) /* be sure to specify the object type also in END and CODESTART macros! */
+ int i;
+CODESTARTobjDebugPrint(rule)
+ dbgoprint((obj_t*) pThis, "rsyslog rule:\n");
+ if(pThis->pCSProgNameComp != NULL)
+ dbgprintf("tag: '%s'\n", rsCStrGetSzStrNoNULL(pThis->pCSProgNameComp));
+ if(pThis->eHostnameCmpMode != HN_NO_COMP)
+ dbgprintf("hostname: %s '%s'\n",
+ pThis->eHostnameCmpMode == HN_COMP_MATCH ?
+ "only" : "allbut",
+ rsCStrGetSzStrNoNULL(pThis->pCSHostnameComp));
+ if(pThis->f_filter_type == FILTER_PRI) {
+ for (i = 0; i <= LOG_NFACILITIES; i++)
+ if (pThis->f_filterData.f_pmask[i] == TABLE_NOPRI)
+ dbgprintf(" X ");
+ else
+ dbgprintf("%2X ", pThis->f_filterData.f_pmask[i]);
+ } else if(pThis->f_filter_type == FILTER_EXPR) {
+ dbgprintf("EXPRESSION-BASED Filter: can currently not be displayed");
+ } else {
+ dbgprintf("PROPERTY-BASED Filter:\n");
+ dbgprintf("\tProperty.: '%s'\n",
+ rsCStrGetSzStrNoNULL(pThis->f_filterData.prop.pCSPropName));
+ dbgprintf("\tOperation: ");
+ if(pThis->f_filterData.prop.isNegated)
+ dbgprintf("NOT ");
+ dbgprintf("'%s'\n", getFIOPName(pThis->f_filterData.prop.operation));
+ dbgprintf("\tValue....: '%s'\n",
+ rsCStrGetSzStrNoNULL(pThis->f_filterData.prop.pCSCompValue));
+ dbgprintf("\tAction...: ");
+ }
+
+ dbgprintf("\nActions:\n");
+ llExecFunc(&pThis->llActList, dbgPrintInitInfoAction, NULL); /* actions */
+
+ dbgprintf("\n");
+ENDobjDebugPrint(rule)
+
+
+/* queryInterface function
+ * rgerhards, 2008-02-21
+ */
+BEGINobjQueryInterface(rule)
+CODESTARTobjQueryInterface(rule)
+ if(pIf->ifVersion != ruleCURR_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 = ruleConstruct;
+ pIf->ConstructFinalize = ruleConstructFinalize;
+ pIf->Destruct = ruleDestruct;
+ pIf->DebugPrint = ruleDebugPrint;
+
+ pIf->IterateAllActions = iterateAllActions;
+ pIf->ProcessMsg = processMsg;
+finalize_it:
+ENDobjQueryInterface(rule)
+
+
+/* Exit the rule class.
+ * rgerhards, 2009-04-06
+ */
+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)
+
+
+/* Initialize the rule class. Must be called as the very first method
+ * before anything else is called inside this class.
+ * rgerhards, 2008-02-19
+ */
+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);
+ OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, ruleConstructFinalize);
+ENDObjClassInit(rule)
+
+/* vi:set ai:
+ */
diff --git a/runtime/rule.h b/runtime/rule.h
new file mode 100644
index 00000000..96be9e30
--- /dev/null
+++ b/runtime/rule.h
@@ -0,0 +1,74 @@
+/* The rule object.
+ *
+ * This implements rules within rsyslog.
+ *
+ * Copyright 2009 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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_RULE_H
+#define INCLUDED_RULE_H
+
+#include "linkedlist.h"
+#include "regexp.h"
+#include "expr.h"
+
+/* the rule object */
+struct rule_s {
+ BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
+ /* filter properties */
+ enum {
+ FILTER_PRI = 0, /* traditional PRI based filer */
+ FILTER_PROP = 1, /* extended filter, property based */
+ FILTER_EXPR = 2 /* extended filter, expression based */
+ } f_filter_type;
+ EHostnameCmpMode eHostnameCmpMode;
+ cstr_t *pCSHostnameComp; /* hostname to check */
+ cstr_t *pCSProgNameComp; /* tag to check or NULL, if not to be checked */
+ union {
+ u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */
+ struct {
+ cstr_t *pCSPropName;
+ fiop_t operation;
+ regex_t *regex_cache; /* cache for compiled REs, if such are used */
+ cstr_t *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 */
+};
+
+/* interfaces */
+BEGINinterface(rule) /* name must also be changed in ENDinterface macro! */
+ INTERFACEObjDebugPrint(rule);
+ rsRetVal (*Construct)(rule_t **ppThis);
+ rsRetVal (*ConstructFinalize)(rule_t __attribute__((unused)) *pThis);
+ rsRetVal (*Destruct)(rule_t **ppThis);
+ rsRetVal (*IterateAllActions)(rule_t *pThis, rsRetVal (*pFunc)(void*, void*), void *pParam);
+ rsRetVal (*ProcessMsg)(rule_t *pThis, msg_t *pMsg);
+ENDinterface(rule)
+#define ruleCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+
+
+/* prototypes */
+PROTOTYPEObj(rule);
+
+#endif /* #ifndef INCLUDED_RULE_H */
diff --git a/runtime/ruleset.c b/runtime/ruleset.c
new file mode 100644
index 00000000..d135074f
--- /dev/null
+++ b/runtime/ruleset.c
@@ -0,0 +1,369 @@
+/* ruleset.c - rsyslog's ruleset object
+ *
+ * We have a two-way structure of linked lists: one global linked list
+ * (llAllRulesets) hold alls rule sets that we know. Included in each
+ * list is a list of rules (which contain a list of actions, but that's
+ * a different story).
+ *
+ * Usually, only a single rule set is executed. However, there exist some
+ * situations where all rules must be iterated over, for example on HUP. Thus,
+ * we also provide interfaces to do that.
+ *
+ * Module begun 2009-06-10 by Rainer Gerhards
+ *
+ * Copyright 2009 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <ctype.h>
+
+#include "rsyslog.h"
+#include "obj.h"
+#include "ruleset.h"
+#include "rule.h"
+#include "errmsg.h"
+#include "unicode-helper.h"
+
+static rsRetVal debugPrintAll(void); // TODO: remove!
+
+/* static data */
+DEFobjStaticHelpers
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(rule)
+
+linkedList_t llRulesets; /* this is NOT a pointer - no typo here ;) */
+
+/* ---------- linked-list key handling functions ---------- */
+
+/* destructor for linked list keys.
+ */
+static rsRetVal keyDestruct(void __attribute__((unused)) *pData)
+{
+ free(pData);
+ return RS_RET_OK;
+}
+
+
+/* ---------- END linked-list key handling functions ---------- */
+
+
+/* dirver to iterate over all of this ruleset actions */
+typedef struct iterateAllActions_s {
+ rsRetVal (*pFunc)(void*, void*);
+ void *pParam;
+} iterateAllActions_t;
+DEFFUNC_llExecFunc(doIterateRulesetActions)
+{
+ DEFiRet;
+ rule_t* pRule = (rule_t*) pData;
+ iterateAllActions_t *pMyParam = (iterateAllActions_t*) pParam;
+ iRet = rule.IterateAllActions(pRule, pMyParam->pFunc, pMyParam->pParam);
+ RETiRet;
+}
+/* iterate over all actions of THIS rule set.
+ */
+static rsRetVal
+iterateRulesetAllActions(ruleset_t *pThis, rsRetVal (*pFunc)(void*, void*), void* pParam)
+{
+ iterateAllActions_t params;
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, ruleset);
+ assert(pFunc != NULL);
+
+ params.pFunc = pFunc;
+ params.pParam = pParam;
+ CHKiRet(llExecFunc(&llRulesets, doIterateRulesetActions, &params));
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* dirver to iterate over all actions */
+DEFFUNC_llExecFunc(doIterateAllActions)
+{
+ DEFiRet;
+ ruleset_t* pThis = (ruleset_t*) pData;
+ iterateAllActions_t *pMyParam = (iterateAllActions_t*) pParam;
+ iRet = iterateRulesetAllActions(pThis, pMyParam->pFunc, pMyParam->pParam);
+ RETiRet;
+}
+/* iterate over ALL actions present in the WHOLE system.
+ * this is often needed, for example when HUP processing
+ * must be done or a shutdown is pending.
+ */
+static rsRetVal
+iterateAllActions(rsRetVal (*pFunc)(void*, void*), void* pParam)
+{
+ iterateAllActions_t params;
+ DEFiRet;
+ assert(pFunc != NULL);
+
+ params.pFunc = pFunc;
+ params.pParam = pParam;
+ CHKiRet(llExecFunc(&llRulesets, doIterateAllActions, &params));
+
+finalize_it:
+ RETiRet;
+}
+
+
+
+/* helper to processMsg(), used to call the configured actions. It is
+ * executed from within llExecFunc() of the action list.
+ * rgerhards, 2007-08-02
+ */
+DEFFUNC_llExecFunc(processMsgDoRules)
+{
+ ISOBJ_TYPE_assert(pData, rule);
+ return rule.ProcessMsg((rule_t*) pData, (msg_t*) pParam);
+}
+
+
+/* Process (consume) a received message. Calls the actions configured.
+ * rgerhards, 2005-10-13
+ */
+static rsRetVal
+processMsg(ruleset_t *pThis, msg_t *pMsg)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, ruleset);
+ assert(pMsg != NULL);
+
+ CHKiRet(llExecFunc(&pThis->llRules, processMsgDoRules, pMsg));
+
+finalize_it:
+ if(iRet == RS_RET_DISCARDMSG)
+ iRet = RS_RET_OK;
+
+ RETiRet;
+}
+
+/* Add a new rule to the end of the current rule set. We do a number
+ * of checks and ignore the rule if it does not pass them.
+ */
+static rsRetVal
+addRule(ruleset_t *pThis, rule_t **ppRule)
+{
+ int iActionCnt;
+ DEFiRet;
+
+ ISOBJ_TYPE_assert(pThis, ruleset);
+ ISOBJ_TYPE_assert(*ppRule, rule);
+
+ CHKiRet(llGetNumElts(&(*ppRule)->llActList, &iActionCnt));
+ if(iActionCnt == 0) {
+ errmsg.LogError(0, NO_ERRCODE, "warning: selector line without actions will be discarded");
+ rule.Destruct(ppRule);
+ } else {
+ CHKiRet(llAppend(&pThis->llRules, NULL, *ppRule));
+ dbgprintf("selector line successfully processed\n");
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* set name for ruleset */
+static rsRetVal setName(ruleset_t *pThis, uchar *pszName)
+{
+ DEFiRet;
+ free(pThis->pszName);
+ CHKmalloc(pThis->pszName = ustrdup(pszName));
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* destructor we need to destruct rules inside our linked list contents.
+ */
+static rsRetVal
+doRuleDestruct(void *pData)
+{
+ rule_t *pRule = (rule_t *) pData;
+ DEFiRet;
+ rule.Destruct(&pRule);
+ RETiRet;
+}
+
+
+/* Standard-Constructor
+ */
+BEGINobjConstruct(ruleset) /* be sure to specify the object type also in END macro! */
+ CHKiRet(llInit(&pThis->llRules, doRuleDestruct, NULL, NULL));
+finalize_it:
+ENDobjConstruct(ruleset)
+
+
+/* ConstructionFinalizer
+ * This also adds the rule set to the list of all known rulesets.
+ */
+static rsRetVal
+rulesetConstructFinalize(ruleset_t *pThis)
+{
+ uchar *keyName;
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, ruleset);
+
+ /* we must duplicate our name, as the key destructer would also
+ * free it, resulting in a double-free. It's also cleaner to have
+ * two separate copies.
+ */
+ CHKmalloc(keyName = ustrdup(pThis->pszName));
+ CHKiRet(llAppend(&llRulesets, keyName, pThis));
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* destructor for the ruleset object */
+BEGINobjDestruct(ruleset) /* be sure to specify the object type also in END and CODESTART macros! */
+CODESTARTobjDestruct(ruleset)
+ dbgprintf("destructing ruleset %p, name %p\n", pThis, pThis->pszName);
+ llDestroy(&pThis->llRules);
+ free(pThis->pszName);
+ENDobjDestruct(ruleset)
+
+/* this is a special destructor for the linkedList class. LinkedList does NOT
+ * provide a pointer to the pointer, but rather the raw pointer itself. So we
+ * must map this, otherwise the destructor will abort.
+ */
+static rsRetVal
+rulesetDestructForLinkedList(void *pData)
+{
+ ruleset_t *pThis = (ruleset_t*) pData;
+ return rulesetDestruct(&pThis);
+}
+
+
+/* destruct ALL rule sets that reside in the system. This must
+ * be callable before unloading this module as the module may
+ * not be unloaded before unload of the actions is required. This is
+ * kind of a left-over from previous logic and may be optimized one
+ * everything runs stable again. -- rgerhards, 2009-06-10
+ */
+static rsRetVal
+destructAllActions(void)
+{
+ DEFiRet;
+
+ CHKiRet(llDestroy(&llRulesets));
+ CHKiRet(llInit(&llRulesets, rulesetDestructForLinkedList, keyDestruct, strcasecmp));
+
+finalize_it:
+ RETiRet;
+}
+
+/* helper for debugPrint(), initiates rule printing */
+DEFFUNC_llExecFunc(doDebugPrintRule)
+{
+ return rule.DebugPrint((rule_t*) pData);
+}
+/* debugprint for the ruleset object */
+BEGINobjDebugPrint(ruleset) /* be sure to specify the object type also in END and CODESTART macros! */
+CODESTARTobjDebugPrint(ruleset)
+ dbgoprint((obj_t*) pThis, "rsyslog ruleset %s:\n", pThis->pszName);
+ llExecFunc(&pThis->llRules, doDebugPrintRule, NULL);
+ENDobjDebugPrint(ruleset)
+
+
+/* helper for debugPrintAll(), prints a single ruleset */
+DEFFUNC_llExecFunc(doDebugPrintAll)
+{
+ return rulesetDebugPrint((ruleset_t*) pData);
+}
+/* debug print all rulesets
+ */
+static rsRetVal
+debugPrintAll(void)
+{
+ DEFiRet;
+ dbgprintf("All Rulesets:\n");
+ llExecFunc(&llRulesets, doDebugPrintAll, NULL);
+ dbgprintf("End of Rulesets.\n");
+ RETiRet;
+}
+
+
+/* queryInterface function
+ * rgerhards, 2008-02-21
+ */
+BEGINobjQueryInterface(ruleset)
+CODESTARTobjQueryInterface(ruleset)
+ if(pIf->ifVersion != rulesetCURR_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 = rulesetConstruct;
+ pIf->ConstructFinalize = rulesetConstructFinalize;
+ pIf->Destruct = rulesetDestruct;
+ pIf->DebugPrint = rulesetDebugPrint;
+
+ pIf->IterateAllActions = iterateAllActions;
+ pIf->DestructAllActions = destructAllActions;
+ pIf->AddRule = addRule;
+ pIf->ProcessMsg = processMsg;
+ pIf->SetName = setName;
+ pIf->DebugPrintAll = debugPrintAll;
+finalize_it:
+ENDobjQueryInterface(ruleset)
+
+
+/* Exit the ruleset class.
+ * rgerhards, 2009-04-06
+ */
+BEGINObjClassExit(ruleset, OBJ_IS_CORE_MODULE) /* class, version */
+ llDestroy(&llRulesets);
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(rule, CORE_COMPONENT);
+ENDObjClassExit(ruleset)
+
+
+/* Initialize the ruleset class. Must be called as the very first method
+ * before anything else is called inside this class.
+ * rgerhards, 2008-02-19
+ */
+BEGINObjClassInit(ruleset, 1, OBJ_IS_CORE_MODULE) /* class, version */
+ /* request objects we use */
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(rule, CORE_COMPONENT));
+
+ /* set our own handlers */
+ OBJSetMethodHandler(objMethod_DEBUGPRINT, rulesetDebugPrint);
+ OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, rulesetConstructFinalize);
+
+ /* prepare global data */
+ CHKiRet(llInit(&llRulesets, rulesetDestructForLinkedList, keyDestruct, strcasecmp));
+ENDObjClassInit(ruleset)
+
+/* vi:set ai:
+ */
diff --git a/runtime/ruleset.h b/runtime/ruleset.h
new file mode 100644
index 00000000..b609e6b3
--- /dev/null
+++ b/runtime/ruleset.h
@@ -0,0 +1,56 @@
+/* The ruleset object.
+ *
+ * This implements rulesets within rsyslog.
+ *
+ * Copyright 2009 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 <http://www.gnu.org/licenses/>.
+ *
+ * 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_RULESET_H
+#define INCLUDED_RULESET_H
+
+#include "linkedlist.h"
+
+/* the ruleset object */
+struct ruleset_s {
+ BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
+ linkedList_t llRules; /* this is NOT a pointer - no typo here ;) */
+ uchar *pszName; /* name of our ruleset */
+};
+
+/* interfaces */
+BEGINinterface(ruleset) /* name must also be changed in ENDinterface macro! */
+ INTERFACEObjDebugPrint(ruleset);
+ rsRetVal (*DebugPrintAll)(void);
+ rsRetVal (*Construct)(ruleset_t **ppThis);
+ rsRetVal (*ConstructFinalize)(ruleset_t __attribute__((unused)) *pThis);
+ rsRetVal (*Destruct)(ruleset_t **ppThis);
+ rsRetVal (*IterateAllActions)(rsRetVal (*pFunc)(void*, void*), void* pParam);
+ rsRetVal (*DestructAllActions)(void);
+ rsRetVal (*AddRule)(ruleset_t *pThis, rule_t **ppRule);
+ rsRetVal (*ProcessMsg)(ruleset_t *pThis, msg_t *pMsg);
+ rsRetVal (*SetName)(ruleset_t *pThis, uchar *pszName);
+ENDinterface(ruleset)
+#define rulesetCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+
+
+/* prototypes */
+PROTOTYPEObj(ruleset);
+
+#endif /* #ifndef INCLUDED_RULESET_H */
diff --git a/runtime/stream.c b/runtime/stream.c
index 8e2f87dc..49d29e0e 100644
--- a/runtime/stream.c
+++ b/runtime/stream.c
@@ -650,7 +650,6 @@ doZipWrite(strm_t *pThis, uchar *pBuf, size_t lenBuf)
dbgprintf("error %d returned from zlib/deflateInit2()\n", zRet);
ABORT_FINALIZE(RS_RET_ZLIB_ERR);
}
-RUNLOG_STR("deflateInit2() done successfully\n");
/* now doing the compression */
zstrm.avail_in = lenBuf;
@@ -668,14 +667,12 @@ RUNLOG_STR("deflateInit2() done successfully\n");
} while (zstrm.avail_out == 0);
assert(zstrm.avail_in == 0); /* all input will be used */
-RUNLOG_STR("deflate() should be done successfully\n");
zRet = zlibw.DeflateEnd(&zstrm);
if(zRet != Z_OK) {
dbgprintf("error %d returned from zlib/deflateEnd()\n", zRet);
ABORT_FINALIZE(RS_RET_ZLIB_ERR);
}
-RUNLOG_STR("deflateEnd() done successfully\n");
finalize_it:
RETiRet;
diff --git a/tests/diskqueue-fsync.sh b/tests/diskqueue-fsync.sh
index f558b491..8d2cb709 100755
--- a/tests/diskqueue-fsync.sh
+++ b/tests/diskqueue-fsync.sh
@@ -5,6 +5,8 @@
# added 2009-06-09 by Rgerhards
# This file is part of the rsyslog project, released under GPLv3
# uncomment for debugging support:
+echo diskqueue-fsync test seems to have some issues
+exit 1
echo testing queue disk-only mode, fsync case
source $srcdir/diag.sh init
source $srcdir/diag.sh startup diskqueue-fsync.conf
diff --git a/tests/ourtail.c b/tests/ourtail.c
index 6781b5fe..4e8a6412 100644
--- a/tests/ourtail.c
+++ b/tests/ourtail.c
@@ -40,4 +40,6 @@ int main(int __attribute__((unused)) argc, char __attribute__((unused)) *argv[])
for( ; c != EOF ; c = getchar())
putchar(c);
+
+ return 0;
}
diff --git a/tests/runtime-dummy.c b/tests/runtime-dummy.c
index 9cddd913..38e6bba1 100644
--- a/tests/runtime-dummy.c
+++ b/tests/runtime-dummy.c
@@ -25,7 +25,9 @@
*
* A copy of the GPL can be found in the file "COPYING" in this distribution.
*/
+#include "config.h"
#include <stdlib.h>
+#include "rsyslog.h"
int bReduceRepeatMsgs = 0;
int repeatinterval = 30;
@@ -37,5 +39,7 @@ void cflineClassic(void) {};
void selectorAddList(void) {};
void selectorConstruct(void) {};
void selectorDestruct(void) {};
+void getFIOPName(void) {};
+ruleset_t *pCurrRuleset;
/* these are required by some dynamically loaded modules */
diff --git a/tests/validation-run.sh b/tests/validation-run.sh
index 10981290..2e922283 100755
--- a/tests/validation-run.sh
+++ b/tests/validation-run.sh
@@ -22,17 +22,18 @@
# A copy of the GPL can be found in the file "COPYING" in this distribution.
#set -x
echo "testing a failed configuration verification run"
-../tools/rsyslogd -u2 -c3 -N1 -f$srcdir/testsuites/invalid.conf
+../tools/rsyslogd -dn -u2 -c4 -N1 -f$srcdir/testsuites/invalid.conf -M../runtime/.libs:../.libs
if [ $? -ne 1 ]; then
exit 1
fi
echo testing a valid config verification run
-../tools/rsyslogd -u2 -c3 -N1 -f$srcdir/testsuites/valid.conf
+../tools/rsyslogd -u2 -c4 -N1 -f$srcdir/testsuites/valid.conf -M../runtime/.libs:../.libs
if [ $? -ne 0 ]; then
exit 1
fi
echo testing empty config file
-../tools/rsyslogd -u2 -c3 -N1 -f/dev/null
+../tools/rsyslogd -u2 -c4 -N1 -f/dev/null -M../runtime/.libs:../.libs
if [ $? -ne 1 ]; then
exit 1
fi
+echo SUCCESS: validation run tests
diff --git a/tools/syslogd.c b/tools/syslogd.c
index 19ece349..183c7760 100644
--- a/tools/syslogd.c
+++ b/tools/syslogd.c
@@ -132,11 +132,13 @@
#include "queue.h"
#include "stream.h"
#include "conf.h"
-#include "vm.h"
#include "errmsg.h"
#include "datetime.h"
#include "parser.h"
#include "unicode-helper.h"
+#include "ruleset.h"
+#include "rule.h"
+#include "vm.h"
/* definitions for objects we access */
DEFobjCurrIf(obj)
@@ -144,10 +146,10 @@ DEFobjCurrIf(glbl)
DEFobjCurrIf(datetime)
DEFobjCurrIf(conf)
DEFobjCurrIf(expr)
-DEFobjCurrIf(vm)
-DEFobjCurrIf(var)
DEFobjCurrIf(module)
DEFobjCurrIf(errmsg)
+DEFobjCurrIf(rule)
+DEFobjCurrIf(ruleset)
DEFobjCurrIf(net) /* TODO: make go away! */
@@ -246,7 +248,7 @@ int repeatinterval[2] = { 30, 60 }; /* # of secs before flush */
#define LIST_DELIMITER ':' /* delimiter between two hosts */
-struct filed *Files = NULL; /* read-only after init() (but beware of sigusr1!) */
+ruleset_t *pCurrRuleset; /* ruleset that is currently being processed */
static pid_t ppid; /* This is a quick and dirty hack used for spliting main/startup thread */
@@ -313,7 +315,8 @@ static int iMainMsgQueueDeqtWinToHr = 25; /* hour begin of time frame when que
/* support for simple textual representation of FIOP names
* rgerhards, 2005-09-27
*/
-static char* getFIOPName(unsigned iFIOP)
+char*
+getFIOPName(unsigned iFIOP)
{
char *pRet;
switch(iFIOP) {
@@ -396,7 +399,6 @@ static char **crunch_list(char *list);
static void reapchild();
static void debug_switch();
static void sighup_handler();
-static void freeSelectors(void);
static void processImInternal(void);
@@ -431,67 +433,6 @@ diagGetMainMsgQSize(int *piSize)
/* ------------------------------ end support functions for imdiag ------------------------------ */
-/* function to destruct a selector_t object
- * rgerhards, 2007-08-01
- */
-rsRetVal
-selectorDestruct(void *pVal)
-{
- selector_t *pThis = (selector_t *) pVal;
-
- assert(pThis != NULL);
-
- if(pThis->pCSHostnameComp != NULL)
- rsCStrDestruct(&pThis->pCSHostnameComp);
- if(pThis->pCSProgNameComp != NULL)
- rsCStrDestruct(&pThis->pCSProgNameComp);
-
- if(pThis->f_filter_type == FILTER_PROP) {
- if(pThis->f_filterData.prop.pCSPropName != NULL)
- rsCStrDestruct(&pThis->f_filterData.prop.pCSPropName);
- if(pThis->f_filterData.prop.pCSCompValue != NULL)
- rsCStrDestruct(&pThis->f_filterData.prop.pCSCompValue);
- if(pThis->f_filterData.prop.regex_cache != NULL)
- rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache);
- } else if(pThis->f_filter_type == FILTER_EXPR) {
- if(pThis->f_filterData.f_expr != NULL)
- expr.Destruct(&pThis->f_filterData.f_expr);
- }
-
- llDestroy(&pThis->llActList);
- free(pThis);
-
- return RS_RET_OK;
-}
-
-
-/* function to construct a selector_t object
- * rgerhards, 2007-08-01
- */
-rsRetVal
-selectorConstruct(selector_t **ppThis)
-{
- DEFiRet;
- selector_t *pThis;
-
- assert(ppThis != NULL);
-
- if((pThis = (selector_t*) calloc(1, sizeof(selector_t))) == NULL) {
- ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
- }
- CHKiRet(llInit(&pThis->llActList, actionDestruct, NULL, NULL));
-
-finalize_it:
- if(iRet != RS_RET_OK) {
- if(pThis != NULL) {
- selectorDestruct(pThis);
- }
- }
- *ppThis = pThis;
- RETiRet;
-}
-
-
/* rgerhards, 2005-10-24: crunch_list is called only during option processing. So
* it is never called once rsyslogd is running (not even when HUPed). This code
* contains some exits, but they are considered safe because they only happen
@@ -993,233 +934,6 @@ finalize_it:
RETiRet;
}
-/* This functions looks at the given message and checks if it matches the
- * provided filter condition. If so, it returns true, else it returns
- * false. This is a helper to logmsg() and meant to drive the decision
- * process if a message is to be processed or not. As I expect this
- * decision code to grow more complex over time AND logmsg() is already
- * a very lengthy function, I thought a separate function is more appropriate.
- * 2005-09-19 rgerhards
- * 2008-02-25 rgerhards: changed interface, now utilizes iRet, bProcessMsg
- * returns is message should be procesed.
- */
-static rsRetVal shouldProcessThisMessage(selector_t *f, msg_t *pMsg, int *bProcessMsg)
-{
- DEFiRet;
- unsigned short pbMustBeFreed;
- char *pszPropVal;
- int bRet = 0;
- vm_t *pVM = NULL;
- var_t *pResult = NULL;
-
- assert(f != NULL);
- assert(pMsg != NULL);
-
- /* we first have a look at the global, BSD-style block filters (for tag
- * and host). Only if they match, we evaluate the actual filter.
- * rgerhards, 2005-10-18
- */
- if(f->eHostnameCmpMode == HN_NO_COMP) {
- /* EMPTY BY INTENSION - we check this value first, because
- * it is the one most often used, so this saves us time!
- */
- } else if(f->eHostnameCmpMode == HN_COMP_MATCH) {
- if(rsCStrSzStrCmp(f->pCSHostnameComp, (uchar*) getHOSTNAME(pMsg), getHOSTNAMELen(pMsg))) {
- /* not equal, so we are already done... */
- dbgprintf("hostname filter '+%s' does not match '%s'\n",
- rsCStrGetSzStrNoNULL(f->pCSHostnameComp), getHOSTNAME(pMsg));
- FINALIZE;
- }
- } else { /* must be -hostname */
- if(!rsCStrSzStrCmp(f->pCSHostnameComp, (uchar*) getHOSTNAME(pMsg), getHOSTNAMELen(pMsg))) {
- /* not equal, so we are already done... */
- dbgprintf("hostname filter '-%s' does not match '%s'\n",
- rsCStrGetSzStrNoNULL(f->pCSHostnameComp), getHOSTNAME(pMsg));
- FINALIZE;
- }
- }
-
- if(f->pCSProgNameComp != NULL) {
- int bInv = 0, bEqv = 0, offset = 0;
- if(*(rsCStrGetSzStrNoNULL(f->pCSProgNameComp)) == '-') {
- if(*(rsCStrGetSzStrNoNULL(f->pCSProgNameComp) + 1) == '-')
- offset = 1;
- else {
- bInv = 1;
- offset = 1;
- }
- }
- if(!rsCStrOffsetSzStrCmp(f->pCSProgNameComp, offset, (uchar*) getProgramName(pMsg), getProgramNameLen(pMsg)))
- bEqv = 1;
-
- if((!bEqv && !bInv) || (bEqv && bInv)) {
- /* not equal or inverted selection, so we are already done... */
- dbgprintf("programname filter '%s' does not match '%s'\n",
- rsCStrGetSzStrNoNULL(f->pCSProgNameComp), getProgramName(pMsg));
- FINALIZE;
- }
- }
-
- /* done with the BSD-style block filters */
-
- if(f->f_filter_type == FILTER_PRI) {
- /* skip messages that are incorrect priority */
- if ( (f->f_filterData.f_pmask[pMsg->iFacility] == TABLE_NOPRI) || \
- ((f->f_filterData.f_pmask[pMsg->iFacility] & (1<<pMsg->iSeverity)) == 0) )
- bRet = 0;
- else
- bRet = 1;
- } else if(f->f_filter_type == FILTER_EXPR) {
- CHKiRet(vm.Construct(&pVM));
- CHKiRet(vm.ConstructFinalize(pVM));
- CHKiRet(vm.SetMsg(pVM, pMsg));
- CHKiRet(vm.ExecProg(pVM, f->f_filterData.f_expr->pVmprg));
- CHKiRet(vm.PopBoolFromStack(pVM, &pResult));
- dbgprintf("result of expression evaluation: %lld\n", pResult->val.num);
- /* VM is destructed on function exit */
- bRet = (pResult->val.num) ? 1 : 0;
- } else {
- assert(f->f_filter_type == FILTER_PROP); /* assert() just in case... */
- pszPropVal = MsgGetProp(pMsg, NULL, f->f_filterData.prop.pCSPropName, &pbMustBeFreed);
-
- /* Now do the compares (short list currently ;)) */
- switch(f->f_filterData.prop.operation ) {
- case FIOP_CONTAINS:
- if(rsCStrLocateInSzStr(f->f_filterData.prop.pCSCompValue, (uchar*) pszPropVal) != -1)
- bRet = 1;
- break;
- case FIOP_ISEQUAL:
- if(rsCStrSzStrCmp(f->f_filterData.prop.pCSCompValue,
- (uchar*) pszPropVal, strlen(pszPropVal)) == 0)
- bRet = 1; /* process message! */
- break;
- case FIOP_STARTSWITH:
- if(rsCStrSzStrStartsWithCStr(f->f_filterData.prop.pCSCompValue,
- (uchar*) pszPropVal, strlen(pszPropVal)) == 0)
- bRet = 1; /* process message! */
- break;
- case FIOP_REGEX:
- if(rsCStrSzStrMatchRegex(f->f_filterData.prop.pCSCompValue,
- (unsigned char*) pszPropVal, 0, &f->f_filterData.prop.regex_cache) == RS_RET_OK)
- bRet = 1;
- break;
- case FIOP_EREREGEX:
- if(rsCStrSzStrMatchRegex(f->f_filterData.prop.pCSCompValue,
- (unsigned char*) pszPropVal, 1, &f->f_filterData.prop.regex_cache) == RS_RET_OK)
- bRet = 1;
- break;
- default:
- /* here, it handles NOP (for performance reasons) */
- assert(f->f_filterData.prop.operation == FIOP_NOP);
- bRet = 1; /* as good as any other default ;) */
- break;
- }
-
- /* now check if the value must be negated */
- if(f->f_filterData.prop.isNegated)
- bRet = (bRet == 1) ? 0 : 1;
-
- if(Debug) {
- dbgprintf("Filter: check for property '%s' (value '%s') ",
- rsCStrGetSzStrNoNULL(f->f_filterData.prop.pCSPropName),
- pszPropVal);
- if(f->f_filterData.prop.isNegated)
- dbgprintf("NOT ");
- dbgprintf("%s '%s': %s\n",
- getFIOPName(f->f_filterData.prop.operation),
- rsCStrGetSzStrNoNULL(f->f_filterData.prop.pCSCompValue),
- bRet ? "TRUE" : "FALSE");
- }
-
- /* cleanup */
- if(pbMustBeFreed)
- free(pszPropVal);
- }
-
-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);
-
- *bProcessMsg = bRet;
- RETiRet;
-}
-
-
-/* helper to processMsg(), used to call the configured actions. It is
- * executed from within llExecFunc() of the action list.
- * rgerhards, 2007-08-02
- */
-typedef struct processMsgDoActions_s {
- int bPrevWasSuspended; /* was the previous action suspended? */
- msg_t *pMsg;
-} processMsgDoActions_t;
-DEFFUNC_llExecFunc(processMsgDoActions)
-{
- DEFiRet;
- rsRetVal iRetMod; /* return value of module - we do not always pass that back */
- action_t *pAction = (action_t*) pData;
- processMsgDoActions_t *pDoActData = (processMsgDoActions_t*) pParam;
-
- assert(pAction != NULL);
-
- if((pAction->bExecWhenPrevSusp == 1) && (pDoActData->bPrevWasSuspended == 0)) {
- dbgprintf("not calling action because the previous one is not suspended\n");
- ABORT_FINALIZE(RS_RET_OK);
- }
-
- iRetMod = actionCallAction(pAction, pDoActData->pMsg);
- if(iRetMod == RS_RET_DISCARDMSG) {
- ABORT_FINALIZE(RS_RET_DISCARDMSG);
- } else if(iRetMod == RS_RET_SUSPENDED) {
- /* indicate suspension for next module to be called */
- pDoActData->bPrevWasSuspended = 1;
- } else {
- pDoActData->bPrevWasSuspended = 0;
- }
-
-finalize_it:
- RETiRet;
-}
-
-
-/* Process (consume) a received message. Calls the actions configured.
- * rgerhards, 2005-10-13
- */
-static void
-processMsg(msg_t *pMsg)
-{
- selector_t *f;
- int bContinue;
- int bProcessMsg;
- processMsgDoActions_t DoActData;
- rsRetVal iRet;
-
- BEGINfunc
- assert(pMsg != NULL);
-
- /* log the message to the particular outputs */
-
- bContinue = 1;
- for (f = Files; f != NULL && bContinue ; f = f->f_next) {
- /* first check the filters... */
- iRet = shouldProcessThisMessage(f, pMsg, &bProcessMsg);
- if(!bProcessMsg) {
- continue;
- }
-
- /* ok -- from here, we have action-specific code, nothing really selector-specific -- rger 2007-08-01 */
- DoActData.pMsg = pMsg;
- DoActData.bPrevWasSuspended = 0;
- if(llExecFunc(&f->llActList, processMsgDoActions, (void*)&DoActData) == RS_RET_DISCARDMSG)
- bContinue = 0;
- }
- ENDfunc
-}
-
/* The consumer of dequeued messages. This function is called by the
* queue engine on dequeueing of a message. It runs on a SEPARATE
@@ -1237,7 +951,7 @@ msgConsumer(void __attribute__((unused)) *notNeeded, void *pUsr)
if((pMsg->msgFlags & NEEDS_PARSING) != 0) {
parseMsg(pMsg);
}
- processMsg(pMsg);
+ ruleset.ProcessMsg(pCurrRuleset, pMsg);
msgDestruct(&pMsg);
RETiRet;
@@ -1744,7 +1458,6 @@ reapchild()
DEFFUNC_llExecFunc(flushRptdMsgsActions)
{
action_t *pAction = (action_t*) pData;
-
assert(pAction != NULL);
BEGINfunc
@@ -1767,20 +1480,12 @@ DEFFUNC_llExecFunc(flushRptdMsgsActions)
}
-/* This method flushes reapeat messages.
+/* This method flushes repeat messages.
*/
static void
doFlushRptdMsgs(void)
{
- register selector_t *f;
-
- /* see if we need to flush any "message repeated n times"...
- * Note that this interferes with objects running on other threads.
- * We are using appropriate locking inside the function to handle that.
- */
- for (f = Files; f != NULL ; f = f->f_next) {
- llExecFunc(&f->llActList, flushRptdMsgsActions, NULL);
- }
+ ruleset.IterateAllActions(flushRptdMsgsActions, NULL);
}
@@ -1971,6 +1676,16 @@ freeAllDynMemForTermination(void)
}
+/* Finalize and destruct all actions.
+ */
+static inline void
+destructAllActions(void)
+{
+ ruleset.DestructAllActions();
+ bHaveMainQueue = 0; // flag that internal messages need to be temporarily stored
+}
+
+
/* die() is called when the program shall end. This typically only occurs
* during sigterm or during the initialization.
* As die() is intended to shutdown rsyslogd, it is
@@ -2021,7 +1736,7 @@ die(int sig)
* repeated msgs.
*/
dbgprintf("Terminating outputs...\n");
- freeSelectors();
+ destructAllActions();
dbgprintf("all primary multi-thread sources have been terminated - now doing aux cleanup...\n");
/* rger 2005-02-22
@@ -2057,7 +1772,7 @@ die(int sig)
* rgerhards, 2007-08-03
* I have added some code now, but all that mod init/de-init should be moved to
* init, so that modules are unloaded and reloaded on HUP to. Eventually it should go
- * into freeSelectors() - but that needs to be seen. -- rgerhards, 2007-08-09
+ * into destructAllActions() - but that needs to be seen. -- rgerhards, 2007-08-09
*/
module.UnloadAndDestructAll(eMOD_LINK_ALL);
@@ -2185,56 +1900,6 @@ static void doDropPrivUid(int iUid)
}
-/* helper to freeSelectors(), used with llExecFunc() to flush
- * pending output. -- rgerhards, 2007-08-02
- * We do not need to lock the action object here as the processing
- * queue is already empty and no other threads are running when
- * we call this function. -- rgerhards, 2007-12-12
- */
-DEFFUNC_llExecFunc(freeSelectorsActions)
-{
- action_t *pAction = (action_t*) pData;
-
- assert(pAction != NULL);
-
- /* flush any pending output */
- if(pAction->f_prevcount) {
- actionWriteToAction(pAction);
- }
-
- return RS_RET_OK; /* never fails ;) */
-}
-
-
-/* Close all open log files and free selector descriptor array.
- */
-static void freeSelectors(void)
-{
- selector_t *f;
- selector_t *fPrev;
-
- if(Files != NULL) {
- dbgprintf("Freeing log structures.\n");
-
- for(f = Files ; f != NULL ; f = f->f_next) {
- llExecFunc(&f->llActList, freeSelectorsActions, NULL);
- }
-
- /* actions flushed and ready for destruction - so do that... */
- f = Files;
- while (f != NULL) {
- fPrev = f;
- f = f->f_next;
- selectorDestruct(fPrev);
- }
-
- /* Reflect the deletion of the selectors linked list. */
- Files = NULL;
- bHaveMainQueue = 0;
- }
-}
-
-
/* helper to generateConfigDAG, to print out all actions via
* the llExecFunc() facility.
* rgerhards, 2007-08-02
@@ -2311,14 +1976,14 @@ DEFFUNC_llExecFunc(generateConfigDAGAction)
static rsRetVal
generateConfigDAG(uchar *pszDAGFile)
{
- selector_t *f;
+ //rule_t *f;
FILE *fp;
int iActUnit = 1;
- int bHasFilter = 0; /* filter associated with this action unit? */
- int bHadFilter;
- int i;
+ //int bHasFilter = 0; /* filter associated with this action unit? */
+ //int bHadFilter;
+ //int i;
struct dag_info dagInfo;
- char *pszFilterName;
+ //char *pszFilterName;
char szConnectingNode[64];
DEFiRet;
@@ -2347,6 +2012,8 @@ generateConfigDAG(uchar *pszDAGFile)
strcpy(szConnectingNode, "act0_0");
dagInfo.bDiscarded = 0;
+/* TODO: re-enable! */
+#if 0
for(f = Files; f != NULL ; f = f->f_next) {
/* BSD-Style filters are currently ignored */
bHadFilter = bHasFilter;
@@ -2402,6 +2069,7 @@ generateConfigDAG(uchar *pszDAGFile)
++iActUnit;
}
+#endif
fprintf(fp, "\t%s -> act%d_0\n", szConnectingNode, iActUnit);
fprintf(fp, "\tact%d_0\t\t[label=discard shape=box]\n"
@@ -2413,20 +2081,6 @@ finalize_it:
}
-/* helper to dbPrintInitInfo, to print out all actions via
- * the llExecFunc() facility.
- * rgerhards, 2007-08-02
- */
-DEFFUNC_llExecFunc(dbgPrintInitInfoAction)
-{
- DEFiRet;
- iRet = actionDbgPrint((action_t*) pData);
- dbgprintf("\n");
-
- RETiRet;
-}
-
-
/* print debug information as part of init(). This pretty much
* outputs the whole config of rsyslogd. I've moved this code
* out of init() to clean it somewhat up.
@@ -2434,46 +2088,7 @@ DEFFUNC_llExecFunc(dbgPrintInitInfoAction)
*/
static void dbgPrintInitInfo(void)
{
- selector_t *f;
- int iSelNbr = 1;
- int i;
-
- dbgprintf("\nActive selectors:\n");
- for (f = Files; f != NULL ; f = f->f_next) {
- dbgprintf("Selector %d:\n", iSelNbr++);
- if(f->pCSProgNameComp != NULL)
- dbgprintf("tag: '%s'\n", rsCStrGetSzStrNoNULL(f->pCSProgNameComp));
- if(f->eHostnameCmpMode != HN_NO_COMP)
- dbgprintf("hostname: %s '%s'\n",
- f->eHostnameCmpMode == HN_COMP_MATCH ?
- "only" : "allbut",
- rsCStrGetSzStrNoNULL(f->pCSHostnameComp));
- if(f->f_filter_type == FILTER_PRI) {
- for (i = 0; i <= LOG_NFACILITIES; i++)
- if (f->f_filterData.f_pmask[i] == TABLE_NOPRI)
- dbgprintf(" X ");
- else
- dbgprintf("%2X ", f->f_filterData.f_pmask[i]);
- } else if(f->f_filter_type == FILTER_EXPR) {
- dbgprintf("EXPRESSION-BASED Filter: can currently not be displayed");
- } else {
- dbgprintf("PROPERTY-BASED Filter:\n");
- dbgprintf("\tProperty.: '%s'\n",
- rsCStrGetSzStrNoNULL(f->f_filterData.prop.pCSPropName));
- dbgprintf("\tOperation: ");
- if(f->f_filterData.prop.isNegated)
- dbgprintf("NOT ");
- dbgprintf("'%s'\n", getFIOPName(f->f_filterData.prop.operation));
- dbgprintf("\tValue....: '%s'\n",
- rsCStrGetSzStrNoNULL(f->f_filterData.prop.pCSCompValue));
- dbgprintf("\tAction...: ");
- }
-
- dbgprintf("\nActions:\n");
- llExecFunc(&f->llActList, dbgPrintInitInfoAction, NULL); /* actions */
-
- dbgprintf("\n");
- }
+ ruleset.DebugPrintAll();
dbgprintf("\n");
if(bDebugPrintTemplateList)
tplPrintList();
@@ -2553,13 +2168,13 @@ startInputModules(void)
static rsRetVal
init(void)
{
- DEFiRet;
rsRetVal localRet;
int iNbrActions;
int bHadConfigErr = 0;
char cbuf[BUFSIZ];
char bufStartUpMsg[512];
struct sigaction sigAct;
+ DEFiRet;
thrdTerminateAll(); /* stop all running input threads - TODO: reconsider location! */
@@ -2580,7 +2195,7 @@ init(void)
/* Close all open log files and free log descriptor array. This also frees
* all output-modules instance data.
*/
- freeSelectors();
+ destructAllActions();
/* Unload all non-static modules */
dbgprintf("Unloading non-static modules.\n");
@@ -2601,6 +2216,11 @@ init(void)
conf.ReInitConf();
+ // TODO: move to the right place
+ ruleset.Construct(&pCurrRuleset);
+ ruleset.SetName(pCurrRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset"));
+ ruleset.ConstructFinalize(pCurrRuleset);
+
/* open the configuration file */
localRet = conf.processConfFile(ConfFile);
CHKiRet(conf.GetNbrActActions(&iNbrActions));
@@ -2622,23 +2242,24 @@ init(void)
* We ignore any errors while doing this - we would be lost anyhow...
*/
errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!");
- selector_t *f = NULL;
/* 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];
- conf.cfline((uchar*)"*.ERR\t" _PATH_CONSOLE, &f);
- conf.cfline((uchar*)"syslog.*\t" _PATH_CONSOLE, &f);
- conf.cfline((uchar*)"*.PANIC\t*", &f);
- conf.cfline((uchar*)"syslog.*\troot", &f);
+ rule_t *pRule;
+ CHKiRet(rule.Construct(&pRule));
+ conf.cfline((uchar*)"*.ERR\t" _PATH_CONSOLE, &pRule);
+ conf.cfline((uchar*)"syslog.*\t" _PATH_CONSOLE, &pRule);
+ conf.cfline((uchar*)"*.PANIC\t*", &pRule);
+ conf.cfline((uchar*)"syslog.*\troot", &pRule);
if(ttyname_r(0, szTTYNameBuf, sizeof(szTTYNameBuf)) == 0) {
snprintf(cbuf,sizeof(cbuf), "*.*\t%s", szTTYNameBuf);
- conf.cfline((uchar*)cbuf, &f);
+ conf.cfline((uchar*)cbuf, &pRule);
} else {
dbgprintf("error %d obtaining controlling terminal, not using that emergency rule\n", errno);
}
- selectorAddList(f);
+ ruleset.AddRule(pCurrRuleset, &pRule);
}
legacyOptsHook();
@@ -2777,53 +2398,6 @@ finalize_it:
}
-/* add a completely-processed selector (after config line parsing) to
- * the linked list of selectors. 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.
- * We have one special case during initialization: then, the current
- * selector is NULL, which means we do not need to care about it at
- * all. -- rgerhards, 2007-08-01
- */
-rsRetVal
-selectorAddList(selector_t *f)
-{
- DEFiRet;
- int iActionCnt;
-
- static selector_t *nextp = NULL; /* TODO: make this go away (see comment below) */
-
- if(f != NULL) {
- CHKiRet(llGetNumElts(&f->llActList, &iActionCnt));
- if(iActionCnt == 0) {
- errmsg.LogError(0, NO_ERRCODE, "warning: selector line without actions will be discarded");
- selectorDestruct(f);
- } else {
- /* successfully created an entry */
- dbgprintf("selector line successfully processed\n");
- /* TODO: we should use the linked list class for the selector list, else we need to add globals
- * ... well nextp could be added temporarily...
- * Thanks to varmojfekoj for having the idea to just use "Files" to make this
- * code work. I had actually forgotten to fix the code here before moving to 1.18.0.
- * And, of course, I also did not migrate the selector_t structure to the linked list class.
- * However, that should still be one of the very next things to happen.
- * rgerhards, 2007-08-06
- */
- if(Files == NULL) {
- Files = f;
- } else {
- nextp->f_next = f;
- }
- nextp = f;
- }
- }
-
-finalize_it:
- RETiRet;
-}
-
-
/* set the main message queue mode
* rgerhards, 2008-01-03
*/
@@ -2911,7 +2485,6 @@ DEFFUNC_llExecFunc(doHUPActions)
static inline void
doHUP(void)
{
- selector_t *f;
char buf[512];
snprintf(buf, sizeof(buf) / sizeof(char),
@@ -2926,9 +2499,7 @@ doHUP(void)
init(); /* main queue is stopped as part of init() */
} else {
DBGPRINTF("Received SIGHUP, configured to be a non-restart type of HUP - notifying actions.\n");
- for(f = Files; f != NULL ; f = f->f_next) {
- llExecFunc(&f->llActList, doHUPActions, NULL);
- }
+ ruleset.IterateAllActions(doHUPActions, NULL);
}
}
@@ -3285,14 +2856,14 @@ InitGlobalClasses(void)
CHKiRet(objUse(errmsg, CORE_COMPONENT));
pErrObj = "module";
CHKiRet(objUse(module, CORE_COMPONENT));
- pErrObj = "var";
- CHKiRet(objUse(var, CORE_COMPONENT));
pErrObj = "datetime";
CHKiRet(objUse(datetime, CORE_COMPONENT));
- pErrObj = "vm";
- CHKiRet(objUse(vm, CORE_COMPONENT));
pErrObj = "expr";
CHKiRet(objUse(expr, CORE_COMPONENT));
+ pErrObj = "rule";
+ CHKiRet(objUse(rule, CORE_COMPONENT));
+ pErrObj = "ruleset";
+ CHKiRet(objUse(ruleset, CORE_COMPONENT));
pErrObj = "conf";
CHKiRet(objUse(conf, CORE_COMPONENT));
@@ -3336,10 +2907,10 @@ GlobalClassExit(void)
/* first, release everything we used ourself */
objRelease(net, LM_NET_FILENAME);/* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */
objRelease(conf, CORE_COMPONENT);
+ 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 */
- objRelease(vm, CORE_COMPONENT);
- objRelease(var, CORE_COMPONENT);
objRelease(datetime, CORE_COMPONENT);
/* TODO: implement the rest of the deinit */
diff --git a/tools/syslogd.h b/tools/syslogd.h
index 8b9bd131..9bcfb2d2 100644
--- a/tools/syslogd.h
+++ b/tools/syslogd.h
@@ -28,67 +28,17 @@
#include "action.h"
#include "linkedlist.h"
#include "expr.h"
+#include "net.h" /* TODO: remove when you remove isAllowedSender from here! */
#ifndef _PATH_CONSOLE
#define _PATH_CONSOLE "/dev/console"
#endif
-
-/* This structure represents the files that will have log
- * copies printed.
- * RGerhards 2004-11-08: Each instance of the filed structure
- * describes what I call an "output channel". This is important
- * to mention as we now allow database connections to be
- * present in the filed structure. If helps immensely, if we
- * think of it as the abstraction of an output channel.
- * rgerhards, 2005-10-26: The structure below provides ample
- * opportunity for non-thread-safety. Each of the variable
- * accesses must be carefully evaluated, many of them probably
- * be guarded by mutexes. But beware of deadlocks...
- * rgerhards, 2007-08-01: as you can see, the structure has shrunk pretty much. I will
- * remove some of the comments some time. It's still the structure that controls much
- * of the processing that goes on in syslogd, but it now has lots of helpers.
- */
-struct filed {
- struct filed *f_next; /* next in linked list */
- /* filter properties */
- enum {
- FILTER_PRI = 0, /* traditional PRI based filer */
- FILTER_PROP = 1, /* extended filter, property based */
- FILTER_EXPR = 2 /* extended filter, expression based */
- } f_filter_type;
- EHostnameCmpMode eHostnameCmpMode;
- cstr_t *pCSHostnameComp; /* hostname to check */
- cstr_t *pCSProgNameComp; /* tag to check or NULL, if not to be checked */
- union {
- u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */
- struct {
- cstr_t *pCSPropName;
- enum {
- FIOP_NOP = 0, /* do not use - No Operation */
- FIOP_CONTAINS = 1, /* contains string? */
- FIOP_ISEQUAL = 2, /* is (exactly) equal? */
- FIOP_STARTSWITH = 3, /* starts with a string? */
- FIOP_REGEX = 4, /* matches a (BRE) regular expression? */
- FIOP_EREREGEX = 5 /* matches a ERE regular expression? */
- } operation;
- regex_t *regex_cache; /* cache for compiled REs, if such are used */
- cstr_t *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 */
-};
-
-
-#include "net.h" /* TODO: remove when you remoe isAllowedSender from here! */
void untty(void);
-rsRetVal selectorConstruct(selector_t **ppThis);
+rsRetVal selectorConstruct(ruleset_t **ppThis);
rsRetVal selectorDestruct(void *pVal);
-rsRetVal selectorAddList(selector_t *f);
+rsRetVal selectorAddList(rule_t *f);
/* the following prototypes should go away once we have an input
* module interface -- rgerhards, 2007-12-12
*/