summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/Makefile.am8
-rw-r--r--runtime/cfsysline.c63
-rw-r--r--runtime/cfsysline.h20
-rw-r--r--runtime/conf.c240
-rw-r--r--runtime/conf.h22
-rw-r--r--runtime/ctok.c3
-rw-r--r--runtime/ctok_token.h1
-rw-r--r--runtime/debug.c40
-rw-r--r--runtime/expr.c5
-rw-r--r--runtime/glbl.c20
-rw-r--r--runtime/glbl.h2
-rw-r--r--runtime/module-template.h54
-rw-r--r--runtime/modules.c171
-rw-r--r--runtime/modules.h22
-rw-r--r--runtime/msg.c121
-rw-r--r--runtime/msg.h8
-rw-r--r--runtime/netstrm.c2
-rw-r--r--runtime/netstrms.c1
-rw-r--r--runtime/nsd.h12
-rw-r--r--runtime/nsd_gtls.c28
-rw-r--r--runtime/nsdpoll_ptcp.c50
-rw-r--r--runtime/nsdpoll_ptcp.h1
-rw-r--r--runtime/nspoll.c6
-rw-r--r--runtime/nspoll.h5
-rw-r--r--runtime/obj.c2
-rw-r--r--runtime/parser.c14
-rw-r--r--runtime/rsconf.c1003
-rw-r--r--runtime/rsconf.h177
-rw-r--r--runtime/rsyslog.c3
-rw-r--r--runtime/rsyslog.h25
-rw-r--r--runtime/rule.c55
-rw-r--r--runtime/rule.h2
-rw-r--r--runtime/ruleset.c138
-rw-r--r--runtime/ruleset.h32
-rw-r--r--runtime/stringbuf.c29
-rw-r--r--runtime/stringbuf.h2
-rw-r--r--runtime/typedefs.h46
-rw-r--r--runtime/var.h1
-rw-r--r--runtime/vm.c27
-rw-r--r--runtime/vmop.h1
40 files changed, 2154 insertions, 308 deletions
diff --git a/runtime/Makefile.am b/runtime/Makefile.am
index 09cb6b41..cfcfdc2c 100644
--- a/runtime/Makefile.am
+++ b/runtime/Makefile.am
@@ -20,6 +20,8 @@ librsyslog_la_SOURCES = \
unlimited_select.h \
conf.c \
conf.h \
+ rsconf.c \
+ rsconf.h \
parser.h \
parser.c \
strgen.h \
@@ -110,12 +112,12 @@ librsyslog_la_SOURCES = \
# runtime or will no longer be needed. -- rgerhards, 2008-06-13
if WITH_MODDIRS
-librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS)
+librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools
else
-librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS)
+librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools
endif
#librsyslog_la_LDFLAGS = -module -avoid-version
-librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS)
+librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS) $(LIBEE_LIBS)
#
# regular expression support
diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c
index 646ab39b..f6581ccd 100644
--- a/runtime/cfsysline.c
+++ b/runtime/cfsysline.c
@@ -39,6 +39,7 @@
#include "cfsysline.h"
#include "obj.h"
+#include "conf.h"
#include "errmsg.h"
#include "srUtils.h"
#include "unicode-helper.h"
@@ -585,6 +586,15 @@ doFacility(uchar **pp, rsRetVal (*pSetHdlr)(void*, int), void *pVal)
}
+static rsRetVal
+doGoneAway(__attribute__((unused)) uchar **pp,
+ __attribute__((unused)) rsRetVal (*pSetHdlr)(void*, int),
+ __attribute__((unused)) void *pVal)
+{
+ errmsg.LogError(0, RS_RET_CMD_GONE_AWAY, "config directive is no longer supported -- ignored");
+ return RS_RET_CMD_GONE_AWAY;
+}
+
/* Implements the severity syntax.
* rgerhards, 2008-02-14
*/
@@ -658,11 +668,13 @@ static int cslchKeyCompare(void *pKey1, void *pKey2)
/* set data members for this object
*/
-rsRetVal cslchSetEntry(cslCmdHdlr_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData)
+rsRetVal cslchSetEntry(cslCmdHdlr_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(),
+ void *pData, ecslConfObjType eConfObjType)
{
assert(pThis != NULL);
assert(eType != eCmdHdlrInvalid);
+ pThis->eConfObjType = eConfObjType;
pThis->eType = eType;
pThis->cslCmdHdlr = pHdlr;
pThis->pData = pData;
@@ -714,6 +726,9 @@ static rsRetVal cslchCallHdlr(cslCmdHdlr_t *pThis, uchar **ppConfLine)
case eCmdHdlrGetWord:
pHdlr = doGetWord;
break;
+ case eCmdHdlrGoneAway:
+ pHdlr = doGoneAway;
+ break;
default:
iRet = RS_RET_NOT_IMPLEMENTED;
goto finalize_it;
@@ -779,7 +794,8 @@ finalize_it:
/* add a handler entry to a known command
*/
-static rsRetVal cslcAddHdlr(cslCmd_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie)
+static rsRetVal cslcAddHdlr(cslCmd_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData,
+ void *pOwnerCookie, ecslConfObjType eConfObjType)
{
DEFiRet;
cslCmdHdlr_t *pCmdHdlr = NULL;
@@ -787,7 +803,7 @@ static rsRetVal cslcAddHdlr(cslCmd_t *pThis, ecslCmdHdrlType eType, rsRetVal (*p
assert(pThis != NULL);
CHKiRet(cslchConstruct(&pCmdHdlr));
- CHKiRet(cslchSetEntry(pCmdHdlr, eType, pHdlr, pData));
+ CHKiRet(cslchSetEntry(pCmdHdlr, eType, pHdlr, pData, eConfObjType));
CHKiRet(llAppend(&pThis->llCmdHdlrs, pOwnerCookie, pCmdHdlr));
finalize_it:
@@ -807,7 +823,7 @@ finalize_it:
* free pCmdName if he allocated it dynamically! -- rgerhards, 2007-08-09
*/
rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData,
- void *pOwnerCookie)
+ void *pOwnerCookie, ecslConfObjType eConfObjType)
{
DEFiRet;
cslCmd_t *pThis;
@@ -817,7 +833,7 @@ rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlTy
if(iRet == RS_RET_NOT_FOUND) {
/* new command */
CHKiRet(cslcConstruct(&pThis, bChainingPermitted));
- CHKiRet_Hdlr(cslcAddHdlr(pThis, eType, pHdlr, pData, pOwnerCookie)) {
+ CHKiRet_Hdlr(cslcAddHdlr(pThis, eType, pHdlr, pData, pOwnerCookie, eConfObjType)) {
cslcDestruct(pThis);
FINALIZE;
}
@@ -837,7 +853,7 @@ rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlTy
if(pThis->bChainingPermitted == 0 || bChainingPermitted == 0) {
ABORT_FINALIZE(RS_RET_CHAIN_NOT_PERMITTED);
}
- CHKiRet_Hdlr(cslcAddHdlr(pThis, eType, pHdlr, pData, pOwnerCookie)) {
+ CHKiRet_Hdlr(cslcAddHdlr(pThis, eType, pHdlr, pData, pOwnerCookie, eConfObjType)) {
cslcDestruct(pThis);
FINALIZE;
}
@@ -912,6 +928,7 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p)
uchar *pHdlrP; /* the handler's private p (else we could only call one handler) */
int bWasOnceOK; /* was the result of an handler at least once RS_RET_OK? */
uchar *pOKp = NULL; /* returned conf line pointer when it was OK */
+ int bHadScopingErr = 0; /* set if a scoping error occured */
iRet = llFind(&llCmdList, (void *) pCmdName, (void*) &pCmd);
@@ -925,17 +942,25 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p)
llCookieCmdHdlr = NULL;
bWasOnceOK = 0;
while((iRetLL = llGetNextElt(&pCmd->llCmdHdlrs, &llCookieCmdHdlr, (void*)&pCmdHdlr)) == RS_RET_OK) {
- /* for the time being, we ignore errors during handlers. The
- * reason is that handlers are independent. An error in one
- * handler does not necessarily mean that another one will
- * fail, too. Later, we might add a config variable to control
- * this behaviour (but I am not sure if that is rally
- * necessary). -- rgerhards, 2007-07-31
- */
- pHdlrP = *p;
- if((iRet = cslchCallHdlr(pCmdHdlr, &pHdlrP)) == RS_RET_OK) {
- bWasOnceOK = 1;
- pOKp = pHdlrP;
+ /* check if handler is valid in current scope */
+ if(pCmdHdlr->eConfObjType == eConfObjAlways ||
+ (bConfStrictScoping == 0 && currConfObj == eConfObjGlobal) ||
+ pCmdHdlr->eConfObjType == currConfObj) {
+ /* for the time being, we ignore errors during handlers. The
+ * reason is that handlers are independent. An error in one
+ * handler does not necessarily mean that another one will
+ * fail, too. Later, we might add a config variable to control
+ * this behaviour (but I am not sure if that is really
+ * necessary). -- rgerhards, 2007-07-31
+ */
+ pHdlrP = *p;
+ if((iRet = cslchCallHdlr(pCmdHdlr, &pHdlrP)) == RS_RET_OK) {
+ bWasOnceOK = 1;
+ pOKp = pHdlrP;
+ }
+ } else {
+ errmsg.LogError(0, RS_RET_CONF_INVLD_SCOPE, "config command invalid for current scope");
+ bHadScopingErr = 1;
}
}
@@ -947,6 +972,10 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p)
if(iRetLL != RS_RET_END_OF_LINKEDLIST)
iRet = iRetLL;
+ if(bHadScopingErr) {
+ iRet = RS_RET_CONF_INVLD_SCOPE;
+ }
+
finalize_it:
RETiRet;
}
diff --git a/runtime/cfsysline.h b/runtime/cfsysline.h
index 07ab5fcd..a4502672 100644
--- a/runtime/cfsysline.h
+++ b/runtime/cfsysline.h
@@ -26,28 +26,12 @@
#include "linkedlist.h"
-/* types of configuration handlers
- */
-typedef enum cslCmdHdlrType {
- eCmdHdlrInvalid = 0, /* invalid handler type - indicates a coding error */
- eCmdHdlrCustomHandler, /* custom handler, just call handler function */
- eCmdHdlrUID,
- eCmdHdlrGID,
- eCmdHdlrBinary,
- eCmdHdlrFileCreateMode,
- eCmdHdlrInt,
- eCmdHdlrSize,
- eCmdHdlrGetChar,
- eCmdHdlrFacility,
- eCmdHdlrSeverity,
- eCmdHdlrGetWord
-} ecslCmdHdrlType;
-
/* this is a single entry for a parse routine. It describes exactly
* one entry point/handler.
* The short name is cslch (Configfile SysLine CommandHandler)
*/
struct cslCmdHdlr_s { /* config file sysline parse entry */
+ ecslConfObjType eConfObjType; /* which config object is this for? */
ecslCmdHdrlType eType; /* which type of handler is this? */
rsRetVal (*cslCmdHdlr)(); /* function pointer to use with handler (params depending on eType) */
void *pData; /* user-supplied data pointer */
@@ -66,7 +50,7 @@ struct cslCmd_s { /* config file sysline parse entry */
typedef struct cslCmd_s cslCmd_t;
/* prototypes */
-rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie);
+rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie, ecslConfObjType eConfObjType);
rsRetVal unregCfSysLineHdlrs(void);
rsRetVal unregCfSysLineHdlrs4Owner(void *pOwnerCookie);
rsRetVal processCfSysLineCommand(uchar *pCmd, uchar **p);
diff --git a/runtime/conf.c b/runtime/conf.c
index 529142ed..ea7102a6 100644
--- a/runtime/conf.c
+++ b/runtime/conf.c
@@ -12,7 +12,7 @@
* the selector lines (e.g. *.info). That code is scheduled for removal
* as part of RainerScript. After this is done, we can change licenses.
*
- * Copyright 2008 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2008-2011 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of rsyslog.
*
@@ -52,7 +52,6 @@
#endif
#include "rsyslog.h"
-#include "../tools/syslogd.h" /* TODO: this must be removed! */
#include "dirty.h"
#include "parse.h"
#include "action.h"
@@ -71,6 +70,7 @@
#include "ctok_token.h"
#include "rule.h"
#include "ruleset.h"
+#include "rsconf.h"
#include "unicode-helper.h"
#ifdef OS_SOLARIS
@@ -78,8 +78,8 @@
#endif
/* forward definitions */
-static rsRetVal cfline(uchar *line, rule_t **pfCurr);
-static rsRetVal processConfFile(uchar *pConfFile);
+static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr);
+static rsRetVal processConfFile(rsconf_t *conf, uchar *pConfFile);
/* static data */
@@ -93,7 +93,9 @@ DEFobjCurrIf(net)
DEFobjCurrIf(rule)
DEFobjCurrIf(ruleset)
-static int iNbrActions = 0; /* number of currently defined actions */
+ecslConfObjType currConfObj = eConfObjGlobal; /* to support scoping - which config object is currently active? */
+int bConfStrictScoping = 0; /* force strict scoping during config processing? */
+
/* The following module-global variables are used for building
* tag and host selector lines during startup and config reload.
@@ -114,7 +116,7 @@ static cstr_t *pDfltProgNameCmp = NULL;
* indeed a directory.
* rgerhards, 2007-08-01
*/
-static rsRetVal doIncludeDirectory(uchar *pDirName)
+static rsRetVal doIncludeDirectory(rsconf_t *conf, uchar *pDirName)
{
DEFiRet;
int iEntriesDone = 0;
@@ -164,7 +166,7 @@ static rsRetVal doIncludeDirectory(uchar *pDirName)
memcpy(szFullFileName + iDirNameLen, res->d_name, iFileNameLen);
*(szFullFileName + iDirNameLen + iFileNameLen) = '\0';
dbgprintf("including file '%s'\n", szFullFileName);
- processConfFile(szFullFileName);
+ processConfFile(conf, szFullFileName);
/* we deliberately ignore the iRet of processConfFile() - this is because
* failure to process one file does not mean all files will fail. By ignoring,
* we retry with the next file, which is the best thing we can do. -- rgerhards, 2007-08-01
@@ -193,7 +195,7 @@ finalize_it:
* rgerhards, 2007-08-01
*/
rsRetVal
-doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal)
+doIncludeLine(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal)
{
DEFiRet;
char pattern[MAXFNAME];
@@ -231,10 +233,10 @@ doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal)
if(S_ISREG(fileInfo.st_mode)) { /* config file */
dbgprintf("requested to include config file '%s'\n", cfgFile);
- iRet = processConfFile(cfgFile);
+ iRet = processConfFile(conf, cfgFile);
} else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */
dbgprintf("requested to include directory '%s'\n", cfgFile);
- iRet = doIncludeDirectory(cfgFile);
+ iRet = doIncludeDirectory(conf, cfgFile);
} else { /* TODO: shall we handle symlinks or not? */
dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile);
}
@@ -247,8 +249,7 @@ finalize_it:
}
-/* process a $ModLoad config line.
- */
+/* process a $ModLoad config line. */
rsRetVal
doModLoad(uchar **pp, __attribute__((unused)) void* pVal)
{
@@ -278,7 +279,7 @@ doModLoad(uchar **pp, __attribute__((unused)) void* pVal)
else
pModName = szName;
- CHKiRet(module.Load(pModName));
+ CHKiRet(module.Load(pModName, 1));
finalize_it:
RETiRet;
@@ -322,7 +323,7 @@ doNameLine(uchar **pp, void* pVal)
switch(eDir) {
case DIR_TEMPLATE:
- tplAddLine(szName, &p);
+ tplAddLine(loadConf, szName, &p);
break;
case DIR_OUTCHANNEL:
ochAddLine(szName, &p);
@@ -353,7 +354,7 @@ finalize_it:
* 2004-11-17 rgerhards
*/
rsRetVal
-cfsysline(uchar *p)
+cfsysline(rsconf_t *conf, uchar *p)
{
DEFiRet;
uchar szCmd[64];
@@ -394,7 +395,7 @@ finalize_it:
* started with code from init() by rgerhards on 2007-07-31
*/
static rsRetVal
-processConfFile(uchar *pConfFile)
+processConfFile(rsconf_t *conf, uchar *pConfFile)
{
int iLnNbr = 0;
FILE *cf;
@@ -461,7 +462,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, &pCurrRule) != RS_RET_OK) {
+ if(cfline(conf, cbuf, &pCurrRule) != RS_RET_OK) {
/* we log a message, but otherwise ignore the error. After all, the next
* line can be correct. -- rgerhards, 2007-08-02
*/
@@ -476,7 +477,7 @@ processConfFile(uchar *pConfFile)
/* we probably have one selector left to be added - so let's do that now */
if(pCurrRule != NULL) {
- CHKiRet(ruleset.AddRule(rule.GetAssRuleset(pCurrRule), &pCurrRule));
+ CHKiRet(ruleset.AddRule(conf, rule.GetAssRuleset(pCurrRule), &pCurrRule));
}
/* close the configuration file */
@@ -871,6 +872,14 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
rsParsDestruct(pPars);
return(iRet);
}
+ if(f->f_filterData.prop.propID == PROP_CEE) {
+ /* in CEE case, we need to preserve the actual property name */
+ if((f->f_filterData.prop.propName =
+ es_newStrFromBuf((char*)cstrGetSzStrNoNULL(pCSPropName)+2, cstrLen(pCSPropName)-2)) == NULL) {
+ cstrDestruct(&pCSPropName);
+ return(RS_RET_ERR);
+ }
+ }
cstrDestruct(&pCSPropName);
/* read operation */
@@ -899,10 +908,13 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
iOffset = 0;
}
+dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSCompOp));
if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) {
f->f_filterData.prop.operation = FIOP_CONTAINS;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) {
f->f_filterData.prop.operation = FIOP_ISEQUAL;
+ } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isempty", 7)) {
+ f->f_filterData.prop.operation = FIOP_ISEMPTY;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "startswith", 10)) {
f->f_filterData.prop.operation = FIOP_STARTSWITH;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) {
@@ -915,12 +927,15 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
}
rsCStrDestruct(&pCSCompOp); /* no longer needed */
- /* read compare value */
- iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue);
- if(iRet != RS_RET_OK) {
- errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet);
- rsParsDestruct(pPars);
- return(iRet);
+dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation);
+ if(f->f_filterData.prop.operation != FIOP_ISEMPTY) {
+ /* read compare value */
+ iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue);
+ if(iRet != RS_RET_OK) {
+ errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet);
+ rsParsDestruct(pPars);
+ return(iRet);
+ }
}
/* skip to action part */
@@ -943,7 +958,7 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
* from the config file ("+/-hostname"). It stores it for further reference.
* rgerhards 2005-10-19
*/
-static rsRetVal cflineProcessHostSelector(uchar **pline)
+static rsRetVal cflineProcessHostSelector(rsconf_t *conf, uchar **pline)
{
DEFiRet;
@@ -993,7 +1008,7 @@ finalize_it:
* from the config file ("!tagname"). It stores it for further reference.
* rgerhards 2005-10-18
*/
-static rsRetVal cflineProcessTagSelector(uchar **pline)
+static rsRetVal cflineProcessTagSelector(rsconf_t *conf, uchar **pline)
{
DEFiRet;
@@ -1062,7 +1077,6 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f)
* and, if so, we copy them over. rgerhards, 2005-10-18
*/
if(pDfltProgNameCmp != NULL) {
-RUNLOG_STR("dflt ProgNameCmp != NULL, setting opCSProgNameComp");
CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp));
}
@@ -1079,7 +1093,7 @@ finalize_it:
/* process the action part of a selector line
* rgerhards, 2007-08-01
*/
-static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
+static rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction)
{
DEFiRet;
modInfo_t *pMod;
@@ -1091,7 +1105,7 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
ASSERT(ppAction != NULL);
/* loop through all modules and see if one picks up the line */
- pMod = module.GetNxtType(NULL, eMOD_OUT);
+ pMod = module.GetNxtCnfType(conf, NULL, eMOD_OUT);
/* Note: clang static analyzer reports that pMod mybe == NULL. However, this is
* not possible, because we have the built-in output modules which are always
* present. Anyhow, we guard this by an assert. -- rgerhards, 2010-12-16
@@ -1102,16 +1116,21 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
iRet = pMod->mod.om.parseSelectorAct(p, &pModData, &pOMSR);
dbgprintf("tried selector action for %s: %d\n", module.GetName(pMod), iRet);
if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) {
+ /* advance our config parser state: we now only accept an $End as valid,
+ * no more action statments.
+ */
+ if(currConfObj == eConfObjAction)
+ currConfObj = eConfObjActionWaitEnd;
if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) {
/* now check if the module is compatible with select features */
if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK)
- pAction->f_ReduceRepeated = bReduceRepeatMsgs;
+ pAction->f_ReduceRepeated = loadConf->globals.bReduceRepeatMsgs;
else {
dbgprintf("module is incompatible with RepeatedMsgReduction - turned off\n");
pAction->f_ReduceRepeated = 0;
}
pAction->eState = ACT_STATE_RDY; /* action is enabled */
- iNbrActions++; /* one more active action! */
+ conf->actions.nbrActions++; /* one more active action! */
}
break;
}
@@ -1125,7 +1144,7 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
dbgprintf("error %d parsing config line\n", (int) iRet);
break;
}
- pMod = module.GetNxtType(pMod, eMOD_OUT);
+ pMod = module.GetNxtCnfType(conf, pMod, eMOD_OUT);
}
*ppAction = pAction;
@@ -1139,7 +1158,7 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
* of the master config file!).
*/
static rsRetVal
-cflineClassic(uchar *p, rule_t **ppRule)
+cflineClassic(rsconf_t *conf, uchar *p, rule_t **ppRule)
{
DEFiRet;
action_t *pAction;
@@ -1161,15 +1180,15 @@ cflineClassic(uchar *p, rule_t **ppRule)
* all. -- rgerhards, 2007-08-01
*/
if(*ppRule != NULL) {
- CHKiRet(ruleset.AddRule(rule.GetAssRuleset(*ppRule), ppRule));
+ CHKiRet(ruleset.AddRule(conf, rule.GetAssRuleset(*ppRule), ppRule));
}
CHKiRet(rule.Construct(ppRule)); /* create "fresh" selector */
- CHKiRet(rule.SetAssRuleset(*ppRule, ruleset.GetCurrent())); /* create "fresh" selector */
+ CHKiRet(rule.SetAssRuleset(*ppRule, ruleset.GetCurrent(conf))); /* create "fresh" selector */
CHKiRet(rule.ConstructFinalize(*ppRule)); /* create "fresh" selector */
CHKiRet(cflineDoFilter(&p, *ppRule)); /* pull filters */
}
- CHKiRet(cflineDoAction(&p, &pAction));
+ CHKiRet(cflineDoAction(conf, &p, &pAction));
CHKiRet(llAppend(&(*ppRule)->llActList, NULL, (void*) pAction));
finalize_it:
@@ -1182,7 +1201,7 @@ finalize_it:
* rgerhards, 2007-08-01
*/
static rsRetVal
-cfline(uchar *line, rule_t **pfCurr)
+cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr)
{
DEFiRet;
@@ -1193,18 +1212,18 @@ cfline(uchar *line, rule_t **pfCurr)
/* check type of line and call respective processing */
switch(*line) {
case '!':
- iRet = cflineProcessTagSelector(&line);
+ iRet = cflineProcessTagSelector(conf, &line);
break;
case '+':
case '-':
- iRet = cflineProcessHostSelector(&line);
+ iRet = cflineProcessHostSelector(conf, &line);
break;
case '$':
++line; /* eat '$' */
- iRet = cfsysline(line);
+ iRet = cfsysline(conf, line);
break;
default:
- iRet = cflineClassic(line, pfCurr);
+ iRet = cflineClassic(conf, line, pfCurr);
break;
}
@@ -1216,11 +1235,11 @@ cfline(uchar *line, rule_t **pfCurr)
* rgerhards, 2008-07-28
*/
static rsRetVal
-GetNbrActActions(int *piNbrActions)
+GetNbrActActions(rsconf_t *conf, int *piNbrActions)
{
DEFiRet;
assert(piNbrActions != NULL);
- *piNbrActions = iNbrActions;
+ *piNbrActions = conf->actions.nbrActions;
RETiRet;
}
@@ -1251,6 +1270,136 @@ finalize_it:
ENDobjQueryInterface(conf)
+/* switch to a new action scope. This means that we switch the current
+ * mode to action, but it also means we need to clear all scope variables,
+ * so that we have a new environment.
+ * rgerhards, 2010-07-23
+ */
+static inline rsRetVal
+setActionScope(void)
+{
+ DEFiRet;
+ modInfo_t *pMod;
+
+ currConfObj = eConfObjAction;
+ DBGPRINTF("entering action scope\n");
+ CHKiRet(actionNewScope());
+
+ /* now tell each action to start the scope */
+ pMod = NULL;
+ while((pMod = module.GetNxtCnfType(loadConf, pMod, eMOD_OUT)) != NULL) {
+ DBGPRINTF("beginning scope on module %s\n", pMod->pszName);
+ pMod->mod.om.newScope();
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* switch back from action scope.
+ * rgerhards, 2010-07-27
+ */
+static inline rsRetVal
+unsetActionScope(void)
+{
+ DEFiRet;
+ modInfo_t *pMod;
+
+ currConfObj = eConfObjAction;
+ DBGPRINTF("exiting action scope\n");
+ CHKiRet(actionRestoreScope());
+
+ /* now tell each action to restore the scope */
+ pMod = NULL;
+ while((pMod = module.GetNxtCnfType(loadConf, pMod, eMOD_OUT)) != NULL) {
+ DBGPRINTF("exiting scope on module %s\n", pMod->pszName);
+ pMod->mod.om.restoreScope();
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* This method is called by our own handlers to begin a new config
+ * object ($Begin statement). This also implies a new scope.
+ * rgerhards, 2010-07-23
+ */
+static rsRetVal
+beginConfObj(void __attribute__((unused)) *pVal, uchar *pszName)
+{
+ DEFiRet;
+
+ if(currConfObj != eConfObjGlobal) {
+ errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "not in global scope - can not nest $Begin");
+ ABORT_FINALIZE(RS_RET_CONF_NOT_GLBL);
+ }
+
+ if(!strcasecmp((char*)pszName, "action")) {
+ setActionScope();
+ } else {
+ errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $Begin", pszName);
+ ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ);
+ }
+
+finalize_it:
+ free(pszName); /* no longer needed */
+ RETiRet;
+}
+
+
+/* This method is called to end a config scope and switch
+ * back to global scope.
+ * rgerhards, 2010-07-23
+ */
+static rsRetVal
+endConfObj(void __attribute__((unused)) *pVal, uchar *pszName)
+{
+ DEFiRet;
+
+ if(currConfObj == eConfObjGlobal) {
+ errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "already in global scope - dangling $End");
+ ABORT_FINALIZE(RS_RET_CONF_IN_GLBL);
+ }
+
+ if(!strcasecmp((char*)pszName, "action")) {
+ if(currConfObj == eConfObjAction) {
+ errmsg.LogError(0, RS_RET_CONF_END_NO_ACT, "$End action but not action specified");
+ /* this is a warning, we continue processing in that case (unscope) */
+ } else if(currConfObj != eConfObjActionWaitEnd) {
+ errmsg.LogError(0, RS_RET_CONF_INVLD_END, "$End not for active config object - "
+ "nesting error?");
+ ABORT_FINALIZE(RS_RET_CONF_INVLD_END);
+ }
+ currConfObj = eConfObjGlobal;
+ CHKiRet(unsetActionScope());
+ } else {
+ errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $End", pszName);
+ ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ);
+ }
+
+finalize_it:
+ free(pszName); /* no longer needed */
+ RETiRet;
+}
+
+
+/* Reset config variables to default values. Note that
+ * when we are inside an scope, we simply reset this to global.
+ * However, $ResetConfigVariables is a global directive, and as such
+ * will not be honored inside a scope!
+ * rgerhards, 2010-07-23
+ */
+static rsRetVal
+resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ currConfObj = eConfObjGlobal;
+ bConfStrictScoping = 0;
+ return RS_RET_OK;
+}
+
+
/* exit our class
* rgerhards, 2008-03-11
*/
@@ -1291,6 +1440,11 @@ BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANG
CHKiRet(objUse(net, LM_NET_FILENAME)); /* TODO: make this dependcy go away! */
CHKiRet(objUse(rule, CORE_COMPONENT));
CHKiRet(objUse(ruleset, CORE_COMPONENT));
+
+ CHKiRet(regCfSysLineHdlr((uchar *)"begin", 0, eCmdHdlrGetWord, beginConfObj, NULL, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"end", 0, eCmdHdlrGetWord, endConfObj, NULL, NULL, eConfObjAlways));
+ CHKiRet(regCfSysLineHdlr((uchar *)"strictscoping", 0, eCmdHdlrBinary, NULL, &bConfStrictScoping, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjAction));
ENDObjClassInit(conf)
/* vi:set ai:
diff --git a/runtime/conf.h b/runtime/conf.h
index d85d1f82..096af630 100644
--- a/runtime/conf.h
+++ b/runtime/conf.h
@@ -28,18 +28,28 @@
* somewhat strange (at least its name). -- rgerhards, 2007-08-01
*/
enum eDirective { DIR_TEMPLATE = 0, DIR_OUTCHANNEL = 1, DIR_ALLOWEDSENDER = 2};
+extern ecslConfObjType currConfObj;
+extern int bConfStrictScoping; /* force strict scoping during config processing? */
/* interfaces */
BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */
rsRetVal (*doNameLine)(uchar **pp, void* pVal);
- rsRetVal (*cfsysline)(uchar *p);
+ rsRetVal (*cfsysline)(rsconf_t *conf, uchar *p);
rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal);
- rsRetVal (*doIncludeLine)(uchar **pp, __attribute__((unused)) void* pVal);
- rsRetVal (*cfline)(uchar *line, rule_t **pfCurr);
- rsRetVal (*processConfFile)(uchar *pConfFile);
- rsRetVal (*GetNbrActActions)(int *);
+ rsRetVal (*doIncludeLine)(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal);
+ rsRetVal (*cfline)(rsconf_t *conf, uchar *line, rule_t **pfCurr);
+ rsRetVal (*processConfFile)(rsconf_t *conf, uchar *pConfFile);
+ rsRetVal (*GetNbrActActions)(rsconf_t *conf, int *);
+ /* version 4 -- 2010-07-23 rgerhards */
+ /* "just" added global variables
+ * FYI: we reconsider repacking as a non-object, as only the core currently
+ * accesses this module. The current object structure complicates things without
+ * any real benefit.
+ */
+ /* version 5 -- 2011-04-19 rgerhards */
+ /* complete revamp, we now use the rsconf object */
ENDinterface(conf)
-#define confCURR_IF_VERSION 3 /* increment whenever you change the interface structure! */
+#define confCURR_IF_VERSION 5 /* increment whenever you change the interface structure! */
/* in Version 3, entry point "ReInitConf()" was removed, as we do not longer need
* to support restart-type HUP -- rgerhards, 2009-07-15
*/
diff --git a/runtime/ctok.c b/runtime/ctok.c
index 99b0e095..19c9bd24 100644
--- a/runtime/ctok.c
+++ b/runtime/ctok.c
@@ -277,6 +277,9 @@ ctokGetVar(ctok_t *pThis, ctok_token_t *pToken)
if(c == '$') { /* second dollar, we have a system variable */
pToken->tok = ctok_SYSVAR;
CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */
+ } else if(c == '!') { /* cee variable indicator */
+ pToken->tok = ctok_CEEVAR;
+ CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */
} else {
pToken->tok = ctok_MSGVAR;
}
diff --git a/runtime/ctok_token.h b/runtime/ctok_token.h
index d36689fa..1413c699 100644
--- a/runtime/ctok_token.h
+++ b/runtime/ctok_token.h
@@ -54,6 +54,7 @@ typedef struct {
ctok_FUNCTION = 17,
ctok_THEN = 18,
ctok_STRADD = 19,
+ ctok_CEEVAR = 20,
ctok_CMP_EQ = 100, /* all compare operations must be in a row */
ctok_CMP_NEQ = 101,
ctok_CMP_LT = 102,
diff --git a/runtime/debug.c b/runtime/debug.c
index 3f1c23bd..283dae3a 100644
--- a/runtime/debug.c
+++ b/runtime/debug.c
@@ -843,12 +843,15 @@ do_dbgprint(uchar *pszObjName, char *pszMsg, size_t lenMsg)
static int bWasNL = 0;
char pszThrdName[64]; /* 64 is to be on the safe side, anything over 20 is bad... */
char pszWriteBuf[32*1024];
+ size_t lenCopy;
+ size_t offsWriteBuf = 0;
size_t lenWriteBuf;
struct timespec t;
# if _POSIX_TIMERS <= 0
struct timeval tv;
# endif
+#if 1
/* The bWasNL handler does not really work. It works if no thread
* switching occurs during non-NL messages. Else, things are messed
* up. Anyhow, it works well enough to provide useful help during
@@ -859,8 +862,8 @@ do_dbgprint(uchar *pszObjName, char *pszMsg, size_t lenMsg)
*/
if(ptLastThrdID != pthread_self()) {
if(!bWasNL) {
- if(stddbg != -1) write(stddbg, "\n", 1);
- if(altdbg != -1) write(altdbg, "\n", 1);
+ pszWriteBuf[0] = '\n';
+ offsWriteBuf = 1;
bWasNL = 1;
}
ptLastThrdID = pthread_self();
@@ -881,25 +884,28 @@ do_dbgprint(uchar *pszObjName, char *pszMsg, size_t lenMsg)
t.tv_sec = tv.tv_sec;
t.tv_nsec = tv.tv_usec * 1000;
# endif
- lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf),
+ lenWriteBuf = snprintf(pszWriteBuf+offsWriteBuf, sizeof(pszWriteBuf) - offsWriteBuf,
"%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
- if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
- if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf);
+ offsWriteBuf += lenWriteBuf;
}
- lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "%s: ", pszThrdName);
- // use for testing: lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "{%ld}%s: ", (long) syscall(SYS_gettid), pszThrdName);
- if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
- if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf);
+ lenWriteBuf = snprintf(pszWriteBuf + offsWriteBuf, sizeof(pszWriteBuf) - offsWriteBuf, "%s: ", pszThrdName);
+ offsWriteBuf += lenWriteBuf;
/* print object name header if we have an object */
if(pszObjName != NULL) {
- lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "%s: ", pszObjName);
- if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
- if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf);
+ lenWriteBuf = snprintf(pszWriteBuf + offsWriteBuf, sizeof(pszWriteBuf) - offsWriteBuf, "%s: ", pszObjName);
+ offsWriteBuf += lenWriteBuf;
}
}
- if(stddbg != -1) write(stddbg, pszMsg, lenMsg);
- if(altdbg != -1) write(altdbg, pszMsg, lenMsg);
+#endif
+ if(lenMsg > sizeof(pszWriteBuf) - offsWriteBuf)
+ lenCopy = sizeof(pszWriteBuf) - offsWriteBuf;
+ else
+ lenCopy = lenMsg;
+ memcpy(pszWriteBuf + offsWriteBuf, pszMsg, lenCopy);
+ offsWriteBuf += lenCopy;
+ if(stddbg != -1) write(stddbg, pszWriteBuf, offsWriteBuf);
+ if(altdbg != -1) write(altdbg, pszWriteBuf, offsWriteBuf);
bWasNL = (pszMsg[lenMsg - 1] == '\n') ? 1 : 0;
}
@@ -923,12 +929,12 @@ dbgprint(obj_t *pObj, char *pszMsg, size_t lenMsg)
pszObjName = obj.GetName(pObj);
}
- pthread_mutex_lock(&mutdbgprint);
- pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprint);
+// pthread_mutex_lock(&mutdbgprint);
+// pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprint);
do_dbgprint(pszObjName, pszMsg, lenMsg);
- pthread_cleanup_pop(1);
+// pthread_cleanup_pop(1);
}
#pragma GCC diagnostic warning "-Wempty-body"
diff --git a/runtime/expr.c b/runtime/expr.c
index e449d1c7..01431474 100644
--- a/runtime/expr.c
+++ b/runtime/expr.c
@@ -151,6 +151,11 @@ terminal(expr_t *pThis, ctok_t *tok)
CHKiRet(ctok_token.UnlinkVar(pToken, &pVar));
CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHMSGVAR, pVar)); /* add to program */
break;
+ case ctok_CEEVAR:
+ dbgoprint((obj_t*) pThis, "SYSVAR\n");
+ CHKiRet(ctok_token.UnlinkVar(pToken, &pVar));
+ CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCEEVAR, pVar)); /* add to program */
+ break;
case ctok_SYSVAR:
dbgoprint((obj_t*) pThis, "SYSVAR\n");
CHKiRet(ctok_token.UnlinkVar(pToken, &pVar));
diff --git a/runtime/glbl.c b/runtime/glbl.c
index 68eb276c..0114b1ac 100644
--- a/runtime/glbl.c
+++ b/runtime/glbl.c
@@ -391,16 +391,16 @@ BEGINAbstractObjClassInit(glbl, 1, OBJ_IS_CORE_MODULE) /* class, version */
CHKiRet(objUse(errmsg, CORE_COMPONENT));
/* register config handlers (TODO: we need to implement a way to unregister them) */
- CHKiRet(regCfSysLineHdlr((uchar *)"workdirectory", 0, eCmdHdlrGetWord, setWorkDir, NULL, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"dropmsgswithmaliciousdnsptrrecords", 0, eCmdHdlrBinary, NULL, &bDropMalPTRMsgs, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriver", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvr, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercafile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCAF, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriverkeyfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrKeyFile, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercertfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCertFile, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"localhostname", 0, eCmdHdlrGetWord, NULL, &LocalHostNameOverride, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"optimizeforuniprocessor", 0, eCmdHdlrBinary, NULL, &bOptimizeUniProc, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"preservefqdn", 0, eCmdHdlrBinary, NULL, &bPreserveFQDN, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"workdirectory", 0, eCmdHdlrGetWord, setWorkDir, NULL, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"dropmsgswithmaliciousdnsptrrecords", 0, eCmdHdlrBinary, NULL, &bDropMalPTRMsgs, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriver", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvr, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercafile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCAF, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdriverkeyfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrKeyFile, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"defaultnetstreamdrivercertfile", 0, eCmdHdlrGetWord, NULL, &pszDfltNetstrmDrvrCertFile, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"localhostname", 0, eCmdHdlrGetWord, NULL, &LocalHostNameOverride, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"optimizeforuniprocessor", 0, eCmdHdlrBinary, NULL, &bOptimizeUniProc, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"preservefqdn", 0, eCmdHdlrBinary, NULL, &bPreserveFQDN, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjGlobal));
INIT_ATOMIC_HELPER_MUT(mutTerminateInputs);
ENDObjClassInit(glbl)
diff --git a/runtime/glbl.h b/runtime/glbl.h
index 4b4bdf83..82bd1a7a 100644
--- a/runtime/glbl.h
+++ b/runtime/glbl.h
@@ -76,7 +76,7 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */
*/
SIMP_PROP(FdSetSize, int)
/* v7: was neeeded to mean v5+v6 - do NOT add anything else for that version! */
- /* next change is v8! */
+ /* next is v8! */
#undef SIMP_PROP
ENDinterface(glbl)
#define glblCURR_IF_VERSION 7 /* increment whenever you change the interface structure! */
diff --git a/runtime/module-template.h b/runtime/module-template.h
index c2585e67..2b0ed593 100644
--- a/runtime/module-template.h
+++ b/runtime/module-template.h
@@ -35,7 +35,7 @@
/* macro to define standard output-module static data members
*/
#define DEF_MOD_STATIC_DATA \
- static __attribute__((unused)) rsRetVal (*omsdRegCFSLineHdlr)();
+ static __attribute__((unused)) rsRetVal (*omsdRegCFSLineHdlr)(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie, ecslConfObjType eConfObjType);
#define DEF_OMOD_STATIC_DATA \
DEF_MOD_STATIC_DATA \
@@ -316,6 +316,50 @@ static rsRetVal tryResume(instanceData __attribute__((unused)) *pData)\
}
+/* Config scoping system.
+ * save current config scope and start a new one. Note that we do NOT implement a
+ * stack. Exactly one scope can be saved.
+ * We assume standard naming conventions (local confgSettings_t holds all
+ * config settings and MUST have been defined before this macro is being used!).
+ * Note that initConfVars() must be defined locally as well.
+ */
+#define SCOPING_SUPPORT \
+static rsRetVal initConfVars(void);\
+static configSettings_t cs; /* our current config settings */ \
+static configSettings_t cs_save; /* our saved (scope!) config settings */ \
+static rsRetVal newScope(void) \
+{ \
+ DEFiRet; \
+ memcpy(&cs_save, &cs, sizeof(cs)); \
+ iRet = initConfVars(); \
+ RETiRet; \
+} \
+static rsRetVal restoreScope(void) \
+{ \
+ DEFiRet; \
+ memcpy(&cs, &cs_save, sizeof(cs)); \
+ RETiRet; \
+}
+/* initConfVars()
+ * This entry point is called to check if a module can resume operations. This
+ * happens when a module requested that it be suspended. In suspended state,
+ * the engine periodically tries to resume the module. If that succeeds, normal
+ * processing continues. If not, the module will not be called unless a
+ * tryResume() call succeeds.
+ * Returns RS_RET_OK, if resumption succeeded, RS_RET_SUSPENDED otherwise
+ * rgerhard, 2007-08-02
+ */
+#define BEGINinitConfVars \
+static rsRetVal initConfVars(void)\
+{\
+ DEFiRet;
+
+#define CODESTARTinitConfVars
+
+#define ENDinitConfVars \
+ RETiRet;\
+}
+
/* queryEtryPt()
*/
@@ -370,6 +414,10 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\
*pEtryPoint = freeInstance;\
} else if(!strcmp((char*) name, "parseSelectorAct")) {\
*pEtryPoint = parseSelectorAct;\
+ } else if(!strcmp((char*) name, "newScope")) {\
+ *pEtryPoint = newScope;\
+ } else if(!strcmp((char*) name, "restoreScope")) {\
+ *pEtryPoint = restoreScope;\
} else if(!strcmp((char*) name, "isCompatibleWithFeature")) {\
*pEtryPoint = isCompatibleWithFeature;\
} else if(!strcmp((char*) name, "tryResume")) {\
@@ -485,6 +533,10 @@ rsRetVal modInit##uniqName(int iIFVersRequested __attribute__((unused)), int *ip
/* now get the obj interface so that we can access other objects */ \
CHKiRet(pObjGetObjInterface(&obj));
+/* do those initializations necessary for scoping */
+#define SCOPINGmodInit \
+ initConfVars();
+
#define ENDmodInit \
finalize_it:\
*pQueryEtryPt = queryEtryPt;\
diff --git a/runtime/modules.c b/runtime/modules.c
index 4541bddf..69c89790 100644
--- a/runtime/modules.c
+++ b/runtime/modules.c
@@ -11,7 +11,7 @@
*
* File begun on 2007-07-22 by RGerhards
*
- * Copyright 2007, 2009 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
@@ -55,6 +55,7 @@
#endif
#include "cfsysline.h"
+#include "rsconf.h"
#include "modules.h"
#include "errmsg.h"
#include "parser.h"
@@ -80,9 +81,7 @@ static modInfo_t *pLoadedModulesLast = NULL; /* tail-pointer */
/* already dlopen()-ed libs */
static struct dlhandle_s *pHandles = NULL;
-/* config settings */
-uchar *pModDir = NULL; /* read-only after startup */
-
+static uchar *pModDir; /* directory where loadable modules are found */
/* we provide a set of dummy functions for modules that do not support the
* some interfaces.
@@ -319,7 +318,7 @@ static uchar *modGetStateName(modInfo_t *pThis)
/* Add a module to the loaded module linked list
*/
static inline void
-addModToList(modInfo_t *pThis)
+addModToGlblList(modInfo_t *pThis)
{
assert(pThis != NULL);
@@ -334,6 +333,53 @@ addModToList(modInfo_t *pThis)
}
+/* Add a module to the config module list for current loadConf
+ */
+rsRetVal
+addModToCnfList(modInfo_t *pThis)
+{
+ cfgmodules_etry_t *pNew;
+ cfgmodules_etry_t *pLast;
+ DEFiRet;
+ assert(pThis != NULL);
+
+ if(loadConf == NULL) {
+ /* we are in an early init state */
+ FINALIZE;
+ }
+
+ /* check for duplicates and, as a side-activity, identify last node */
+ pLast = loadConf->modules.root;
+ if(pLast != NULL) {
+ while(1) { /* loop broken inside */
+ if(pLast->pMod == pThis) {
+ DBGPRINTF("module '%s' already in this config\n", modGetName(pThis));
+ FINALIZE;
+ }
+ if(pLast->next == NULL)
+ break;
+ pLast = pLast -> next;
+ }
+ }
+
+ /* if we reach this point, pLast is the tail pointer */
+
+ CHKmalloc(pNew = MALLOC(sizeof(cfgmodules_etry_t)));
+ pNew->next = NULL;
+ pNew->pMod = pThis;
+
+ if(pLast == NULL) {
+ loadConf->modules.root = pNew;
+ } else {
+ /* there already exist entries */
+ pLast->next = pNew;
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
/* Get the next module pointer - this is used to traverse the list.
* The function returns the next pointer or NULL, if there is no next one.
* The last object must be provided to the function. If NULL is provided,
@@ -355,19 +401,31 @@ static modInfo_t *GetNxt(modInfo_t *pThis)
/* this function is like GetNxt(), but it returns pointers to
- * modules of specific type only. As we currently deal just with output modules,
- * it is a dummy, to be filled with real code later.
- * rgerhards, 2007-07-24
+ * modules of specific type only. Only modules from the provided
+ * config are returned. Note that processing speed could be improved,
+ * but this is really not relevant, as config file loading is not really
+ * something we are concerned about in regard to runtime.
*/
-static modInfo_t *GetNxtType(modInfo_t *pThis, eModType_t rqtdType)
+static modInfo_t *GetNxtCnfType(rsconf_t *cnf, modInfo_t *pThis, eModType_t rqtdType)
{
- modInfo_t *pMod = pThis;
+ cfgmodules_etry_t *node;
+
+ if(pThis == NULL) { /* start at beginning of module list */
+ node = cnf->modules.root;
+ } else { /* start at last location - then we need to find the module in the config list */
+ for(node = cnf->modules.root ; node != NULL && node->pMod != pThis ; node = node->next)
+ /*search only, all done in for() */;
+ if(node != NULL)
+ node = node->next; /* skip to NEXT element in list */
+ }
- do {
- pMod = GetNxt(pMod);
- } while(!(pMod == NULL || pMod->eType == rqtdType)); /* warning: do ... while() */
+dbgprintf("XXXX: entering node, ptr %p: %s\n", node, (node == NULL)? "":modGetName(node->pMod));
+ while(node != NULL && node->pMod->eType != rqtdType) {
+ node = node->next; /* warning: do ... while() */
+dbgprintf("XXXX: in loop, ptr %p: %s\n", node, (node == NULL)? "":modGetName(node->pMod));
+ }
- return pMod;
+ return (node == NULL) ? NULL : node->pMod;
}
@@ -409,7 +467,8 @@ finalize_it:
* everything needed to fully initialize the module.
*/
static rsRetVal
-doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_t*), uchar *name, void *pModHdlr)
+doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_t*),
+ uchar *name, void *pModHdlr, modInfo_t **pNewModule)
{
rsRetVal localRet;
modInfo_t *pNew = NULL;
@@ -470,6 +529,8 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"doAction", &pNew->mod.om.doAction));
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"parseSelectorAct", &pNew->mod.om.parseSelectorAct));
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"tryResume", &pNew->tryResume));
+ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"newScope", &pNew->mod.om.newScope));
+ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"restoreScope", &pNew->mod.om.restoreScope));
/* try load optional interfaces */
localRet = (*pNew->modQueryEtryPt)((uchar*)"doHUP", &pNew->doHUP);
if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND)
@@ -569,12 +630,14 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_
}
/* we initialized the structure, now let's add it to the linked list of modules */
- addModToList(pNew);
+ addModToGlblList(pNew);
+ *pNewModule = pNew;
finalize_it:
if(iRet != RS_RET_OK) {
if(pNew != NULL)
moduleDestruct(pNew);
+ *pNewModule = NULL;
}
RETiRet;
@@ -623,6 +686,8 @@ static void modPrintList(void)
dbgprintf("\tparseSelectorAct: 0x%lx\n", (unsigned long) pMod->mod.om.parseSelectorAct);
dbgprintf("\ttryResume: 0x%lx\n", (unsigned long) pMod->tryResume);
dbgprintf("\tdoHUP: 0x%lx\n", (unsigned long) pMod->doHUP);
+ dbgprintf("\tnewScope: 0x%lx\n", (unsigned long) pMod->mod.om.newScope);
+ dbgprintf("\trestoreScope: 0x%lx\n", (unsigned long) pMod->mod.om.restoreScope);
dbgprintf("\tBeginTransaction: 0x%lx\n", (unsigned long)
((pMod->mod.om.beginTransaction == dummyBeginTransaction) ?
0 : pMod->mod.om.beginTransaction));
@@ -751,6 +816,27 @@ modUnloadAndDestructAll(eModLinkType_t modLinkTypesToUnload)
RETiRet;
}
+/* find module with given name in global list */
+static inline rsRetVal
+findModule(uchar *pModName, int iModNameLen, modInfo_t **pMod)
+{
+ modInfo_t *pModInfo;
+ uchar *pModNameCmp;
+ DEFiRet;
+
+ pModInfo = GetNxt(NULL);
+ while(pModInfo != NULL) {
+ if(!strncmp((char *) pModName, (char *) (pModNameCmp = modGetName(pModInfo)), iModNameLen) &&
+ (!*(pModNameCmp + iModNameLen) || !strcmp((char *) pModNameCmp + iModNameLen, ".so"))) {
+ dbgprintf("Module '%s' found\n", pModName);
+ break;
+ }
+ pModInfo = GetNxt(pModInfo);
+ }
+ *pMod = pModInfo;
+ RETiRet;
+}
+
/* load a module and initialize it, based on doModLoad() from conf.c
* rgerhards, 2008-03-05
@@ -760,15 +846,20 @@ modUnloadAndDestructAll(eModLinkType_t modLinkTypesToUnload)
* configuration file processing, which is executed on a single thread. Should we
* change that design at any stage (what is unlikely), we need to find a
* replacement.
+ * rgerhards, 2011-04-27:
+ * Parameter "bConfLoad" tells us if the load was triggered by a config handler, in
+ * which case we need to tie the loaded module to the current config. If bConfLoad == 0,
+ * the system loads a module for internal reasons, this is not directly tied to a
+ * configuration. We could also think if it would be useful to add only certain types
+ * of modules, but the current implementation at least looks simpler.
*/
static rsRetVal
-Load(uchar *pModName)
+Load(uchar *pModName, sbool bConfLoad)
{
DEFiRet;
size_t iPathLen, iModNameLen;
uchar szPath[PATH_MAX];
- uchar *pModNameCmp;
int bHasExtension;
void *pModHdlr, *pModInit;
modInfo_t *pModInfo;
@@ -788,17 +879,16 @@ Load(uchar *pModName)
} else
bHasExtension = FALSE;
- pModInfo = GetNxt(NULL);
- while(pModInfo != NULL) {
- if(!strncmp((char *) pModName, (char *) (pModNameCmp = modGetName(pModInfo)), iModNameLen) &&
- (!*(pModNameCmp + iModNameLen) || !strcmp((char *) pModNameCmp + iModNameLen, ".so"))) {
- dbgprintf("Module '%s' already loaded\n", pModName);
- ABORT_FINALIZE(RS_RET_OK);
- }
- pModInfo = GetNxt(pModInfo);
+ CHKiRet(findModule(pModName, iModNameLen, &pModInfo));
+ if(pModInfo != NULL) {
+ if(bConfLoad)
+ addModToCnfList(pModInfo);
+ dbgprintf("Module '%s' already loaded\n", pModName);
+ FINALIZE;
}
- pModDirCurr = (uchar *)((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir);
+ pModDirCurr = (uchar *)((pModDir == NULL) ?
+ _PATH_MODDIR : (char *)pModDir);
pModDirNext = NULL;
pModHdlr = NULL;
iLoadCnt = 0;
@@ -822,7 +912,8 @@ Load(uchar *pModName)
}
break;
} else if(iPathLen > sizeof(szPath) - 1) {
- errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', module path too long\n", pModName);
+ errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', "
+ "module path too long\n", pModName);
ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN);
}
@@ -848,17 +939,13 @@ Load(uchar *pModName)
/* now see if we have an extension and, if not, append ".so" */
if(!bHasExtension) {
- /* we do not have an extension and so need to add ".so"
- * TODO: I guess this is highly importable, so we should change the
- * algo over time... -- rgerhards, 2008-03-05
- */
- /* ... so now add the extension */
strncat((char *) szPath, ".so", sizeof(szPath) - strlen((char*) szPath) - 1);
iPathLen += 3;
}
if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) {
- errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName);
+ errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN,
+ "could not load module '%s', path too long\n", pModName);
ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN);
}
@@ -884,7 +971,8 @@ Load(uchar *pModName)
if(!pModHdlr) {
if(iLoadCnt) {
- errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", szPath, dlerror());
+ errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN,
+ "could not load module '%s', dlopen: %s\n", szPath, dlerror());
} else {
errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', ModDir was '%s'\n", szPath,
((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir));
@@ -892,15 +980,19 @@ Load(uchar *pModName)
ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_DLOPEN);
}
if(!(pModInit = dlsym(pModHdlr, "modInit"))) {
- errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_NO_INIT, "could not load module '%s', dlsym: %s\n", szPath, dlerror());
+ errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_NO_INIT,
+ "could not load module '%s', dlsym: %s\n", szPath, dlerror());
dlclose(pModHdlr);
ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_NO_INIT);
}
- if((iRet = doModInit(pModInit, (uchar*) pModName, pModHdlr)) != RS_RET_OK) {
- errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_INIT_FAILED, "could not load module '%s', rsyslog error %d\n", szPath, iRet);
+ if((iRet = doModInit(pModInit, (uchar*) pModName, pModHdlr, &pModInfo)) != RS_RET_OK) {
+ errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_INIT_FAILED,
+ "could not load module '%s', rsyslog error %d\n", szPath, iRet);
dlclose(pModHdlr);
ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_INIT_FAILED);
}
+ if(bConfLoad)
+ addModToCnfList(pModInfo);
finalize_it:
pthread_mutex_unlock(&mutLoadUnload);
@@ -1010,6 +1102,7 @@ CODESTARTObjClassExit(module)
* TODO: add again: pthread_mutex_destroy(&mutLoadUnload);
*/
+ free(pModDir);
# ifdef DEBUG
modUsrPrintAll(); /* debug aid - TODO: integrate with debug.c, at least the settings! */
# endif
@@ -1031,7 +1124,7 @@ CODESTARTobjQueryInterface(module)
* of course, also affects the "if" above).
*/
pIf->GetNxt = GetNxt;
- pIf->GetNxtType = GetNxtType;
+ pIf->GetNxtCnfType = GetNxtCnfType;
pIf->GetName = modGetName;
pIf->GetStateName = modGetStateName;
pIf->PrintList = modPrintList;
diff --git a/runtime/modules.h b/runtime/modules.h
index 4daaf1f9..37a73ecd 100644
--- a/runtime/modules.h
+++ b/runtime/modules.h
@@ -47,8 +47,10 @@
* version 5 changes the way parsing works for input modules. This is
* an important change, parseAndSubmitMessage() goes away. Other
* module types are not affected. -- rgerhards, 2008-10-09
+ * version 6 introduces scoping support (starting with the output
+ * modules) -- rgerhards, 2010-07-27
*/
-#define CURR_MOD_IF_VERSION 5
+#define CURR_MOD_IF_VERSION 6
typedef enum eModType_ {
eMOD_IN = 0, /* input module */
@@ -131,6 +133,8 @@ struct modInfo_s {
rsRetVal (*doAction)(uchar**, unsigned, void*);
rsRetVal (*endTransaction)(void*);
rsRetVal (*parseSelectorAct)(uchar**, void**,omodStringRequest_t**);
+ rsRetVal (*newScope)(void);
+ rsRetVal (*restoreScope)(void);
} om;
struct { /* data for library modules */
char dummy;
@@ -155,23 +159,25 @@ struct modInfo_s {
/* interfaces */
BEGINinterface(module) /* name must also be changed in ENDinterface macro! */
modInfo_t *(*GetNxt)(modInfo_t *pThis);
- modInfo_t *(*GetNxtType)(modInfo_t *pThis, eModType_t rqtdType);
+ modInfo_t *(*GetNxtCnfType)(rsconf_t *cnf, modInfo_t *pThis, eModType_t rqtdType);
uchar *(*GetName)(modInfo_t *pThis);
uchar *(*GetStateName)(modInfo_t *pThis);
rsRetVal (*Use)(char *srcFile, modInfo_t *pThis); /**< must be called before a module is used (ref counting) */
rsRetVal (*Release)(char *srcFile, modInfo_t **ppThis); /**< release a module (ref counting) */
void (*PrintList)(void);
rsRetVal (*UnloadAndDestructAll)(eModLinkType_t modLinkTypesToUnload);
- rsRetVal (*doModInit)(rsRetVal (*modInit)(), uchar *name, void *pModHdlr);
- rsRetVal (*Load)(uchar *name);
+ rsRetVal (*doModInit)(rsRetVal (*modInit)(), uchar *name, void *pModHdlr, modInfo_t **pNew);
+ rsRetVal (*Load)(uchar *name, sbool bConfLoad);
rsRetVal (*SetModDir)(uchar *name);
ENDinterface(module)
-#define moduleCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+#define moduleCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */
+/* Changes:
+ * v2
+ * - added param bCondLoad to Load call - 2011-04-27
+ * - removed GetNxtType, added GetNxtCnfType - 2011-04-27
+ */
/* prototypes */
PROTOTYPEObj(module);
-/* TODO: remove them below (means move the config init code) -- rgerhards, 2008-02-19 */
-extern uchar *pModDir; /* read-only after startup */
-
#endif /* #ifndef MODULES_H_INCLUDED */
diff --git a/runtime/msg.c b/runtime/msg.c
index d1e67aa2..c5cbb5c8 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -37,6 +37,7 @@
#include <ctype.h>
#include <sys/socket.h>
#include <netdb.h>
+#include <libee/libee.h>
#if HAVE_MALLOC_H
# include <malloc.h>
#endif
@@ -561,6 +562,10 @@ rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID)
*pPropID = PROP_SYS_MINUTE;
} else if(!strcmp((char*) pName, "$myhostname")) {
*pPropID = PROP_SYS_MYHOSTNAME;
+ } else if(!strcmp((char*) pName, "$!all-json")) {
+ *pPropID = PROP_CEE_ALL_JSON;
+ } else if(!strncmp((char*) pName, "$!", 2)) {
+ *pPropID = PROP_CEE;
} else if(!strcmp((char*) pName, "$bom")) {
*pPropID = PROP_SYS_BOM;
} else {
@@ -644,6 +649,10 @@ uchar *propIDToName(propid_t propID)
return UCHAR_CONSTANT("$MINUTE");
case PROP_SYS_MYHOSTNAME:
return UCHAR_CONSTANT("$MYHOSTNAME");
+ case PROP_CEE:
+ return UCHAR_CONSTANT("*CEE-based property*");
+ case PROP_CEE_ALL_JSON:
+ return UCHAR_CONSTANT("$!all-json");
case PROP_SYS_BOM:
return UCHAR_CONSTANT("$BOM");
default:
@@ -714,6 +723,7 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis)
pM->pRcvFromIP = NULL;
pM->rcvFrom.pRcvFrom = NULL;
pM->pRuleset = NULL;
+ pM->event = NULL;
memset(&pM->tRcvdAt, 0, sizeof(pM->tRcvdAt));
memset(&pM->tTIMESTAMP, 0, sizeof(pM->tTIMESTAMP));
pM->TAG.pszTAG = NULL;
@@ -849,6 +859,8 @@ CODESTARTobjDestruct(msg)
rsCStrDestruct(&pThis->pCSPROCID);
if(pThis->pCSMSGID != NULL)
rsCStrDestruct(&pThis->pCSMSGID);
+ if(pThis->event != NULL)
+ ee_deleteEvent(pThis->event);
# ifndef HAVE_ATOMIC_BUILTINS
MsgUnlock(pThis);
# endif
@@ -1215,7 +1227,7 @@ char *getProtocolVersionString(msg_t *pM)
}
-static inline void
+void
getRawMsg(msg_t *pM, uchar **pBuf, int *piLen)
{
if(pM == NULL) {
@@ -2236,6 +2248,41 @@ static uchar *getNOW(eNOWType eNow)
#undef tmpBUFSIZE /* clean up */
+/* Get a CEE-Property from libee. This function probably should be
+ * placed somewhere else, but this smells like a big restructuring
+ * useful in any case. So for the time being, I'll simply leave the
+ * function here, as the context seems good enough. -- rgerhards, 2010-12-01
+ */
+static inline void
+getCEEPropVal(msg_t *pMsg, es_str_t *propName, uchar **pRes, int *buflen, unsigned short *pbMustBeFreed)
+{
+ es_str_t *str = NULL;
+ int r;
+
+ if(*pbMustBeFreed)
+ free(*pRes);
+ *pRes = NULL;
+
+ if(pMsg->event == NULL) goto finalize_it;
+ r = ee_getEventFieldAsString(pMsg->event, propName, &str);
+
+ if(r != EE_OK) {
+ DBGPRINTF("msgGtCEEVar: libee error %d during ee_getEventFieldAsString\n", r);
+ FINALIZE;
+ }
+ *pRes = (unsigned char*) es_str2cstr(str, "#000");
+ es_deleteStr(str);
+ *buflen = (int) ustrlen(*pRes);
+ *pbMustBeFreed = 1;
+
+finalize_it:
+ if(*pRes == NULL) {
+ /* could not find any value, so set it to empty */
+ *pRes = (unsigned char*)"";
+ *pbMustBeFreed = 0;
+ }
+}
+
/* This function returns a string-representation of the
* requested message property. This is a generic function used
* to abstract properties so that these can be easier
@@ -2278,7 +2325,7 @@ static uchar *getNOW(eNOWType eNow)
*pPropLen = sizeof("**OUT OF MEMORY**") - 1; \
return(UCHAR_CONSTANT("**OUT OF MEMORY**"));}
uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
- propid_t propID, size_t *pPropLen,
+ propid_t propid, es_str_t *propName, size_t *pPropLen,
unsigned short *pbMustBeFreed)
{
uchar *pRes; /* result pointer */
@@ -2287,6 +2334,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
uchar *pBuf;
int iLen;
short iOffs;
+ es_str_t *str; /* for CEE handling, temp. string */
BEGINfunc
assert(pMsg != NULL);
@@ -2300,7 +2348,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
*pbMustBeFreed = 0;
- switch(propID) {
+ switch(propid) {
case PROP_MSG:
pRes = getMSG(pMsg);
bufLen = getMSGLen(pMsg);
@@ -2433,6 +2481,15 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
case PROP_SYS_MYHOSTNAME:
pRes = glbl.GetLocalHostName();
break;
+ case PROP_CEE_ALL_JSON:
+ ee_fmtEventToJSON(pMsg->event, &str);
+ pRes = (uchar*) es_str2cstr(str, "#000");
+ es_deleteStr(str);
+ *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
+ break;
+ case PROP_CEE:
+ getCEEPropVal(pMsg, propName, &pRes, &bufLen, pbMustBeFreed);
+ break;
case PROP_SYS_BOM:
if(*pbMustBeFreed == 1)
free(pRes);
@@ -2443,7 +2500,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
/* there is no point in continuing, we may even otherwise render the
* error message unreadable. rgerhards, 2007-07-10
*/
- dbgprintf("invalid property id: '%d'\n", propID);
+ dbgprintf("invalid property id: '%d'\n", propid);
*pbMustBeFreed = 0;
*pPropLen = sizeof("**INVALID PROPERTY NAME**") - 1;
return UCHAR_CONSTANT("**INVALID PROPERTY NAME**");
@@ -2451,6 +2508,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
/* If we did not receive a template pointer, we are already done... */
if(pTpe == NULL) {
+ *pPropLen = (bufLen == -1) ? ustrlen(pRes) : bufLen;
return pRes;
}
@@ -3037,6 +3095,57 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
}
+/* The function returns a cee variable suitable for use with RainerScript. Most importantly, this means
+ * that the value is returned in a var_t object. The var_t is constructed inside this function and
+ * MUST be freed by the caller.
+ * Note that we need to do a lot of conversions between es_str_t and cstr -- this will go away once
+ * we have moved larger parts of rsyslog to es_str_t. Acceptable for the moment, especially as we intend
+ * to rewrite the script engine as well!
+ * rgerhards, 2010-12-03
+ */
+rsRetVal
+msgGetCEEVar(msg_t *pMsg, cstr_t *propName, var_t **ppVar)
+{
+ DEFiRet;
+ var_t *pVar;
+ cstr_t *pstrProp;
+ es_str_t *str = NULL;
+ es_str_t *epropName = NULL;
+ int r;
+
+ ISOBJ_TYPE_assert(pMsg, msg);
+ ASSERT(propName != NULL);
+ ASSERT(ppVar != NULL);
+
+ /* make sure we have a var_t instance */
+ CHKiRet(var.Construct(&pVar));
+ CHKiRet(var.ConstructFinalize(pVar));
+
+ epropName = es_newStrFromBuf((char*)propName->pBuf, propName->iStrLen);
+ r = ee_getEventFieldAsString(pMsg->event, epropName, &str);
+
+ if(r != EE_OK) {
+ DBGPRINTF("msgGtCEEVar: libee error %d during ee_getEventFieldAsString\n", r);
+ CHKiRet(cstrConstruct(&pstrProp));
+ CHKiRet(cstrFinalize(pstrProp));
+ } else {
+ CHKiRet(cstrConstructFromESStr(&pstrProp, str));
+ }
+
+ /* now create a string object out of it and hand that over to the var */
+ CHKiRet(var.SetString(pVar, pstrProp));
+ es_deleteStr(str);
+
+ /* finally store var */
+ *ppVar = pVar;
+
+finalize_it:
+ if(epropName != NULL)
+ es_deleteStr(epropName);
+ RETiRet;
+}
+
+
/* The returns a message variable suitable for use with RainerScript. Most importantly, this means
* that the value is returned in a var_t object. The var_t is constructed inside this function and
* MUST be freed by the caller.
@@ -3064,7 +3173,7 @@ msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar)
/* always call MsgGetProp() without a template specifier */
/* TODO: optimize propNameToID() call -- rgerhards, 2009-06-26 */
propNameToID(pstrPropName, &propid);
- pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, &propLen, &bMustBeFreed);
+ pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, NULL, &propLen, &bMustBeFreed);
/* now create a string object out of it and hand that over to the var */
CHKiRet(rsCStrConstructFromszStr(&pstrProp, pszProp));
@@ -3079,6 +3188,8 @@ finalize_it:
RETiRet;
}
+
+
/* This function can be used as a generic way to set properties.
* We have to handle a lot of legacy, so our return value is not always
* 100% correct (called functions do not always provide one, should
diff --git a/runtime/msg.h b/runtime/msg.h
index 26a07aca..01a1e059 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -29,10 +29,12 @@
#define MSG_H_INCLUDED 1
#include <pthread.h>
+#include <libestr.h>
#include "obj.h"
#include "syslogd-types.h"
#include "template.h"
#include "atomic.h"
+#include "libee/libee.h"
/* rgerhards 2004-11-08: The following structure represents a
@@ -106,6 +108,7 @@ struct msg {
it obviously is solved in way or another...). */
struct syslogTime tRcvdAt;/* time the message entered this program */
struct syslogTime tTIMESTAMP;/* (parsed) value of the timestamp */
+ struct ee_event *event; /**< libee event */
/* some fixed-size buffers to save malloc()/free() for frequently used fields (from the default templates) */
uchar szRawMsg[CONF_RAWMSG_BUFSIZE]; /* most messages are small, and these are stored here (without malloc/free!) */
uchar szHOSTNAME[CONF_HOSTNAME_BUFSIZE];
@@ -163,7 +166,8 @@ void MsgSetRawMsgWOSize(msg_t *pMsg, char* pszRawMsg);
void MsgSetRawMsg(msg_t *pMsg, char* pszRawMsg, size_t lenMsg);
rsRetVal MsgReplaceMSG(msg_t *pThis, uchar* pszMSG, int lenMSG);
uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
- propid_t propID, size_t *pPropLen, unsigned short *pbMustBeFreed);
+ propid_t propid, es_str_t *propName,
+ size_t *pPropLen, unsigned short *pbMustBeFreed);
char *textpri(char *pRes, size_t pResLen, int pri);
rsRetVal msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar);
rsRetVal MsgEnableThreadSafety(void);
@@ -171,6 +175,8 @@ uchar *getRcvFrom(msg_t *pM);
void getTAG(msg_t *pM, uchar **ppBuf, int *piLen);
char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt);
char *getPRI(msg_t *pMsg);
+void getRawMsg(msg_t *pM, uchar **pBuf, int *piLen);
+rsRetVal msgGetCEEVar(msg_t *pThis, cstr_t *propName, var_t **ppVar);
/* TODO: remove these five (so far used in action.c) */
diff --git a/runtime/netstrm.c b/runtime/netstrm.c
index 3658006f..a6f840a5 100644
--- a/runtime/netstrm.c
+++ b/runtime/netstrm.c
@@ -64,6 +64,7 @@ ENDobjConstruct(netstrm)
/* destructor for the netstrm object */
BEGINobjDestruct(netstrm) /* be sure to specify the object type also in END and CODESTART macros! */
CODESTARTobjDestruct(netstrm)
+//printf("destruct driver data %p\n", pThis->pDrvrData);
if(pThis->pDrvrData != NULL)
iRet = pThis->Drvr.Destruct(&pThis->pDrvrData);
ENDobjDestruct(netstrm)
@@ -169,6 +170,7 @@ Rcv(netstrm_t *pThis, uchar *pBuf, ssize_t *pLenBuf)
{
DEFiRet;
ISOBJ_TYPE_assert(pThis, netstrm);
+//printf("Rcv %p\n", pThis);
iRet = pThis->Drvr.Rcv(pThis->pDrvrData, pBuf, pLenBuf);
RETiRet;
}
diff --git a/runtime/netstrms.c b/runtime/netstrms.c
index ea2dd9f3..0122064d 100644
--- a/runtime/netstrms.c
+++ b/runtime/netstrms.c
@@ -32,7 +32,6 @@
#include "rsyslog.h"
#include "module-template.h"
#include "obj.h"
-//#include "errmsg.h"
#include "nsd.h"
#include "netstrm.h"
#include "nssel.h"
diff --git a/runtime/nsd.h b/runtime/nsd.h
index e5b9320b..5a3f462e 100644
--- a/runtime/nsd.h
+++ b/runtime/nsd.h
@@ -29,6 +29,16 @@
#include <sys/socket.h>
+/**
+ * The following structure is a set of descriptors that need to be processed.
+ * This set will be the result of the epoll call and be used
+ * in the actual request processing stage. -- rgerhards, 2011-01-24
+ */
+struct nsd_epworkset_s {
+ int id;
+ void *pUsr;
+};
+
enum nsdsel_waitOp_e {
NSDSEL_RD = 1,
NSDSEL_WR = 2,
@@ -92,7 +102,7 @@ BEGINinterface(nsdpoll) /* name must also be changed in ENDinterface macro! */
rsRetVal (*Construct)(nsdpoll_t **ppThis);
rsRetVal (*Destruct)(nsdpoll_t **ppThis);
rsRetVal (*Ctl)(nsdpoll_t *pNsdpoll, nsd_t *pNsd, int id, void *pUsr, int mode, int op);
- rsRetVal (*Wait)(nsdpoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr);
+ rsRetVal (*Wait)(nsdpoll_t *pNsdpoll, int timeout, int *numReady, nsd_epworkset_t workset[]);
ENDinterface(nsdpoll)
#define nsdpollCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c
index 152dc8de..d0fd0e0f 100644
--- a/runtime/nsd_gtls.c
+++ b/runtime/nsd_gtls.c
@@ -50,7 +50,6 @@
#include "nsd_gtls.h"
/* things to move to some better place/functionality - TODO */
-#define DH_BITS 1024
#define CRLFILE "crl.pem"
@@ -82,7 +81,6 @@ static pthread_mutex_t mutGtlsStrerror; /**< a mutex protecting the potentially
/* ------------------------------ GnuTLS specifics ------------------------------ */
static gnutls_certificate_credentials xcred;
-static gnutls_dh_params dh_params;
#ifdef DEBUG
#if 0 /* uncomment, if needed some time again -- DEV Debug only */
@@ -610,7 +608,6 @@ gtlsInitSession(nsd_gtls_t *pThis)
/* request client certificate if any. */
gnutls_certificate_server_set_request( session, GNUTLS_CERT_REQUEST);
- gnutls_dh_set_prime_bits(session, DH_BITS);
pThis->sess = session;
@@ -619,23 +616,6 @@ finalize_it:
}
-static rsRetVal
-generate_dh_params(void)
-{
- int gnuRet;
- DEFiRet;
- /* Generate Diffie Hellman parameters - for use with DHE
- * kx algorithms. These should be discarded and regenerated
- * once a day, once a week or once a month. Depending on the
- * security requirements.
- */
- CHKgnutls(gnutls_dh_params_init( &dh_params));
- CHKgnutls(gnutls_dh_params_generate2( dh_params, DH_BITS));
-finalize_it:
- RETiRet;
-}
-
-
/* set up all global things that are needed for server operations
* rgerhards, 2008-04-30
*/
@@ -649,8 +629,6 @@ gtlsGlblInitLstn(void)
* considered legacy. -- rgerhards, 2008-05-05
*/
/*CHKgnutls(gnutls_certificate_set_x509_crl_file(xcred, CRLFILE, GNUTLS_X509_FMT_PEM));*/
- CHKiRet(generate_dh_params());
- gnutls_certificate_set_dh_params(xcred, dh_params); /* this is void */
bGlblSrvrInitDone = 1; /* we are all set now */
/* now we need to add our certificate */
@@ -1174,6 +1152,8 @@ CODESTARTobjDestruct(nsd_gtls)
gnutls_x509_crt_deinit(pThis->ourCert);
if(pThis->bOurKeyIsInit)
gnutls_x509_privkey_deinit(pThis->ourKey);
+#warning need more checks if the new gnutls_deinit() breaks things during normal operations
+// gnutls_deinit(pThis->sess); /* see ln 600 pThis->bInSess as something to check? */
ENDobjDestruct(nsd_gtls)
@@ -1419,6 +1399,10 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew)
/* we got a handshake, now check authorization */
CHKiRet(gtlsChkPeerAuth(pNew));
} else {
+ uchar *pGnuErr = gtlsStrerror(gnuRet);
+ errmsg.LogError(0, RS_RET_TLS_HANDSHAKE_ERR,
+ "gnutls returned error on handshake: %s\n", pGnuErr);
+ free(pGnuErr);
ABORT_FINALIZE(RS_RET_TLS_HANDSHAKE_ERR);
}
diff --git a/runtime/nsdpoll_ptcp.c b/runtime/nsdpoll_ptcp.c
index ef9c37a3..8c90d7fd 100644
--- a/runtime/nsdpoll_ptcp.c
+++ b/runtime/nsdpoll_ptcp.c
@@ -71,13 +71,16 @@ addEvent(nsdpoll_ptcp_t *pThis, int id, void *pUsr, int mode, nsd_ptcp_t *pSock,
pNew->pUsr = pUsr;
pNew->pSock = pSock;
pNew->event.events = 0; /* TODO: at some time we should be able to use EPOLLET */
+ //pNew->event.events = EPOLLET;
if(mode & NSDPOLL_IN)
pNew->event.events |= EPOLLIN;
if(mode & NSDPOLL_OUT)
pNew->event.events |= EPOLLOUT;
pNew->event.data.u64 = (uint64) pNew;
+ pthread_mutex_lock(&pThis->mutEvtLst);
pNew->pNext = pThis->pRoot;
pThis->pRoot = pNew;
+ pthread_mutex_unlock(&pThis->mutEvtLst);
*pEvtLst = pNew;
finalize_it:
@@ -94,6 +97,7 @@ unlinkEvent(nsdpoll_ptcp_t *pThis, int id, void *pUsr, nsdpoll_epollevt_lst_t **
nsdpoll_epollevt_lst_t *pPrev = NULL;
DEFiRet;
+ pthread_mutex_lock(&pThis->mutEvtLst);
pEvtLst = pThis->pRoot;
while(pEvtLst != NULL && !(pEvtLst->id == id && pEvtLst->pUsr == pUsr)) {
pPrev = pEvtLst;
@@ -111,6 +115,7 @@ unlinkEvent(nsdpoll_ptcp_t *pThis, int id, void *pUsr, nsdpoll_epollevt_lst_t **
pPrev->pNext = pEvtLst->pNext;
finalize_it:
+ pthread_mutex_unlock(&pThis->mutEvtLst);
RETiRet;
}
@@ -147,13 +152,27 @@ BEGINobjConstruct(nsdpoll_ptcp) /* be sure to specify the object type also in EN
DBGPRINTF("epoll_create1() could not create fd\n");
ABORT_FINALIZE(RS_RET_IO_ERROR);
}
+ pthread_mutex_init(&pThis->mutEvtLst, NULL);
finalize_it:
ENDobjConstruct(nsdpoll_ptcp)
/* destructor for the nsdpoll_ptcp object */
BEGINobjDestruct(nsdpoll_ptcp) /* be sure to specify the object type also in END and CODESTART macros! */
+ nsdpoll_epollevt_lst_t *node;
+ nsdpoll_epollevt_lst_t *nextnode;
CODESTARTobjDestruct(nsdpoll_ptcp)
+ /* we check if the epoll list still holds entries. This may happen, but
+ * is a bit unusual.
+ */
+ if(pThis->pRoot != NULL) {
+ for(node = pThis->pRoot ; node != NULL ; node = nextnode) {
+ nextnode = node->pNext;
+ dbgprintf("nsdpoll_ptcp destruct, need to destruct node %p\n", node);
+ delEvent(&node);
+ }
+ }
+ pthread_mutex_destroy(&pThis->mutEvtLst);
ENDobjDestruct(nsdpoll_ptcp)
@@ -202,23 +221,25 @@ finalize_it:
/* Wait for io to become ready. After the successful call, idRdy contains the
* id set by the caller for that i/o event, ppUsr is a pointer to a location
* where the user pointer shall be stored.
- * TODO: this is a trivial implementation that only polls one event at a time. We
- * may later extend it to poll for multiple events, what would cause less
- * overhead.
+ * numEntries contains the maximum number of entries on entry and the actual
+ * number of entries actually read on exit.
* rgerhards, 2009-11-18
*/
static rsRetVal
-Wait(nsdpoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr) {
+Wait(nsdpoll_t *pNsdpoll, int timeout, int *numEntries, nsd_epworkset_t workset[]) {
nsdpoll_ptcp_t *pThis = (nsdpoll_ptcp_t*) pNsdpoll;
nsdpoll_epollevt_lst_t *pOurEvt;
- struct epoll_event event;
+ struct epoll_event event[128];
int nfds;
+ int i;
DEFiRet;
- assert(idRdy != NULL);
- assert(ppUsr != NULL);
+ assert(workset != NULL);
- nfds = epoll_wait(pThis->efd, &event, 1, timeout);
+ if(*numEntries > 128)
+ *numEntries = 128;
+ DBGPRINTF("doing epoll_wait for max %d events\n", *numEntries);
+ nfds = epoll_wait(pThis->efd, event, *numEntries, timeout);
if(nfds == -1) {
if(errno == EINTR) {
ABORT_FINALIZE(RS_RET_EINTR);
@@ -230,10 +251,15 @@ Wait(nsdpoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr) {
ABORT_FINALIZE(RS_RET_TIMEOUT);
}
- /* we got a valid event, so tell the caller... */
- pOurEvt = (nsdpoll_epollevt_lst_t*) event.data.u64;
- *idRdy = pOurEvt->id;
- *ppUsr = pOurEvt->pUsr;
+ /* we got valid events, so tell the caller... */
+dbgprintf("epoll returned %d entries\n", nfds);
+ for(i = 0 ; i < nfds ; ++i) {
+ pOurEvt = (nsdpoll_epollevt_lst_t*) event[i].data.u64;
+ workset[i].id = pOurEvt->id;
+ workset[i].pUsr = pOurEvt->pUsr;
+dbgprintf("epoll push ppusr[%d]: %p\n", i, pOurEvt->pUsr);
+ }
+ *numEntries = nfds;
finalize_it:
RETiRet;
diff --git a/runtime/nsdpoll_ptcp.h b/runtime/nsdpoll_ptcp.h
index cea2823d..dfefad1b 100644
--- a/runtime/nsdpoll_ptcp.h
+++ b/runtime/nsdpoll_ptcp.h
@@ -49,6 +49,7 @@ struct nsdpoll_ptcp_s {
BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
int efd; /* file descriptor used by epoll */
nsdpoll_epollevt_lst_t *pRoot; /* Root of the epoll event list */
+ pthread_mutex_t mutEvtLst;
};
/* interface is defined in nsd.h, we just implement it! */
diff --git a/runtime/nspoll.c b/runtime/nspoll.c
index 64927280..a936b255 100644
--- a/runtime/nspoll.c
+++ b/runtime/nspoll.c
@@ -129,11 +129,11 @@ finalize_it:
/* Carries out the actual wait (all done in lower layers)
*/
static rsRetVal
-Wait(nspoll_t *pThis, int timeout, int *idRdy, void **ppUsr) {
+Wait(nspoll_t *pThis, int timeout, int *numEntries, nsd_epworkset_t workset[]) {
DEFiRet;
ISOBJ_TYPE_assert(pThis, nspoll);
- assert(idRdy != NULL);
- iRet = pThis->Drvr.Wait(pThis->pDrvrData, timeout, idRdy, ppUsr);
+ assert(workset != NULL);
+ iRet = pThis->Drvr.Wait(pThis->pDrvrData, timeout, numEntries, workset);
RETiRet;
}
diff --git a/runtime/nspoll.h b/runtime/nspoll.h
index a77759c0..037f6c38 100644
--- a/runtime/nspoll.h
+++ b/runtime/nspoll.h
@@ -50,11 +50,12 @@ BEGINinterface(nspoll) /* name must also be changed in ENDinterface macro! */
rsRetVal (*Construct)(nspoll_t **ppThis);
rsRetVal (*ConstructFinalize)(nspoll_t *pThis);
rsRetVal (*Destruct)(nspoll_t **ppThis);
- rsRetVal (*Wait)(nspoll_t *pNsdpoll, int timeout, int *idRdy, void **ppUsr);
+ rsRetVal (*Wait)(nspoll_t *pNsdpoll, int timeout, int *numEntries, nsd_epworkset_t workset[]);
rsRetVal (*Ctl)(nspoll_t *pNsdpoll, netstrm_t *pStrm, int id, void *pUsr, int mode, int op);
rsRetVal (*IsEPollSupported)(void); /* static method */
ENDinterface(nspoll)
-#define nspollCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+#define nspollCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */
+/* interface change in v2 is that wait supports multiple return objects */
/* prototypes */
PROTOTYPEObj(nspoll);
diff --git a/runtime/obj.c b/runtime/obj.c
index 45dac776..b45e5588 100644
--- a/runtime/obj.c
+++ b/runtime/obj.c
@@ -1154,7 +1154,7 @@ UseObj(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *pIf)
if(pObjFile == NULL) {
FINALIZE; /* no chance, we have lost... */
} else {
- CHKiRet(module.Load(pObjFile));
+ CHKiRet(module.Load(pObjFile, 0));
/* NOW, we must find it or we have a problem... */
CHKiRet(FindObjInfo(pStr, &pObjInfo));
}
diff --git a/runtime/parser.c b/runtime/parser.c
index b385c54b..14ccb49a 100644
--- a/runtime/parser.c
+++ b/runtime/parser.c
@@ -496,7 +496,7 @@ ParseMsg(msg_t *pMsg)
* will cause it to happen. After that, access to the unsanitized message is no
* loger possible.
*/
- pParserList = ruleset.GetParserList(pMsg);
+ pParserList = ruleset.GetParserList(ourConf, pMsg);
if(pParserList == NULL) {
pParserList = pDfltParsLst;
}
@@ -695,12 +695,12 @@ BEGINObjClassInit(parser, 1, OBJ_IS_CORE_MODULE) /* class, version */
CHKiRet(objUse(datetime, CORE_COMPONENT));
CHKiRet(objUse(ruleset, CORE_COMPONENT));
- CHKiRet(regCfSysLineHdlr((uchar *)"controlcharacterescapeprefix", 0, eCmdHdlrGetChar, NULL, &cCCEscapeChar, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"droptrailinglfonreception", 0, eCmdHdlrBinary, NULL, &bDropTrailingLF, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscapeCCOnRcv, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"escape8bitcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscape8BitChars, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactertab", 0, eCmdHdlrBinary, NULL, &bEscapeTab, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"controlcharacterescapeprefix", 0, eCmdHdlrGetChar, NULL, &cCCEscapeChar, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"droptrailinglfonreception", 0, eCmdHdlrBinary, NULL, &bDropTrailingLF, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscapeCCOnRcv, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"escape8bitcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscape8BitChars, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactertab", 0, eCmdHdlrBinary, NULL, &bEscapeTab, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjGlobal));
InitParserList(&pParsLstRoot);
InitParserList(&pDfltParsLst);
diff --git a/runtime/rsconf.c b/runtime/rsconf.c
new file mode 100644
index 00000000..45822f19
--- /dev/null
+++ b/runtime/rsconf.c
@@ -0,0 +1,1003 @@
+/* rsconf.c - the rsyslog configuration system.
+ *
+ * Module begun 2011-04-19 by Rainer Gerhards
+ *
+ * Copyright 2011 by Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <grp.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "rsyslog.h"
+#include "obj.h"
+#include "srUtils.h"
+#include "ruleset.h"
+#include "modules.h"
+#include "conf.h"
+#include "queue.h"
+#include "rsconf.h"
+#include "cfsysline.h"
+#include "errmsg.h"
+#include "action.h"
+#include "glbl.h"
+#include "unicode-helper.h"
+#include "omshell.h"
+#include "omusrmsg.h"
+#include "omfwd.h"
+#include "omfile.h"
+#include "ompipe.h"
+#include "omdiscard.h"
+#include "pmrfc5424.h"
+#include "pmrfc3164.h"
+#include "smfile.h"
+#include "smtradfile.h"
+#include "smfwd.h"
+#include "smtradfwd.h"
+#include "parser.h"
+#include "outchannel.h"
+#include "threads.h"
+#include "dirty.h"
+
+/* static data */
+DEFobjStaticHelpers
+DEFobjCurrIf(ruleset)
+DEFobjCurrIf(module)
+DEFobjCurrIf(conf)
+DEFobjCurrIf(errmsg)
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(parser)
+
+/* exported static data */
+rsconf_t *runConf = NULL;/* the currently running config */
+rsconf_t *loadConf = NULL;/* the config currently being loaded (no concurrent config load supported!) */
+
+/* hardcoded standard templates (used for defaults) */
+static uchar template_DebugFormat[] = "\"Debug line with all properties:\nFROMHOST: '%FROMHOST%', fromhost-ip: '%fromhost-ip%', HOSTNAME: '%HOSTNAME%', PRI: %PRI%,\nsyslogtag '%syslogtag%', programname: '%programname%', APP-NAME: '%APP-NAME%', PROCID: '%PROCID%', MSGID: '%MSGID%',\nTIMESTAMP: '%TIMESTAMP%', STRUCTURED-DATA: '%STRUCTURED-DATA%',\nmsg: '%msg%'\nescaped msg: '%msg:::drop-cc%'\ninputname: %inputname% rawmsg: '%rawmsg%'\n\n\"";
+static uchar template_SyslogProtocol23Format[] = "\"<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME% %APP-NAME% %PROCID% %MSGID% %STRUCTURED-DATA% %msg%\n\"";
+static uchar template_TraditionalFileFormat[] = "=RSYSLOG_TraditionalFileFormat";
+static uchar template_FileFormat[] = "=RSYSLOG_FileFormat";
+static uchar template_ForwardFormat[] = "=RSYSLOG_ForwardFormat";
+static uchar template_TraditionalForwardFormat[] = "=RSYSLOG_TraditionalForwardFormat";
+static uchar template_WallFmt[] = "\"\r\n\7Message from syslogd@%HOSTNAME% at %timegenerated% ...\r\n %syslogtag%%msg%\n\r\"";
+static uchar template_StdUsrMsgFmt[] = "\" %syslogtag%%msg%\n\r\"";
+static uchar template_StdDBFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-mysql%', '%timegenerated:::date-mysql%', %iut%, '%syslogtag%')\",SQL";
+static uchar template_StdPgSQLFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-pgsql%', '%timegenerated:::date-pgsql%', %iut%, '%syslogtag%')\",STDSQL";
+static uchar template_spoofadr[] = "\"%fromhost-ip%\"";
+/* end templates */
+
+
+/* Standard-Constructor
+ */
+BEGINobjConstruct(rsconf) /* be sure to specify the object type also in END macro! */
+ pThis->globals.bDebugPrintTemplateList = 1;
+ pThis->globals.bDebugPrintModuleList = 1;
+ pThis->globals.bDebugPrintCfSysLineHandlerList = 1;
+ pThis->globals.bLogStatusMsgs = DFLT_bLogStatusMsgs;
+ pThis->globals.bErrMsgToStderr = 1;
+ pThis->templates.root = NULL;
+ pThis->templates.last = NULL;
+ pThis->templates.lastStatic = NULL;
+ pThis->actions.nbrActions = 0;
+ CHKiRet(llInit(&pThis->rulesets.llRulesets, rulesetDestructForLinkedList,
+ rulesetKeyDestruct, strcasecmp));
+ /* queue params */
+ pThis->globals.mainQ.iMainMsgQueueSize = 10000;
+ pThis->globals.mainQ.iMainMsgQHighWtrMark = 8000;
+ pThis->globals.mainQ.iMainMsgQLowWtrMark = 2000;
+ pThis->globals.mainQ.iMainMsgQDiscardMark = 9800;
+ pThis->globals.mainQ.iMainMsgQDiscardSeverity = 8;
+ pThis->globals.mainQ.iMainMsgQueueNumWorkers = 1;
+ pThis->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
+ pThis->globals.mainQ.pszMainMsgQFName = NULL;
+ pThis->globals.mainQ.iMainMsgQueMaxFileSize = 1024*1024;
+ pThis->globals.mainQ.iMainMsgQPersistUpdCnt = 0;
+ pThis->globals.mainQ.bMainMsgQSyncQeueFiles = 0;
+ pThis->globals.mainQ.iMainMsgQtoQShutdown = 1500;
+ pThis->globals.mainQ.iMainMsgQtoActShutdown = 1000;
+ pThis->globals.mainQ.iMainMsgQtoEnq = 2000;
+ pThis->globals.mainQ.iMainMsgQtoWrkShutdown = 60000;
+ pThis->globals.mainQ.iMainMsgQWrkMinMsgs = 100;
+ pThis->globals.mainQ.iMainMsgQDeqSlowdown = 0;
+ pThis->globals.mainQ.iMainMsgQueMaxDiskSpace = 0;
+ pThis->globals.mainQ.iMainMsgQueDeqBatchSize = 32;
+ pThis->globals.mainQ.bMainMsgQSaveOnShutdown = 1;
+ pThis->globals.mainQ.iMainMsgQueueDeqtWinFromHr = 0;
+ pThis->globals.mainQ.iMainMsgQueueDeqtWinToHr = 25;
+ /* end queue params */
+finalize_it:
+ENDobjConstruct(rsconf)
+
+
+/* ConstructionFinalizer
+ */
+rsRetVal rsconfConstructFinalize(rsconf_t __attribute__((unused)) *pThis)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, rsconf);
+ RETiRet;
+}
+
+
+/* destructor for the rsconf object */
+BEGINobjDestruct(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */
+CODESTARTobjDestruct(rsconf)
+ free(pThis->globals.mainQ.pszMainMsgQFName);
+ llDestroy(&(pThis->rulesets.llRulesets));
+ENDobjDestruct(rsconf)
+
+
+/* DebugPrint support for the rsconf object */
+BEGINobjDebugPrint(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */
+ cfgmodules_etry_t *modNode;
+
+ dbgprintf("configuration object %p\n", pThis);
+ dbgprintf("Global Settings:\n");
+ dbgprintf(" bDebugPrintTemplateList.............: %d\n",
+ pThis->globals.bDebugPrintTemplateList);
+ dbgprintf(" bDebugPrintModuleList : %d\n",
+ pThis->globals.bDebugPrintModuleList);
+ dbgprintf(" bDebugPrintCfSysLineHandlerList.....: %d\n",
+ pThis->globals.bDebugPrintCfSysLineHandlerList);
+ dbgprintf(" bLogStatusMsgs : %d\n",
+ pThis->globals.bLogStatusMsgs);
+ dbgprintf(" bErrMsgToStderr.....................: %d\n",
+ pThis->globals.bErrMsgToStderr);
+ dbgprintf(" drop Msgs with malicious PTR Record : %d\n",
+ glbl.GetDropMalPTRMsgs());
+ ruleset.DebugPrintAll(pThis);
+ dbgprintf("\n");
+ if(pThis->globals.bDebugPrintTemplateList)
+ tplPrintList(pThis);
+ if(pThis->globals.bDebugPrintModuleList)
+ module.PrintList();
+ if(pThis->globals.bDebugPrintCfSysLineHandlerList)
+ dbgPrintCfSysLineHandlers();
+ // TODO: The following code needs to be "streamlined", so far just moved over...
+ dbgprintf("Main queue size %d messages.\n", pThis->globals.mainQ.iMainMsgQueueSize);
+ dbgprintf("Main queue worker threads: %d, wThread shutdown: %d, Perists every %d updates.\n",
+ pThis->globals.mainQ.iMainMsgQueueNumWorkers,
+ pThis->globals.mainQ.iMainMsgQtoWrkShutdown, pThis->globals.mainQ.iMainMsgQPersistUpdCnt);
+ dbgprintf("Main queue timeouts: shutdown: %d, action completion shutdown: %d, enq: %d\n",
+ pThis->globals.mainQ.iMainMsgQtoQShutdown,
+ pThis->globals.mainQ.iMainMsgQtoActShutdown, pThis->globals.mainQ.iMainMsgQtoEnq);
+ dbgprintf("Main queue watermarks: high: %d, low: %d, discard: %d, discard-severity: %d\n",
+ pThis->globals.mainQ.iMainMsgQHighWtrMark, pThis->globals.mainQ.iMainMsgQLowWtrMark,
+ pThis->globals.mainQ.iMainMsgQDiscardMark, pThis->globals.mainQ.iMainMsgQDiscardSeverity);
+ dbgprintf("Main queue save on shutdown %d, max disk space allowed %lld\n",
+ pThis->globals.mainQ.bMainMsgQSaveOnShutdown, pThis->globals.mainQ.iMainMsgQueMaxDiskSpace);
+ /* TODO: add
+ iActionRetryCount = 0;
+ iActionRetryInterval = 30000;
+ static int iMainMsgQtoWrkMinMsgs = 100;
+ static int iMainMsgQbSaveOnShutdown = 1;
+ iMainMsgQueMaxDiskSpace = 0;
+ setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", 100);
+ setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", 1);
+ */
+ dbgprintf("Work Directory: '%s'.\n", glbl.GetWorkDir());
+ ochPrintList();
+ dbgprintf("Modules used in this configuration:\n");
+ for(modNode = pThis->modules.root ; modNode != NULL ; modNode = modNode->next) {
+ dbgprintf(" %s\n", module.GetName(modNode->pMod));
+ }
+CODESTARTobjDebugPrint(rsconf)
+ENDobjDebugPrint(rsconf)
+
+
+/* drop to specified group
+ * if something goes wrong, the function never returns
+ * Note that such an abort can cause damage to on-disk structures, so we should
+ * re-design the "interface" in the long term. -- rgerhards, 2008-11-26
+ */
+static void doDropPrivGid(int iGid)
+{
+ int res;
+ uchar szBuf[1024];
+
+ res = setgroups(0, NULL); /* remove all supplementary group IDs */
+ if(res) {
+ perror("could not remove supplemental group IDs");
+ exit(1);
+ }
+ DBGPRINTF("setgroups(0, NULL): %d\n", res);
+ res = setgid(iGid);
+ if(res) {
+ /* if we can not set the userid, this is fatal, so let's unconditionally abort */
+ perror("could not set requested group id");
+ exit(1);
+ }
+ DBGPRINTF("setgid(%d): %d\n", iGid, res);
+ snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's groupid changed to %d", iGid);
+ logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0);
+}
+
+
+/* drop to specified user
+ * if something goes wrong, the function never returns
+ * Note that such an abort can cause damage to on-disk structures, so we should
+ * re-design the "interface" in the long term. -- rgerhards, 2008-11-19
+ */
+static void doDropPrivUid(int iUid)
+{
+ int res;
+ uchar szBuf[1024];
+
+ res = setuid(iUid);
+ if(res) {
+ /* if we can not set the userid, this is fatal, so let's unconditionally abort */
+ perror("could not set requested userid");
+ exit(1);
+ }
+ DBGPRINTF("setuid(%d): %d\n", iUid, res);
+ snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's userid changed to %d", iUid);
+ logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0);
+}
+
+
+
+/* drop privileges. This will drop to the configured privileges, if
+ * set by the user. After this method has been executed, the previous
+ * privileges can no be re-gained.
+ */
+static inline rsRetVal
+dropPrivileges(rsconf_t *cnf)
+{
+ DEFiRet;
+
+ /* If instructed to do so, we now drop privileges. Note that this is not 100% secure,
+ * because outputs are already running at this time. However, we can implement
+ * dropping of privileges rather quickly and it will work in many cases. While it is not
+ * the ultimate solution, the current one is still much better than not being able to
+ * drop privileges at all. Doing it correctly, requires a change in architecture, which
+ * we should do over time. TODO -- rgerhards, 2008-11-19
+ */
+ if(cnf->globals.gidDropPriv != 0) {
+ doDropPrivGid(ourConf->globals.gidDropPriv);
+ DBGPRINTF("group privileges have been dropped to gid %u\n", (unsigned)
+ ourConf->globals.gidDropPriv);
+ }
+
+ if(cnf->globals.uidDropPriv != 0) {
+ doDropPrivUid(ourConf->globals.uidDropPriv);
+ DBGPRINTF("user privileges have been dropped to uid %u\n", (unsigned)
+ ourConf->globals.uidDropPriv);
+ }
+
+ RETiRet;
+}
+
+
+/* Actually run the input modules. This happens after privileges are dropped,
+ * if that is requested.
+ */
+static rsRetVal
+runInputModules(void)
+{
+ modInfo_t *pMod;
+ int bNeedsCancel;
+
+ BEGINfunc
+ pMod = module.GetNxtCnfType(runConf, NULL, eMOD_IN);
+ while(pMod != NULL) {
+ if(pMod->mod.im.bCanRun) {
+ /* activate here */
+ bNeedsCancel = (pMod->isCompatibleWithFeature(sFEATURENonCancelInputTermination) == RS_RET_OK) ?
+ 0 : 1;
+ thrdCreate(pMod->mod.im.runInput, pMod->mod.im.afterRun, bNeedsCancel);
+ }
+ pMod = module.GetNxtCnfType(runConf, pMod, eMOD_IN);
+ }
+
+ ENDfunc
+ return RS_RET_OK; /* intentional: we do not care about module errors */
+}
+
+
+/* Make the input modules check if they are ready to start.
+ */
+static rsRetVal
+startInputModules(void)
+{
+ DEFiRet;
+ modInfo_t *pMod;
+
+ pMod = module.GetNxtCnfType(runConf, NULL, eMOD_IN);
+ while(pMod != NULL) {
+ iRet = pMod->mod.im.willRun();
+ pMod->mod.im.bCanRun = (iRet == RS_RET_OK);
+ if(!pMod->mod.im.bCanRun) {
+ DBGPRINTF("module %lx will not run, iRet %d\n", (unsigned long) pMod, iRet);
+ }
+ pMod = module.GetNxtCnfType(runConf, pMod, eMOD_IN);
+ }
+
+ ENDfunc
+ return RS_RET_OK; /* intentional: we do not care about module errors */
+}
+
+
+/* activate the main queue */
+static inline rsRetVal
+activateMainQueue()
+{
+ DEFiRet;
+ /* create message queue */
+ CHKiRet_Hdlr(createMainQueue(&pMsgQueue, UCHAR_CONSTANT("main Q"))) {
+ /* no queue is fatal, we need to give up in that case... */
+ fprintf(stderr, "fatal error %d: could not create message queue - rsyslogd can not run!\n", iRet);
+ FINALIZE;
+ }
+
+ bHaveMainQueue = (ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1;
+ DBGPRINTF("Main processing queue is initialized and running\n");
+finalize_it:
+ RETiRet;
+}
+
+
+/* Activate an already-loaded configuration. The configuration will become
+ * the new running conf (if successful). Note that in theory this method may
+ * be called when there already is a running conf. In practice, the current
+ * version of rsyslog does not support this. Future versions probably will.
+ * Begun 2011-04-20, rgerhards
+ */
+rsRetVal
+activate(rsconf_t *cnf)
+{
+ DEFiRet;
+
+ /* at this point, we "switch" over to the running conf */
+ runConf = cnf;
+# if 0 /* currently the DAG is not supported -- code missing! */
+ /* TODO: re-enable this functionality some time later! */
+ /* check if we need to generate a config DAG and, if so, do that */
+ if(ourConf->globals.pszConfDAGFile != NULL)
+ generateConfigDAG(ourConf->globals.pszConfDAGFile);
+# endif
+
+ /* the output part and the queue is now ready to run. So it is a good time
+ * to initialize the inputs. Please note that the net code above should be
+ * shuffled to down here once we have everything in input modules.
+ * rgerhards, 2007-12-14
+ * NOTE: as of 2009-06-29, the input modules are initialized, but not yet run.
+ * Keep in mind. though, that the outputs already run if the queue was
+ * persisted to disk. -- rgerhards
+ */
+ startInputModules();
+
+ CHKiRet(dropPrivileges(cnf));
+
+ CHKiRet(activateMainQueue());
+ /* finally let the inputs run... */
+ runInputModules();
+
+ dbgprintf("configuration %p activated\n", cnf);
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* -------------------- some legacy config handlers --------------------
+ * TODO: move to conf.c?
+ */
+
+/* legacy config system: set the action resume interval */
+static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int iNewVal)
+{
+ return actionSetGlobalResumeInterval(iNewVal);
+}
+
+
+/* this method is needed to shuffle the current conf object down to the
+ * IncludeConfig handler.
+ */
+static rsRetVal
+doIncludeLine(void *pVal, uchar *pNewVal)
+{
+ DEFiRet;
+ iRet = conf.doIncludeLine(ourConf, pVal, pNewVal);
+ free(pNewVal);
+ RETiRet;
+}
+
+
+/* set the processes umask (upon configuration request) */
+static rsRetVal
+setUmask(void __attribute__((unused)) *pVal, int iUmask)
+{
+#warning this *really* needs to be done differently!
+ umask(iUmask);
+ DBGPRINTF("umask set to 0%3.3o.\n", iUmask);
+
+ return RS_RET_OK;
+}
+
+
+/* set the maximum message size */
+static rsRetVal setMaxMsgSize(void __attribute__((unused)) *pVal, long iNewVal)
+{
+ return glbl.SetMaxLine(iNewVal);
+}
+
+
+/* Switch the default ruleset (that, what servcies bind to if nothing specific
+ * is specified).
+ * rgerhards, 2009-06-12
+ */
+static rsRetVal
+setDefaultRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
+{
+ DEFiRet;
+
+ CHKiRet(ruleset.SetDefaultRuleset(ourConf, pszName));
+
+finalize_it:
+ free(pszName); /* no longer needed */
+ RETiRet;
+}
+
+
+/* Switch to either an already existing rule set or start a new one. The
+ * named rule set becomes the new "current" rule set (what means that new
+ * actions are added to it).
+ * rgerhards, 2009-06-12
+ */
+static rsRetVal
+setCurrRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
+{
+ ruleset_t *pRuleset;
+ rsRetVal localRet;
+ DEFiRet;
+
+ localRet = ruleset.SetCurrRuleset(ourConf, pszName);
+
+ if(localRet == RS_RET_NOT_FOUND) {
+ DBGPRINTF("begin new current rule set '%s'\n", pszName);
+ CHKiRet(ruleset.Construct(&pRuleset));
+ CHKiRet(ruleset.SetName(ourConf, pRuleset, pszName));
+ CHKiRet(ruleset.ConstructFinalize(ourConf, pRuleset));
+ } else {
+ ABORT_FINALIZE(localRet);
+ }
+
+finalize_it:
+ free(pszName); /* no longer needed */
+ RETiRet;
+}
+
+
+/* set the main message queue mode
+ * rgerhards, 2008-01-03
+ */
+static rsRetVal setMainMsgQueType(void __attribute__((unused)) *pVal, uchar *pszType)
+{
+ DEFiRet;
+
+ if (!strcasecmp((char *) pszType, "fixedarray")) {
+ loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
+ DBGPRINTF("main message queue type set to FIXED_ARRAY\n");
+ } else if (!strcasecmp((char *) pszType, "linkedlist")) {
+ loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_LINKEDLIST;
+ DBGPRINTF("main message queue type set to LINKEDLIST\n");
+ } else if (!strcasecmp((char *) pszType, "disk")) {
+ loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_DISK;
+ DBGPRINTF("main message queue type set to DISK\n");
+ } else if (!strcasecmp((char *) pszType, "direct")) {
+ loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_DIRECT;
+ DBGPRINTF("main message queue type set to DIRECT (no queueing at all)\n");
+ } else {
+ errmsg.LogError(0, RS_RET_INVALID_PARAMS, "unknown mainmessagequeuetype parameter: %s", (char *) pszType);
+ iRet = RS_RET_INVALID_PARAMS;
+ }
+ free(pszType); /* no longer needed */
+
+ RETiRet;
+}
+
+
+/* -------------------- end legacy config handlers -------------------- */
+
+
+/* set the processes max number ob files (upon configuration request)
+ * 2009-04-14 rgerhards
+ */
+static rsRetVal setMaxFiles(void __attribute__((unused)) *pVal, int iFiles)
+{
+// TODO this must use a local var, then carry out action during activate!
+ struct rlimit maxFiles;
+ char errStr[1024];
+ DEFiRet;
+
+ maxFiles.rlim_cur = iFiles;
+ maxFiles.rlim_max = iFiles;
+
+ if(setrlimit(RLIMIT_NOFILE, &maxFiles) < 0) {
+ /* NOTE: under valgrind, we seem to be unable to extend the size! */
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ errmsg.LogError(0, RS_RET_ERR_RLIM_NOFILE, "could not set process file limit to %d: %s [kernel max %ld]",
+ iFiles, errStr, (long) maxFiles.rlim_max);
+ ABORT_FINALIZE(RS_RET_ERR_RLIM_NOFILE);
+ }
+#ifdef USE_UNLIMITED_SELECT
+ glbl.SetFdSetSize(howmany(iFiles, __NFDBITS) * sizeof (fd_mask));
+#endif
+ DBGPRINTF("Max number of files set to %d [kernel max %ld].\n", iFiles, (long) maxFiles.rlim_max);
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* legac config system: reset config variables to default values. */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ loadConf->globals.bLogStatusMsgs = DFLT_bLogStatusMsgs;
+ loadConf->globals.bDebugPrintTemplateList = 1;
+ loadConf->globals.bDebugPrintCfSysLineHandlerList = 1;
+ loadConf->globals.bDebugPrintModuleList = 1;
+ loadConf->globals.bAbortOnUncleanConfig = 0;
+ loadConf->globals.bReduceRepeatMsgs = 0;
+ free(loadConf->globals.mainQ.pszMainMsgQFName);
+ loadConf->globals.mainQ.pszMainMsgQFName = NULL;
+ loadConf->globals.mainQ.iMainMsgQueueSize = 10000;
+ loadConf->globals.mainQ.iMainMsgQHighWtrMark = 8000;
+ loadConf->globals.mainQ.iMainMsgQLowWtrMark = 2000;
+ loadConf->globals.mainQ.iMainMsgQDiscardMark = 9800;
+ loadConf->globals.mainQ.iMainMsgQDiscardSeverity = 8;
+ loadConf->globals.mainQ.iMainMsgQueMaxFileSize = 1024 * 1024;
+ loadConf->globals.mainQ.iMainMsgQueueNumWorkers = 1;
+ loadConf->globals.mainQ.iMainMsgQPersistUpdCnt = 0;
+ loadConf->globals.mainQ.bMainMsgQSyncQeueFiles = 0;
+ loadConf->globals.mainQ.iMainMsgQtoQShutdown = 1500;
+ loadConf->globals.mainQ.iMainMsgQtoActShutdown = 1000;
+ loadConf->globals.mainQ.iMainMsgQtoEnq = 2000;
+ loadConf->globals.mainQ.iMainMsgQtoWrkShutdown = 60000;
+ loadConf->globals.mainQ.iMainMsgQWrkMinMsgs = 100;
+ loadConf->globals.mainQ.iMainMsgQDeqSlowdown = 0;
+ loadConf->globals.mainQ.bMainMsgQSaveOnShutdown = 1;
+ loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
+ loadConf->globals.mainQ.iMainMsgQueMaxDiskSpace = 0;
+ loadConf->globals.mainQ.iMainMsgQueDeqBatchSize = 32;
+
+ return RS_RET_OK;
+}
+
+
+/* legacy config system: set the action resume interval */
+static rsRetVal
+setModDir(void __attribute__((unused)) *pVal, uchar* pszNewVal)
+{
+ DEFiRet;
+ iRet = module.SetModDir(pszNewVal);
+ free(pszNewVal);
+ RETiRet;
+}
+
+
+/* "load" a build in module and register it for the current load config */
+static rsRetVal
+regBuildInModule(rsRetVal (*modInit)(), uchar *name, void *pModHdlr)
+{
+ modInfo_t *pMod;
+ DEFiRet;
+ CHKiRet(module.doModInit(modInit, name, pModHdlr, &pMod));
+ addModToCnfList(pMod);
+finalize_it:
+ RETiRet;
+}
+
+
+/* load build-in modules
+ * very first version begun on 2007-07-23 by rgerhards
+ */
+static rsRetVal
+loadBuildInModules()
+{
+ DEFiRet;
+
+ CHKiRet(regBuildInModule(modInitFile, UCHAR_CONSTANT("builtin-file"), NULL));
+ CHKiRet(regBuildInModule(modInitPipe, UCHAR_CONSTANT("builtin-pipe"), NULL));
+ CHKiRet(regBuildInModule(modInitShell, UCHAR_CONSTANT("builtin-shell"), NULL));
+ CHKiRet(regBuildInModule(modInitDiscard, UCHAR_CONSTANT("builtin-discard"), NULL));
+# ifdef SYSLOG_INET
+ CHKiRet(regBuildInModule(modInitFwd, UCHAR_CONSTANT("builtin-fwd"), NULL));
+# endif
+
+ /* dirty, but this must be for the time being: the usrmsg module must always be
+ * loaded as last module. This is because it processes any type of action selector.
+ * If we load it before other modules, these others will never have a chance of
+ * working with the config file. We may change that implementation so that a user name
+ * must start with an alnum, that would definitely help (but would it break backwards
+ * compatibility?). * rgerhards, 2007-07-23
+ * User names now must begin with:
+ * [a-zA-Z0-9_.]
+ */
+ CHKiRet(regBuildInModule(modInitUsrMsg, (uchar*) "builtin-usrmsg", NULL));
+
+ /* load build-in parser modules */
+ CHKiRet(regBuildInModule(modInitpmrfc5424, UCHAR_CONSTANT("builtin-pmrfc5424"), NULL));
+ CHKiRet(regBuildInModule(modInitpmrfc3164, UCHAR_CONSTANT("builtin-pmrfc3164"), NULL));
+
+ /* and set default parser modules. Order is *very* important, legacy
+ * (3164) parser needs to go last! */
+ CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc5424")));
+ CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc3164")));
+
+ /* load build-in strgen modules */
+ CHKiRet(regBuildInModule(modInitsmfile, UCHAR_CONSTANT("builtin-smfile"), NULL));
+ CHKiRet(regBuildInModule(modInitsmtradfile, UCHAR_CONSTANT("builtin-smtradfile"), NULL));
+ CHKiRet(regBuildInModule(modInitsmfwd, UCHAR_CONSTANT("builtin-smfwd"), NULL));
+ CHKiRet(regBuildInModule(modInitsmtradfwd, UCHAR_CONSTANT("builtin-smtradfwd"), NULL));
+
+finalize_it:
+ if(iRet != RS_RET_OK) {
+ /* we need to do fprintf, as we do not yet have an error reporting system
+ * in place.
+ */
+ fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n",
+ iRet);
+ }
+ RETiRet;
+}
+
+
+/* intialize the legacy config system */
+static inline rsRetVal
+initLegacyConf(void)
+{
+ DEFiRet;
+ uchar *pTmp;
+ ruleset_t *pRuleset;
+
+ DBGPRINTF("doing legacy config system init\n");
+ /* construct the default ruleset */
+ ruleset.Construct(&pRuleset);
+ ruleset.SetName(loadConf, pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset"));
+ ruleset.ConstructFinalize(loadConf, pRuleset);
+
+ /* now register config handlers */
+ CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrGoneAway,
+ NULL, NULL, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"logrsyslogstatusmessages", 0, eCmdHdlrBinary,
+ NULL, &loadConf->globals.bLogStatusMsgs, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary,
+ NULL, &loadConf->globals.bErrMsgToStderr, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"abortonuncleanconfig", 0, eCmdHdlrBinary,
+ NULL, &loadConf->globals.bAbortOnUncleanConfig, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgreduction", 0, eCmdHdlrBinary,
+ NULL, &loadConf->globals.bReduceRepeatMsgs, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"debugprinttemplatelist", 0, eCmdHdlrBinary,
+ NULL, &(loadConf->globals.bDebugPrintTemplateList), NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"debugprintmodulelist", 0, eCmdHdlrBinary,
+ NULL, &(loadConf->globals.bDebugPrintModuleList), NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"debugprintcfsyslinehandlerlist", 0, eCmdHdlrBinary,
+ NULL, &(loadConf->globals.bDebugPrintCfSysLineHandlerList), NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouser", 0, eCmdHdlrUID,
+ NULL, &loadConf->globals.uidDropPriv, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouserid", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.uidDropPriv, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroup", 0, eCmdHdlrGID,
+ NULL, &loadConf->globals.gidDropPriv, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroupid", 0, eCmdHdlrGID,
+ NULL, &loadConf->globals.gidDropPriv, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"generateconfiggraph", 0, eCmdHdlrGetWord,
+ NULL, &loadConf->globals.pszConfDAGFile, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"maxopenfiles", 0, eCmdHdlrInt,
+ setMaxFiles, NULL, NULL, eConfObjGlobal));
+
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt,
+ setActionResumeInterval, NULL, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler,
+ conf.doModLoad, NULL, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler,
+ doIncludeLine, NULL, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode,
+ setUmask, NULL, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize,
+ setMaxMsgSize, NULL, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord,
+ setDefaultRuleset, NULL, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord,
+ setCurrRuleset, NULL, NULL, eConfObjGlobal));
+
+ /* handler for "larger" config statements (tie into legacy conf system) */
+ CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler,
+ conf.doNameLine, (void*)DIR_TEMPLATE, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler,
+ conf.doNameLine, (void*)DIR_OUTCHANNEL, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"allowedsender", 0, eCmdHdlrCustomHandler,
+ conf.doNameLine, (void*)DIR_ALLOWEDSENDER, NULL, eConfObjGlobal));
+
+ /* the following are parameters for the main message queue. I have the
+ * strong feeling that this needs to go to a different space, but that
+ * feeling may be wrong - we'll see how things evolve.
+ * rgerhards, 2011-04-21
+ */
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord,
+ NULL, &loadConf->globals.mainQ.pszMainMsgQFName, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueueSize, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQHighWtrMark, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuelowwatermark", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQLowWtrMark, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardmark", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQDiscardMark, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardseverity", 0, eCmdHdlrSeverity,
+ NULL, &loadConf->globals.mainQ.iMainMsgQDiscardSeverity, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuecheckpointinterval", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQPersistUpdCnt, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesyncqueuefiles", 0, eCmdHdlrBinary,
+ NULL, &loadConf->globals.mainQ.bMainMsgQSyncQeueFiles, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetype", 0, eCmdHdlrGetWord,
+ setMainMsgQueType, NULL, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreads", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueueNumWorkers, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutshutdown", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQtoQShutdown, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutactioncompletion", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQtoActShutdown, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutenqueue", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQtoEnq, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkertimeoutthreadshutdown", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQtoWrkShutdown, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeueslowdown", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQDeqSlowdown, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreadminimummessages", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQWrkMinMsgs, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxfilesize", 0, eCmdHdlrSize,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueMaxFileSize, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuebatchsize", 0, eCmdHdlrSize,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueDeqBatchSize, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxdiskspace", 0, eCmdHdlrSize,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueMaxDiskSpace, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesaveonshutdown", 0, eCmdHdlrBinary,
+ NULL, &loadConf->globals.mainQ.bMainMsgQSaveOnShutdown, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimebegin", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueueDeqtWinFromHr, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimeend", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueueDeqtWinToHr, NULL, eConfObjGlobal));
+ /* moddir is a bit hard problem -- because it actually needs to
+ * modify a setting that is specific to module.c. The important point
+ * is that this action MUST actually be carried out during config load,
+ * because we must load modules in order to get their config extensions
+ * (no way around).
+ * TODO: think about a clean solution
+ */
+ CHKiRet(regCfSysLineHdlr((uchar *)"moddir", 0, eCmdHdlrGetWord,
+ setModDir, NULL, NULL, eConfObjGlobal));
+
+ /* finally, the reset handler */
+ CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
+ resetConfigVariables, NULL, NULL, eConfObjGlobal));
+
+ /* initialize the build-in templates */
+ pTmp = template_DebugFormat;
+ tplAddLine(ourConf, "RSYSLOG_DebugFormat", &pTmp);
+ pTmp = template_SyslogProtocol23Format;
+ tplAddLine(ourConf, "RSYSLOG_SyslogProtocol23Format", &pTmp);
+ pTmp = template_FileFormat; /* new format for files with high-precision stamp */
+ tplAddLine(ourConf, "RSYSLOG_FileFormat", &pTmp);
+ pTmp = template_TraditionalFileFormat;
+ tplAddLine(ourConf, "RSYSLOG_TraditionalFileFormat", &pTmp);
+ pTmp = template_WallFmt;
+ tplAddLine(ourConf, " WallFmt", &pTmp);
+ pTmp = template_ForwardFormat;
+ tplAddLine(ourConf, "RSYSLOG_ForwardFormat", &pTmp);
+ pTmp = template_TraditionalForwardFormat;
+ tplAddLine(ourConf, "RSYSLOG_TraditionalForwardFormat", &pTmp);
+ pTmp = template_StdUsrMsgFmt;
+ tplAddLine(ourConf, " StdUsrMsgFmt", &pTmp);
+ pTmp = template_StdDBFmt;
+ tplAddLine(ourConf, " StdDBFmt", &pTmp);
+ pTmp = template_StdPgSQLFmt;
+ tplAddLine(ourConf, " StdPgSQLFmt", &pTmp);
+ pTmp = template_spoofadr;
+ tplLastStaticInit(ourConf, tplAddLine(ourConf, "RSYSLOG_omudpspoofDfltSourceTpl", &pTmp));
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* validate the current configuration, generate error messages, do
+ * optimizations, etc, etc,...
+ */
+static inline rsRetVal
+validateConf(void)
+{
+ DEFiRet;
+
+ /* some checks */
+ if(ourConf->globals.mainQ.iMainMsgQueueNumWorkers < 1) {
+ errmsg.LogError(0, NO_ERRCODE, "$MainMsgQueueNumWorkers must be at least 1! Set to 1.\n");
+ ourConf->globals.mainQ.iMainMsgQueueNumWorkers = 1;
+ }
+
+ if(ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DISK) {
+ errno = 0; /* for logerror! */
+ if(glbl.GetWorkDir() == NULL) {
+ errmsg.LogError(0, NO_ERRCODE, "No $WorkDirectory specified - can not run main message queue in 'disk' mode. "
+ "Using 'FixedArray' instead.\n");
+ ourConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
+ }
+ if(ourConf->globals.mainQ.pszMainMsgQFName == NULL) {
+ errmsg.LogError(0, NO_ERRCODE, "No $MainMsgQueueFileName specified - can not run main message queue in "
+ "'disk' mode. Using 'FixedArray' instead.\n");
+ ourConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
+ }
+ }
+ RETiRet;
+}
+
+
+/* Load a configuration. This will do all necessary steps to create
+ * the in-memory representation of the configuration, including support
+ * for multiple configuration languages.
+ * Note that to support the legacy language we must provide some global
+ * object that holds the currently-being-loaded config ptr.
+ * Begun 2011-04-20, rgerhards
+ */
+rsRetVal
+load(rsconf_t **cnf, uchar *confFile)
+{
+ rsRetVal localRet;
+ int iNbrActions;
+ int bHadConfigErr = 0;
+ char cbuf[BUFSIZ];
+ DEFiRet;
+
+ CHKiRet(rsconfConstruct(&loadConf));
+ourConf = loadConf; // TODO: remove, once ourConf is gone!
+
+ CHKiRet(loadBuildInModules());
+ CHKiRet(initLegacyConf());
+
+ /* open the configuration file */
+ localRet = conf.processConfFile(loadConf, confFile);
+ CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions));
+
+ if(localRet != RS_RET_OK) {
+ errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", confFile);
+ bHadConfigErr = 1;
+ } else if(iNbrActions == 0) {
+ errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no active actions configured. Inputs will "
+ "run, but no output whatsoever is created.");
+ bHadConfigErr = 1;
+ }
+
+ if((localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) || iNbrActions == 0) {
+
+ /* rgerhards: this code is executed to set defaults when the
+ * config file could not be opened. We might think about
+ * abandoning the run in this case - but this, too, is not
+ * very clever... So we stick with what we have.
+ * We ignore any errors while doing this - we would be lost anyhow...
+ */
+ errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!");
+
+ /* note: we previously used _POSIY_TTY_NAME_MAX+1, but this turned out to be
+ * too low on linux... :-S -- rgerhards, 2008-07-28
+ */
+ char szTTYNameBuf[128];
+ rule_t *pRule = NULL; /* initialization to NULL is *vitally* important! */
+ conf.cfline(loadConf, UCHAR_CONSTANT("*.ERR\t" _PATH_CONSOLE), &pRule);
+ conf.cfline(loadConf, UCHAR_CONSTANT("syslog.*\t" _PATH_CONSOLE), &pRule);
+ conf.cfline(loadConf, UCHAR_CONSTANT("*.PANIC\t*"), &pRule);
+ conf.cfline(loadConf, UCHAR_CONSTANT("syslog.*\troot"), &pRule);
+ if(ttyname_r(0, szTTYNameBuf, sizeof(szTTYNameBuf)) == 0) {
+ snprintf(cbuf,sizeof(cbuf), "*.*\t%s", szTTYNameBuf);
+ conf.cfline(loadConf, (uchar*)cbuf, &pRule);
+ } else {
+ DBGPRINTF("error %d obtaining controlling terminal, not using that emergency rule\n", errno);
+ }
+ ruleset.AddRule(loadConf, ruleset.GetCurrent(loadConf), &pRule);
+ }
+
+ CHKiRet(validateConf());
+
+ /* we are done checking the config - now validate if we should actually run or not.
+ * If not, terminate. -- rgerhards, 2008-07-25
+ * TODO: iConfigVerify -- should it be pulled from the config, or leave as is (option)?
+ */
+ if(iConfigVerify) {
+ ABORT_FINALIZE(RS_RET_VALIDATION_RUN);
+ }
+
+ /* all OK, pass loaded conf to caller */
+ *cnf = loadConf;
+// TODO: enable this once all config code is moved to here! loadConf = NULL;
+
+ dbgprintf("rsyslog finished loading initial config %p\n", loadConf);
+ rsconfDebugPrint(loadConf);
+
+ /* return warning state if we had some acceptable problems */
+ if(bHadConfigErr)
+ iRet = RS_RET_NONFATAL_CONFIG_ERR;
+finalize_it:
+ RETiRet;
+}
+
+
+/* queryInterface function
+ */
+BEGINobjQueryInterface(rsconf)
+CODESTARTobjQueryInterface(rsconf)
+ if(pIf->ifVersion != rsconfCURR_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 = rsconfConstruct;
+ pIf->ConstructFinalize = rsconfConstructFinalize;
+ pIf->Destruct = rsconfDestruct;
+ pIf->DebugPrint = rsconfDebugPrint;
+ pIf->Load = load;
+ pIf->Activate = activate;
+finalize_it:
+ENDobjQueryInterface(rsconf)
+
+
+/* Initialize the rsconf class. Must be called as the very first method
+ * before anything else is called inside this class.
+ */
+BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */
+ /* request objects we use */
+ CHKiRet(objUse(ruleset, CORE_COMPONENT));
+ CHKiRet(objUse(module, CORE_COMPONENT));
+ CHKiRet(objUse(conf, CORE_COMPONENT));
+ CHKiRet(objUse(errmsg, CORE_COMPONENT));
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(parser, CORE_COMPONENT));
+
+ /* now set our own handlers */
+ OBJSetMethodHandler(objMethod_DEBUGPRINT, rsconfDebugPrint);
+ OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, rsconfConstructFinalize);
+ENDObjClassInit(rsconf)
+
+
+/* De-initialize the rsconf class.
+ */
+BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */
+ objRelease(ruleset, CORE_COMPONENT);
+ objRelease(module, CORE_COMPONENT);
+ objRelease(conf, CORE_COMPONENT);
+ objRelease(errmsg, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(parser, CORE_COMPONENT);
+ENDObjClassExit(rsconf)
+
+/* vi:set ai:
+ */
diff --git a/runtime/rsconf.h b/runtime/rsconf.h
new file mode 100644
index 00000000..63754e6f
--- /dev/null
+++ b/runtime/rsconf.h
@@ -0,0 +1,177 @@
+/* The rsconf object. It models a complete rsyslog configuration.
+ *
+ * Copyright 2011 Rainer Gerhards and Adiscon GmbH.
+ *
+ * This file is part of the rsyslog runtime library.
+ *
+ * The rsyslog runtime library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The rsyslog runtime library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the rsyslog runtime library. If not, see <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_RSCONF_H
+#define INCLUDED_RSCONF_H
+
+#include "linkedlist.h"
+#include "queue.h"
+
+/* --- configuration objects (the plan is to have ALL upper layers in this file) --- */
+
+/* queue config parameters. TODO: move to queue.c? */
+struct queuecnf_s {
+ int iMainMsgQueueSize; /* size of the main message queue above */
+ int iMainMsgQHighWtrMark; /* high water mark for disk-assisted queues */
+ int iMainMsgQLowWtrMark; /* low water mark for disk-assisted queues */
+ int iMainMsgQDiscardMark; /* begin to discard messages */
+ int iMainMsgQDiscardSeverity; /* by default, discard nothing to prevent unintentional loss */
+ int iMainMsgQueueNumWorkers; /* number of worker threads for the mm queue above */
+ queueType_t MainMsgQueType; /* type of the main message queue above */
+ uchar *pszMainMsgQFName; /* prefix for the main message queue file */
+ int64 iMainMsgQueMaxFileSize;
+ int iMainMsgQPersistUpdCnt; /* persist queue info every n updates */
+ int bMainMsgQSyncQeueFiles; /* sync queue files on every write? */
+ int iMainMsgQtoQShutdown; /* queue shutdown (ms) */
+ int iMainMsgQtoActShutdown; /* action shutdown (in phase 2) */
+ int iMainMsgQtoEnq; /* timeout for queue enque */
+ int iMainMsgQtoWrkShutdown; /* timeout for worker thread shutdown */
+ int iMainMsgQWrkMinMsgs; /* minimum messages per worker needed to start a new one */
+ int iMainMsgQDeqSlowdown; /* dequeue slowdown (simple rate limiting) */
+ int64 iMainMsgQueMaxDiskSpace; /* max disk space allocated 0 ==> unlimited */
+ int64 iMainMsgQueDeqBatchSize; /* dequeue batch size */
+ int bMainMsgQSaveOnShutdown; /* save queue on shutdown (when DA enabled)? */
+ int iMainMsgQueueDeqtWinFromHr; /* hour begin of time frame when queue is to be dequeued */
+ int iMainMsgQueueDeqtWinToHr; /* hour begin of time frame when queue is to be dequeued */
+};
+
+/* globals are data items that are really global, and can be set only
+ * once (at least in theory, because the legacy system permits them to
+ * be re-set as often as the user likes).
+ */
+struct globals_s {
+ int bDebugPrintTemplateList;
+ int bDebugPrintModuleList;
+ int bDebugPrintCfSysLineHandlerList;
+ int bLogStatusMsgs; /* log rsyslog start/stop/HUP messages? */
+ int bErrMsgToStderr; /* print error messages to stderr
+ (in addition to everything else)? */
+ int bAbortOnUncleanConfig; /* abort run (rather than starting with partial
+ config) if there was any issue in conf */
+ int uidDropPriv; /* user-id to which priveleges should be dropped to */
+ int gidDropPriv; /* group-id to which priveleges should be dropped to */
+ uchar *pszConfDAGFile; /* name of config DAG file, non-NULL means generate one */
+
+ // TODO are the following ones defaults?
+ int bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */
+
+ //TODO: other representation for main queue? Or just load it differently?
+ queuecnf_t mainQ; /* main queue paramters */
+};
+
+/* (global) defaults are global in the sense that they are accessible
+ * to all code, but they can change value and other objects (like
+ * actions) actually copy the value a global had at the time the action
+ * was defined. In that sense, a global default is just that, a default,
+ * wich can (and will) be changed in the course of config file
+ * processing. Once the config file has been processed, defaults
+ * can be dropped. The current code does not do this for simplicity.
+ * That is not a problem, because the defaults do not take up much memory.
+ * At a later stage, we may think about dropping them. -- rgerhards, 2011-04-19
+ */
+struct defaults_s {
+};
+
+
+/* list of modules loaded in this configuration (config specific module list) */
+struct cfgmodules_etry_s {
+ cfgmodules_etry_t *next;
+ modInfo_t *pMod;
+};
+
+struct cfgmodules_s {
+ cfgmodules_etry_t *root;
+};
+
+/* outchannel-specific data */
+struct outchannels_s {
+ struct outchannel *ochRoot; /* the root of the outchannel list */
+ struct outchannel *ochLast; /* points to the last element of the outchannel list */
+};
+
+struct templates_s {
+ struct template *root; /* the root of the template list */
+ struct template *last; /* points to the last element of the template list */
+ struct template *lastStatic; /* last static element of the template list */
+};
+
+
+struct actions_s {
+ unsigned nbrActions; /* number of actions */
+};
+
+
+struct rulesets_s {
+ linkedList_t llRulesets; /* this is NOT a pointer - no typo here ;) */
+
+ /* support for legacy rsyslog.conf format */
+ ruleset_t *pCurr; /* currently "active" ruleset */
+ ruleset_t *pDflt; /* current default ruleset, e.g. for binding to actions which have no other */
+};
+
+
+/* --- end configuration objects --- */
+
+/* the rsconf object */
+struct rsconf_s {
+ BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
+ cfgmodules_t modules;
+ globals_t globals;
+ defaults_t defaults;
+ templates_t templates;
+ outchannels_t och;
+ actions_t actions;
+ rulesets_t rulesets;
+ /* note: rulesets include the complete output part:
+ * - rules
+ * - filter (as part of the action)
+ * - actions
+ * Of course, we need to debate if we shall change that some time...
+ */
+};
+
+
+/* interfaces */
+BEGINinterface(rsconf) /* name must also be changed in ENDinterface macro! */
+ INTERFACEObjDebugPrint(rsconf);
+ rsRetVal (*Construct)(rsconf_t **ppThis);
+ rsRetVal (*ConstructFinalize)(rsconf_t __attribute__((unused)) *pThis);
+ rsRetVal (*Destruct)(rsconf_t **ppThis);
+ rsRetVal (*Load)(rsconf_t **ppThis, uchar *confFile);
+ rsRetVal (*Activate)(rsconf_t *ppThis);
+ENDinterface(rsconf)
+// TODO: switch version to 1 for first "complete" version!!!! 2011-04-20
+#define rsconfCURR_IF_VERSION 0 /* increment whenever you change the interface above! */
+
+
+/* prototypes */
+PROTOTYPEObj(rsconf);
+
+/* globally-visible external data */
+extern rsconf_t *runConf;/* the currently running config */
+extern rsconf_t *loadConf;/* the config currently being loaded (no concurrent config load supported!) */
+
+
+/* some defaults (to be removed?) */
+#define DFLT_bLogStatusMsgs 1
+
+#endif /* #ifndef INCLUDED_RSCONF_H */
diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c
index bdb1c9ff..2b8f2b64 100644
--- a/runtime/rsyslog.c
+++ b/runtime/rsyslog.c
@@ -75,6 +75,7 @@
#include "datetime.h"
#include "queue.h"
#include "conf.h"
+#include "rsconf.h"
#include "glbl.h"
#include "errmsg.h"
#include "prop.h"
@@ -209,6 +210,8 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF)
CHKiRet(parserClassInit(NULL));
if(ppErrObj != NULL) *ppErrObj = "strgen";
CHKiRet(strgenClassInit(NULL));
+ if(ppErrObj != NULL) *ppErrObj = "rsconf";
+ CHKiRet(rsconfClassInit(NULL));
/* dummy "classes" */
if(ppErrObj != NULL) *ppErrObj = "str";
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index d63dbe4f..fcc0d626 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -137,6 +137,8 @@ typedef uintTiny propid_t;
#define PROP_SYS_QHOUR 156
#define PROP_SYS_MINUTE 157
#define PROP_SYS_MYHOSTNAME 158
+#define PROP_CEE 200
+#define PROP_CEE_ALL_JSON 201
#define PROP_SYS_BOM 159
@@ -332,6 +334,11 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_TIMEOUT = -2164, /**< timeout occured during operation */
RS_RET_RCV_ERR = -2165, /**< error occured during socket rcv operation */
RS_RET_NO_SOCK_CONFIGURED = -2166, /**< no socket (name) was configured where one is required */
+ RS_RET_CONF_NOT_GLBL = -2167, /**< $Begin not in global scope */
+ RS_RET_CONF_IN_GLBL = -2168, /**< $End when in global scope */
+ RS_RET_CONF_INVLD_END = -2169, /**< $End for wrong conf object (probably nesting error) */
+ RS_RET_CONF_INVLD_SCOPE = -2170,/**< config statement not valid in current scope (e.g. global stmt in action block) */
+ RS_RET_CONF_END_NO_ACT = -2171, /**< end of action block, but no actual action specified */
RS_RET_NO_LSTN_DEFINED = -2172, /**< no listener defined (e.g. inside an input module) */
RS_RET_EPOLL_CR_FAILED = -2173, /**< epoll_create() failed */
RS_RET_EPOLL_CTL_FAILED = -2174, /**< epoll_ctl() failed */
@@ -343,6 +350,12 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_FILE_NOT_SPECIFIED = -2180, /**< file name not configured where this was required */
RS_RET_ERR_WRKDIR = -2181, /**< problems with the rsyslog working directory */
+ RS_RET_INVLD_CONF_OBJ= -2200, /**< invalid config object (e.g. $Begin conf statement) */
+ RS_RET_ERR_LIBEE_INIT = -2201, /**< cannot obtain libee ctx */
+ RS_RET_ERR_LIBLOGNORM_INIT = -2202,/**< cannot obtain liblognorm ctx */
+ RS_RET_ERR_LIBLOGNORM_SAMPDB_LOAD = -2203,/**< liblognorm sampledb load failed */
+ RS_RET_CMD_GONE_AWAY = -2204,/**< config directive existed, but no longer supported */
+
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
@@ -467,6 +480,18 @@ rsRetVal rsrtExit(void);
int rsrtIsInit(void);
rsRetVal rsrtSetErrLogger(rsRetVal (*errLogger)(int, uchar*));
+/* this define below is (later) intended to be used to implement empty
+ * structs. TODO: check if compilers supports this and, if not, define
+ * a dummy variable. This requires review of where in code empty structs
+ * are already defined. -- rgerhards, 2010-07-26
+ */
+#define EMPTY_STRUCT
+
+/* TODO: remove this -- this is only for transition of the config system */
+extern rsconf_t *ourConf; /* defined by syslogd.c, a hack for functions that do not
+ yet receive a copy, so that we can incrementially
+ compile and change... -- rgerhars, 2011-04-19 */
+
#endif /* multi-include protection */
/* vim:set ai:
*/
diff --git a/runtime/rule.c b/runtime/rule.c
index d5f18e71..d023bcec 100644
--- a/runtime/rule.c
+++ b/runtime/rule.c
@@ -4,7 +4,7 @@
*
* Module begun 2009-06-10 by Rainer Gerhards
*
- * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2009-2011 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
@@ -70,6 +70,12 @@ getFIOPName(unsigned iFIOP)
case FIOP_REGEX:
pRet = "regex";
break;
+ case FIOP_EREREGEX:
+ pRet = "ereregex";
+ break;
+ case FIOP_ISEMPTY:
+ pRet = "isempty";
+ break;
default:
pRet = "NOP";
break;
@@ -190,7 +196,8 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg)
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.propID, &propLen, &pbMustBeFreed);
+ pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID,
+ pRule->f_filterData.prop.propName, &propLen, &pbMustBeFreed);
/* Now do the compares (short list currently ;)) */
switch(pRule->f_filterData.prop.operation ) {
@@ -198,6 +205,10 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg)
if(rsCStrLocateInSzStr(pRule->f_filterData.prop.pCSCompValue, (uchar*) pszPropVal) != -1)
bRet = 1;
break;
+ case FIOP_ISEMPTY:
+ if(propLen == 0)
+ bRet = 1; /* process message! */
+ break;
case FIOP_ISEQUAL:
if(rsCStrSzStrCmp(pRule->f_filterData.prop.pCSCompValue,
pszPropVal, ustrlen(pszPropVal)) == 0)
@@ -230,14 +241,28 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg)
bRet = (bRet == 1) ? 0 : 1;
if(Debug) {
- dbgprintf("Filter: check for property '%s' (value '%s') ",
- propIDToName(pRule->f_filterData.prop.propID), pszPropVal);
+ char *cstr;
+ if(pRule->f_filterData.prop.propID == PROP_CEE) {
+ cstr = es_str2cstr(pRule->f_filterData.prop.propName, NULL);
+ dbgprintf("Filter: check for CEE property '%s' (value '%s') ",
+ cstr, pszPropVal);
+ free(cstr);
+ } else {
+ dbgprintf("Filter: check for property '%s' (value '%s') ",
+ propIDToName(pRule->f_filterData.prop.propID), 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");
+ if(pRule->f_filterData.prop.operation == FIOP_ISEMPTY) {
+ dbgprintf("%s : %s\n",
+ getFIOPName(pRule->f_filterData.prop.operation),
+ bRet ? "TRUE" : "FALSE");
+ } else {
+ dbgprintf("%s '%s': %s\n",
+ getFIOPName(pRule->f_filterData.prop.operation),
+ rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSCompValue),
+ bRet ? "TRUE" : "FALSE");
+ }
}
/* cleanup */
@@ -324,6 +349,8 @@ CODESTARTobjDestruct(rule)
rsCStrDestruct(&pThis->f_filterData.prop.pCSCompValue);
if(pThis->f_filterData.prop.regex_cache != NULL)
rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache);
+ if(pThis->f_filterData.prop.propName != NULL)
+ es_deleteStr(pThis->f_filterData.prop.propName);
} else if(pThis->f_filter_type == FILTER_EXPR) {
if(pThis->f_filterData.f_expr != NULL)
expr.Destruct(&pThis->f_filterData.f_expr);
@@ -368,6 +395,7 @@ DEFFUNC_llExecFunc(dbgPrintInitInfoAction)
/* debugprint for the rule object */
BEGINobjDebugPrint(rule) /* be sure to specify the object type also in END and CODESTART macros! */
int i;
+ char *cstr;
CODESTARTobjDebugPrint(rule)
dbgoprint((obj_t*) pThis, "rsyslog rule:\n");
if(pThis->pCSProgNameComp != NULL)
@@ -388,12 +416,19 @@ CODESTARTobjDebugPrint(rule)
} else {
dbgprintf("PROPERTY-BASED Filter:\n");
dbgprintf("\tProperty.: '%s'\n", propIDToName(pThis->f_filterData.prop.propID));
+ if(pThis->f_filterData.prop.propName != NULL) {
+ cstr = es_str2cstr(pThis->f_filterData.prop.propName, NULL);
+ dbgprintf("\tCEE-Prop.: '%s'\n", cstr);
+ free(cstr);
+ }
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));
+ if(pThis->f_filterData.prop.pCSCompValue != NULL) {
+ dbgprintf("\tValue....: '%s'\n",
+ rsCStrGetSzStrNoNULL(pThis->f_filterData.prop.pCSCompValue));
+ }
dbgprintf("\tAction...: ");
}
diff --git a/runtime/rule.h b/runtime/rule.h
index 309a2ed8..3b34e11a 100644
--- a/runtime/rule.h
+++ b/runtime/rule.h
@@ -25,6 +25,7 @@
#ifndef INCLUDED_RULE_H
#define INCLUDED_RULE_H
+#include "libestr.h"
#include "linkedlist.h"
#include "regexp.h"
#include "expr.h"
@@ -49,6 +50,7 @@ struct rule_s {
cstr_t *pCSCompValue; /* value to "compare" against */
sbool isNegated;
propid_t propID; /* ID of the requested property */
+ es_str_t *propName; /* name of property for CEE-based filters */
} prop;
expr_t *f_expr; /* expression object */
} f_filterData;
diff --git a/runtime/ruleset.c b/runtime/ruleset.c
index 5ee2a55a..d472a560 100644
--- a/runtime/ruleset.c
+++ b/runtime/ruleset.c
@@ -1,7 +1,7 @@
/* 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
+ * We have a two-way structure of linked lists: one config-specifc linked list
+ * (conf->rulesets.llRulesets) 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).
*
@@ -11,7 +11,7 @@
*
* Module begun 2009-06-10 by Rainer Gerhards
*
- * Copyright 2009 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2009-2011 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
@@ -34,7 +34,6 @@
#include "config.h"
#include <stdlib.h>
-#include <string.h>
#include <assert.h>
#include <ctype.h>
@@ -48,6 +47,7 @@
#include "parser.h"
#include "batch.h"
#include "unicode-helper.h"
+#include "rsconf.h"
#include "dirty.h" /* for main ruleset queue creation */
/* static data */
@@ -56,26 +56,23 @@ DEFobjCurrIf(errmsg)
DEFobjCurrIf(rule)
DEFobjCurrIf(parser)
-linkedList_t llRulesets; /* this is NOT a pointer - no typo here ;) */
-ruleset_t *pCurrRuleset = NULL; /* currently "active" ruleset */
-ruleset_t *pDfltRuleset = NULL; /* current default ruleset, e.g. for binding to actions which have no other */
-
/* forward definitions */
static rsRetVal processBatch(batch_t *pBatch);
-/* ---------- linked-list key handling functions ---------- */
+
+/* ---------- linked-list key handling functions (ruleset) ---------- */
/* destructor for linked list keys.
*/
-static rsRetVal keyDestruct(void __attribute__((unused)) *pData)
+rsRetVal
+rulesetKeyDestruct(void __attribute__((unused)) *pData)
{
free(pData);
return RS_RET_OK;
}
+/* ---------- END linked-list key handling functions (ruleset) ---------- */
-/* ---------- END linked-list key handling functions ---------- */
-
/* driver to iterate over all of this ruleset actions */
typedef struct iterateAllActions_s {
@@ -122,7 +119,7 @@ DEFFUNC_llExecFunc(doIterateAllActions)
* must be done or a shutdown is pending.
*/
static rsRetVal
-iterateAllActions(rsRetVal (*pFunc)(void*, void*), void* pParam)
+iterateAllActions(rsconf_t *conf, rsRetVal (*pFunc)(void*, void*), void* pParam)
{
iterateAllActions_t params;
DEFiRet;
@@ -130,7 +127,7 @@ iterateAllActions(rsRetVal (*pFunc)(void*, void*), void* pParam)
params.pFunc = pFunc;
params.pParam = pParam;
- CHKiRet(llExecFunc(&llRulesets, doIterateAllActions, &params));
+ CHKiRet(llExecFunc(&(conf->rulesets.llRulesets), doIterateAllActions, &params));
finalize_it:
RETiRet;
@@ -227,7 +224,7 @@ processBatch(batch_t *pBatch)
if(pBatch->bSingleRuleset) {
pThis = batchGetRuleset(pBatch);
if(pThis == NULL)
- pThis = pDfltRuleset;
+ pThis = ourConf->rulesets.pDflt;
ISOBJ_TYPE_assert(pThis, ruleset);
CHKiRet(llExecFunc(&pThis->llRules, processBatchDoRules, pBatch));
} else {
@@ -245,9 +242,9 @@ finalize_it:
* rgerhards, 2009-11-04
*/
static parserList_t*
-GetParserList(msg_t *pMsg)
+GetParserList(rsconf_t *conf, msg_t *pMsg)
{
- return (pMsg->pRuleset == NULL) ? pDfltRuleset->pParserLst : pMsg->pRuleset->pParserLst;
+ return (pMsg->pRuleset == NULL) ? conf->rulesets.pDflt->pParserLst : pMsg->pRuleset->pParserLst;
}
@@ -255,7 +252,7 @@ GetParserList(msg_t *pMsg)
* of checks and ignore the rule if it does not pass them.
*/
static rsRetVal
-addRule(ruleset_t *pThis, rule_t **ppRule)
+addRule(rsconf_t *conf, ruleset_t *pThis, rule_t **ppRule)
{
int iActionCnt;
DEFiRet;
@@ -278,7 +275,7 @@ finalize_it:
/* set name for ruleset */
-static rsRetVal setName(ruleset_t *pThis, uchar *pszName)
+static rsRetVal setName(rsconf_t *conf, ruleset_t *pThis, uchar *pszName)
{
DEFiRet;
free(pThis->pszName);
@@ -294,9 +291,9 @@ finalize_it:
* is really much more natural to return the pointer directly.
*/
static ruleset_t*
-GetCurrent(void)
+GetCurrent(rsconf_t *conf)
{
- return pCurrRuleset;
+ return conf->rulesets.pCurr;
}
@@ -316,13 +313,13 @@ GetRulesetQueue(ruleset_t *pThis)
/* Find the ruleset with the given name and return a pointer to its object.
*/
static rsRetVal
-GetRuleset(ruleset_t **ppRuleset, uchar *pszName)
+GetRuleset(rsconf_t *conf, ruleset_t **ppRuleset, uchar *pszName)
{
DEFiRet;
assert(ppRuleset != NULL);
assert(pszName != NULL);
- CHKiRet(llFind(&llRulesets, pszName, (void*) ppRuleset));
+ CHKiRet(llFind(&(conf->rulesets.llRulesets), pszName, (void*) ppRuleset));
finalize_it:
RETiRet;
@@ -332,14 +329,14 @@ finalize_it:
/* Set a new default rule set. If the default can not be found, no change happens.
*/
static rsRetVal
-SetDefaultRuleset(uchar *pszName)
+SetDefaultRuleset(rsconf_t *conf, uchar *pszName)
{
ruleset_t *pRuleset;
DEFiRet;
assert(pszName != NULL);
- CHKiRet(GetRuleset(&pRuleset, pszName));
- pDfltRuleset = pRuleset;
+ CHKiRet(GetRuleset(conf, &pRuleset, pszName));
+ conf->rulesets.pDflt = pRuleset;
dbgprintf("default rule set changed to %p: '%s'\n", pRuleset, pszName);
finalize_it:
@@ -350,14 +347,14 @@ finalize_it:
/* Set a new current rule set. If the ruleset can not be found, no change happens.
*/
static rsRetVal
-SetCurrRuleset(uchar *pszName)
+SetCurrRuleset(rsconf_t *conf, uchar *pszName)
{
ruleset_t *pRuleset;
DEFiRet;
assert(pszName != NULL);
- CHKiRet(GetRuleset(&pRuleset, pszName));
- pCurrRuleset = pRuleset;
+ CHKiRet(GetRuleset(conf, &pRuleset, pszName));
+ conf->rulesets.pCurr = pRuleset;
dbgprintf("current rule set changed to %p: '%s'\n", pRuleset, pszName);
finalize_it:
@@ -389,7 +386,7 @@ ENDobjConstruct(ruleset)
* This also adds the rule set to the list of all known rulesets.
*/
static rsRetVal
-rulesetConstructFinalize(ruleset_t *pThis)
+rulesetConstructFinalize(rsconf_t *conf, ruleset_t *pThis)
{
uchar *keyName;
DEFiRet;
@@ -400,14 +397,14 @@ rulesetConstructFinalize(ruleset_t *pThis)
* two separate copies.
*/
CHKmalloc(keyName = ustrdup(pThis->pszName));
- CHKiRet(llAppend(&llRulesets, keyName, pThis));
+ CHKiRet(llAppend(&(conf->rulesets.llRulesets), keyName, pThis));
/* this now also is the new current ruleset */
- pCurrRuleset = pThis;
+ conf->rulesets.pCurr = pThis;
/* and also the default, if so far none has been set */
- if(pDfltRuleset == NULL)
- pDfltRuleset = pThis;
+ if(conf->rulesets.pDflt == NULL)
+ conf->rulesets.pDflt = pThis;
finalize_it:
RETiRet;
@@ -428,17 +425,6 @@ CODESTARTobjDestruct(ruleset)
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
@@ -447,18 +433,29 @@ rulesetDestructForLinkedList(void *pData)
* everything runs stable again. -- rgerhards, 2009-06-10
*/
static rsRetVal
-destructAllActions(void)
+destructAllActions(rsconf_t *conf)
{
DEFiRet;
- CHKiRet(llDestroy(&llRulesets));
- CHKiRet(llInit(&llRulesets, rulesetDestructForLinkedList, keyDestruct, strcasecmp));
- pDfltRuleset = NULL;
+ CHKiRet(llDestroy(&(conf->rulesets.llRulesets)));
+ CHKiRet(llInit(&(conf->rulesets.llRulesets), rulesetDestructForLinkedList, rulesetKeyDestruct, strcasecmp));
+ conf->rulesets.pDflt = NULL;
finalize_it:
RETiRet;
}
+/* 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.
+ */
+rsRetVal
+rulesetDestructForLinkedList(void *pData)
+{
+ ruleset_t *pThis = (ruleset_t*) pData;
+ return rulesetDestruct(&pThis);
+}
+
/* helper for debugPrint(), initiates rule printing */
DEFFUNC_llExecFunc(doDebugPrintRule)
{
@@ -480,11 +477,11 @@ DEFFUNC_llExecFunc(doDebugPrintAll)
/* debug print all rulesets
*/
static rsRetVal
-debugPrintAll(void)
+debugPrintAll(rsconf_t *conf)
{
DEFiRet;
dbgprintf("All Rulesets:\n");
- llExecFunc(&llRulesets, doDebugPrintAll, NULL);
+ llExecFunc(&(conf->rulesets.llRulesets), doDebugPrintAll, NULL);
dbgprintf("End of Rulesets.\n");
RETiRet;
}
@@ -497,18 +494,18 @@ debugPrintAll(void)
* considered acceptable for the time being.
* rgerhards, 2009-10-27
*/
-static rsRetVal
-rulesetCreateQueue(void __attribute__((unused)) *pVal, int *pNewVal)
+static inline rsRetVal
+doRulesetCreateQueue(rsconf_t *conf, int *pNewVal)
{
DEFiRet;
- if(pCurrRuleset == NULL) {
+ if(conf->rulesets.pCurr == NULL) {
errmsg.LogError(0, RS_RET_NO_CURR_RULESET, "error: currently no specific ruleset specified, thus a "
"queue can not be added to it");
ABORT_FINALIZE(RS_RET_NO_CURR_RULESET);
}
- if(pCurrRuleset->pQueue != NULL) {
+ if(conf->rulesets.pCurr->pQueue != NULL) {
errmsg.LogError(0, RS_RET_RULES_QUEUE_EXISTS, "error: ruleset already has a main queue, can not "
"add another one");
ABORT_FINALIZE(RS_RET_RULES_QUEUE_EXISTS);
@@ -518,12 +515,17 @@ rulesetCreateQueue(void __attribute__((unused)) *pVal, int *pNewVal)
FINALIZE; /* if it is turned off, we do not need to change anything ;) */
dbgprintf("adding a ruleset-specific \"main\" queue");
- CHKiRet(createMainQueue(&pCurrRuleset->pQueue, UCHAR_CONSTANT("ruleset")));
+ CHKiRet(createMainQueue(&conf->rulesets.pCurr->pQueue, UCHAR_CONSTANT("ruleset")));
finalize_it:
RETiRet;
}
+static rsRetVal
+rulesetCreateQueue(void __attribute__((unused)) *pVal, int *pNewVal)
+{
+ return doRulesetCreateQueue(ourConf, pNewVal);
+}
/* Add a ruleset specific parser to the ruleset. Note that adding the first
* parser automatically disables the default parsers. If they are needed as well,
@@ -535,12 +537,12 @@ finalize_it:
* rgerhards, 2009-11-04
*/
static rsRetVal
-rulesetAddParser(void __attribute__((unused)) *pVal, uchar *pName)
+doRulesetAddParser(rsconf_t *conf, uchar *pName)
{
parser_t *pParser;
DEFiRet;
- assert(pCurrRuleset != NULL);
+ assert(conf->rulesets.pCurr != NULL);
CHKiRet(objUse(parser, CORE_COMPONENT));
iRet = parser.FindParser(&pParser, pName);
@@ -553,10 +555,10 @@ rulesetAddParser(void __attribute__((unused)) *pVal, uchar *pName)
FINALIZE;
}
- CHKiRet(parser.AddParserToList(&pCurrRuleset->pParserLst, pParser));
+ CHKiRet(parser.AddParserToList(&conf->rulesets.pCurr->pParserLst, pParser));
- dbgprintf("added parser '%s' to ruleset '%s'\n", pName, pCurrRuleset->pszName);
-RUNLOG_VAR("%p", pCurrRuleset->pParserLst);
+ dbgprintf("added parser '%s' to ruleset '%s'\n", pName, conf->rulesets.pCurr->pszName);
+RUNLOG_VAR("%p", conf->rulesets.pCurr->pParserLst);
finalize_it:
d_free(pName); /* no longer needed */
@@ -564,6 +566,12 @@ finalize_it:
RETiRet;
}
+static rsRetVal
+rulesetAddParser(void __attribute__((unused)) *pVal, uchar *pName)
+{
+ return doRulesetAddParser(ourConf, pName);
+}
+
/* queryInterface function
* rgerhards, 2008-02-21
@@ -604,7 +612,6 @@ ENDobjQueryInterface(ruleset)
* rgerhards, 2009-04-06
*/
BEGINObjClassExit(ruleset, OBJ_IS_CORE_MODULE) /* class, version */
- llDestroy(&llRulesets);
objRelease(errmsg, CORE_COMPONENT);
objRelease(rule, CORE_COMPONENT);
objRelease(parser, CORE_COMPONENT);
@@ -624,12 +631,9 @@ BEGINObjClassInit(ruleset, 1, OBJ_IS_CORE_MODULE) /* class, version */
OBJSetMethodHandler(objMethod_DEBUGPRINT, rulesetDebugPrint);
OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, rulesetConstructFinalize);
- /* prepare global data */
- CHKiRet(llInit(&llRulesets, rulesetDestructForLinkedList, keyDestruct, strcasecmp));
-
/* config file handlers */
- CHKiRet(regCfSysLineHdlr((uchar *)"rulesetparser", 0, eCmdHdlrGetWord, rulesetAddParser, NULL, NULL));
- CHKiRet(regCfSysLineHdlr((uchar *)"rulesetcreatemainqueue", 0, eCmdHdlrBinary, rulesetCreateQueue, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"rulesetparser", 0, eCmdHdlrGetWord, rulesetAddParser, NULL, NULL, eConfObjGlobal));
+ CHKiRet(regCfSysLineHdlr((uchar *)"rulesetcreatemainqueue", 0, eCmdHdlrBinary, rulesetCreateQueue, NULL, NULL, eConfObjGlobal));
ENDObjClassInit(ruleset)
/* vi:set ai:
diff --git a/runtime/ruleset.h b/runtime/ruleset.h
index acebd17a..8966a884 100644
--- a/runtime/ruleset.h
+++ b/runtime/ruleset.h
@@ -40,27 +40,35 @@ struct ruleset_s {
/* interfaces */
BEGINinterface(ruleset) /* name must also be changed in ENDinterface macro! */
INTERFACEObjDebugPrint(ruleset);
- rsRetVal (*DebugPrintAll)(void);
+ rsRetVal (*DebugPrintAll)(rsconf_t *conf);
rsRetVal (*Construct)(ruleset_t **ppThis);
- rsRetVal (*ConstructFinalize)(ruleset_t __attribute__((unused)) *pThis);
+ rsRetVal (*ConstructFinalize)(rsconf_t *conf, 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 (*SetName)(ruleset_t *pThis, uchar *pszName);
+ rsRetVal (*IterateAllActions)(rsconf_t *conf, rsRetVal (*pFunc)(void*, void*), void* pParam);
+ rsRetVal (*DestructAllActions)(rsconf_t *conf);
+ rsRetVal (*AddRule)(rsconf_t *conf, ruleset_t *pThis, rule_t **ppRule);
+ rsRetVal (*SetName)(rsconf_t *conf, ruleset_t *pThis, uchar *pszName);
rsRetVal (*ProcessBatch)(batch_t*);
- rsRetVal (*GetRuleset)(ruleset_t **ppThis, uchar*);
- rsRetVal (*SetDefaultRuleset)(uchar*);
- rsRetVal (*SetCurrRuleset)(uchar*);
- ruleset_t* (*GetCurrent)(void);
+ rsRetVal (*GetRuleset)(rsconf_t *conf, ruleset_t **ppThis, uchar*);
+ rsRetVal (*SetDefaultRuleset)(rsconf_t *conf, uchar*);
+ rsRetVal (*SetCurrRuleset)(rsconf_t *conf, uchar*);
+ ruleset_t* (*GetCurrent)(rsconf_t *conf);
qqueue_t* (*GetRulesetQueue)(ruleset_t*);
/* v3, 2009-11-04 */
- parserList_t* (*GetParserList)(msg_t *);
+ parserList_t* (*GetParserList)(rsconf_t *conf, msg_t *);
+ /* v5, 2011-04-19
+ * added support for the rsconf object -- fundamental change
+ */
ENDinterface(ruleset)
-#define rulesetCURR_IF_VERSION 4 /* increment whenever you change the interface structure! */
+#define rulesetCURR_IF_VERSION 5 /* increment whenever you change the interface structure! */
/* prototypes */
PROTOTYPEObj(ruleset);
+/* TODO: remove these -- currently done dirty for config file
+ * redo -- rgerhards, 2011-04-19
+ */
+rsRetVal rulesetDestructForLinkedList(void *pData);
+rsRetVal rulesetKeyDestruct(void __attribute__((unused)) *pData);
#endif /* #ifndef INCLUDED_RULESET_H */
diff --git a/runtime/stringbuf.c b/runtime/stringbuf.c
index 2b6815a4..d8c5923b 100644
--- a/runtime/stringbuf.c
+++ b/runtime/stringbuf.c
@@ -35,6 +35,7 @@
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
+#include <libestr.h>
#include "rsyslog.h"
#include "stringbuf.h"
#include "srUtils.h"
@@ -104,6 +105,34 @@ finalize_it:
RETiRet;
}
+
+/* construct from es_str_t string
+ * rgerhards 2010-12-03
+ */
+rsRetVal cstrConstructFromESStr(cstr_t **ppThis, es_str_t *str)
+{
+ DEFiRet;
+ cstr_t *pThis;
+
+ assert(ppThis != NULL);
+
+ CHKiRet(rsCStrConstruct(&pThis));
+
+ pThis->iBufSize = pThis->iStrLen = es_strlen(str);
+ if((pThis->pBuf = (uchar*) MALLOC(sizeof(uchar) * pThis->iStrLen)) == NULL) {
+ RSFREEOBJ(pThis);
+ ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY);
+ }
+
+ /* we do NOT need to copy the \0! */
+ memcpy(pThis->pBuf, es_getBufAddr(str), pThis->iStrLen);
+
+ *ppThis = pThis;
+
+finalize_it:
+ RETiRet;
+}
+
/* construct from CStr object. only the counted string is
* copied, not the szString.
* rgerhards 2005-10-18
diff --git a/runtime/stringbuf.h b/runtime/stringbuf.h
index c5130238..df234012 100644
--- a/runtime/stringbuf.h
+++ b/runtime/stringbuf.h
@@ -36,6 +36,7 @@
#define _STRINGBUF_H_INCLUDED__ 1
#include <assert.h>
+#include <libestr.h>
/**
* The dynamic string buffer object.
@@ -57,6 +58,7 @@ typedef struct cstr_s
*/
rsRetVal cstrConstruct(cstr_t **ppThis);
#define rsCStrConstruct(x) cstrConstruct((x))
+rsRetVal cstrConstructFromESStr(cstr_t **ppThis, es_str_t *str);
rsRetVal rsCStrConstructFromszStr(cstr_t **ppThis, uchar *sz);
rsRetVal rsCStrConstructFromCStr(cstr_t **ppThis, cstr_t *pFrom);
diff --git a/runtime/typedefs.h b/runtime/typedefs.h
index d3da7699..1c8e93ce 100644
--- a/runtime/typedefs.h
+++ b/runtime/typedefs.h
@@ -79,6 +79,17 @@ typedef struct parserList_s parserList_t;
typedef struct strgen_s strgen_t;
typedef struct strgenList_s strgenList_t;
typedef struct statsobj_s statsobj_t;
+typedef struct nsd_epworkset_s nsd_epworkset_t;
+typedef struct templates_s templates_t;
+typedef struct queuecnf_s queuecnf_t;
+typedef struct rulesets_s rulesets_t;
+typedef struct globals_s globals_t;
+typedef struct defaults_s defaults_t;
+typedef struct actions_s actions_t;
+typedef struct rsconf_s rsconf_t;
+typedef struct cfgmodules_s cfgmodules_t;
+typedef struct cfgmodules_etry_s cfgmodules_etry_t;
+typedef struct outchannels_s outchannels_t;
typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript function */
typedef uint64 qDeqID; /* queue Dequeue order ID. 32 bits is considered dangerously few */
@@ -127,9 +138,42 @@ typedef enum {
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_EREREGEX = 5, /* matches a ERE regular expression? */
+ FIOP_ISEMPTY = 6 /* string empty <=> strlen(s) == 0 ?*/
} fiop_t;
+/* types of configuration handlers
+ */
+typedef enum cslCmdHdlrType {
+ eCmdHdlrInvalid = 0, /* invalid handler type - indicates a coding error */
+ eCmdHdlrCustomHandler, /* custom handler, just call handler function */
+ eCmdHdlrUID,
+ eCmdHdlrGID,
+ eCmdHdlrBinary,
+ eCmdHdlrFileCreateMode,
+ eCmdHdlrInt,
+ eCmdHdlrSize,
+ eCmdHdlrGetChar,
+ eCmdHdlrFacility,
+ eCmdHdlrSeverity,
+ eCmdHdlrGetWord,
+ eCmdHdlrGoneAway /* statment existed, but is no longer supported */
+} ecslCmdHdrlType;
+
+
+/* the next type describes $Begin .. $End block object types
+ */
+typedef enum cslConfObjType {
+ eConfObjGlobal = 0, /* global directives */
+ eConfObjAction, /* action-specific directives */
+ /* now come states that indicate that we wait for a block-end. These are
+ * states that permit us to do some safety checks and they hopefully ease
+ * migration to a "real" parser/grammar.
+ */
+ eConfObjActionWaitEnd,
+ eConfObjAlways /* always valid, very special case (guess $End only!) */
+} ecslConfObjType;
+
/* multi-submit support.
* This is done via a simple data structure, which holds the number of elements
diff --git a/runtime/var.h b/runtime/var.h
index 6d890ec9..ae971bb5 100644
--- a/runtime/var.h
+++ b/runtime/var.h
@@ -40,6 +40,7 @@ typedef struct var_s {
varType_t varType;
union {
number_t num;
+ es_str_t *str;
cstr_t *pStr;
syslogTime_t vSyslogTime;
diff --git a/runtime/vm.c b/runtime/vm.c
index 84ba4bcf..bbc8d346 100644
--- a/runtime/vm.c
+++ b/runtime/vm.c
@@ -448,6 +448,7 @@ BEGINop(PUSHMSGVAR) /* remember to set the instruction also in the ENDop macro!
var_t *pVal; /* the value to push */
cstr_t *pstrVal;
CODESTARTop(PUSHMSGVAR)
+dbgprintf("XXX: pushMSGVAR, var '%s'\n", rsCStrGetSzStr(pOp->operand.pVar->val.pStr));
if(pThis->pMsg == NULL) {
/* TODO: flag an error message! As a work-around, we permit
* execution to continue here with an empty string
@@ -468,6 +469,31 @@ finalize_it:
ENDop(PUSHMSGVAR)
+BEGINop(PUSHCEEVAR) /* remember to set the instruction also in the ENDop macro! */
+ var_t *pVal; /* the value to push */
+ cstr_t *pstrVal;
+CODESTARTop(PUSHCEEVAR)
+dbgprintf("XXX: pushCEEVAR, var '%s'\n", rsCStrGetSzStr(pOp->operand.pVar->val.pStr));
+ if(pThis->pMsg == NULL) {
+ /* TODO: flag an error message! As a work-around, we permit
+ * execution to continue here with an empty string
+ */
+ CHKiRet(var.Construct(&pVal));
+ CHKiRet(var.ConstructFinalize(pVal));
+ CHKiRet(rsCStrConstructFromszStr(&pstrVal, (uchar*)""));
+ CHKiRet(var.SetString(pVal, pstrVal));
+ } else {
+ /* we have a message, so pull value from there */
+ CHKiRet(msgGetCEEVar(pThis->pMsg, pOp->operand.pVar->val.pStr, &pVal));
+ }
+
+ /* if we reach this point, we have a valid pVal and can push it */
+ vmstk.Push(pThis->pStk, pVal);
+dbgprintf("XXX: pushCEEVAR, result '%s'\n", rsCStrGetSzStr(pVal->val.pStr));
+finalize_it:
+ENDop(PUSHCEEVAR)
+
+
BEGINop(PUSHSYSVAR) /* remember to set the instruction also in the ENDop macro! */
var_t *pVal; /* the value to push */
CODESTARTop(PUSHSYSVAR)
@@ -696,6 +722,7 @@ execProg(vm_t *pThis, vmprg_t *pProg)
doOP(NOT);
doOP(PUSHCONSTANT);
doOP(PUSHMSGVAR);
+ doOP(PUSHCEEVAR);
doOP(PUSHSYSVAR);
doOP(STRADD);
doOP(PLUS);
diff --git a/runtime/vmop.h b/runtime/vmop.h
index 67048c26..c085a940 100644
--- a/runtime/vmop.h
+++ b/runtime/vmop.h
@@ -59,6 +59,7 @@ typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc(
opcode_PUSHSYSVAR = 1001, /* requires var operand */
opcode_PUSHMSGVAR = 1002, /* requires var operand */
opcode_PUSHCONSTANT = 1003, /* requires var operand */
+ opcode_PUSHCEEVAR = 1004, /* requires var operand */
opcode_UNARY_MINUS = 1010,
opcode_FUNC_CALL = 1012,
opcode_END_PROG = 2000