diff options
Diffstat (limited to 'runtime/conf.c')
-rw-r--r-- | runtime/conf.c | 145 |
1 files changed, 144 insertions, 1 deletions
diff --git a/runtime/conf.c b/runtime/conf.c index d41f2950..1f0badcb 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,6 +92,10 @@ DEFobjCurrIf(net) DEFobjCurrIf(rule) DEFobjCurrIf(ruleset) +ecslConfObjType currConfObj = eConfObjGlobal; /* to support scoping - which config object is currently active? */ +int bConfStrictScoping = 0; /* force strict scoping during config processing? */ + + static int iNbrActions = 0; /* number of currently defined actions */ /* The following module-global variables are used for building @@ -1097,6 +1100,11 @@ 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) @@ -1246,6 +1254,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.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 */ @@ -1286,6 +1424,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: |