summaryrefslogtreecommitdiffstats
path: root/runtime/conf.c
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/conf.c')
-rw-r--r--runtime/conf.c220
1 files changed, 187 insertions, 33 deletions
diff --git a/runtime/conf.c b/runtime/conf.c
index bbd2147a..1d28a884 100644
--- a/runtime/conf.c
+++ b/runtime/conf.c
@@ -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"
@@ -93,19 +92,22 @@ DEFobjCurrIf(net)
DEFobjCurrIf(rule)
DEFobjCurrIf(ruleset)
-static int iNbrActions; /* number of actions the running config has. Needs to be init on ReInitConf() */
+ecslConfObjType currConfObj = eConfObjGlobal; /* to support scoping - which config object is currently active? */
+int bConfStrictScoping = 0; /* force strict scoping during config processing? */
-/* The following global variables are used for building
+
+static int iNbrActions = 0; /* number of currently defined actions */
+
+/* The following module-global variables are used for building
* tag and host selector lines during startup and config reload.
* This is stored as a global variable pool because of its ease. It is
* also fairly compatible with multi-threading as the stratup code must
- * be run in a single thread anyways. So there can be no race conditions. These
- * variables are no longer used once the configuration has been loaded (except,
- * of course, during a reload). rgerhards 2005-10-18
+ * be run in a single thread anyways. So there can be no race conditions.
+ * rgerhards 2005-10-18
*/
-EHostnameCmpMode eDfltHostnameCmpMode;
-cstr_t *pDfltHostnameCmp;
-cstr_t *pDfltProgNameCmp;
+static EHostnameCmpMode eDfltHostnameCmpMode = HN_NO_COMP;
+static cstr_t *pDfltHostnameCmp = NULL;
+static cstr_t *pDfltProgNameCmp = NULL;
/* process a directory and include all of its files into
@@ -872,6 +874,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 */
@@ -900,10 +910,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)) {
@@ -916,12 +929,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 */
@@ -1041,7 +1057,7 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f)
DEFiRet;
ASSERT(pp != NULL);
- ASSERT(f != NULL);
+ ISOBJ_TYPE_assert(f, rule);
/* check which filter we need to pull... */
switch(**pp) {
@@ -1092,11 +1108,21 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
/* loop through all modules and see if one picks up the line */
pMod = module.GetNxtType(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
+ */
+ assert(pMod != NULL);
while(pMod != NULL) {
pOMSR = NULL;
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)
@@ -1105,7 +1131,7 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
dbgprintf("module is incompatible with RepeatedMsgReduction - turned off\n");
pAction->f_ReduceRepeated = 0;
}
- pAction->bEnabled = 1; /* action is enabled */
+ pAction->eState = ACT_STATE_RDY; /* action is enabled */
iNbrActions++; /* one more active action! */
}
break;
@@ -1207,21 +1233,6 @@ cfline(uchar *line, rule_t **pfCurr)
}
-/* Reinitialize the configuration subsystem. This is a "work-around" to the fact
- * that we do not yet have actual config objects. This method is to be called
- * whenever a totally new config is started (which means on startup and HUP).
- * Note that it MUST NOT be called for an included config file.
- * rgerhards, 2008-07-28
- */
-static rsRetVal
-ReInitConf(void)
-{
- DEFiRet;
- iNbrActions = 0; /* this is what we created the function for ;) - action count is reset */
- RETiRet;
-}
-
-
/* return the current number of active actions
* rgerhards, 2008-07-28
*/
@@ -1255,18 +1266,156 @@ CODESTARTobjQueryInterface(conf)
pIf->doIncludeLine = doIncludeLine;
pIf->cfline = cfline;
pIf->processConfFile = processConfFile;
- pIf->ReInitConf = ReInitConf;
pIf->GetNbrActActions = GetNbrActActions;
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.GetNxtType(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.GetNxtType(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
*/
BEGINObjClassExit(conf, OBJ_IS_CORE_MODULE) /* CHANGE class also in END MACRO! */
CODESTARTObjClassExit(conf)
+ /* free no-longer needed module-global variables */
+ if(pDfltHostnameCmp != NULL) {
+ rsCStrDestruct(&pDfltHostnameCmp);
+ }
+
+ if(pDfltProgNameCmp != NULL) {
+ rsCStrDestruct(&pDfltProgNameCmp);
+ }
+
/* release objects we no longer need */
objRelease(expr, CORE_COMPONENT);
objRelease(ctok, CORE_COMPONENT);
@@ -1293,6 +1442,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: