summaryrefslogtreecommitdiffstats
path: root/runtime/conf.c
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/conf.c')
-rw-r--r--runtime/conf.c703
1 files changed, 194 insertions, 509 deletions
diff --git a/runtime/conf.c b/runtime/conf.c
index cbba1790..94322f10 100644
--- a/runtime/conf.c
+++ b/runtime/conf.c
@@ -48,7 +48,6 @@
#endif
#include "rsyslog.h"
-#include "../tools/syslogd.h" /* TODO: this must be removed! */
#include "dirty.h"
#include "parse.h"
#include "action.h"
@@ -62,11 +61,9 @@
#include "srUtils.h"
#include "errmsg.h"
#include "net.h"
-#include "expr.h"
-#include "ctok.h"
-#include "ctok_token.h"
#include "rule.h"
#include "ruleset.h"
+#include "rsconf.h"
#include "unicode-helper.h"
#ifdef OS_SOLARIS
@@ -74,22 +71,20 @@
#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 data */
DEFobjStaticHelpers
-DEFobjCurrIf(expr)
-DEFobjCurrIf(ctok)
-DEFobjCurrIf(ctok_token)
DEFobjCurrIf(module)
DEFobjCurrIf(errmsg)
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.
@@ -98,153 +93,12 @@ static int iNbrActions = 0; /* number of currently defined actions */
* be run in a single thread anyways. So there can be no race conditions.
* rgerhards 2005-10-18
*/
-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
- * the current config file. There is no specific order of inclusion,
- * files are included in the order they are read from the directory.
- * The caller must have make sure that the provided parameter is
- * indeed a directory.
- * rgerhards, 2007-08-01
- */
-static rsRetVal doIncludeDirectory(uchar *pDirName)
-{
- DEFiRet;
- int iEntriesDone = 0;
- DIR *pDir;
- union {
- struct dirent d;
- char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
- } u;
- struct dirent *res;
- size_t iDirNameLen;
- size_t iFileNameLen;
- uchar szFullFileName[MAXFNAME];
-
- ASSERT(pDirName != NULL);
-
- if((pDir = opendir((char*) pDirName)) == NULL) {
- errmsg.LogError(errno, RS_RET_FOPEN_FAILURE, "error opening include directory");
- ABORT_FINALIZE(RS_RET_FOPEN_FAILURE);
- }
-
- /* prepare file name buffer */
- iDirNameLen = strlen((char*) pDirName);
- memcpy(szFullFileName, pDirName, iDirNameLen);
-
- /* now read the directory */
- iEntriesDone = 0;
- while(readdir_r(pDir, &u.d, &res) == 0) {
- if(res == NULL)
- break; /* this also indicates end of directory */
-# ifdef DT_REG
- /* TODO: find an alternate way to checking for special files if this is
- * not defined. This is currently a known problem on HP UX, but the work-
- * around is simple: do not create special files in that directory. So
- * fixing this is actually not the most important thing on earth...
- * rgerhards, 2008-03-04
- */
- if(res->d_type != DT_REG)
- continue; /* we are not interested in special files */
-# endif
- if(res->d_name[0] == '.')
- continue; /* these files we are also not interested in */
- ++iEntriesDone;
- /* construct filename */
- iFileNameLen = strlen(res->d_name);
- if (iFileNameLen > NAME_MAX)
- iFileNameLen = NAME_MAX;
- memcpy(szFullFileName + iDirNameLen, res->d_name, iFileNameLen);
- *(szFullFileName + iDirNameLen + iFileNameLen) = '\0';
- dbgprintf("including file '%s'\n", szFullFileName);
- processConfFile(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
- */
- }
-
- if(iEntriesDone == 0) {
- /* I just make it a debug output, because I can think of a lot of cases where it
- * makes sense not to have any files. E.g. a system maintainer may place a $Include
- * into the config file just in case, when additional modules be installed. When none
- * are installed, the directory will be empty, which is fine. -- rgerhards 2007-08-01
- */
- dbgprintf("warning: the include directory contained no files - this may be ok.\n");
- }
-
-finalize_it:
- if(pDir != NULL)
- closedir(pDir);
-
- RETiRet;
-}
-
-
-/* process a $include config line. That type of line requires
- * inclusion of another file.
- * rgerhards, 2007-08-01
- */
-rsRetVal
-doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal)
-{
- DEFiRet;
- char pattern[MAXFNAME];
- uchar *cfgFile;
- glob_t cfgFiles;
- int result;
- size_t i = 0;
- struct stat fileInfo;
-
- ASSERT(pp != NULL);
- ASSERT(*pp != NULL);
-
- if(getSubString(pp, (char*) pattern, sizeof(pattern) / sizeof(char), ' ') != 0) {
- errmsg.LogError(0, RS_RET_NOT_FOUND, "could not parse config file name");
- ABORT_FINALIZE(RS_RET_NOT_FOUND);
- }
+EHostnameCmpMode eDfltHostnameCmpMode = HN_NO_COMP;
+cstr_t *pDfltHostnameCmp = NULL;
+cstr_t *pDfltProgNameCmp = NULL;
- /* Use GLOB_MARK to append a trailing slash for directories.
- * Required by doIncludeDirectory().
- */
- result = glob(pattern, GLOB_MARK, NULL, &cfgFiles);
- if(result == GLOB_NOSPACE || result == GLOB_ABORTED) {
- char errStr[1024];
- rs_strerror_r(errno, errStr, sizeof(errStr));
- errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s",
- pattern, errStr);
- ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
- }
-
- for(i = 0; i < cfgFiles.gl_pathc; i++) {
- cfgFile = (uchar*) cfgFiles.gl_pathv[i];
-
- if(stat((char*) cfgFile, &fileInfo) != 0)
- continue; /* continue with the next file if we can't stat() the file */
-
- if(S_ISREG(fileInfo.st_mode)) { /* config file */
- dbgprintf("requested to include config file '%s'\n", cfgFile);
- iRet = processConfFile(cfgFile);
- } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */
- dbgprintf("requested to include directory '%s'\n", cfgFile);
- iRet = doIncludeDirectory(cfgFile);
- } else { /* TODO: shall we handle symlinks or not? */
- dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile);
- }
- }
-
- globfree(&cfgFiles);
-finalize_it:
- RETiRet;
-}
-
-
-/* process a $ModLoad config line.
- */
+/* process a $ModLoad config line. */
rsRetVal
doModLoad(uchar **pp, __attribute__((unused)) void* pVal)
{
@@ -274,7 +128,7 @@ doModLoad(uchar **pp, __attribute__((unused)) void* pVal)
else
pModName = szName;
- CHKiRet(module.Load(pModName));
+ CHKiRet(module.Load(pModName, 1));
finalize_it:
RETiRet;
@@ -318,7 +172,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);
@@ -384,125 +238,6 @@ finalize_it:
}
-
-
-/* process a configuration file
- * started with code from init() by rgerhards on 2007-07-31
- */
-static rsRetVal
-processConfFile(uchar *pConfFile)
-{
- int iLnNbr = 0;
- FILE *cf;
- rule_t *pCurrRule = NULL;
- uchar *p;
- uchar cbuf[CFGLNSIZ];
- uchar *cline;
- int i;
- rsRetVal localRet;
- int bHadAnError = 0;
- uchar *pszOrgLine = NULL;
- size_t lenLine;
- DEFiRet;
- ASSERT(pConfFile != NULL);
-
- if((cf = fopen((char*)pConfFile, "r")) == NULL) {
- ABORT_FINALIZE(RS_RET_FOPEN_FAILURE);
- }
-
- /* Now process the file.
- */
- cline = cbuf;
- while (fgets((char*)cline, sizeof(cbuf) - (cline - cbuf), cf) != NULL) {
- ++iLnNbr;
- /* drop LF - TODO: make it better, replace fgets(), but its clean as it is */
- lenLine = ustrlen(cline);
- if(cline[lenLine-1] == '\n') {
- cline[lenLine-1] = '\0';
- }
- free(pszOrgLine);
- pszOrgLine = ustrdup(cline); /* save if needed for errmsg, NULL ptr is OK */
- /* check for end-of-section, comments, strip off trailing
- * spaces and newline character.
- */
- p = cline;
- skipWhiteSpace(&p);
- if (*p == '\0' || *p == '#')
- continue;
-
- /* we now need to copy the characters to the begin of line. As this overlaps,
- * we can not use strcpy(). -- rgerhards, 2008-03-20
- * TODO: review the code at whole - this is highly suspect (but will go away
- * once we do the rest of RainerScript).
- */
- for( i = 0 ; p[i] != '\0' ; ++i) {
- cline[i] = p[i];
- }
- cline[i] = '\0';
-
- for (p = (uchar*) strchr((char*)cline, '\0'); isspace((int) *--p);)
- /*EMPTY*/;
- if (*p == '\\') {
- if ((p - cbuf) > CFGLNSIZ - 30) {
- /* Oops the buffer is full - what now? */
- cline = cbuf;
- } else {
- *p = 0;
- cline = p;
- continue;
- }
- } else
- cline = cbuf;
- *++p = '\0'; /* TODO: check this */
-
- /* we now have the complete line, and are positioned at the first non-whitespace
- * character. So let's process it
- */
- if((localRet = cfline(cbuf, &pCurrRule)) != RS_RET_OK) {
- /* we log a message, but otherwise ignore the error. After all, the next
- * line can be correct. -- rgerhards, 2007-08-02
- */
- uchar szErrLoc[MAXFNAME + 64];
- if(localRet != RS_RET_OK_WARN) {
- dbgprintf("config line NOT successfully processed\n");
- bHadAnError = 1;
- }
- snprintf((char*)szErrLoc, sizeof(szErrLoc) / sizeof(uchar),
- "%s, line %d", pConfFile, iLnNbr);
- errmsg.LogError(0, NO_ERRCODE, "the last %s occured in %s:\"%s\"",
- (localRet == RS_RET_OK_WARN) ? "warning" : "error",
- (char*)szErrLoc, (char*)pszOrgLine);
- }
- }
-
- /* 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));
- }
-
- /* close the configuration file */
- fclose(cf);
-
-finalize_it:
- if(iRet != RS_RET_OK) {
- char errStr[1024];
- if(pCurrRule != NULL)
- rule.Destruct(&pCurrRule);
-
- rs_strerror_r(errno, errStr, sizeof(errStr));
- dbgprintf("error %d processing config file '%s'; os error (if any): %s\n",
- iRet, pConfFile, errStr);
- }
-
- free(pszOrgLine);
-
- if(bHadAnError && (iRet == RS_RET_OK)) { /* a bit dirty, enhance in future releases */
- iRet = RS_RET_NONFATAL_CONFIG_ERR;
- }
- RETiRet;
-}
-
-
/* Helper to cfline() and its helpers. Parses a template name
* from an "action" line. Must be called with the Line pointer
* pointing to the first character after the semicolon.
@@ -602,7 +337,7 @@ cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int
* rgerhards 2005-09-15
*/
/* GPLv3 - stems back to sysklogd */
-static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule)
+rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule)
{
uchar *p;
register uchar *q;
@@ -619,7 +354,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule
ASSERT(*pline != NULL);
ISOBJ_TYPE_assert(pRule, rule);
- dbgprintf(" - traditional PRI filter\n");
+ dbgprintf(" - traditional PRI filter '%s'\n", *pline);
errno = 0; /* keep strerror_r() stuff out of logerror messages */
pRule->f_filter_type = FILTER_PRI;
@@ -632,7 +367,6 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule
/* scan through the list of selectors */
for (p = *pline; *p && *p != '\t' && *p != ' ';) {
-
/* find the end of this facility name list */
for (q = p; *q && *q != '\t' && *q++ != '.'; )
continue;
@@ -643,8 +377,10 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule
*bp = '\0';
/* skip cruft */
- while (strchr(",;", *q))
- q++;
+ if(*q) {
+ while (strchr(",;", *q))
+ q++;
+ }
/* decode priority name */
if ( *buf == '!' ) {
@@ -755,81 +491,12 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule
}
-/* Helper to cfline(). This function processes an "if" type of filter,
- * what essentially means it parses an expression. As usual,
- * It processes the line up to the beginning of the action part.
- * A pointer to that beginnig is passed back to the caller.
- * rgerhards 2008-01-19
- */
-static rsRetVal cflineProcessIfFilter(uchar **pline, register rule_t *f)
-{
- DEFiRet;
- ctok_t *tok;
- ctok_token_t *pToken;
-
- ASSERT(pline != NULL);
- ASSERT(*pline != NULL);
- ASSERT(f != NULL);
-
- dbgprintf(" - general expression-based filter\n");
- errno = 0; /* keep strerror_r() stuff out of logerror messages */
-
- f->f_filter_type = FILTER_EXPR;
-
- /* if we come to over here, pline starts with "if ". We just skip that part. */
- (*pline) += 3;
-
- /* we first need a tokenizer... */
- CHKiRet(ctok.Construct(&tok));
- CHKiRet(ctok.Setpp(tok, *pline));
- CHKiRet(ctok.ConstructFinalize(tok));
-
- /* now construct our expression */
- CHKiRet(expr.Construct(&f->f_filterData.f_expr));
- CHKiRet(expr.ConstructFinalize(f->f_filterData.f_expr));
-
- /* ready to go... */
- CHKiRet(expr.Parse(f->f_filterData.f_expr, tok));
-
- /* we now need to parse off the "then" - and note an error if it is
- * missing...
- */
- CHKiRet(ctok.GetToken(tok, &pToken));
- if(pToken->tok != ctok_THEN) {
- ctok_token.Destruct(&pToken);
- ABORT_FINALIZE(RS_RET_SYNTAX_ERROR);
- }
-
- ctok_token.Destruct(&pToken); /* no longer needed */
-
- /* we are done, so we now need to restore things */
- CHKiRet(ctok.Getpp(tok, pline));
- CHKiRet(ctok.Destruct(&tok));
-
- /* debug support - print vmprg after construction (uncomment to use) */
- /* vmprgDebugPrint(f->f_filterData.f_expr->pVmprg); */
-
- /* we now need to skip whitespace to the action part, else we confuse
- * the legacy rsyslog conf parser. -- rgerhards, 2008-02-25
- */
- while(isspace(**pline))
- ++(*pline);
-
-finalize_it:
- if(iRet == RS_RET_SYNTAX_ERROR) {
- errmsg.LogError(0, RS_RET_SYNTAX_ERROR, "syntax error in expression");
- }
-
- RETiRet;
-}
-
-
/* Helper to cfline(). This function takes the filter part of a property
* based filter and decodes it. It processes the line up to the beginning
* of the action part. A pointer to that beginnig is passed back to the caller.
* rgerhards 2005-09-15
*/
-static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
+rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
{
rsParsObj *pPars;
cstr_t *pCSCompOp;
@@ -841,7 +508,7 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
ASSERT(*pline != NULL);
ASSERT(f != NULL);
- dbgprintf(" - property-based filter\n");
+ dbgprintf(" - property-based filter '%s'\n", *pline);
errno = 0; /* keep strerror_r() stuff out of logerror messages */
f->f_filter_type = FILTER_PROP;
@@ -865,6 +532,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 */
@@ -897,6 +572,8 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
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)) {
@@ -909,12 +586,14 @@ 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);
+ 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 */
@@ -937,7 +616,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)
+rsRetVal cflineProcessHostSelector(uchar **pline)
{
DEFiRet;
@@ -987,7 +666,7 @@ finalize_it:
* from the config file ("!tagname"). It stores it for further reference.
* rgerhards 2005-10-18
*/
-static rsRetVal cflineProcessTagSelector(uchar **pline)
+rsRetVal cflineProcessTagSelector(uchar **pline)
{
DEFiRet;
@@ -1025,75 +704,32 @@ finalize_it:
}
-/* read the filter part of a configuration line and store the filter
- * in the supplied rule_t
- * rgerhards, 2007-08-01
- */
-static rsRetVal cflineDoFilter(uchar **pp, rule_t *f)
-{
- DEFiRet;
-
- ASSERT(pp != NULL);
- ISOBJ_TYPE_assert(f, rule);
-
- /* check which filter we need to pull... */
- switch(**pp) {
- case ':':
- CHKiRet(cflineProcessPropFilter(pp, f));
- break;
- case 'i': /* "if" filter? */
- if(*(*pp+1) && (*(*pp+1) == 'f') && isspace(*(*pp+2))) {
- CHKiRet(cflineProcessIfFilter(pp, f));
- break;
- }
- /*FALLTHROUGH*/
- default:
- CHKiRet(cflineProcessTradPRIFilter(pp, f));
- break;
- }
-
- /* we now check if there are some global (BSD-style) filter conditions
- * 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));
- }
-
- if(eDfltHostnameCmpMode != HN_NO_COMP) {
- f->eHostnameCmpMode = eDfltHostnameCmpMode;
- CHKiRet(rsCStrConstructFromCStr(&(f->pCSHostnameComp), pDfltHostnameCmp));
- }
-
-finalize_it:
- RETiRet;
-}
-
-
/* process the action part of a selector line
* rgerhards, 2007-08-01
*/
-static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
+rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction)
{
- DEFiRet;
modInfo_t *pMod;
+ cfgmodules_etry_t *node;
omodStringRequest_t *pOMSR;
+ int bHadWarning = 0;
action_t *pAction = NULL;
void *pModData;
- int bHadWarning = 0;
+ DEFiRet;
ASSERT(p != NULL);
ASSERT(ppAction != NULL);
/* 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
+ node = module.GetNxtCnfType(conf, NULL, eMOD_OUT);
+ /* Note: clang static analyzer reports that node maybe == 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) {
+ assert(node != NULL);
+ while(node != NULL) {
pOMSR = NULL;
+ pMod = node->pMod;
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_WARN) {
@@ -1101,16 +737,22 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
iRet = RS_RET_OK;
}
if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) {
- if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) {
+ /* 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, NULL, NULL,
+ (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;
}
@@ -1124,7 +766,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);
+ node = module.GetNxtCnfType(conf, node, eMOD_OUT);
}
*ppAction = pAction;
@@ -1134,131 +776,170 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
}
-/* Process a configuration file line in traditional "filter selector" format
- * or one that builds upon this format. Note that ppRule may be a NULL pointer,
- * which is valid and happens if there is no previous line (right at the start
- * of the master config file!).
+/* return the current number of active actions
+ * rgerhards, 2008-07-28
*/
static rsRetVal
-cflineClassic(uchar *p, rule_t **ppRule)
+GetNbrActActions(rsconf_t *conf, int *piNbrActions)
{
DEFiRet;
- action_t *pAction;
- rsRetVal localRet;
- int bHadWarning = 0;
+ assert(piNbrActions != NULL);
+ *piNbrActions = conf->actions.nbrActions;
+ RETiRet;
+}
- /* lines starting with '&' have no new filters and just add
- * new actions to the currently processed selector.
- */
- if(*p == '&') {
- ++p; /* eat '&' */
- skipWhiteSpace(&p); /* on to command */
- } else {
- /* we are finished with the current selector (on previous line).
- * So we now need to check
- * if it has any actions associated and, if so, link it to the linked
- * list. If it has nothing associated with it, we can simply discard
- * it. In any case, we create a fresh selector for our new filter.
- * We have one special case during initialization: then, the current
- * selector is NULL, which means we do not need to care about it at
- * all. -- rgerhards, 2007-08-01
- */
- if(*ppRule != NULL) {
- CHKiRet(ruleset.AddRule(rule.GetAssRuleset(*ppRule), ppRule));
- }
- CHKiRet(rule.Construct(ppRule)); /* create "fresh" selector */
- CHKiRet(rule.SetAssRuleset(*ppRule, ruleset.GetCurrent())); /* create "fresh" selector */
- CHKiRet(rule.ConstructFinalize(*ppRule)); /* create "fresh" selector */
- CHKiRet(cflineDoFilter(&p, *ppRule)); /* pull filters */
+
+/* queryInterface function
+ * rgerhards, 2008-02-29
+ */
+BEGINobjQueryInterface(conf)
+CODESTARTobjQueryInterface(conf)
+ if(pIf->ifVersion != confCURR_IF_VERSION) { /* check for current version, increment on each change */
+ ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
}
- localRet = cflineDoAction(&p, &pAction);
- if(localRet == RS_RET_OK_WARN) {
- bHadWarning = 1;
- } else {
- CHKiRet(localRet);
+ /* 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->doNameLine = doNameLine;
+ pIf->cfsysline = cfsysline;
+ pIf->doModLoad = doModLoad;
+ 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;
+ cfgmodules_etry_t *node;
+
+ currConfObj = eConfObjAction;
+ DBGPRINTF("entering action scope\n");
+ CHKiRet(actionNewScope());
+
+ /* now tell each action to start the scope */
+ node = NULL;
+ while((node = module.GetNxtCnfType(loadConf, node, eMOD_OUT)) != NULL) {
+ DBGPRINTF("beginning scope on module %s\n", node->pMod->pszName);
+ node->pMod->mod.om.newScope();
}
- CHKiRet(llAppend(&(*ppRule)->llActList, NULL, (void*) pAction));
finalize_it:
- if(iRet == RS_RET_OK && bHadWarning)
- iRet = RS_RET_OK_WARN;
RETiRet;
}
-/* process a configuration line
- * I re-did this functon because it was desperately time to do so
- * rgerhards, 2007-08-01
+/* switch back from action scope.
+ * rgerhards, 2010-07-27
*/
-static rsRetVal
-cfline(uchar *line, rule_t **pfCurr)
+static inline rsRetVal
+unsetActionScope(void)
{
DEFiRet;
+ cfgmodules_etry_t *node;
- ASSERT(line != NULL);
-
- dbgprintf("cfline: '%s'\n", line);
+ currConfObj = eConfObjAction;
+ DBGPRINTF("exiting action scope\n");
+ CHKiRet(actionRestoreScope());
- /* check type of line and call respective processing */
- switch(*line) {
- case '!':
- iRet = cflineProcessTagSelector(&line);
- break;
- case '+':
- case '-':
- iRet = cflineProcessHostSelector(&line);
- break;
- case '$':
- ++line; /* eat '$' */
- iRet = cfsysline(line);
- break;
- default:
- iRet = cflineClassic(line, pfCurr);
- break;
+ /* now tell each action to restore the scope */
+ node = NULL;
+ while((node = module.GetNxtCnfType(loadConf, node, eMOD_OUT)) != NULL) {
+ DBGPRINTF("exiting scope on module %s\n", node->pMod->pszName);
+ node->pMod->mod.om.restoreScope();
}
+finalize_it:
RETiRet;
}
-/* return the current number of active actions
- * rgerhards, 2008-07-28
+/* 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
-GetNbrActActions(int *piNbrActions)
+beginConfObj(void __attribute__((unused)) *pVal, uchar *pszName)
{
DEFiRet;
- assert(piNbrActions != NULL);
- *piNbrActions = iNbrActions;
+
+ 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;
}
-/* queryInterface function
- * rgerhards, 2008-02-29
+/* This method is called to end a config scope and switch
+ * back to global scope.
+ * rgerhards, 2010-07-23
*/
-BEGINobjQueryInterface(conf)
-CODESTARTobjQueryInterface(conf)
- if(pIf->ifVersion != confCURR_IF_VERSION) { /* check for current version, increment on each change */
- ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED);
+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);
}
- /* 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->doNameLine = doNameLine;
- pIf->cfsysline = cfsysline;
- pIf->doModLoad = doModLoad;
- pIf->doIncludeLine = doIncludeLine;
- pIf->cfline = cfline;
- pIf->processConfFile = processConfFile;
- pIf->GetNbrActActions = GetNbrActActions;
+ 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:
-ENDobjQueryInterface(conf)
+ 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
@@ -1276,9 +957,6 @@ CODESTARTObjClassExit(conf)
}
/* release objects we no longer need */
- objRelease(expr, CORE_COMPONENT);
- objRelease(ctok, CORE_COMPONENT);
- objRelease(ctok_token, CORE_COMPONENT);
objRelease(module, CORE_COMPONENT);
objRelease(errmsg, CORE_COMPONENT);
objRelease(net, LM_NET_FILENAME);
@@ -1293,14 +971,21 @@ ENDObjClassExit(conf)
*/
BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */
/* request objects we use */
- CHKiRet(objUse(expr, CORE_COMPONENT));
- CHKiRet(objUse(ctok, CORE_COMPONENT));
- CHKiRet(objUse(ctok_token, CORE_COMPONENT));
CHKiRet(objUse(module, CORE_COMPONENT));
CHKiRet(objUse(errmsg, CORE_COMPONENT));
CHKiRet(objUse(net, LM_NET_FILENAME)); /* TODO: make this dependcy go away! */
CHKiRet(objUse(rule, CORE_COMPONENT));
CHKiRet(objUse(ruleset, CORE_COMPONENT));
+
+ /* These commands will NOT be supported -- the new v6.3 config system provides
+ * far better methods. We will remove the related code soon. -- rgerhards, 2012-01-09
+ */
+#if 0
+ 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));
+#endif
+ CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjAction));
ENDObjClassInit(conf)
/* vi:set ai: