diff options
Diffstat (limited to 'runtime/conf.c')
-rw-r--r-- | runtime/conf.c | 220 |
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: |