summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/Makefile.am2
-rw-r--r--runtime/batch.h5
-rw-r--r--runtime/cfsysline.c35
-rw-r--r--runtime/cfsysline.h2
-rw-r--r--runtime/conf.c217
-rw-r--r--runtime/conf.h7
-rw-r--r--runtime/debug.h9
-rw-r--r--runtime/im-helper.h1
-rw-r--r--runtime/module-template.h60
-rw-r--r--runtime/modules.c172
-rw-r--r--runtime/modules.h28
-rw-r--r--runtime/msg.c519
-rw-r--r--runtime/msg.h20
-rw-r--r--runtime/nsd_ptcp.c4
-rw-r--r--runtime/obj.c4
-rw-r--r--runtime/objomsr.c7
-rw-r--r--runtime/objomsr.h7
-rw-r--r--runtime/parser.c14
-rw-r--r--runtime/parser.h1
-rw-r--r--runtime/queue.c144
-rw-r--r--runtime/rsconf.c247
-rw-r--r--runtime/rsconf.h2
-rw-r--r--runtime/rsyslog.c4
-rw-r--r--runtime/rsyslog.h19
-rw-r--r--runtime/rule.c477
-rw-r--r--runtime/rule.h78
-rw-r--r--runtime/ruleset.c638
-rw-r--r--runtime/ruleset.h23
-rw-r--r--runtime/statsobj.c12
-rw-r--r--runtime/statsobj.h3
-rw-r--r--runtime/typedefs.h5
-rw-r--r--runtime/wti.c16
32 files changed, 1591 insertions, 1191 deletions
diff --git a/runtime/Makefile.am b/runtime/Makefile.am
index 67e235a0..7af26d2b 100644
--- a/runtime/Makefile.am
+++ b/runtime/Makefile.am
@@ -63,8 +63,6 @@ librsyslog_la_SOURCES = \
queue.h \
ruleset.c \
ruleset.h \
- rule.c \
- rule.h \
prop.c \
prop.h \
cfsysline.c \
diff --git a/runtime/batch.h b/runtime/batch.h
index 944889bd..f743c188 100644
--- a/runtime/batch.h
+++ b/runtime/batch.h
@@ -51,7 +51,6 @@ struct batch_obj_s {
/* work variables for action processing; these are reused for each action (or block of
* actions)
*/
- sbool bFilterOK; /* work area for filter processing (per action, reused!) */
sbool bPrevWasSuspended;
/* following are caches to save allocs if not absolutely necessary */
uchar *staticActStrings[CONF_OMOD_NUMSTRINGS_MAXSIZE]; /**< for strings */
@@ -83,6 +82,7 @@ struct batch_s {
int iDoneUpTo; /* all messages below this index have state other than RDY */
qDeqID deqID; /* ID of dequeue operation that generated this batch */
int *pbShutdownImmediate;/* end processing of this batch immediately if set to 1 */
+ sbool *active; /* which messages are active for processing, NULL=all */
sbool bSingleRuleset; /* do all msgs of this batch use a single ruleset? */
batch_obj_t *pElem; /* batch elements */
};
@@ -129,7 +129,8 @@ batchSetElemState(batch_t *pBatch, int i, batch_state_t newState) {
*/
static inline int
batchIsValidElem(batch_t *pBatch, int i) {
- return(pBatch->pElem[i].bFilterOK && pBatch->pElem[i].state != BATCH_STATE_DISC);
+ return( (pBatch->pElem[i].state != BATCH_STATE_DISC)
+ && (pBatch->active == NULL || pBatch->active[i]));
}
diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c
index fdbb8f2a..6b06d427 100644
--- a/runtime/cfsysline.c
+++ b/runtime/cfsysline.c
@@ -686,7 +686,7 @@ 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, int *permitted)
{
assert(pThis != NULL);
assert(eType != eCmdHdlrInvalid);
@@ -694,6 +694,7 @@ rsRetVal cslchSetEntry(cslCmdHdlr_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pH
pThis->eType = eType;
pThis->cslCmdHdlr = pHdlr;
pThis->pData = pData;
+ pThis->permitted = permitted;
return RS_RET_OK;
}
@@ -810,7 +811,7 @@ 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, int *permitted)
{
DEFiRet;
cslCmdHdlr_t *pCmdHdlr = NULL;
@@ -818,7 +819,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, permitted));
CHKiRet(llAppend(&pThis->llCmdHdlrs, pOwnerCookie, pCmdHdlr));
finalize_it:
@@ -836,8 +837,16 @@ finalize_it:
* buffer is automatically destroyed when the element is freed, the
* caller does not need to take care of that. The caller must, however,
* free pCmdName if he allocated it dynamically! -- rgerhards, 2007-08-09
+ * Parameter permitted has been added to support the v2 config system. With it,
+ * we can tell the legacy system (us here!) to check if a config directive is
+ * still permitted. For example, the v2 system will disable module global
+ * paramters if the are supplied via the native v2 callbacks. In order not
+ * to break exisiting modules, we have renamed the rgCfSysLinHdlr routine to
+ * version 2 and added a new one with the original name. It just calls the
+ * v2 function and supplies a "don't care (NULL)" pointer as this argument.
+ * rgerhards, 2012-06-26
*/
-rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie)
+rsRetVal regCfSysLineHdlr2(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie, int *permitted)
{
DEFiRet;
cslCmd_t *pThis;
@@ -847,7 +856,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, permitted)) {
cslcDestruct(pThis);
FINALIZE;
}
@@ -867,7 +876,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, permitted)) {
cslcDestruct(pThis);
FINALIZE;
}
@@ -877,6 +886,13 @@ finalize_it:
RETiRet;
}
+rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie)
+{
+ DEFiRet;
+ iRet = regCfSysLineHdlr2(pCmdName, bChainingPermitted, eType, pHdlr, pData, pOwnerCookie, NULL);
+ RETiRet;
+}
+
rsRetVal unregCfSysLineHdlrs(void)
{
@@ -965,7 +981,12 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p)
* necessary). -- rgerhards, 2007-07-31
*/
pHdlrP = *p;
- if((iRet = cslchCallHdlr(pCmdHdlr, &pHdlrP)) == RS_RET_OK) {
+ if(pCmdHdlr->permitted != NULL && !*(pCmdHdlr->permitted)) {
+ errmsg.LogError(0, RS_RET_PARAM_NOT_PERMITTED, "command '%s' is currently not "
+ "permitted - did you already set it via a RainerScript command (v6+ config)?",
+ pCmdName);
+ ABORT_FINALIZE(RS_RET_PARAM_NOT_PERMITTED);
+ } else if((iRet = cslchCallHdlr(pCmdHdlr, &pHdlrP)) == RS_RET_OK) {
bWasOnceOK = 1;
pOKp = pHdlrP;
}
diff --git a/runtime/cfsysline.h b/runtime/cfsysline.h
index 2768243f..69389f84 100644
--- a/runtime/cfsysline.h
+++ b/runtime/cfsysline.h
@@ -33,6 +33,7 @@ struct cslCmdHdlr_s { /* config file sysline parse entry */
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 */
+ int *permitted; /* is this parameter currently permitted? (NULL=don't check) */
};
typedef struct cslCmdHdlr_s cslCmdHdlr_t;
@@ -49,6 +50,7 @@ typedef struct cslCmd_s cslCmd_t;
/* prototypes */
rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie);
+rsRetVal regCfSysLineHdlr2(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie, int *permitted);
rsRetVal unregCfSysLineHdlrs(void);
rsRetVal unregCfSysLineHdlrs4Owner(void *pOwnerCookie);
rsRetVal processCfSysLineCommand(uchar *pCmd, uchar **p);
diff --git a/runtime/conf.c b/runtime/conf.c
index eec04df8..23fb6bbd 100644
--- a/runtime/conf.c
+++ b/runtime/conf.c
@@ -61,17 +61,16 @@
#include "srUtils.h"
#include "errmsg.h"
#include "net.h"
-#include "rule.h"
#include "ruleset.h"
#include "rsconf.h"
#include "unicode-helper.h"
+#include "rainerscript.h"
#ifdef OS_SOLARIS
# define NAME_MAX MAXNAMELEN
#endif
/* forward definitions */
-//static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr);
/* static data */
@@ -79,7 +78,6 @@ DEFobjStaticHelpers
DEFobjCurrIf(module)
DEFobjCurrIf(errmsg)
DEFobjCurrIf(net)
-DEFobjCurrIf(rule)
DEFobjCurrIf(ruleset)
int bConfStrictScoping = 0; /* force strict scoping during config processing? */
@@ -116,18 +114,15 @@ doModLoad(uchar **pp, __attribute__((unused)) void* pVal)
skipWhiteSpace(pp); /* skip over any whitespace */
/* this below is a quick and dirty hack to provide compatibility with the
- * $ModLoad MySQL forward compatibility statement. TODO: clean this up
- * For the time being, it is clean enough, it just needs to be done
- * differently when we have a full design for loadable plug-ins. For the
- * time being, we just mangle the names a bit.
- * rgerhards, 2007-08-14
+ * $ModLoad MySQL forward compatibility statement. This needs to be supported
+ * for legacy format.
*/
if(!strcmp((char*) szName, "MySQL"))
pModName = (uchar*) "ommysql.so";
else
pModName = szName;
- CHKiRet(module.Load(pModName, 1));
+ CHKiRet(module.Load(pModName, 1, NULL));
finalize_it:
RETiRet;
@@ -329,14 +324,9 @@ cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int
}
-/* Helper to cfline(). This function takes the filter part of a traditional, PRI
- * based line and decodes the PRIs given in the selector line. It processed 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
- */
+/* Decode a traditional PRI filter */
/* GPLv3 - stems back to sysklogd */
-rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule)
+rsRetVal DecodePRIFilter(uchar *pline, uchar pmask[])
{
uchar *p;
register uchar *q;
@@ -350,22 +340,15 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule)
DEFiRet;
ASSERT(pline != NULL);
- ASSERT(*pline != NULL);
- ISOBJ_TYPE_assert(pRule, rule);
- dbgprintf(" - traditional PRI filter '%s'\n", *pline);
- errno = 0; /* keep strerror_r() stuff out of logerror messages */
+ dbgprintf("Decoding traditional PRI filter '%s'\n", pline);
- pRule->f_filter_type = FILTER_PRI;
- /* Note: file structure is pre-initialized to zero because it was
- * created with calloc()!
- */
for (i = 0; i <= LOG_NFACILITIES; i++) {
- pRule->f_filterData.f_pmask[i] = TABLE_NOPRI;
+ pmask[i] = TABLE_NOPRI;
}
/* scan through the list of selectors */
- for (p = *pline; *p && *p != '\t' && *p != ' ';) {
+ for (p = pline; *p && *p != '\t' && *p != ' ';) {
/* find the end of this facility name list */
for (q = p; *q && *q != '\t' && *q++ != '.'; )
continue;
@@ -414,28 +397,28 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule)
for (i = 0; i <= LOG_NFACILITIES; i++) {
if ( pri == INTERNAL_NOPRI ) {
if ( ignorepri )
- pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI;
+ pmask[i] = TABLE_ALLPRI;
else
- pRule->f_filterData.f_pmask[i] = TABLE_NOPRI;
+ pmask[i] = TABLE_NOPRI;
}
else if ( singlpri ) {
if ( ignorepri )
- pRule->f_filterData.f_pmask[i] &= ~(1<<pri);
+ pmask[i] &= ~(1<<pri);
else
- pRule->f_filterData.f_pmask[i] |= (1<<pri);
+ pmask[i] |= (1<<pri);
} else {
if ( pri == TABLE_ALLPRI ) {
if ( ignorepri )
- pRule->f_filterData.f_pmask[i] = TABLE_NOPRI;
+ pmask[i] = TABLE_NOPRI;
else
- pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI;
+ pmask[i] = TABLE_ALLPRI;
} else {
if ( ignorepri )
for (i2= 0; i2 <= pri; ++i2)
- pRule->f_filterData.f_pmask[i] &= ~(1<<i2);
+ pmask[i] &= ~(1<<i2);
else
for (i2= 0; i2 <= pri; ++i2)
- pRule->f_filterData.f_pmask[i] |= (1<<i2);
+ pmask[i] |= (1<<i2);
}
}
}
@@ -450,27 +433,27 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule)
if ( pri == INTERNAL_NOPRI ) {
if ( ignorepri )
- pRule->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI;
+ pmask[i >> 3] = TABLE_ALLPRI;
else
- pRule->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI;
+ pmask[i >> 3] = TABLE_NOPRI;
} else if ( singlpri ) {
if ( ignorepri )
- pRule->f_filterData.f_pmask[i >> 3] &= ~(1<<pri);
+ pmask[i >> 3] &= ~(1<<pri);
else
- pRule->f_filterData.f_pmask[i >> 3] |= (1<<pri);
+ pmask[i >> 3] |= (1<<pri);
} else {
if ( pri == TABLE_ALLPRI ) {
if ( ignorepri )
- pRule->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI;
+ pmask[i >> 3] = TABLE_NOPRI;
else
- pRule->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI;
+ pmask[i >> 3] = TABLE_ALLPRI;
} else {
if ( ignorepri )
for (i2= 0; i2 <= pri; ++i2)
- pRule->f_filterData.f_pmask[i >> 3] &= ~(1<<i2);
+ pmask[i >> 3] &= ~(1<<i2);
else
for (i2= 0; i2 <= pri; ++i2)
- pRule->f_filterData.f_pmask[i >> 3] |= (1<<i2);
+ pmask[i >> 3] |= (1<<i2);
}
}
}
@@ -481,11 +464,6 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule)
p = q;
}
- /* skip to action part */
- while (*p == '\t' || *p == ' ')
- p++;
-
- *pline = p;
RETiRet;
}
@@ -495,7 +473,7 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule)
* of the action part. A pointer to that beginnig is passed back to the caller.
* rgerhards 2005-09-15
*/
-rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
+rsRetVal DecodePropFilter(uchar *pline, struct cnfstmt *stmt)
{
rsParsObj *pPars;
cstr_t *pCSCompOp;
@@ -504,16 +482,11 @@ rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
int iOffset; /* for compare operations */
ASSERT(pline != NULL);
- ASSERT(*pline != NULL);
- ASSERT(f != NULL);
- dbgprintf(" - property-based filter '%s'\n", *pline);
- errno = 0; /* keep strerror_r() stuff out of logerror messages */
-
- f->f_filter_type = FILTER_PROP;
+ dbgprintf("Decoding property-based filter '%s'\n", pline);
/* create parser object starting with line string without leading colon */
- if((iRet = rsParsConstructFromSz(&pPars, (*pline)+1)) != RS_RET_OK) {
+ if((iRet = rsParsConstructFromSz(&pPars, pline+1)) != RS_RET_OK) {
errmsg.LogError(0, iRet, "Error %d constructing parser object - ignoring selector", iRet);
return(iRet);
}
@@ -525,15 +498,15 @@ rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
rsParsDestruct(pPars);
return(iRet);
}
- iRet = propNameToID(pCSPropName, &f->f_filterData.prop.propID);
+ iRet = propNameToID(pCSPropName, &stmt->d.s_propfilt.propID);
if(iRet != RS_RET_OK) {
errmsg.LogError(0, iRet, "error %d parsing filter property - ignoring selector", iRet);
rsParsDestruct(pPars);
return(iRet);
}
- if(f->f_filterData.prop.propID == PROP_CEE) {
+ if(stmt->d.s_propfilt.propID == PROP_CEE) {
/* in CEE case, we need to preserve the actual property name */
- if((f->f_filterData.prop.propName =
+ if((stmt->d.s_propfilt.propName =
es_newStrFromBuf((char*)cstrGetSzStrNoNULL(pCSPropName)+2, cstrLen(pCSPropName)-2)) == NULL) {
cstrDestruct(&pCSPropName);
return(RS_RET_ERR);
@@ -556,38 +529,38 @@ rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
*/
if(rsCStrLen(pCSCompOp) > 0) {
if(*rsCStrGetBufBeg(pCSCompOp) == '!') {
- f->f_filterData.prop.isNegated = 1;
+ stmt->d.s_propfilt.isNegated = 1;
iOffset = 1; /* ignore '!' */
} else {
- f->f_filterData.prop.isNegated = 0;
+ stmt->d.s_propfilt.isNegated = 0;
iOffset = 0;
}
} else {
- f->f_filterData.prop.isNegated = 0;
+ stmt->d.s_propfilt.isNegated = 0;
iOffset = 0;
}
if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) {
- f->f_filterData.prop.operation = FIOP_CONTAINS;
+ stmt->d.s_propfilt.operation = FIOP_CONTAINS;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) {
- f->f_filterData.prop.operation = FIOP_ISEQUAL;
+ stmt->d.s_propfilt.operation = FIOP_ISEQUAL;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isempty", 7)) {
- f->f_filterData.prop.operation = FIOP_ISEMPTY;
+ stmt->d.s_propfilt.operation = FIOP_ISEMPTY;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "startswith", 10)) {
- f->f_filterData.prop.operation = FIOP_STARTSWITH;
+ stmt->d.s_propfilt.operation = FIOP_STARTSWITH;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) {
- f->f_filterData.prop.operation = FIOP_REGEX;
+ stmt->d.s_propfilt.operation = FIOP_REGEX;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "ereregex", 8)) {
- f->f_filterData.prop.operation = FIOP_EREREGEX;
+ stmt->d.s_propfilt.operation = FIOP_EREREGEX;
} else {
errmsg.LogError(0, NO_ERRCODE, "error: invalid compare operation '%s' - ignoring selector",
(char*) rsCStrGetSzStrNoNULL(pCSCompOp));
}
rsCStrDestruct(&pCSCompOp); /* no longer needed */
- if(f->f_filterData.prop.operation != FIOP_ISEMPTY) {
+ if(stmt->d.s_propfilt.operation != FIOP_ISEMPTY) {
/* read compare value */
- iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue);
+ iRet = parsQuotedCStr(pPars, &stmt->d.s_propfilt.pCSCompValue);
if(iRet != RS_RET_OK) {
errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet);
rsParsDestruct(pPars);
@@ -595,114 +568,10 @@ rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
}
}
- /* skip to action part */
- if((iRet = parsSkipWhitespace(pPars)) != RS_RET_OK) {
- errmsg.LogError(0, iRet, "error %d skipping to action part - ignoring selector", iRet);
- rsParsDestruct(pPars);
- return(iRet);
- }
-
- /* cleanup */
- *pline = *pline + rsParsGetParsePointer(pPars) + 1;
- /* we are adding one for the skipped initial ":" */
-
return rsParsDestruct(pPars);
}
-/*
- * Helper to cfline(). This function interprets a BSD host selector line
- * from the config file ("+/-hostname"). It stores it for further reference.
- * rgerhards 2005-10-19
- */
-rsRetVal cflineProcessHostSelector(uchar **pline)
-{
- DEFiRet;
-
- ASSERT(pline != NULL);
- ASSERT(*pline != NULL);
- ASSERT(**pline == '-' || **pline == '+');
-
- dbgprintf(" - host selector line\n");
-
- /* check include/exclude setting */
- if(**pline == '+') {
- eDfltHostnameCmpMode = HN_COMP_MATCH;
- } else { /* we do not check for '-', it must be, else we wouldn't be here */
- eDfltHostnameCmpMode = HN_COMP_NOMATCH;
- }
- (*pline)++; /* eat + or - */
-
- /* the below is somewhat of a quick hack, but it is efficient (this is
- * why it is in here. "+*" resets the tag selector with BSD syslog. We mimic
- * this, too. As it is easy to check that condition, we do not fire up a
- * parser process, just make sure we do not address beyond our space.
- * Order of conditions in the if-statement is vital! rgerhards 2005-10-18
- */
- if(**pline != '\0' && **pline == '*' && *(*pline+1) == '\0') {
- dbgprintf("resetting BSD-like hostname filter\n");
- eDfltHostnameCmpMode = HN_NO_COMP;
- if(pDfltHostnameCmp != NULL) {
- CHKiRet(rsCStrSetSzStr(pDfltHostnameCmp, NULL));
- }
- } else {
- dbgprintf("setting BSD-like hostname filter to '%s'\n", *pline);
- if(pDfltHostnameCmp == NULL) {
- /* create string for parser */
- CHKiRet(rsCStrConstructFromszStr(&pDfltHostnameCmp, *pline));
- } else { /* string objects exists, just update... */
- CHKiRet(rsCStrSetSzStr(pDfltHostnameCmp, *pline));
- }
- }
-
-finalize_it:
- RETiRet;
-}
-
-
-/*
- * Helper to cfline(). This function interprets a BSD tag selector line
- * from the config file ("!tagname"). It stores it for further reference.
- * rgerhards 2005-10-18
- */
-rsRetVal cflineProcessTagSelector(uchar **pline)
-{
- DEFiRet;
-
- ASSERT(pline != NULL);
- ASSERT(*pline != NULL);
- ASSERT(**pline == '!');
-
- dbgprintf(" - programname selector line\n");
-
- (*pline)++; /* eat '!' */
-
- /* the below is somewhat of a quick hack, but it is efficient (this is
- * why it is in here. "!*" resets the tag selector with BSD syslog. We mimic
- * this, too. As it is easy to check that condition, we do not fire up a
- * parser process, just make sure we do not address beyond our space.
- * Order of conditions in the if-statement is vital! rgerhards 2005-10-18
- */
- if(**pline != '\0' && **pline == '*' && *(*pline+1) == '\0') {
- dbgprintf("resetting programname filter\n");
- if(pDfltProgNameCmp != NULL) {
- rsCStrDestruct(&pDfltProgNameCmp);
- }
- } else {
- dbgprintf("setting programname filter to '%s'\n", *pline);
- if(pDfltProgNameCmp == NULL) {
- /* create string for parser */
- CHKiRet(rsCStrConstructFromszStr(&pDfltProgNameCmp, *pline));
- } else { /* string objects exists, just update... */
- CHKiRet(rsCStrSetSzStr(pDfltProgNameCmp, *pline));
- }
- }
-
-finalize_it:
- RETiRet;
-}
-
-
/* process the action part of a selector line
* rgerhards, 2007-08-01
*/
@@ -834,7 +703,6 @@ CODESTARTObjClassExit(conf)
objRelease(module, CORE_COMPONENT);
objRelease(errmsg, CORE_COMPONENT);
objRelease(net, LM_NET_FILENAME);
- objRelease(rule, CORE_COMPONENT);
objRelease(ruleset, CORE_COMPONENT);
ENDObjClassExit(conf)
@@ -848,7 +716,6 @@ BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANG
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
diff --git a/runtime/conf.h b/runtime/conf.h
index 018d9111..a1bb51ad 100644
--- a/runtime/conf.h
+++ b/runtime/conf.h
@@ -62,11 +62,8 @@ PROTOTYPEObj(conf);
rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName);
rsRetVal cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *pszTpl);
-/* more dirt to cover the new config interface (will go away...) */
-rsRetVal cflineProcessTagSelector(uchar **pline);
-rsRetVal cflineProcessHostSelector(uchar **pline);
-rsRetVal cflineProcessTradPRIFilter(uchar **pline, rule_t *pRule);
-rsRetVal cflineProcessPropFilter(uchar **pline, rule_t *f);
+rsRetVal DecodePRIFilter(uchar *pline, uchar pmask[]);
+rsRetVal DecodePropFilter(uchar *pline, struct cnfstmt *stmt);
rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction);
extern EHostnameCmpMode eDfltHostnameCmpMode;
extern cstr_t *pDfltHostnameCmp;
diff --git a/runtime/debug.h b/runtime/debug.h
index 26672c3e..5bd26bd8 100644
--- a/runtime/debug.h
+++ b/runtime/debug.h
@@ -106,8 +106,13 @@ void dbgPrintAllDebugInfo(void);
void *dbgmalloc(size_t size);
/* macros */
-#define DBGPRINTF(...) if(Debug) { dbgprintf(__VA_ARGS__); }
-#define DBGOPRINT(...) if(Debug) { dbgoprint(__VA_ARGS__); }
+#ifdef DEBUGLESS
+# define DBGPRINTF(...) {}
+# define DBGOPRINT(...) {}
+#else
+# define DBGPRINTF(...) if(Debug) { dbgprintf(__VA_ARGS__); }
+# define DBGOPRINT(...) if(Debug) { dbgoprint(__VA_ARGS__); }
+#endif
#ifdef RTINST
# define BEGINfunc static dbgFuncDB_t *pdbgFuncDB; int dbgCALLStaCK_POP_POINT = dbgEntrFunc(&pdbgFuncDB, __FILE__, __func__, __LINE__);
# define ENDfunc dbgExitFunc(pdbgFuncDB, dbgCALLStaCK_POP_POINT, RS_RET_NO_IRET);
diff --git a/runtime/im-helper.h b/runtime/im-helper.h
index 6bbd6d70..5c58dcd8 100644
--- a/runtime/im-helper.h
+++ b/runtime/im-helper.h
@@ -47,7 +47,6 @@ std_checkRuleset(modConfData_t *modConf, instanceConf_t *inst)
if(inst->pszBindRuleset == NULL)
FINALIZE;
-dbgprintf("ZZZZZ: inst->pszBindRuleset %s\n", inst->pszBindRuleset);
localRet = ruleset.GetRuleset(modConf->pConf, &pRuleset, inst->pszBindRuleset);
if(localRet == RS_RET_NOT_FOUND) {
diff --git a/runtime/module-template.h b/runtime/module-template.h
index 75bf7312..9dd759a5 100644
--- a/runtime/module-template.h
+++ b/runtime/module-template.h
@@ -4,7 +4,7 @@
*
* File begun on 2007-07-25 by RGerhards
*
- * Copyright 2007 Adiscon GmbH. This is Adiscon-exclusive code without any other
+ * Copyright 2007-2012 Adiscon GmbH. This is Adiscon-exclusive code without any other
* contributions. *** GPLv3 ***
*
* This file is part of the rsyslog runtime library.
@@ -353,6 +353,24 @@ finalize_it:\
}
+/* newInpInst()
+ * This is basically the equivalent to newActInst() for creating input
+ * module (listener) instances.
+ */
+#define BEGINnewInpInst \
+static rsRetVal newInpInst(struct nvlst *lst)\
+{\
+ DEFiRet;
+
+#define CODESTARTnewInpInst \
+
+#define CODE_STD_FINALIZERnewInpInst
+
+#define ENDnewInpInst \
+ RETiRet;\
+}
+
+
/* tryResume()
* 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,
@@ -503,6 +521,14 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\
} \
CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES
+/* the following block is to be added for modules that support v2
+ * module global parameters [module(...)]
+ */
+#define CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES \
+ else if(!strcmp((char*) name, "setModCnf")) {\
+ *pEtryPoint = setModCnf;\
+ } \
+
/* the following block is to be added for output modules that support the v2
* config system. The config name is also provided.
*/
@@ -513,6 +539,16 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\
CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES
+/* the following block is to be added for input modules that support the v2
+ * config system. The config name is also provided.
+ */
+#define CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES \
+ else if(!strcmp((char*) name, "newInpInst")) {\
+ *pEtryPoint = newInpInst;\
+ } \
+ CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES
+
+
/* the following block is to be added for modules that require
* pre priv drop activation support.
*/
@@ -693,6 +729,28 @@ static rsRetVal beginCnfLoad(modConfData_t **ptr, __attribute__((unused)) rsconf
}
+/* setModCnf()
+ * This function permits to set module global parameters via the v2 config
+ * interface. It may be called multiple times, but parameters must not be
+ * set in a conflicting way. The module must use its current config load
+ * context when processing the directives.
+ * Note that lst may be NULL, especially if the module is loaded via the
+ * legacy config system. The module must check for this.
+ * NOTE: This entry point must only be implemented if module global
+ * parameters are actually required.
+ */
+#define BEGINsetModCnf \
+static rsRetVal setModCnf(struct nvlst *lst)\
+{\
+ DEFiRet;
+
+#define CODESTARTsetModCnf
+
+#define ENDsetModCnf \
+ RETiRet;\
+}
+
+
/* endCnfLoad()
* This is a function tells an input module that the current config load ended.
* It gets a last chance to make changes to its in-memory config object. After
diff --git a/runtime/modules.c b/runtime/modules.c
index 39f977dd..9f7ff31c 100644
--- a/runtime/modules.c
+++ b/runtime/modules.c
@@ -11,7 +11,7 @@
*
* File begun on 2007-07-22 by RGerhards
*
- * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007-2012 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
@@ -75,6 +75,18 @@ static struct dlhandle_s *pHandles = NULL;
static uchar *pModDir; /* directory where loadable modules are found */
+/* tables for interfacing with the v6 config system */
+/* action (instance) parameters */
+static struct cnfparamdescr actpdescr[] = {
+ { "load", eCmdHdlrGetWord, 1 }
+};
+static struct cnfparamblk pblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(actpdescr)/sizeof(struct cnfparamdescr),
+ actpdescr
+ };
+
+
/* we provide a set of dummy functions for modules that do not support the
* some interfaces.
* On the commit feature: As the modules do not support it, they commit each message they
@@ -301,7 +313,8 @@ finalize_it:
/* get the name of a module
*/
-static uchar *modGetName(modInfo_t *pThis)
+uchar *
+modGetName(modInfo_t *pThis)
{
return((pThis->pszName == NULL) ? (uchar*) "" : pThis->pszName);
}
@@ -337,10 +350,13 @@ addModToGlblList(modInfo_t *pThis)
}
-/* Add a module to the config module list for current loadConf
+/* ready module for config processing. this includes checking if the module
+ * is already in the config, so this function may return errors. Returns a
+ * pointer to the last module inthe current config. That pointer needs to
+ * be passed to addModToCnfLst() when it is called later in the process.
*/
rsRetVal
-addModToCnfList(modInfo_t *pThis)
+readyModForCnf(modInfo_t *pThis, cfgmodules_etry_t **ppNew, cfgmodules_etry_t **ppLast)
{
cfgmodules_etry_t *pNew;
cfgmodules_etry_t *pLast;
@@ -348,8 +364,7 @@ addModToCnfList(modInfo_t *pThis)
assert(pThis != NULL);
if(loadConf == NULL) {
- /* we are in an early init state */
- FINALIZE;
+ FINALIZE; /* we are in an early init state */
}
/* check for duplicates and, as a side-activity, identify last node */
@@ -358,11 +373,16 @@ addModToCnfList(modInfo_t *pThis)
while(1) { /* loop broken inside */
if(pLast->pMod == pThis) {
DBGPRINTF("module '%s' already in this config\n", modGetName(pThis));
+ if(strncmp((char*)modGetName(pThis), "builtin:", sizeof("builtin:")-1)) {
+ errmsg.LogError(0, RS_RET_MODULE_ALREADY_IN_CONF,
+ "module '%s' already in this config, cannot be added\n", modGetName(pThis));
+ ABORT_FINALIZE(RS_RET_MODULE_ALREADY_IN_CONF);
+ }
FINALIZE;
}
if(pLast->next == NULL)
break;
- pLast = pLast -> next;
+ pLast = pLast->next;
}
}
@@ -380,6 +400,36 @@ addModToCnfList(modInfo_t *pThis)
CHKiRet(pThis->beginCnfLoad(&pNew->modCnf, loadConf));
}
+ *ppLast = pLast;
+ *ppNew = pNew;
+finalize_it:
+ RETiRet;
+}
+
+
+/* abort the creation of a module entry without adding it to the
+ * module list. Needed to prevent mem leaks.
+ */
+static inline void
+abortCnfUse(cfgmodules_etry_t *pNew)
+{
+ free(pNew);
+}
+
+
+/* Add a module to the config module list for current loadConf.
+ * Requires last pointer obtained by readyModForCnf().
+ */
+rsRetVal
+addModToCnfList(cfgmodules_etry_t *pNew, cfgmodules_etry_t *pLast)
+{
+ DEFiRet;
+ assert(pNew != NULL);
+
+ if(loadConf == NULL) {
+ FINALIZE; /* we are in an early init state */
+ }
+
if(pLast == NULL) {
loadConf->modules.root = pNew;
} else {
@@ -535,7 +585,7 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_
CHKiRet((*modGetType)(&pNew->eType));
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getKeepType", &modGetKeepType));
CHKiRet((*modGetKeepType)(&pNew->eKeepType));
- dbgprintf("module %s of type %d being loaded.\n", name, pNew->eType);
+ dbgprintf("module %s of type %d being loaded (keepType=%d).\n", name, pNew->eType, pNew->eKeepType);
/* OK, we know we can successfully work with the module. So we now fill the
* rest of the data elements. First we load the interfaces common to all
@@ -548,6 +598,11 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_
pNew->isCompatibleWithFeature = dummyIsCompatibleWithFeature;
else if(localRet != RS_RET_OK)
ABORT_FINALIZE(localRet);
+ localRet = (*pNew->modQueryEtryPt)((uchar*)"setModCnf", &pNew->setModCnf);
+ if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND)
+ pNew->setModCnf = NULL;
+ else if(localRet != RS_RET_OK)
+ ABORT_FINALIZE(localRet);
/* optional calls for new config system */
localRet = (*pNew->modQueryEtryPt)((uchar*)"getModCnfName", &getModCnfName);
@@ -584,6 +639,12 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"willRun", &pNew->mod.im.willRun));
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"afterRun", &pNew->mod.im.afterRun));
pNew->mod.im.bCanRun = 0;
+ localRet = (*pNew->modQueryEtryPt)((uchar*)"newInpInst", &pNew->mod.im.newInpInst);
+ if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) {
+ pNew->mod.om.newActInst = NULL;
+ } else if(localRet != RS_RET_OK) {
+ ABORT_FINALIZE(localRet);
+ }
break;
case eMOD_OUT:
CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeInstance", &pNew->freeInstance));
@@ -602,7 +663,8 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_
else if(localRet != RS_RET_OK)
ABORT_FINALIZE(localRet);
- localRet = (*pNew->modQueryEtryPt)((uchar*)"endTransaction", &pNew->mod.om.endTransaction);
+ localRet = (*pNew->modQueryEtryPt)((uchar*)"endTransaction",
+ &pNew->mod.om.endTransaction);
if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) {
pNew->mod.om.endTransaction = dummyEndTransaction;
} else if(localRet != RS_RET_OK) {
@@ -754,6 +816,7 @@ static void modPrintList(void)
dbgprintf("\tdbgPrintInstInfo: 0x%lx\n", (unsigned long) pMod->dbgPrintInstInfo);
dbgprintf("\tfreeInstance: 0x%lx\n", (unsigned long) pMod->freeInstance);
dbgprintf("\tbeginCnfLoad: 0x%lx\n", (unsigned long) pMod->beginCnfLoad);
+ dbgprintf("\tSetModCnf: 0x%lx\n", (unsigned long) pMod->setModCnf);
dbgprintf("\tcheckCnf: 0x%lx\n", (unsigned long) pMod->checkCnf);
dbgprintf("\tactivateCnfPrePrivDrop: 0x%lx\n", (unsigned long) pMod->activateCnfPrePrivDrop);
dbgprintf("\tactivateCnf: 0x%lx\n", (unsigned long) pMod->activateCnf);
@@ -931,17 +994,17 @@ findModule(uchar *pModName, int iModNameLen, modInfo_t **pMod)
* 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.
+ * Note: pvals = NULL means legacy config system
*/
static rsRetVal
-Load(uchar *pModName, sbool bConfLoad)
+Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst)
{
- DEFiRet;
-
size_t iPathLen, iModNameLen;
- uchar *pModNameCmp;
int bHasExtension;
void *pModHdlr, *pModInit;
modInfo_t *pModInfo;
+ cfgmodules_etry_t *pNew;
+ cfgmodules_etry_t *pLast;
uchar *pModDirCurr, *pModDirNext;
int iLoadCnt;
struct dlhandle_s *pHandle = NULL;
@@ -952,9 +1015,11 @@ Load(uchar *pModName, sbool bConfLoad)
# endif
uchar *pPathBuf = pathBuf;
size_t lenPathBuf = sizeof(pathBuf);
+ rsRetVal localRet;
+ DEFiRet;
assert(pModName != NULL);
- dbgprintf("Requested to load module '%s'\n", pModName);
+ DBGPRINTF("Requested to load module '%s'\n", pModName);
iModNameLen = strlen((char*)pModName);
/* overhead for a full path is potentially 1 byte for a slash,
@@ -972,9 +1037,29 @@ Load(uchar *pModName, sbool bConfLoad)
CHKiRet(findModule(pModName, iModNameLen, &pModInfo));
if(pModInfo != NULL) {
- if(bConfLoad)
- addModToCnfList(pModInfo);
- dbgprintf("Module '%s' already loaded\n", pModName);
+ DBGPRINTF("Module '%s' already loaded\n", pModName);
+ if(bConfLoad) {
+ localRet = readyModForCnf(pModInfo, &pNew, &pLast);
+ if(pModInfo->setModCnf != NULL && localRet == RS_RET_OK) {
+ addModToCnfList(pNew, pLast);
+ if(!strncmp((char*)pModName, "builtin:", sizeof("builtin:")-1)) {
+ if(pModInfo->bSetModCnfCalled) {
+ errmsg.LogError(0, RS_RET_DUP_PARAM,
+ "parameters for built-in module %s already set - ignored\n",
+ pModName);
+ ABORT_FINALIZE(RS_RET_DUP_PARAM);
+ } else {
+ /* for built-in moules, we need to call setModConf,
+ * because there is no way to set parameters at load
+ * time for obvious reasons...
+ */
+ if(lst != NULL)
+ pModInfo->setModCnf(lst);
+ pModInfo->bSetModCnfCalled = 1;
+ }
+ }
+ }
+ }
FINALIZE;
}
@@ -1082,8 +1167,24 @@ Load(uchar *pModName, sbool bConfLoad)
dlclose(pModHdlr);
ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_INIT_FAILED);
}
- if(bConfLoad)
- addModToCnfList(pModInfo);
+
+ if(bConfLoad) {
+ readyModForCnf(pModInfo, &pNew, &pLast);
+ if(pModInfo->setModCnf != NULL) {
+ if(lst != NULL) {
+ localRet = pModInfo->setModCnf(lst);
+ if(localRet != RS_RET_OK) {
+ errmsg.LogError(0, localRet,
+ "module '%s', failed processing config parameters",
+ pPathBuf);
+ abortCnfUse(pNew);
+ ABORT_FINALIZE(localRet);
+ }
+ }
+ pModInfo->bSetModCnfCalled = 1;
+ }
+ addModToCnfList(pNew, pLast);
+ }
finalize_it:
if(pPathBuf != pathBuf) /* used malloc()ed memory? */
@@ -1093,6 +1194,39 @@ finalize_it:
}
+/* the v6+ way of loading modules: process a "module(...)" directive.
+ * rgerhards, 2012-06-20
+ */
+rsRetVal
+modulesProcessCnf(struct cnfobj *o)
+{
+ struct cnfparamvals *pvals;
+ uchar *cnfModName = NULL;
+ int typeIdx;
+ DEFiRet;
+
+ pvals = nvlstGetParams(o->nvlst, &pblk, NULL);
+ if(pvals == NULL) {
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ DBGPRINTF("modulesProcessCnf params:\n");
+ cnfparamsPrint(&pblk, pvals);
+ typeIdx = cnfparamGetIdx(&pblk, "load");
+ if(pvals[typeIdx].bUsed == 0) {
+ errmsg.LogError(0, RS_RET_CONF_RQRD_PARAM_MISSING, "module type missing");
+ ABORT_FINALIZE(RS_RET_CONF_RQRD_PARAM_MISSING);
+ }
+
+ cnfModName = (uchar*)es_str2cstr(pvals[typeIdx].val.d.estr, NULL);
+ iRet = Load(cnfModName, 1, o->nvlst);
+
+finalize_it:
+ free(cnfModName);
+ cnfparamvalsDestruct(pvals, &pblk);
+ RETiRet;
+}
+
+
/* set the default module load directory. A NULL value may be provided, in
* which case any previous value is deleted but no new one set. The caller-provided
* string is duplicated. If it needs to be freed, that's the caller's duty.
diff --git a/runtime/modules.h b/runtime/modules.h
index 6c5a2cba..e42d19e1 100644
--- a/runtime/modules.h
+++ b/runtime/modules.h
@@ -12,7 +12,7 @@
*
* File begun on 2007-07-22 by RGerhards
*
- * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007-2012 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
@@ -101,6 +101,7 @@ struct modInfo_s {
uchar* pszName; /* printable module name, e.g. for dbgprintf */
uchar* cnfName; /* name to be used in config statements (e.g. 'name="omusrmsg"') */
unsigned uRefCnt; /* reference count for this module; 0 -> may be unloaded */
+ sbool bSetModCnfCalled;/* is setModCnf already called? Needed for built-in modules */
/* functions supported by all types of modules */
rsRetVal (*modInit)(int, int*, rsRetVal(**)()); /* initialize the module */
/* be sure to support version handshake! */
@@ -114,6 +115,7 @@ struct modInfo_s {
rsRetVal (*doHUP)(void *); /* non-restart type HUP handler */
/* v2 config system specific */
rsRetVal (*beginCnfLoad)(void*newCnf, rsconf_t *pConf);
+ rsRetVal (*setModCnf)(struct nvlst *lst);
rsRetVal (*endCnfLoad)(void*Cnf);
rsRetVal (*checkCnf)(void*Cnf);
rsRetVal (*activateCnfPrePrivDrop)(void*Cnf);
@@ -129,6 +131,7 @@ struct modInfo_s {
/* TODO: remove? */rsRetVal (*willRun)(void); /* check if the current config will be able to run*/
rsRetVal (*runInput)(thrdInfo_t*); /* function to gather input and submit to queue */
rsRetVal (*afterRun)(thrdInfo_t*); /* function to gather input and submit to queue */
+ rsRetVal (*newInpInst)(struct nvlst *lst);
int bCanRun; /* cached value of whether willRun() succeeded */
} im;
struct {/* data for output modules */
@@ -152,9 +155,7 @@ struct modInfo_s {
} mod;
void *pModHdlr; /* handler to the dynamic library holding the module */
# ifdef DEBUG
- /* we add some home-grown support to track our users (and detect who does not free us). In
- * the long term, this should probably be migrated into debug.c (TODO). -- rgerhards, 2008-03-11
- */
+ /* we add some home-grown support to track our users (and detect who does not free us). */
modUsr_t *pModUsrRoot;
# endif
};
@@ -171,20 +172,29 @@ BEGINinterface(module) /* name must also be changed in ENDinterface macro! */
void (*PrintList)(void);
rsRetVal (*UnloadAndDestructAll)(eModLinkType_t modLinkTypesToUnload);
rsRetVal (*doModInit)(rsRetVal (*modInit)(), uchar *name, void *pModHdlr, modInfo_t **pNew);
- rsRetVal (*Load)(uchar *name, sbool bConfLoad);
+ rsRetVal (*Load)(uchar *name, sbool bConfLoad, struct nvlst *lst);
rsRetVal (*SetModDir)(uchar *name);
modInfo_t *(*FindWithCnfName)(rsconf_t *cnf, uchar *name, eModType_t rqtdType); /* added v3, 2011-07-19 */
ENDinterface(module)
-#define moduleCURR_IF_VERSION 3 /* increment whenever you change the interface structure! */
+#define moduleCURR_IF_VERSION 4 /* 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
+ * v3 (see above)
+ * v4
+ * - added third parameter to Load() - 2012-06-20
*/
/* prototypes */
PROTOTYPEObj(module);
-
-/* TODO: remove "dirty" calls! */
-rsRetVal addModToCnfList(modInfo_t *pThis);
+/* in v6, we go back to in-core static link for core objects, at least those
+ * that are not called from plugins.
+ * ... and we need to know that none of the module functions are called from plugins!
+ * rgerhards, 2012-09-24
+ */
+rsRetVal modulesProcessCnf(struct cnfobj *o);
+uchar *modGetName(modInfo_t *pThis);
+rsRetVal addModToCnfList(cfgmodules_etry_t *pNew, cfgmodules_etry_t *pLast);
+rsRetVal readyModForCnf(modInfo_t *pThis, cfgmodules_etry_t **ppNew, cfgmodules_etry_t **ppLast);
#endif /* #ifndef MODULES_H_INCLUDED */
diff --git a/runtime/msg.c b/runtime/msg.c
index 44d36fef..d874178b 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -39,10 +39,13 @@
#include <sys/sysinfo.h>
#include <netdb.h>
#include <libestr.h>
-#include <libee/libee.h>
+#include <json/json.h>
+/* For struct json_object_iter, should not be necessary in future versions */
+#include <json/json_object_private.h>
#if HAVE_MALLOC_H
# include <malloc.h>
#endif
+#include <uuid/uuid.h>
#include "rsyslog.h"
#include "srUtils.h"
#include "stringbuf.h"
@@ -290,6 +293,9 @@ static pthread_mutex_t mutTrimCtr; /* mutex to handle malloc trim */
/* some forward declarations */
static int getAPPNAMELen(msg_t *pM, sbool bLockMutex);
+static rsRetVal jsonPathFindParent(msg_t *pM, uchar *name, uchar *leaf, struct json_object **parent, int bCreate);
+static uchar * jsonPathGetLeaf(uchar *name, int lenName);
+static struct json_object *jsonDeepCopy(struct json_object *src);
/* The following functions will support advanced output module
@@ -541,6 +547,8 @@ propNameStrToID(uchar *pName, propid_t *pPropID)
*pPropID = PROP_MSGID;
} else if(!strcmp((char*) pName, "parsesuccess")) {
*pPropID = PROP_PARSESUCCESS;
+ } else if(!strcmp((char*) pName, "uuid")) {
+ *pPropID = PROP_UUID;
/* here start system properties (those, that do not relate to the message itself */
} else if(!strcmp((char*) pName, "$now")) {
*pPropID = PROP_SYS_NOW;
@@ -666,6 +674,8 @@ uchar *propIDToName(propid_t propID)
return UCHAR_CONSTANT("$!all-json");
case PROP_SYS_BOM:
return UCHAR_CONSTANT("$BOM");
+ case PROP_UUID:
+ return UCHAR_CONSTANT("uuid");
default:
return UCHAR_CONSTANT("*invalid property id*");
}
@@ -735,7 +745,7 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis)
pM->pRcvFromIP = NULL;
pM->rcvFrom.pRcvFrom = NULL;
pM->pRuleset = NULL;
- pM->event = NULL;
+ pM->json = NULL;
memset(&pM->tRcvdAt, 0, sizeof(pM->tRcvdAt));
memset(&pM->tTIMESTAMP, 0, sizeof(pM->tTIMESTAMP));
pM->TAG.pszTAG = NULL;
@@ -745,6 +755,7 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis)
pM->pszRcvdAt_SecFrac[0] = '\0';
pM->pszTIMESTAMP_Unix[0] = '\0';
pM->pszRcvdAt_Unix[0] = '\0';
+ pM->pszUUID = NULL;
/* DEV debugging only! dbgprintf("msgConstruct\t0x%x, ref 1\n", (int)pM);*/
@@ -873,8 +884,10 @@ CODESTARTobjDestruct(msg)
rsCStrDestruct(&pThis->pCSPROCID);
if(pThis->pCSMSGID != NULL)
rsCStrDestruct(&pThis->pCSMSGID);
- if(pThis->event != NULL)
- ee_deleteEvent(pThis->event);
+ if(pThis->json != NULL)
+ json_object_put(pThis->json);
+ if(pThis->pszUUID != NULL)
+ free(pThis->pszUUID);
# ifndef HAVE_ATOMIC_BUILTINS
MsgUnlock(pThis);
# endif
@@ -1021,6 +1034,9 @@ msg_t* MsgDup(msg_t* pOld)
tmpCOPYCSTR(PROCID);
tmpCOPYCSTR(MSGID);
+ if(pOld->json != NULL)
+ pNew->json = jsonDeepCopy(pOld->json);
+
/* we do not copy all other cache properties, as we do not even know
* if they are needed once again. So we let them re-create if needed.
*/
@@ -1074,12 +1090,18 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm)
CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRcvFrom"), PROPTYPE_PSZ, (void*) psz));
psz = getRcvFromIP(pThis);
CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRcvFromIP"), PROPTYPE_PSZ, (void*) psz));
+ if(pThis->json != NULL) {
+ psz = (uchar*) json_object_get_string(pThis->json);
+ CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("json"), PROPTYPE_PSZ, (void*) psz));
+ }
objSerializePTR(pStrm, pCSStrucData, CSTR);
objSerializePTR(pStrm, pCSAPPNAME, CSTR);
objSerializePTR(pStrm, pCSPROCID, CSTR);
objSerializePTR(pStrm, pCSMSGID, CSTR);
+ objSerializePTR(pStrm, pszUUID, PSZ);
+
if(pThis->pRuleset != NULL) {
rulesetGetName(pThis->pRuleset);
CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRuleset"), PROPTYPE_PSZ,
@@ -1242,6 +1264,60 @@ char *getProtocolVersionString(msg_t *pM)
return(pM->iProtocolVersion ? "1" : "0");
}
+/* note: libuuid seems not to be thread-safe, so we need
+ * to get some safeguards in place.
+ */
+static void msgSetUUID(msg_t *pM)
+{
+ size_t lenRes = sizeof(uuid_t) * 2 + 1;
+ char hex_char [] = "0123456789ABCDEF";
+ unsigned int byte_nbr;
+ uuid_t uuid;
+ static pthread_mutex_t mutUUID = PTHREAD_MUTEX_INITIALIZER;
+
+ dbgprintf("[MsgSetUUID] START\n");
+ assert(pM != NULL);
+
+ if((pM->pszUUID = (uchar*) MALLOC(lenRes)) == NULL) {
+ pM->pszUUID = (uchar *)"";
+ } else {
+ pthread_mutex_lock(&mutUUID);
+ uuid_generate(uuid);
+ pthread_mutex_unlock(&mutUUID);
+ for (byte_nbr = 0; byte_nbr < sizeof (uuid_t); byte_nbr++) {
+ pM->pszUUID[byte_nbr * 2 + 0] = hex_char[uuid [byte_nbr] >> 4];
+ pM->pszUUID[byte_nbr * 2 + 1] = hex_char[uuid [byte_nbr] & 15];
+ }
+
+ dbgprintf("[MsgSetUUID] UUID : %s LEN: %d \n", pM->pszUUID, (int)lenRes);
+ pM->pszUUID[lenRes] = '\0';
+ }
+ dbgprintf("[MsgSetUUID] END\n");
+}
+
+void getUUID(msg_t *pM, uchar **pBuf, int *piLen)
+{
+ dbgprintf("[getUUID] START\n");
+ if(pM == NULL) {
+ dbgprintf("[getUUID] pM is NULL\n");
+ *pBuf= UCHAR_CONSTANT("");
+ *piLen = 0;
+ } else {
+ if(pM->pszUUID == NULL) {
+ dbgprintf("[getUUID] pM->pszUUID is NULL\n");
+ MsgLock(pM);
+ /* re-query, things may have changed in the mean time... */
+ if(pM->pszUUID == NULL)
+ msgSetUUID(pM);
+ MsgUnlock(pM);
+ } else { /* UUID already there we reuse it */
+ dbgprintf("[getUUID] pM->pszUUID already exists\n");
+ }
+ *pBuf = pM->pszUUID;
+ *piLen = sizeof(uuid_t) * 2;
+ }
+ dbgprintf("[getUUID] END\n");
+}
void
getRawMsg(msg_t *pM, uchar **pBuf, int *piLen)
@@ -1908,7 +1984,6 @@ static inline char *getStructuredData(msg_t *pM)
return (char*) pszRet;
}
-
/* check if we have a ProgramName, and, if not, try to aquire/emulate it.
* rgerhards, 2009-06-26
*/
@@ -2232,7 +2307,6 @@ finalize_it:
RETiRet;
}
-
/* set raw message in message object. Size of message is provided.
* The function makes sure that the stored rawmsg is properly
* terminated by '\0'.
@@ -2341,39 +2415,77 @@ 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)
+/* Get a CEE-Property as string value*/
+rsRetVal
+getCEEPropVal(msg_t *pM, es_str_t *propName, uchar **pRes, rs_size_t *buflen, unsigned short *pbMustBeFreed)
{
- es_str_t *str = NULL;
- int r;
+ uchar *name = NULL;
+ uchar *leaf;
+ struct json_object *parent;
+ struct json_object *field;
+ DEFiRet;
if(*pbMustBeFreed)
free(*pRes);
*pRes = NULL;
+ // TODO: mutex?
+ if(pM->json == NULL) goto finalize_it;
- 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;
+ if(!es_strbufcmp(propName, (uchar*)"!", 1)) {
+ field = pM->json;
+ } else {
+ name = (uchar*)es_str2cstr(propName, NULL);
+ leaf = jsonPathGetLeaf(name, ustrlen(name));
+ CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1));
+ field = json_object_object_get(parent, (char*)leaf);
+ }
+ if(field != NULL) {
+ *pRes = (uchar*) strdup(json_object_get_string(field));
+ *buflen = (int) ustrlen(*pRes);
+ *pbMustBeFreed = 1;
}
- *pRes = (unsigned char*) es_str2cstr(str, "#000");
- es_deleteStr(str);
- *buflen = (int) ustrlen(*pRes);
- *pbMustBeFreed = 1;
finalize_it:
+ free(name);
if(*pRes == NULL) {
/* could not find any value, so set it to empty */
*pRes = (unsigned char*)"";
*pbMustBeFreed = 0;
}
+ RETiRet;
+}
+
+
+/* Get a CEE-Property as native json object
+ */
+rsRetVal
+msgGetCEEPropJSON(msg_t *pM, es_str_t *propName, struct json_object **pjson)
+{
+ uchar *name = NULL;
+ uchar *leaf;
+ struct json_object *parent;
+ DEFiRet;
+
+ // TODO: mutex?
+ if(pM->json == NULL) {
+ ABORT_FINALIZE(RS_RET_NOT_FOUND);
+ }
+
+ if(!es_strbufcmp(propName, (uchar*)"!", 1)) {
+ *pjson = pM->json;
+ FINALIZE;
+ }
+ name = (uchar*)es_str2cstr(propName, NULL);
+ leaf = jsonPathGetLeaf(name, ustrlen(name));
+ CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1));
+ *pjson = json_object_object_get(parent, (char*)leaf);
+ if(*pjson == NULL) {
+ ABORT_FINALIZE(RS_RET_NOT_FOUND);
+ }
+
+finalize_it:
+ free(name);
+ RETiRet;
}
@@ -2515,9 +2627,9 @@ jsonField(struct templateEntry *pTpe, uchar **ppRes, unsigned short *pbMustBeFre
pSrc = *ppRes;
buflen = (*pBufLen == -1) ? ustrlen(pSrc) : *pBufLen;
/* we hope we have only few escapes... */
- dst = es_newStr(buflen+es_strlen(pTpe->data.field.fieldName)+15);
+ dst = es_newStr(buflen+pTpe->lenFieldName+15);
es_addChar(&dst, '"');
- es_addStr(&dst, pTpe->data.field.fieldName);
+ es_addBuf(&dst, (char*)pTpe->fieldName, pTpe->lenFieldName);
es_addBufConstcstr(&dst, "\":\"");
CHKiRet(jsonAddVal(pSrc, buflen, &dst));
es_addChar(&dst, '"');
@@ -2577,16 +2689,16 @@ finalize_it:
*pPropLen = sizeof("**OUT OF MEMORY**") - 1; \
return(UCHAR_CONSTANT("**OUT OF MEMORY**"));}
uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
- propid_t propid, es_str_t *propName, size_t *pPropLen,
+ propid_t propid, es_str_t *propName, rs_size_t *pPropLen,
unsigned short *pbMustBeFreed)
{
uchar *pRes; /* result pointer */
- int bufLen = -1; /* length of string or -1, if not known */
+ rs_size_t bufLen = -1; /* length of string or -1, if not known */
uchar *pBufStart;
uchar *pBuf;
int iLen;
short iOffs;
- es_str_t *str; /* for CEE handling, temp. string */
+ enum tplFormatTypes datefmt;
BEGINfunc
assert(pMsg != NULL);
@@ -2606,7 +2718,11 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
bufLen = getMSGLen(pMsg);
break;
case PROP_TIMESTAMP:
- pRes = (uchar*)getTimeReported(pMsg, pTpe->data.field.eDateFormat);
+ if (pTpe != NULL)
+ datefmt = pTpe->data.field.eDateFormat;
+ else
+ datefmt = tplFmtDefault;
+ pRes = (uchar*)getTimeReported(pMsg, datefmt);
break;
case PROP_HOSTNAME:
pRes = (uchar*)getHOSTNAME(pMsg);
@@ -2656,7 +2772,11 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
pRes = (uchar*)getSeverityStr(pMsg);
break;
case PROP_TIMEGENERATED:
- pRes = (uchar*)getTimeGenerated(pMsg, pTpe->data.field.eDateFormat);
+ if (pTpe != NULL)
+ datefmt = pTpe->data.field.eDateFormat;
+ else
+ datefmt = tplFmtDefault;
+ pRes = (uchar*)getTimeGenerated(pMsg, datefmt);
break;
case PROP_PROGRAMNAME:
pRes = getProgramName(pMsg, LOCK_MUTEX);
@@ -2676,6 +2796,9 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
case PROP_MSGID:
pRes = (uchar*)getMSGID(pMsg);
break;
+ case PROP_UUID:
+ getUUID(pMsg, &pRes, &bufLen);
+ break;
case PROP_PARSESUCCESS:
pRes = (uchar*)getParseSuccess(pMsg);
break;
@@ -2731,16 +2854,15 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
pRes = glbl.GetLocalHostName();
break;
case PROP_CEE_ALL_JSON:
- if(pMsg->event == NULL) {
- if(*pbMustBeFreed == 1)
- free(pRes);
- pRes = (uchar*) "{}";
- *pbMustBeFreed = 0;
+ if(pMsg->json == NULL) {
+ if(*pbMustBeFreed == 1)
+ free(pRes);
+ pRes = (uchar*) "{}";
+ bufLen = 2;
+ *pbMustBeFreed = 0;
} else {
- ee_fmtEventToJSON(pMsg->event, &str);
- pRes = (uchar*) es_str2cstr(str, "#000");
- es_deleteStr(str);
- *pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
+ pRes = (uchar*)strdup(json_object_get_string(pMsg->json));
+ *pbMustBeFreed = 1;
}
break;
case PROP_CEE:
@@ -3391,29 +3513,25 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
es_str_t*
msgGetCEEVarNew(msg_t *pMsg, char *name)
{
+ uchar *leaf;
+ char *val;
es_str_t *estr = NULL;
- es_str_t *epropName = NULL;
- struct ee_field *field;
+ struct json_object *json, *parent;
ISOBJ_TYPE_assert(pMsg, msg);
- if(pMsg->event == NULL) {
+ if(pMsg->json == NULL) {
estr = es_newStr(1);
goto done;
}
-
- epropName = es_newStrFromCStr(name, strlen(name)); // TODO: optimize (in grammar!)
- field = ee_getEventField(pMsg->event, epropName);
- if(field != NULL) {
- ee_getFieldAsString(field, &estr);
- }
- if(estr == NULL) {
- DBGPRINTF("msgGetCEEVar: error obtaining var (field=%p, var='%s')\n",
- field, name);
- estr = es_newStrFromCStr("*ERROR*", sizeof("*ERROR*") - 1);
+ leaf = jsonPathGetLeaf((uchar*)name, strlen(name));
+ if(jsonPathFindParent(pMsg, (uchar*)name, leaf, &parent, 1) != RS_RET_OK) {
+ estr = es_newStr(1);
+ goto done;
}
- es_deleteStr(epropName);
-
+ json = json_object_object_get(parent, (char*)leaf);
+ val = (char*)json_object_get_string(json);
+ estr = es_newStrFromCStr(val, strlen(val));
done:
return estr;
}
@@ -3424,7 +3542,7 @@ done:
es_str_t*
msgGetMsgVarNew(msg_t *pThis, uchar *name)
{
- size_t propLen;
+ rs_size_t propLen;
uchar *pszProp = NULL;
propid_t propid;
unsigned short bMustBeFreed = 0;
@@ -3457,6 +3575,8 @@ rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp)
prop_t *myProp;
prop_t *propRcvFrom = NULL;
prop_t *propRcvFromIP = NULL;
+ struct json_tokener *tokener;
+ struct json_object *json;
DEFiRet;
ISOBJ_TYPE_assert(pThis, msg);
@@ -3511,6 +3631,12 @@ rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp)
MsgSetRulesetByName(pThis, pProp->val.pStr);
} else if(isProp("pszMSG")) {
dbgprintf("no longer supported property pszMSG silently ignored\n");
+ } else if(isProp("json")) {
+ tokener = json_tokener_new();
+ json = json_tokener_parse_ex(tokener, (char*)rsCStrGetSzStrNoNULL(pProp->val.pStr),
+ cstrLen(pProp->val.pStr));
+ json_tokener_free(tokener);
+ msgAddJSON(pThis, (uchar*)"!", json);
} else {
dbgprintf("unknown supported property '%s' silently ignored\n",
rsCStrGetSzStrNoNULL(pProp->pcsName));
@@ -3548,6 +3674,285 @@ MsgGetSeverity(obj_t_ptr pThis, int *piSeverity)
}
+static uchar *
+jsonPathGetLeaf(uchar *name, int lenName)
+{
+ int i;
+ for(i = lenName ; name[i] != '!' && i >= 0 ; --i)
+ /* just skip */;
+ if(name[i] == '!')
+ ++i;
+ return name + i;
+}
+
+
+static rsRetVal
+jsonPathFindNext(struct json_object *root, uchar **name, uchar *leaf,
+ struct json_object **found, int bCreate)
+{
+ uchar namebuf[1024];
+ struct json_object *json;
+ size_t i;
+ uchar *p = *name;
+ DEFiRet;
+
+ if(*p == '!')
+ ++p;
+ for(i = 0 ; *p && *p != '!' && p != leaf && i < sizeof(namebuf)-1 ; ++i, ++p)
+ namebuf[i] = *p;
+ if(i > 0) {
+ namebuf[i] = '\0';
+ dbgprintf("AAAA: next JSONPath elt: '%s'\n", namebuf);
+ json = json_object_object_get(root, (char*)namebuf);
+ } else
+ json = root;
+ if(json == NULL) {
+ if(!bCreate) {
+ ABORT_FINALIZE(RS_RET_JNAME_INVALID);
+ } else {
+ json = json_object_new_object();
+ json_object_object_add(root, (char*)namebuf, json);
+ }
+ }
+
+ *name = p;
+ *found = json;
+finalize_it:
+ RETiRet;
+}
+
+static rsRetVal
+jsonPathFindParent(msg_t *pM, uchar *name, uchar *leaf, struct json_object **parent, int bCreate)
+{
+ DEFiRet;
+ *parent = pM->json;
+ while(name < leaf-1) {
+ jsonPathFindNext(*parent, &name, leaf, parent, bCreate);
+ }
+ RETiRet;
+}
+
+static rsRetVal
+jsonMerge(struct json_object *existing, struct json_object *json)
+{
+ /* TODO: check & handle duplicate names */
+ DEFiRet;
+ struct json_object_iter it;
+
+ json_object_object_foreachC(json, it) {
+DBGPRINTF("AAAA jsonMerge adds '%s'\n", it.key);
+ json_object_object_add(existing, it.key,
+ json_object_get(it.val));
+ }
+ /* note: json-c does ref counting. We added all descandants refcounts
+ * in the loop above. So when we now free(_put) the root object, only
+ * root gets freed().
+ */
+ json_object_put(json);
+ RETiRet;
+}
+
+/* find a JSON structure element (field or container doesn't matter). */
+rsRetVal
+jsonFind(msg_t *pM, es_str_t *propName, struct json_object **jsonres)
+{
+ uchar *name = NULL;
+ uchar *leaf;
+ struct json_object *parent;
+ struct json_object *field;
+ DEFiRet;
+
+ if(pM->json == NULL) {
+ field = NULL;
+ goto finalize_it;
+ }
+
+ if(!es_strbufcmp(propName, (uchar*)"!", 1)) {
+ field = pM->json;
+ } else {
+ name = (uchar*)es_str2cstr(propName, NULL);
+ leaf = jsonPathGetLeaf(name, ustrlen(name));
+ CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 0));
+ field = json_object_object_get(parent, (char*)leaf);
+ }
+ *jsonres = field;
+
+finalize_it:
+ free(name);
+ RETiRet;
+}
+
+rsRetVal
+msgAddJSON(msg_t *pM, uchar *name, struct json_object *json)
+{
+ /* TODO: error checks! This is a quick&dirty PoC! */
+ struct json_object *parent, *leafnode;
+ uchar *leaf;
+ DEFiRet;
+
+ MsgLock(pM);
+ if(name[0] == '!' && name[1] == '\0') {
+ if(pM->json == NULL)
+ pM->json = json;
+ else
+ CHKiRet(jsonMerge(pM->json, json));
+ } else {
+ if(pM->json == NULL) {
+ /* now we need a root obj */
+ pM->json = json_object_new_object();
+ }
+ leaf = jsonPathGetLeaf(name, ustrlen(name));
+ CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1));
+ leafnode = json_object_object_get(parent, (char*)leaf);
+ if(leafnode == NULL) {
+ json_object_object_add(parent, (char*)leaf, json);
+ } else {
+ if(json_object_get_type(json) == json_type_object) {
+ CHKiRet(jsonMerge(pM->json, json));
+ } else {
+//dbgprintf("AAAA: leafnode already exists, type is %d, update with %d\n", (int)json_object_get_type(leafnode), (int)json_object_get_type(json));
+ /* TODO: improve the code below, however, the current
+ * state is not really bad */
+ if(json_object_get_type(leafnode) == json_type_object) {
+ DBGPRINTF("msgAddJSON: trying to update a container "
+ "node with a leaf, name is '%s' - "
+ "forbidden\n", name);
+ json_object_put(json);
+ ABORT_FINALIZE(RS_RET_INVLD_SETOP);
+ }
+ /* json-c code indicates we can simply replace a
+ * json type. Unfortunaltely, this is not documented
+ * as part of the interface spec. We still use it,
+ * because it speeds up processing. If it does not work
+ * at some point, use
+ * json_object_object_del(parent, (char*)leaf);
+ * before adding. rgerhards, 2012-09-17
+ */
+ json_object_object_add(parent, (char*)leaf, json);
+ }
+ }
+ }
+
+finalize_it:
+ MsgUnlock(pM);
+ RETiRet;
+}
+
+rsRetVal
+msgDelJSON(msg_t *pM, uchar *name)
+{
+ struct json_object *parent, *leafnode;
+ uchar *leaf;
+ DEFiRet;
+
+dbgprintf("AAAA: unset variable '%s'\n", name);
+ MsgLock(pM);
+ if(name[0] == '!' && name[1] == '\0') {
+ /* strange, but I think we should permit this. After all,
+ * we trust rsyslog.conf to be written by the admin.
+ */
+ DBGPRINTF("unsetting JSON root object\n");
+ json_object_put(pM->json);
+ pM->json = NULL;
+ } else {
+ if(pM->json == NULL) {
+ /* now we need a root obj */
+ pM->json = json_object_new_object();
+ }
+ leaf = jsonPathGetLeaf(name, ustrlen(name));
+ CHKiRet(jsonPathFindParent(pM, name, leaf, &parent, 1));
+ leafnode = json_object_object_get(parent, (char*)leaf);
+DBGPRINTF("AAAA: unset found JSON value path '%s', " "leaf '%s', leafnode %p\n", name, leaf, leafnode);
+ if(leafnode == NULL) {
+ DBGPRINTF("unset JSON: could not find '%s'\n", name);
+ ABORT_FINALIZE(RS_RET_JNAME_NOTFOUND);
+ } else {
+ DBGPRINTF("deleting JSON value path '%s', "
+ "leaf '%s', type %d\n",
+ name, leaf, json_object_get_type(leafnode));
+ json_object_object_del(parent, (char*)leaf);
+ }
+ }
+
+finalize_it:
+ MsgUnlock(pM);
+ RETiRet;
+}
+
+static struct json_object *
+jsonDeepCopy(struct json_object *src)
+{
+ struct json_object *dst = NULL, *json;
+ struct json_object_iter it;
+ int arrayLen, i;
+
+ if(src == NULL) goto done;
+
+ switch(json_object_get_type(src)) {
+ case json_type_boolean:
+ dst = json_object_new_boolean(json_object_get_boolean(src));
+ break;
+ case json_type_double:
+ dst = json_object_new_double(json_object_get_double(src));
+ break;
+ case json_type_int:
+ dst = json_object_new_int(json_object_get_int(src));
+ break;
+ case json_type_string:
+ dst = json_object_new_string(json_object_get_string(src));
+ break;
+ case json_type_object:
+ dst = json_object_new_object();
+ json_object_object_foreachC(src, it) {
+ json = jsonDeepCopy(it.val);
+ json_object_object_add(dst, it.key, json);
+ }
+ break;
+ case json_type_array:
+ arrayLen = json_object_array_length(src);
+ dst = json_object_new_array();
+ for(i = 0 ; i < arrayLen ; ++i) {
+ json = json_object_array_get_idx(src, i);
+ json = jsonDeepCopy(json);
+ json_object_array_add(dst, json);
+ }
+ break;
+ default:DBGPRINTF("jsonDeepCopy(): error unknown type %d\n",
+ json_object_get_type(src));
+ dst = NULL;
+ break;
+ }
+done: return dst;
+}
+
+
+rsRetVal
+msgSetJSONFromVar(msg_t *pMsg, uchar *varname, struct var *var)
+{
+ struct json_object *json = NULL;
+ char *cstr;
+ DEFiRet;
+ switch(var->datatype) {
+ case 'S':/* string */
+ cstr = es_str2cstr(var->d.estr, NULL);
+ json = json_object_new_string(cstr);
+ free(cstr);
+ break;
+ case 'N':/* number (integer) */
+ json = json_object_new_int((int) var->d.n);
+ break;
+ case 'J':/* native JSON */
+ json = jsonDeepCopy(var->d.json);
+ break;
+ default:DBGPRINTF("msgSetJSONFromVar: unsupported datatype %c\n",
+ var->datatype);
+ ABORT_FINALIZE(RS_RET_ERR);
+ }
+ msgAddJSON(pMsg, varname+1, json);
+finalize_it:
+ RETiRet;
+}
+
/* dummy */
rsRetVal msgQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; }
diff --git a/runtime/msg.h b/runtime/msg.h
index ed2e9d04..396e861f 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -3,7 +3,7 @@
*
* File begun on 2007-07-13 by RGerhards (extracted from syslogd.c)
*
- * Copyright 2007-2009 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2007-2012 Rainer Gerhards and Adiscon GmbH.
*
* This file is part of the rsyslog runtime library.
*
@@ -30,6 +30,7 @@
#include <pthread.h>
#include <libestr.h>
+#include <json/json.h>
#include "obj.h"
#include "syslogd-types.h"
#include "template.h"
@@ -109,7 +110,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 */
+ struct json_object *json;
/* 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];
@@ -123,6 +124,7 @@ struct msg {
char pszRcvdAt_SecFrac[7]; /* same as above. Both are fractional seconds for their respective timestamp */
char pszTIMESTAMP_Unix[12]; /* almost as small as a pointer! */
char pszRcvdAt_Unix[12];
+ uchar *pszUUID; /* The message's UUID */
};
@@ -171,7 +173,7 @@ 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, es_str_t *propName,
- size_t *pPropLen, unsigned short *pbMustBeFreed);
+ rs_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);
es_str_t* msgGetMsgVarNew(msg_t *pThis, uchar *name);
@@ -183,7 +185,8 @@ 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);
es_str_t* msgGetCEEVarNew(msg_t *pMsg, char *name);
-
+rsRetVal msgAddJSON(msg_t *pM, uchar *name, struct json_object *json);
+rsRetVal getCEEPropVal(msg_t *pM, es_str_t *propName, uchar **pRes, rs_size_t *buflen, unsigned short *pbMustBeFreed);
/* TODO: remove these five (so far used in action.c) */
uchar *getMSG(msg_t *pM);
@@ -199,6 +202,15 @@ int getProgramNameLen(msg_t *pM, sbool bLockMutex);
uchar *getRcvFrom(msg_t *pM);
rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID);
uchar *propIDToName(propid_t propID);
+rsRetVal msgGetCEEPropJSON(msg_t *pM, es_str_t *propName, struct json_object **pjson);
+rsRetVal msgSetJSONFromVar(msg_t *pMsg, uchar *varname, struct var *var);
+rsRetVal msgDelJSON(msg_t *pMsg, uchar *varname);
+rsRetVal jsonFind(msg_t *pM, es_str_t *propName, struct json_object **jsonres);
+
+static inline rsRetVal
+msgUnsetJSON(msg_t *pMsg, uchar *varname) {
+ return msgDelJSON(pMsg, varname+1);
+}
/* The MsgPrepareEnqueue() function is a macro for performance reasons.
diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c
index 12f891ea..d355d19c 100644
--- a/runtime/nsd_ptcp.c
+++ b/runtime/nsd_ptcp.c
@@ -460,7 +460,9 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*),
#endif
) {
/* TODO: check if *we* bound the socket - else we *have* an error! */
- dbgprintf("error %d while binding tcp socket\n", errno);
+ char errStr[1024];
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ dbgprintf("error %d while binding tcp socket: %s\n", errno, errStr);
close(sock);
sock = -1;
continue;
diff --git a/runtime/obj.c b/runtime/obj.c
index ffc8f608..3ecf9ab2 100644
--- a/runtime/obj.c
+++ b/runtime/obj.c
@@ -665,7 +665,7 @@ static rsRetVal objDeserializeProperty(var_t *pProp, strm_t *pStrm)
if(c != '\n') ABORT_FINALIZE(RS_RET_INVALID_PROPFRAME);
finalize_it:
- if(Debug && iRet != RS_RET_OK) {
+ if(Debug && iRet != RS_RET_OK && iRet != RS_RET_NO_PROPLINE) {
strm.GetCurrOffset(pStrm, &offs);
dbgprintf("error %d deserializing property name, offset %lld, step %d\n",
iRet, offs, step);
@@ -1188,7 +1188,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, 0));
+ CHKiRet(module.Load(pObjFile, 0, NULL));
/* NOW, we must find it or we have a problem... */
CHKiRet(FindObjInfo(pStr, &pObjInfo));
}
diff --git a/runtime/objomsr.c b/runtime/objomsr.c
index 7241fa27..e63eb681 100644
--- a/runtime/objomsr.c
+++ b/runtime/objomsr.c
@@ -42,9 +42,7 @@ rsRetVal OMSRdestruct(omodStringRequest_t *pThis)
/* free the strings */
if(pThis->ppTplName != NULL) {
for(i = 0 ; i < pThis->iNumEntries ; ++i) {
- if(pThis->ppTplName[i] != NULL) {
- free(pThis->ppTplName[i]);
- }
+ free(pThis->ppTplName[i]);
}
free(pThis->ppTplName);
}
@@ -149,7 +147,8 @@ OMSRgetSupportedTplOpts(unsigned long *pOpts)
{
DEFiRet;
assert(pOpts != NULL);
- *pOpts = OMSR_RQD_TPL_OPT_SQL | OMSR_TPL_AS_ARRAY | OMSR_TPL_AS_MSG;
+ *pOpts = OMSR_RQD_TPL_OPT_SQL | OMSR_TPL_AS_ARRAY | OMSR_TPL_AS_MSG
+ | OMSR_TPL_AS_JSON;
RETiRet;
}
diff --git a/runtime/objomsr.h b/runtime/objomsr.h
index 643e02c5..3baccaa3 100644
--- a/runtime/objomsr.h
+++ b/runtime/objomsr.h
@@ -25,12 +25,13 @@
/* define flags for required template options */
#define OMSR_NO_RQD_TPL_OPTS 0
#define OMSR_RQD_TPL_OPT_SQL 1
-/* only one of OMSR_TPL_AS_ARRAY or _AS_MSG must be specified, if both are given
- * results are unpredictable.
+/* only one of OMSR_TPL_AS_ARRAY, _AS_MSG, or _AS_JSON must be specified,
+ * if all are given results are unpredictable.
*/
#define OMSR_TPL_AS_ARRAY 2 /* introduced in 4.1.6, 2009-04-03 */
#define OMSR_TPL_AS_MSG 4 /* introduced in 5.3.4, 2009-11-02 */
-/* next option is 8, 16, 32, ... */
+#define OMSR_TPL_AS_JSON 8 /* introduced in 6.5.1, 2012-09-02 */
+/* next option is 16, 32, 64, ... */
struct omodStringRequest_s { /* strings requested by output module for doAction() */
int iNumEntries; /* number of array entries for data elements below */
diff --git a/runtime/parser.c b/runtime/parser.c
index fd940e9d..b40edf4c 100644
--- a/runtime/parser.c
+++ b/runtime/parser.c
@@ -143,6 +143,14 @@ finalize_it:
RETiRet;
}
+void
+printParserList(parserList_t *pList)
+{
+ while(pList != NULL) {
+ dbgprintf("parser: %s\n", pList->pParser->pName);
+ pList = pList->pNext;
+ }
+}
/* find a parser based on the provided name */
static rsRetVal
@@ -180,7 +188,7 @@ AddDfltParser(uchar *pName)
CHKiRet(FindParser(&pParser, pName));
CHKiRet(AddParserToList(&pDfltParsLst, pParser));
- dbgprintf("Parser '%s' added to default parser set.\n", pName);
+ DBGPRINTF("Parser '%s' added to default parser set.\n", pName);
finalize_it:
RETiRet;
@@ -209,7 +217,7 @@ finalize_it:
BEGINobjDestruct(parser) /* be sure to specify the object type also in END and CODESTART macros! */
CODESTARTobjDestruct(parser)
- dbgprintf("destructing parser '%s'\n", pThis->pName);
+ DBGPRINTF("destructing parser '%s'\n", pThis->pName);
free(pThis->pName);
ENDobjDestruct(parser)
@@ -521,7 +529,7 @@ ParseMsg(msg_t *pMsg)
bIsSanitized = RSTRUE;
}
localRet = pParser->pModule->mod.pm.parse(pMsg);
- dbgprintf("Parser '%s' returned %d\n", pParser->pName, localRet);
+ DBGPRINTF("Parser '%s' returned %d\n", pParser->pName, localRet);
if(localRet != RS_RET_COULD_NOT_PARSE)
break;
pParserList = pParserList->pNext;
diff --git a/runtime/parser.h b/runtime/parser.h
index f214ba0c..87a6269e 100644
--- a/runtime/parser.h
+++ b/runtime/parser.h
@@ -62,6 +62,7 @@ BEGINinterface(parser) /* name must also be changed in ENDinterface macro! */
ENDinterface(parser)
#define parserCURR_IF_VERSION 1 /* increment whenever you change the interface above! */
+void printParserList(parserList_t *pList);
/* prototypes */
PROTOTYPEObj(parser);
diff --git a/runtime/queue.c b/runtime/queue.c
index 3c91fd02..0cd33701 100644
--- a/runtime/queue.c
+++ b/runtime/queue.c
@@ -131,7 +131,7 @@ static void displayBatchState(batch_t *pBatch)
{
int i;
for(i = 0 ; i < pBatch->nElem ; ++i) {
- dbgprintf("XXXXX: displayBatchState %p[%d]: %d\n", pBatch, i, pBatch->pElem[i].state);
+ DBGPRINTF("displayBatchState %p[%d]: %d\n", pBatch, i, pBatch->pElem[i].state);
}
}
@@ -232,12 +232,16 @@ getQueueTypeName(queueType_t t)
switch(t) {
case QUEUETYPE_FIXED_ARRAY:
r = "FixedArray";
+ break;
case QUEUETYPE_LINKEDLIST:
r = "LinkedList";
+ break;
case QUEUETYPE_DISK:
r = "Disk";
+ break;
case QUEUETYPE_DIRECT:
r = "Direct";
+ break;
}
return r;
}
@@ -976,6 +980,7 @@ static rsRetVal qAddDirect(qqueue_t *pThis, void* pUsr)
{
batch_t singleBatch;
batch_obj_t batchObj;
+ sbool active = 1;
int i;
DEFiRet;
@@ -994,9 +999,9 @@ static rsRetVal qAddDirect(qqueue_t *pThis, void* pUsr)
memset(&singleBatch, 0, sizeof(batch_t));
batchObj.state = BATCH_STATE_RDY;
batchObj.pUsrp = (obj_t*) pUsr;
- batchObj.bFilterOK = 1;
singleBatch.nElem = 1; /* there always is only one in direct mode */
singleBatch.pElem = &batchObj;
+ singleBatch.active = &active;
iRet = pThis->pConsumer(pThis->pUsr, &singleBatch, &pThis->bShutdownImmediate);
/* delete the batch string params: TODO: create its own "class" for this */
for(i = 0 ; i < CONF_OMOD_NUMSTRINGS_MAXSIZE ; ++i) {
@@ -1467,7 +1472,8 @@ DoDeleteBatchFromQStore(qqueue_t *pThis, int nElem)
/* iQueueSize is not decremented by qDel(), so we need to do it ourselves */
ATOMIC_SUB(&pThis->iQueueSize, nElem, &pThis->mutQueueSize);
ATOMIC_SUB(&pThis->nLogDeq, nElem, &pThis->mutLogDeq);
-dbgprintf("delete batch from store, new sizes: log %d, phys %d\n", getLogicalQueueSize(pThis), getPhysicalQueueSize(pThis));
+ DBGPRINTF("delete batch from store, new sizes: log %d, phys %d\n",
+ getLogicalQueueSize(pThis), getPhysicalQueueSize(pThis));
++pThis->deqIDDel; /* one more batch dequeued */
RETiRet;
@@ -1503,7 +1509,7 @@ DeleteBatchFromQStore(qqueue_t *pThis, batch_t *pBatch)
DoDeleteBatchFromQStore(pThis, pBatch->nElem);
} else {
/* can not delete, insert into to-delete list */
- dbgprintf("not at head of to-delete list, enqueue %d\n", (int) pBatch->deqID);
+ DBGPRINTF("not at head of to-delete list, enqueue %d\n", (int) pBatch->deqID);
CHKiRet(tdlAdd(pThis, pBatch->deqID, pBatch->nElem));
}
@@ -1533,7 +1539,6 @@ DeleteProcessedBatch(qqueue_t *pThis, batch_t *pBatch)
pUsr = pBatch->pElem[i].pUsrp;
if( pBatch->pElem[i].state == BATCH_STATE_RDY
|| pBatch->pElem[i].state == BATCH_STATE_SUB) {
-dbgprintf("XXX: DeleteProcessedBatch re-enqueue %d of %d, state %d\n", i, pBatch->nElem, pBatch->pElem[i].state);
localRet = doEnqSingleObj(pThis, eFLOWCTL_NO_DELAY,
(obj_t*)MsgAddRef((msg_t*) pUsr));
++nEnqueued;
@@ -1544,7 +1549,7 @@ dbgprintf("XXX: DeleteProcessedBatch re-enqueue %d of %d, state %d\n", i, pBatch
objDestruct(pUsr);
}
- dbgprintf("we deleted %d objects and enqueued %d objects\n", i-nEnqueued, nEnqueued);
+ DBGPRINTF("we deleted %d objects and enqueued %d objects\n", i-nEnqueued, nEnqueued);
if(nEnqueued > 0)
qqueueChkPersist(pThis, nEnqueued);
@@ -1596,7 +1601,6 @@ DequeueConsumableElements(qqueue_t *pThis, wti_t *pWti, int *piRemainingQueueSiz
/* all well, use this element */
pWti->batch.pElem[nDequeued].pUsrp = pUsr;
pWti->batch.pElem[nDequeued].state = BATCH_STATE_RDY;
- pWti->batch.pElem[nDequeued].bFilterOK = 1; // TODO: think again if we can handle that with more performance
++nDequeued;
}
@@ -2075,6 +2079,7 @@ qqueueStart(qqueue_t *pThis) /* this is the ConstructionFinalizer */
pThis->pqParent == NULL ? 0 : 1, pThis->iFullDlyMrk, pThis->iLightDlyMrk,
pThis->iDeqBatchSize);
+ pThis->bQueueStarted = 1;
if(pThis->qType == QUEUETYPE_DIRECT)
FINALIZE; /* with direct queues, we are already finished... */
@@ -2105,7 +2110,6 @@ qqueueStart(qqueue_t *pThis) /* this is the ConstructionFinalizer */
* the case when a disk queue has been loaded. If we did not start it here, it would never start.
*/
qqueueAdviseMaxWorkers(pThis);
- pThis->bQueueStarted = 1;
/* support statistics gathering */
qName = obj.GetName((obj_t*)pThis);
@@ -2303,73 +2307,75 @@ DoSaveOnShutdown(qqueue_t *pThis)
/* destructor for the queue object */
BEGINobjDestruct(qqueue) /* be sure to specify the object type also in END and CODESTART macros! */
CODESTARTobjDestruct(qqueue)
- /* shut down all workers
- * We do not need to shutdown workers when we are in enqueue-only mode or we are a
- * direct queue - because in both cases we have none... ;)
- * with a child! -- rgerhards, 2008-01-28
- */
- if(pThis->qType != QUEUETYPE_DIRECT && !pThis->bEnqOnly && pThis->pqParent == NULL
- && pThis->pWtpReg != NULL)
- ShutdownWorkers(pThis);
+ if(pThis->bQueueStarted) {
+ /* shut down all workers
+ * We do not need to shutdown workers when we are in enqueue-only mode or we are a
+ * direct queue - because in both cases we have none... ;)
+ * with a child! -- rgerhards, 2008-01-28
+ */
+ if(pThis->qType != QUEUETYPE_DIRECT && !pThis->bEnqOnly && pThis->pqParent == NULL
+ && pThis->pWtpReg != NULL)
+ ShutdownWorkers(pThis);
- if(pThis->bIsDA && getPhysicalQueueSize(pThis) > 0 && pThis->bSaveOnShutdown) {
- CHKiRet(DoSaveOnShutdown(pThis));
- }
+ if(pThis->bIsDA && getPhysicalQueueSize(pThis) > 0 && pThis->bSaveOnShutdown) {
+ CHKiRet(DoSaveOnShutdown(pThis));
+ }
- /* finally destruct our (regular) worker thread pool
- * Note: currently pWtpReg is never NULL, but if we optimize our logic, this may happen,
- * e.g. when they are not created in enqueue-only mode. We already check the condition
- * as this may otherwise be very hard to find once we optimize (and have long forgotten
- * about this condition here ;)
- * rgerhards, 2008-01-25
- */
- if(pThis->qType != QUEUETYPE_DIRECT && pThis->pWtpReg != NULL) {
- wtpDestruct(&pThis->pWtpReg);
- }
+ /* finally destruct our (regular) worker thread pool
+ * Note: currently pWtpReg is never NULL, but if we optimize our logic, this may happen,
+ * e.g. when they are not created in enqueue-only mode. We already check the condition
+ * as this may otherwise be very hard to find once we optimize (and have long forgotten
+ * about this condition here ;)
+ * rgerhards, 2008-01-25
+ */
+ if(pThis->qType != QUEUETYPE_DIRECT && pThis->pWtpReg != NULL) {
+ wtpDestruct(&pThis->pWtpReg);
+ }
- /* Now check if we actually have a DA queue and, if so, destruct it.
- * Note that the wtp must be destructed first, it may be in cancel cleanup handler
- * *right now* and actually *need* to access the queue object to persist some final
- * data (re-queueing case). So we need to destruct the wtp first, which will make
- * sure all workers have terminated. Please note that this also generates a situation
- * where it is possible that the DA queue has a parent pointer but the parent has
- * no WtpDA associated with it - which is perfectly legal thanks to this code here.
- */
- if(pThis->pWtpDA != NULL) {
- wtpDestruct(&pThis->pWtpDA);
- }
- if(pThis->pqDA != NULL) {
- qqueueDestruct(&pThis->pqDA);
- }
+ /* Now check if we actually have a DA queue and, if so, destruct it.
+ * Note that the wtp must be destructed first, it may be in cancel cleanup handler
+ * *right now* and actually *need* to access the queue object to persist some final
+ * data (re-queueing case). So we need to destruct the wtp first, which will make
+ * sure all workers have terminated. Please note that this also generates a situation
+ * where it is possible that the DA queue has a parent pointer but the parent has
+ * no WtpDA associated with it - which is perfectly legal thanks to this code here.
+ */
+ if(pThis->pWtpDA != NULL) {
+ wtpDestruct(&pThis->pWtpDA);
+ }
+ if(pThis->pqDA != NULL) {
+ qqueueDestruct(&pThis->pqDA);
+ }
- /* persist the queue (we always do that - queuePersits() does cleanup if the queue is empty)
- * This handler is most important for disk queues, it will finally persist the necessary
- * on-disk structures. In theory, other queueing modes may implement their other (non-DA)
- * methods of persisting a queue between runs, but in practice all of this is done via
- * disk queues and DA mode. Anyhow, it doesn't hurt to know that we could extend it here
- * if need arises (what I doubt...) -- rgerhards, 2008-01-25
- */
- CHKiRet_Hdlr(qqueuePersist(pThis, QUEUE_NO_CHECKPOINT)) {
- DBGOPRINT((obj_t*) pThis, "error %d persisting queue - data lost!\n", iRet);
- }
+ /* persist the queue (we always do that - queuePersits() does cleanup if the queue is empty)
+ * This handler is most important for disk queues, it will finally persist the necessary
+ * on-disk structures. In theory, other queueing modes may implement their other (non-DA)
+ * methods of persisting a queue between runs, but in practice all of this is done via
+ * disk queues and DA mode. Anyhow, it doesn't hurt to know that we could extend it here
+ * if need arises (what I doubt...) -- rgerhards, 2008-01-25
+ */
+ CHKiRet_Hdlr(qqueuePersist(pThis, QUEUE_NO_CHECKPOINT)) {
+ DBGOPRINT((obj_t*) pThis, "error %d persisting queue - data lost!\n", iRet);
+ }
- /* finally, clean up some simple things... */
- if(pThis->pqParent == NULL) {
- /* if we are not a child, we allocated our own mutex, which we now need to destroy */
- pthread_mutex_destroy(pThis->mut);
- free(pThis->mut);
- }
- pthread_mutex_destroy(&pThis->mutThrdMgmt);
- pthread_cond_destroy(&pThis->notFull);
- pthread_cond_destroy(&pThis->notEmpty);
- pthread_cond_destroy(&pThis->belowFullDlyWtrMrk);
- pthread_cond_destroy(&pThis->belowLightDlyWtrMrk);
+ /* finally, clean up some simple things... */
+ if(pThis->pqParent == NULL) {
+ /* if we are not a child, we allocated our own mutex, which we now need to destroy */
+ pthread_mutex_destroy(pThis->mut);
+ free(pThis->mut);
+ }
+ pthread_mutex_destroy(&pThis->mutThrdMgmt);
+ pthread_cond_destroy(&pThis->notFull);
+ pthread_cond_destroy(&pThis->notEmpty);
+ pthread_cond_destroy(&pThis->belowFullDlyWtrMrk);
+ pthread_cond_destroy(&pThis->belowLightDlyWtrMrk);
- DESTROY_ATOMIC_HELPER_MUT(pThis->mutQueueSize);
- DESTROY_ATOMIC_HELPER_MUT(pThis->mutLogDeq);
+ DESTROY_ATOMIC_HELPER_MUT(pThis->mutQueueSize);
+ DESTROY_ATOMIC_HELPER_MUT(pThis->mutLogDeq);
- /* type-specific destructor */
- iRet = pThis->qDestruct(pThis);
+ /* type-specific destructor */
+ iRet = pThis->qDestruct(pThis);
+ }
free(pThis->pszFilePrefix);
free(pThis->pszSpoolDir);
@@ -2731,7 +2737,7 @@ qqueueApplyCnfParam(qqueue_t *pThis, struct cnfparamvals *pvals)
} else if(!strcmp(pblk.descr[i].name, "queuedequeuetimend.")) {
pThis->iDeqtWinToHr = pvals[i].val.d.n;
} else {
- dbgprintf("queue: program error, non-handled "
+ DBGPRINTF("queue: program error, non-handled "
"param '%s'\n", pblk.descr[i].name);
}
}
diff --git a/runtime/rsconf.c b/runtime/rsconf.c
index 946d1014..ad588832 100644
--- a/runtime/rsconf.c
+++ b/runtime/rsconf.c
@@ -36,7 +36,6 @@
#include "rsyslog.h"
#include "obj.h"
#include "srUtils.h"
-#include "rule.h"
#include "ruleset.h"
#include "modules.h"
#include "conf.h"
@@ -64,11 +63,12 @@
#include "threads.h"
#include "datetime.h"
#include "parserif.h"
+#include "modules.h"
#include "dirty.h"
+#include "template.h"
/* static data */
DEFobjStaticHelpers
-DEFobjCurrIf(rule)
DEFobjCurrIf(ruleset)
DEFobjCurrIf(module)
DEFobjCurrIf(conf)
@@ -97,6 +97,17 @@ static uchar template_SysklogdFileFormat[] = "\"%TIMESTAMP% %HOSTNAME% %syslogta
static uchar template_StdJSONFmt[] = "\"{\\\"message\\\":\\\"%msg:::json%\\\",\\\"fromhost\\\":\\\"%HOSTNAME:::json%\\\",\\\"facility\\\":\\\"%syslogfacility-text%\\\",\\\"priority\\\":\\\"%syslogpriority-text%\\\",\\\"timereported\\\":\\\"%timereported:::date-rfc3339%\\\",\\\"timegenerated\\\":\\\"%timegenerated:::date-rfc3339%\\\"}\"";
/* end templates */
+/* tables for interfacing with the v6 config system (as far as we need to) */
+static struct cnfparamdescr inppdescr[] = {
+ { "type", eCmdHdlrString, CNFPARAM_REQUIRED }
+};
+static struct cnfparamblk inppblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(inppdescr)/sizeof(struct cnfparamdescr),
+ inppdescr
+ };
+
+/* forward-definitions */
void cnfDoCfsysline(char *ln);
/* Standard-Constructor
@@ -152,10 +163,33 @@ rsRetVal rsconfConstructFinalize(rsconf_t __attribute__((unused)) *pThis)
}
+/* call freeCnf() module entry points AND free the module entries themselfes.
+ */
+static inline void
+freeCnf(rsconf_t *pThis)
+{
+ cfgmodules_etry_t *etry, *del;
+ etry = pThis->modules.root;
+ while(etry != NULL) {
+ if(etry->pMod->beginCnfLoad != NULL) {
+ dbgprintf("calling freeCnf(%p) for module '%s'\n",
+ etry->modCnf, (char*) module.GetName(etry->pMod));
+ etry->pMod->freeCnf(etry->modCnf);
+ }
+ del = etry;
+ etry = etry->next;
+ free(del);
+ }
+}
+
+
/* destructor for the rsconf object */
BEGINobjDestruct(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */
CODESTARTobjDestruct(rsconf)
+ freeCnf(pThis);
+ tplDeleteAll(pThis);
free(pThis->globals.mainQ.pszMainMsgQFName);
+ free(pThis->globals.pszConfDAGFile);
llDestroy(&(pThis->rulesets.llRulesets));
ENDobjDestruct(rsconf)
@@ -218,54 +252,6 @@ CODESTARTobjDebugPrint(rsconf)
ENDobjDebugPrint(rsconf)
-rsRetVal
-cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule)
-{
- struct cnfcfsyslinelst *cflst;
- action_t *pAction;
- uchar *str;
- rsRetVal localRet;
- DEFiRet;
-
- while(actlst != NULL) {
- dbgprintf("aclst %p: ", actlst);
- if(actlst->actType == CNFACT_V2) {
- dbgprintf("v6+ action object\n");
- if(actionNewInst(actlst->data.lst, &pAction) == RS_RET_OK) {
- iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction);
- } else {
- errmsg.LogError(0, RS_RET_ERR, "errors occured in file '%s' "
- "around line %d", actlst->cnfFile, actlst->lineno);
- }
- } else {
- DBGPRINTF("legacy action line:%s\n", actlst->data.legActLine);
- str = (uchar*) actlst->data.legActLine;
- if((localRet = cflineDoAction(loadConf, &str, &pAction)) != RS_RET_OK) {
- uchar szErrLoc[MAXFNAME + 64];
- if(localRet != RS_RET_OK_WARN) {
- DBGPRINTF("legacy action line NOT successfully processed\n");
- }
- snprintf((char*)szErrLoc, sizeof(szErrLoc) / sizeof(uchar),
- "%s, line %d", actlst->cnfFile, actlst->lineno);
- errmsg.LogError(0, NO_ERRCODE, "the last %s occured in %s:\"%s\"",
- (localRet == RS_RET_OK_WARN) ? "warning" : "error",
- (char*)szErrLoc, (char*)actlst->data.legActLine);
- if(localRet != RS_RET_OK_WARN) {
- ABORT_FINALIZE(localRet);
- }
- }
- iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction);
- }
- for( cflst = actlst->syslines
- ; cflst != NULL ; cflst = cflst->next) {
- cnfDoCfsysline(cflst->line);
- }
- actlst = actlst->next;
- }
-finalize_it:
- RETiRet;
-}
-
/* This function returns the current date in different
* variants. It is used to construct the $NOW series of
* system properties. The returned buffer must be freed
@@ -348,6 +334,41 @@ finalize_it:
return estr;
}
+
+/* Process input() objects */
+rsRetVal
+inputProcessCnf(struct cnfobj *o)
+{
+ struct cnfparamvals *pvals;
+ modInfo_t *pMod;
+ uchar *cnfModName = NULL;
+ int typeIdx;
+ DEFiRet;
+
+ pvals = nvlstGetParams(o->nvlst, &inppblk, NULL);
+ if(pvals == NULL) {
+ ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
+ }
+ DBGPRINTF("input param blk after inputProcessCnf:\n");
+ cnfparamsPrint(&inppblk, pvals);
+ typeIdx = cnfparamGetIdx(&inppblk, "type");
+ cnfModName = (uchar*)es_str2cstr(pvals[typeIdx].val.d.estr, NULL);
+ if((pMod = module.FindWithCnfName(loadConf, cnfModName, eMOD_IN)) == NULL) {
+ errmsg.LogError(0, RS_RET_MOD_UNKNOWN, "input module name '%s' is unknown", cnfModName);
+ ABORT_FINALIZE(RS_RET_MOD_UNKNOWN);
+ }
+ if(pMod->mod.im.newInpInst == NULL) {
+ errmsg.LogError(0, RS_RET_MOD_NO_INPUT_STMT,
+ "input module '%s' does not support input() statement", cnfModName);
+ ABORT_FINALIZE(RS_RET_MOD_NO_INPUT_STMT);
+ }
+ CHKiRet(pMod->mod.im.newInpInst(o->nvlst));
+finalize_it:
+ free(cnfModName);
+ cnfparamvalsDestruct(pvals, &inppblk);
+ RETiRet;
+}
+
/*------------------------------ interface to flex/bison parser ------------------------------*/
extern int yylineno;
@@ -360,9 +381,6 @@ parser_errmsg(char *fmt, ...)
va_start(ap, fmt);
if(vsnprintf(errBuf, sizeof(errBuf), fmt, ap) == sizeof(errBuf))
errBuf[sizeof(errBuf)-1] = '\0';
-dbgprintf("XXXX: msg: %s\n", errBuf);
-dbgprintf("XXXX: cnfcurrfn: %s\n", cnfcurrfn);
-dbgprintf("XXXX: yylineno: %d\n", yylineno);
errmsg.LogError(0, RS_RET_CONF_PARSE_ERROR,
"error during parsing file %s, on or before line %d: %s",
cnfcurrfn, yylineno, errBuf);
@@ -377,69 +395,45 @@ yyerror(char *s)
}
void cnfDoObj(struct cnfobj *o)
{
+ int bChkUnuse = 1;
+
dbgprintf("cnf:global:obj: ");
cnfobjPrint(o);
switch(o->objType) {
case CNFOBJ_GLOBAL:
glblProcessCnf(o);
break;
- case CNFOBJ_ACTION:
- actionProcessCnf(o);
+ case CNFOBJ_MODULE:
+ modulesProcessCnf(o);
break;
- }
- nvlstChkUnused(o->nvlst);
- cnfobjDestruct(o);
-}
-
-void cnfDoRule(struct cnfrule *cnfrule)
-{
- rule_t *pRule;
- uchar *str;
- rsRetVal iRet = RS_RET_OK; //DEFiRet;
-
- dbgprintf("cnf:global:rule\n");
- cnfrulePrint(cnfrule);
-
- CHKiRet(rule.Construct(&pRule)); /* create "fresh" selector */
- CHKiRet(rule.SetAssRuleset(pRule, ruleset.GetCurrent(loadConf)));
- CHKiRet(rule.ConstructFinalize(pRule));
-
- switch(cnfrule->filttype) {
- case CNFFILT_NONE:
+ case CNFOBJ_INPUT:
+ inputProcessCnf(o);
break;
- case CNFFILT_PRI:
- str = (uchar*) cnfrule->filt.s;
- iRet = cflineProcessTradPRIFilter(&str, pRule);
+ case CNFOBJ_TPL:
+ tplProcessCnf(o);
break;
- case CNFFILT_PROP:
- dbgprintf("%s\n", cnfrule->filt.s);
- str = (uchar*) cnfrule->filt.s;
- iRet = cflineProcessPropFilter(&str, pRule);
+ case CNFOBJ_RULESET:
+ rulesetProcessCnf(o);
break;
- case CNFFILT_SCRIPT:
- pRule->f_filter_type = FILTER_EXPR;
- pRule->f_filterData.expr = cnfrule->filt.expr;
+ case CNFOBJ_PROPERTY:
+ case CNFOBJ_CONSTANT:
+ /* these types are processed at a later stage */
+ bChkUnuse = 0;
+ break;
+ default:
+ dbgprintf("cnfDoObj program error: unexpected object type %u\n",
+ o->objType);
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) {
- CHKiRet(rsCStrConstructFromCStr(&(pRule->pCSProgNameComp), pDfltProgNameCmp));
- }
-
- if(eDfltHostnameCmpMode != HN_NO_COMP) {
- pRule->eHostnameCmpMode = eDfltHostnameCmpMode;
- CHKiRet(rsCStrConstructFromCStr(&(pRule->pCSHostnameComp), pDfltHostnameCmp));
- }
-
- cnfDoActlst(cnfrule->actlst, pRule);
-
- CHKiRet(ruleset.AddRule(rule.GetAssRuleset(pRule), &pRule));
+ if(bChkUnuse)
+ nvlstChkUnused(o->nvlst);
+ cnfobjDestruct(o);
+}
-finalize_it:
- //TODO: do something with error states
- cnfruleDestruct(cnfrule);
+void cnfDoScript(struct cnfstmt *script)
+{
+ dbgprintf("cnf:global:script\n");
+ ruleset.AddScript(ruleset.GetCurrent(loadConf), script);
}
void cnfDoCfsysline(char *ln)
@@ -453,13 +447,21 @@ void cnfDoCfsysline(char *ln)
void cnfDoBSDTag(char *ln)
{
DBGPRINTF("cnf:global:BSD tag: %s\n", ln);
- cflineProcessTagSelector((uchar**)&ln);
+ errmsg.LogError(0, RS_RET_BSD_BLOCKS_UNSUPPORTED,
+ "BSD-style blocks are no longer supported in rsyslog, "
+ "see http://www.rsyslog.com/g/BSD for details and a "
+ "solution (Block '%s')", ln);
+ free(ln);
}
void cnfDoBSDHost(char *ln)
{
DBGPRINTF("cnf:global:BSD host: %s\n", ln);
- cflineProcessHostSelector((uchar**)&ln);
+ errmsg.LogError(0, RS_RET_BSD_BLOCKS_UNSUPPORTED,
+ "BSD-style blocks are no longer supported in rsyslog, "
+ "see http://www.rsyslog.com/g/BSD for details and a "
+ "solution (Block '%s')", ln);
+ free(ln);
}
es_str_t*
@@ -701,9 +703,10 @@ runInputModules(void)
node = module.GetNxtCnfType(runConf, NULL, eMOD_IN);
while(node != NULL) {
if(node->canRun) {
- DBGPRINTF("running module %s with config %p\n", node->pMod->pszName, node);
bNeedsCancel = (node->pMod->isCompatibleWithFeature(sFEATURENonCancelInputTermination) == RS_RET_OK) ?
0 : 1;
+ DBGPRINTF("running module %s with config %p, term mode: %s\n", node->pMod->pszName, node,
+ bNeedsCancel ? "cancel" : "cooperative/SIGTTIN");
thrdCreate(node->pMod->mod.im.runInput, node->pMod->mod.im.afterRun, bNeedsCancel,
(node->pMod->cnfName == NULL) ? node->pMod->pszName : node->pMod->cnfName);
}
@@ -868,6 +871,7 @@ setCurrRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
CHKiRet(ruleset.Construct(&pRuleset));
CHKiRet(ruleset.SetName(pRuleset, pszName));
CHKiRet(ruleset.ConstructFinalize(ourConf, pRuleset));
+ rulesetSetCurrRulesetPtr(pRuleset);
} else {
ABORT_FINALIZE(localRet);
}
@@ -990,10 +994,13 @@ setModDir(void __attribute__((unused)) *pVal, uchar* pszNewVal)
static rsRetVal
regBuildInModule(rsRetVal (*modInit)(), uchar *name, void *pModHdlr)
{
+ cfgmodules_etry_t *pNew;
+ cfgmodules_etry_t *pLast;
modInfo_t *pMod;
DEFiRet;
CHKiRet(module.doModInit(modInit, name, pModHdlr, &pMod));
- addModToCnfList(pMod);
+ readyModForCnf(pMod, &pNew, &pLast);
+ addModToCnfList(pNew, pLast);
finalize_it:
RETiRet;
}
@@ -1007,12 +1014,12 @@ loadBuildInModules()
{
DEFiRet;
- CHKiRet(regBuildInModule(modInitFile, UCHAR_CONSTANT("builtin-file"), NULL));
- CHKiRet(regBuildInModule(modInitPipe, UCHAR_CONSTANT("builtin-pipe"), NULL));
+ CHKiRet(regBuildInModule(modInitFile, UCHAR_CONSTANT("builtin:omfile"), NULL));
+ CHKiRet(regBuildInModule(modInitPipe, UCHAR_CONSTANT("builtin:ompipe"), NULL));
CHKiRet(regBuildInModule(modInitShell, UCHAR_CONSTANT("builtin-shell"), NULL));
- CHKiRet(regBuildInModule(modInitDiscard, UCHAR_CONSTANT("builtin-discard"), NULL));
+ CHKiRet(regBuildInModule(modInitDiscard, UCHAR_CONSTANT("builtin:omdiscard"), NULL));
# ifdef SYSLOG_INET
- CHKiRet(regBuildInModule(modInitFwd, UCHAR_CONSTANT("builtin-fwd"), NULL));
+ CHKiRet(regBuildInModule(modInitFwd, UCHAR_CONSTANT("builtin:omfwd"), NULL));
# endif
/* dirty, but this must be for the time being: the usrmsg module must always be
@@ -1024,11 +1031,11 @@ loadBuildInModules()
* User names now must begin with:
* [a-zA-Z0-9_.]
*/
- CHKiRet(regBuildInModule(modInitUsrMsg, (uchar*) "builtin-usrmsg", NULL));
+ CHKiRet(regBuildInModule(modInitUsrMsg, (uchar*) "builtin:omusrmsg", NULL));
/* load build-in parser modules */
- CHKiRet(regBuildInModule(modInitpmrfc5424, UCHAR_CONSTANT("builtin-pmrfc5424"), NULL));
- CHKiRet(regBuildInModule(modInitpmrfc3164, UCHAR_CONSTANT("builtin-pmrfc3164"), NULL));
+ 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! */
@@ -1036,10 +1043,10 @@ loadBuildInModules()
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));
+ 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) {
@@ -1066,6 +1073,7 @@ initLegacyConf(void)
ruleset.Construct(&pRuleset);
ruleset.SetName(pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset"));
ruleset.ConstructFinalize(loadConf, pRuleset);
+ rulesetSetCurrRulesetPtr(pRuleset);
/* now register config handlers */
CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrGoneAway,
@@ -1282,6 +1290,7 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone!
ABORT_FINALIZE(RS_RET_NO_ACTIONS);
}
tellLexEndParsing();
+ rulesetOptimizeAll(loadConf);
tellCoreConfigLoadDone();
tellModulesConfigLoadDone();
@@ -1340,7 +1349,6 @@ ENDobjQueryInterface(rsconf)
BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */
/* request objects we use */
CHKiRet(objUse(ruleset, CORE_COMPONENT));
- CHKiRet(objUse(rule, CORE_COMPONENT));
CHKiRet(objUse(module, CORE_COMPONENT));
CHKiRet(objUse(conf, CORE_COMPONENT));
CHKiRet(objUse(errmsg, CORE_COMPONENT));
@@ -1357,7 +1365,6 @@ ENDObjClassInit(rsconf)
/* De-initialize the rsconf class.
*/
BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */
- objRelease(rule, CORE_COMPONENT);
objRelease(ruleset, CORE_COMPONENT);
objRelease(module, CORE_COMPONENT);
objRelease(conf, CORE_COMPONENT);
diff --git a/runtime/rsconf.h b/runtime/rsconf.h
index 8715cf1b..484fec8c 100644
--- a/runtime/rsconf.h
+++ b/runtime/rsconf.h
@@ -97,8 +97,8 @@ struct defaults_s {
struct cfgmodules_etry_s {
cfgmodules_etry_t *next;
modInfo_t *pMod;
- /* the following data is input module specific */
void *modCnf; /* pointer to the input module conf */
+ /* the following data is input module specific */
sbool canActivate; /* OK to activate this config? */
sbool canRun; /* OK to run this config? */
};
diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c
index cbab06b7..047dfa9b 100644
--- a/runtime/rsyslog.c
+++ b/runtime/rsyslog.c
@@ -72,7 +72,6 @@
#include "glbl.h"
#include "errmsg.h"
#include "prop.h"
-#include "rule.h"
#include "ruleset.h"
#include "parser.h"
#include "strgen.h"
@@ -171,8 +170,6 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF)
CHKiRet(glblClassInit(NULL));
if(ppErrObj != NULL) *ppErrObj = "msg";
CHKiRet(msgClassInit(NULL));
- if(ppErrObj != NULL) *ppErrObj = "rule";
- CHKiRet(ruleClassInit(NULL));
if(ppErrObj != NULL) *ppErrObj = "ruleset";
CHKiRet(rulesetClassInit(NULL));
if(ppErrObj != NULL) *ppErrObj = "wti";
@@ -220,7 +217,6 @@ rsrtExit(void)
confClassExit();
glblClassExit();
rulesetClassExit();
- ruleClassExit();
objClassExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */
}
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 1da56085..07d58d68 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -142,6 +142,7 @@ typedef uintTiny propid_t;
#define PROP_CEE_ALL_JSON 201
#define PROP_SYS_BOM 159
#define PROP_SYS_UPTIME 160
+#define PROP_UUID 161
/* The error codes below are orginally "borrowed" from
@@ -375,9 +376,27 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_LEGA_ACT_NOT_SUPPORTED = -2215, /**< the module (no longer) supports legacy action syntax */
RS_RET_MAX_OMSR_REACHED = -2216, /**< max nbr of string requests reached, not supported by core */
RS_RET_UID_MISSING = -2217, /**< a user id is missing (but e.g. a password provided) */
+ /* reserved for pre-v6.5 */
+ RS_RET_DUP_PARAM = -2220, /**< config parameter is given more than once */
+ RS_RET_MODULE_ALREADY_IN_CONF = -2221, /**< module already in current configuration */
+ RS_RET_PARAM_NOT_PERMITTED = -2222, /**< legacy parameter no longer permitted (usally already set by v2) */
+ RS_RET_NO_JSON_PASSING = -2223, /**< rsyslog core does not support JSON-passing plugin API */
+ RS_RET_MOD_NO_INPUT_STMT = -2224, /**< (input) module does not support input() statement */
+ RS_RET_NO_CEE_MSG = -2225, /**< the message being processed is NOT CEE-enhanced */
+
+ /**** up to 2300 is reserved for v6 use ****/
+ RS_RET_JNAME_NO_ROOT = -2301, /**< root element is missing in JSON path */
+ RS_RET_JNAME_INVALID = -2302, /**< JSON path is invalid */
+ RS_RET_JSON_PARSE_ERR = -2303, /**< we had a problem parsing JSON (or extra data) */
+ RS_RET_BSD_BLOCKS_UNSUPPORTED = -2304, /**< BSD-style config blocks are no longer supported */
+ RS_RET_JNAME_NOTFOUND = -2305, /**< JSON name not found (does not exist) */
+ RS_RET_INVLD_SETOP = -2305, /**< invalid variable set operation, incompatible type */
+ RS_RET_RULESET_EXISTS = -2306,/**< ruleset already exists */
+ RS_RET_DEPRECATED = -2307,/**< deprecated functionality is used */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
+ RS_RET_FIELD_NOT_FOUND = 1002, /**< field() function did not find requested field */
/* some generic error/status codes */
RS_RET_OK = 0, /**< operation successful */
diff --git a/runtime/rule.c b/runtime/rule.c
deleted file mode 100644
index 9290195c..00000000
--- a/runtime/rule.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/* rule.c - rsyslog's rule object
- *
- * See file comment in rule.c for the overall structure of rule processing.
- *
- * Module begun 2009-06-10 by Rainer Gerhards
- *
- * Copyright 2009-2012 Adiscon GmbH.
- *
- * This file is part of the rsyslog runtime library.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * -or-
- * see COPYING.ASL20 in the source distribution
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "config.h"
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <ctype.h>
-
-#include "rsyslog.h"
-#include "obj.h"
-#include "action.h"
-#include "rule.h"
-#include "errmsg.h"
-#include "srUtils.h"
-#include "batch.h"
-#include "parserif.h"
-#include "unicode-helper.h"
-
-/* static data */
-DEFobjStaticHelpers
-DEFobjCurrIf(errmsg)
-
-
-/* support for simple textual representation of FIOP names
- * rgerhards, 2005-09-27
- */
-static char*
-getFIOPName(unsigned iFIOP)
-{
- char *pRet;
- switch(iFIOP) {
- case FIOP_CONTAINS:
- pRet = "contains";
- break;
- case FIOP_ISEQUAL:
- pRet = "isequal";
- break;
- case FIOP_STARTSWITH:
- pRet = "startswith";
- break;
- case FIOP_REGEX:
- pRet = "regex";
- break;
- case FIOP_EREREGEX:
- pRet = "ereregex";
- break;
- case FIOP_ISEMPTY:
- pRet = "isempty";
- break;
- default:
- pRet = "NOP";
- break;
- }
- return pRet;
-}
-
-
-/* iterate over all actions, this is often needed, for example when HUP processing
- * must be done or a shutdown is pending.
- */
-static rsRetVal
-iterateAllActions(rule_t *pThis, rsRetVal (*pFunc)(void*, void*), void* pParam)
-{
- return llExecFunc(&pThis->llActList, pFunc, pParam);
-}
-
-
-/* helper to processMsg(), used to call the configured actions. It is
- * executed from within llExecFunc() of the action list.
- * rgerhards, 2007-08-02
- */
-DEFFUNC_llExecFunc(processBatchDoActions)
-{
- DEFiRet;
- rsRetVal iRetMod; /* return value of module - we do not always pass that back */
- action_t *pAction = (action_t*) pData;
- batch_t *pBatch = (batch_t*) pParam;
-
- DBGPRINTF("Processing next action\n");
- iRetMod = pAction->submitToActQ(pAction, pBatch);
-
- RETiRet;
-}
-
-
-/* This functions looks at the given message and checks if it matches the
- * provided filter condition.
- */
-static rsRetVal
-shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg)
-{
- DEFiRet;
- unsigned short pbMustBeFreed;
- uchar *pszPropVal;
- int bRet = 0;
- size_t propLen;
-
- ISOBJ_TYPE_assert(pRule, rule);
- assert(pMsg != NULL);
-
- /* we first have a look at the global, BSD-style block filters (for tag
- * and host). Only if they match, we evaluate the actual filter.
- * rgerhards, 2005-10-18
- */
- if(pRule->eHostnameCmpMode == HN_NO_COMP) {
- /* EMPTY BY INTENSION - we check this value first, because
- * it is the one most often used, so this saves us time!
- */
- } else if(pRule->eHostnameCmpMode == HN_COMP_MATCH) {
- if(rsCStrSzStrCmp(pRule->pCSHostnameComp, (uchar*) getHOSTNAME(pMsg), getHOSTNAMELen(pMsg))) {
- /* not equal, so we are already done... */
- dbgprintf("hostname filter '+%s' does not match '%s'\n",
- rsCStrGetSzStrNoNULL(pRule->pCSHostnameComp), getHOSTNAME(pMsg));
- FINALIZE;
- }
- } else { /* must be -hostname */
- if(!rsCStrSzStrCmp(pRule->pCSHostnameComp, (uchar*) getHOSTNAME(pMsg), getHOSTNAMELen(pMsg))) {
- /* not equal, so we are already done... */
- dbgprintf("hostname filter '-%s' does not match '%s'\n",
- rsCStrGetSzStrNoNULL(pRule->pCSHostnameComp), getHOSTNAME(pMsg));
- FINALIZE;
- }
- }
-
- if(pRule->pCSProgNameComp != NULL) {
- int bInv = 0, bEqv = 0, offset = 0;
- if(*(rsCStrGetSzStrNoNULL(pRule->pCSProgNameComp)) == '-') {
- if(*(rsCStrGetSzStrNoNULL(pRule->pCSProgNameComp) + 1) == '-')
- offset = 1;
- else {
- bInv = 1;
- offset = 1;
- }
- }
- if(!rsCStrOffsetSzStrCmp(pRule->pCSProgNameComp, offset,
- (uchar*) getProgramName(pMsg, LOCK_MUTEX), getProgramNameLen(pMsg, LOCK_MUTEX)))
- bEqv = 1;
-
- if((!bEqv && !bInv) || (bEqv && bInv)) {
- /* not equal or inverted selection, so we are already done... */
- DBGPRINTF("programname filter '%s' does not match '%s'\n",
- rsCStrGetSzStrNoNULL(pRule->pCSProgNameComp), getProgramName(pMsg, LOCK_MUTEX));
- FINALIZE;
- }
- }
-
- /* done with the BSD-style block filters */
-
- if(pRule->f_filter_type == FILTER_PRI) {
- /* skip messages that are incorrect priority */
- if ( (pRule->f_filterData.f_pmask[pMsg->iFacility] == TABLE_NOPRI) || \
- ((pRule->f_filterData.f_pmask[pMsg->iFacility] & (1<<pMsg->iSeverity)) == 0) )
- bRet = 0;
- else
- bRet = 1;
- dbgprintf("testing filter, f_pmask %d, result %d\n", pRule->f_filterData.f_pmask[pMsg->iFacility], bRet);
- } else if(pRule->f_filter_type == FILTER_EXPR) {
- bRet = cnfexprEvalBool(pRule->f_filterData.expr, pMsg);
- dbgprintf("result of rainerscript filter evaluation: %d\n", bRet);
- } else {
- assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */
- if(pRule->f_filterData.prop.propID == PROP_INVALID) {
- DBGPRINTF("invalid property ID, filter always returns 0\n");
- bRet = 0;
- } else {
- 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 ) {
- case FIOP_CONTAINS:
- 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)
- bRet = 1; /* process message! */
- break;
- case FIOP_STARTSWITH:
- if(rsCStrSzStrStartsWithCStr(pRule->f_filterData.prop.pCSCompValue,
- pszPropVal, ustrlen(pszPropVal)) == 0)
- bRet = 1; /* process message! */
- break;
- case FIOP_REGEX:
- if(rsCStrSzStrMatchRegex(pRule->f_filterData.prop.pCSCompValue,
- (unsigned char*) pszPropVal, 0, &pRule->f_filterData.prop.regex_cache) == RS_RET_OK)
- bRet = 1;
- break;
- case FIOP_EREREGEX:
- if(rsCStrSzStrMatchRegex(pRule->f_filterData.prop.pCSCompValue,
- (unsigned char*) pszPropVal, 1, &pRule->f_filterData.prop.regex_cache) == RS_RET_OK)
- bRet = 1;
- break;
- default:
- /* here, it handles NOP (for performance reasons) */
- assert(pRule->f_filterData.prop.operation == FIOP_NOP);
- bRet = 1; /* as good as any other default ;) */
- break;
- }
-
- /* now check if the value must be negated */
- if(pRule->f_filterData.prop.isNegated)
- bRet = (bRet == 1) ? 0 : 1;
-
- if(Debug) {
- 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 ");
- 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 */
- if(pbMustBeFreed)
- free(pszPropVal);
- }
- }
-
-finalize_it:
- *bProcessMsg = bRet;
- RETiRet;
-}
-
-
-
-/* Process (consume) a batch of messages. Calls the actions configured.
- * rgerhards, 2005-10-13
- */
-static rsRetVal
-processBatch(rule_t *pThis, batch_t *pBatch)
-{
- int i;
- rsRetVal localRet;
- DEFiRet;
-
- ISOBJ_TYPE_assert(pThis, rule);
- assert(pBatch != NULL);
-
- /* first check the filters and reset status variables */
- for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate) ; ++i) {
- localRet = shouldProcessThisMessage(pThis, (msg_t*)(pBatch->pElem[i].pUsrp),
- &(pBatch->pElem[i].bFilterOK));
- if(localRet != RS_RET_OK) {
- DBGPRINTF("processBatch: iRet %d returned from shouldProcessThisMessage, "
- "ignoring message\n", localRet);
- pBatch->pElem[i].bFilterOK = 0;
- }
- if(pBatch->pElem[i].bFilterOK) {
- /* re-init only when actually needed (cache write cost!) */
- pBatch->pElem[i].bPrevWasSuspended = 0;
- }
- }
- CHKiRet(llExecFunc(&pThis->llActList, processBatchDoActions, pBatch));
-
-finalize_it:
- RETiRet;
-}
-
-
-/* Standard-Constructor
- */
-BEGINobjConstruct(rule) /* be sure to specify the object type also in END macro! */
-ENDobjConstruct(rule)
-
-
-/* ConstructionFinalizer
- * rgerhards, 2008-01-09
- */
-static rsRetVal
-ruleConstructFinalize(rule_t *pThis)
-{
- DEFiRet;
- ISOBJ_TYPE_assert(pThis, rule);
-
- /* note: actionDestruct is from action.c API! */
- CHKiRet(llInit(&pThis->llActList, actionDestruct, NULL, NULL));
-
-finalize_it:
- RETiRet;
-}
-
-
-/* destructor for the rule object */
-BEGINobjDestruct(rule) /* be sure to specify the object type also in END and CODESTART macros! */
-CODESTARTobjDestruct(rule)
- if(pThis->pCSHostnameComp != NULL)
- rsCStrDestruct(&pThis->pCSHostnameComp);
- if(pThis->pCSProgNameComp != NULL)
- rsCStrDestruct(&pThis->pCSProgNameComp);
-
- if(pThis->f_filter_type == FILTER_PROP) {
- if(pThis->f_filterData.prop.pCSCompValue != NULL)
- 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);
- }
-
- llDestroy(&pThis->llActList);
-ENDobjDestruct(rule)
-
-
-/* set the associated ruleset */
-static rsRetVal
-setAssRuleset(rule_t *pThis, ruleset_t *pRuleset)
-{
- DEFiRet;
- ISOBJ_TYPE_assert(pThis, rule);
- ISOBJ_TYPE_assert(pRuleset, ruleset);
- pThis->pRuleset = pRuleset;
- RETiRet;
-}
-
-/* get the associated ruleset (may be NULL if not set!) */
-static ruleset_t*
-getAssRuleset(rule_t *pThis)
-{
- ISOBJ_TYPE_assert(pThis, rule);
- return pThis->pRuleset;
-}
-
-
-/* helper to DebugPrint, to print out all actions via
- * the llExecFunc() facility.
- */
-DEFFUNC_llExecFunc(dbgPrintInitInfoAction)
-{
- DEFiRet;
- iRet = actionDbgPrint((action_t*) pData);
- dbgprintf("\n");
- RETiRet;
-}
-
-
-/* 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)
- dbgprintf("tag: '%s'\n", rsCStrGetSzStrNoNULL(pThis->pCSProgNameComp));
- if(pThis->eHostnameCmpMode != HN_NO_COMP)
- dbgprintf("hostname: %s '%s'\n",
- pThis->eHostnameCmpMode == HN_COMP_MATCH ?
- "only" : "allbut",
- rsCStrGetSzStrNoNULL(pThis->pCSHostnameComp));
- if(pThis->f_filter_type == FILTER_PRI) {
- for (i = 0; i <= LOG_NFACILITIES; i++)
- if (pThis->f_filterData.f_pmask[i] == TABLE_NOPRI)
- dbgprintf(" X ");
- else
- dbgprintf("%2X ", pThis->f_filterData.f_pmask[i]);
- } else if(pThis->f_filter_type == FILTER_EXPR) {
- dbgprintf("EXPRESSION-BASED Filter: can currently not be displayed");
- } else {
- dbgprintf("PROPERTY-BASED Filter:\n");
- dbgprintf("\tProperty.: '%s'\n", propIDToName(pThis->f_filterData.prop.propID));
- if(pThis->f_filterData.prop.propID != PROP_INVALID) {
- 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));
- }
- dbgprintf("\tAction...: ");
- }
-
- dbgprintf("\nActions:\n");
- llExecFunc(&pThis->llActList, dbgPrintInitInfoAction, NULL); /* actions */
-
- dbgprintf("\n");
-ENDobjDebugPrint(rule)
-
-
-/* queryInterface function
- * rgerhards, 2008-02-21
- */
-BEGINobjQueryInterface(rule)
-CODESTARTobjQueryInterface(rule)
- if(pIf->ifVersion != ruleCURR_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 = ruleConstruct;
- pIf->ConstructFinalize = ruleConstructFinalize;
- pIf->Destruct = ruleDestruct;
- pIf->DebugPrint = ruleDebugPrint;
-
- pIf->IterateAllActions = iterateAllActions;
- pIf->ProcessBatch = processBatch;
- pIf->SetAssRuleset = setAssRuleset;
- pIf->GetAssRuleset = getAssRuleset;
-finalize_it:
-ENDobjQueryInterface(rule)
-
-
-/* Exit the rule class.
- * rgerhards, 2009-04-06
- */
-BEGINObjClassExit(rule, OBJ_IS_CORE_MODULE) /* class, version */
- objRelease(errmsg, CORE_COMPONENT);
-ENDObjClassExit(rule)
-
-
-/* Initialize the rule class. Must be called as the very first method
- * before anything else is called inside this class.
- * rgerhards, 2008-02-19
- */
-BEGINObjClassInit(rule, 1, OBJ_IS_CORE_MODULE) /* class, version */
- /* request objects we use */
- CHKiRet(objUse(errmsg, CORE_COMPONENT));
-
- /* set our own handlers */
- OBJSetMethodHandler(objMethod_DEBUGPRINT, ruleDebugPrint);
- OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, ruleConstructFinalize);
-ENDObjClassInit(rule)
-
-/* vi:set ai:
- */
diff --git a/runtime/rule.h b/runtime/rule.h
deleted file mode 100644
index 1b07279b..00000000
--- a/runtime/rule.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/* The rule object.
- *
- * This implements rules within rsyslog.
- *
- * Copyright 2009-2012 Adiscon GmbH.
- *
- * This file is part of the rsyslog runtime library.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- * -or-
- * see COPYING.ASL20 in the source distribution
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef INCLUDED_RULE_H
-#define INCLUDED_RULE_H
-
-#include "libestr.h"
-#include "linkedlist.h"
-#include "regexp.h"
-#include "rainerscript.h"
-
-/* the rule object */
-struct rule_s {
- BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
- /* filter properties */
- enum {
- FILTER_PRI = 0, /* traditional PRI based filer */
- FILTER_PROP = 1, /* extended filter, property based */
- FILTER_EXPR = 2 /* extended filter, expression based */
- } f_filter_type;
- EHostnameCmpMode eHostnameCmpMode;
- cstr_t *pCSHostnameComp; /* hostname to check */
- cstr_t *pCSProgNameComp; /* tag to check or NULL, if not to be checked */
- union {
- u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */
- struct {
- fiop_t operation;
- regex_t *regex_cache; /* cache for compiled REs, if such are used */
- 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;
- struct cnfexpr *expr; /* expression object */
- } f_filterData;
-
- ruleset_t *pRuleset; /* associated ruleset */
- linkedList_t llActList; /* list of configured actions */
-};
-
-/* interfaces */
-BEGINinterface(rule) /* name must also be changed in ENDinterface macro! */
- INTERFACEObjDebugPrint(rule);
- rsRetVal (*Construct)(rule_t **ppThis);
- rsRetVal (*ConstructFinalize)(rule_t __attribute__((unused)) *pThis);
- rsRetVal (*Destruct)(rule_t **ppThis);
- rsRetVal (*IterateAllActions)(rule_t *pThis, rsRetVal (*pFunc)(void*, void*), void *pParam);
- rsRetVal (*ProcessBatch)(rule_t *pThis, batch_t *pBatch);
- rsRetVal (*SetAssRuleset)(rule_t *pThis, ruleset_t*);
- ruleset_t* (*GetAssRuleset)(rule_t *pThis);
-ENDinterface(rule)
-#define ruleCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */
-/* change for v2: ProcessMsg replaced by ProcessBatch - 2010-06-10 */
-
-
-/* prototypes */
-PROTOTYPEObj(rule);
-
-#endif /* #ifndef INCLUDED_RULE_H */
diff --git a/runtime/ruleset.c b/runtime/ruleset.c
index a6eca307..bdeb61b7 100644
--- a/runtime/ruleset.c
+++ b/runtime/ruleset.c
@@ -11,27 +11,24 @@
*
* Module begun 2009-06-10 by Rainer Gerhards
*
- * Copyright 2009-2011 Rainer Gerhards and Adiscon GmbH.
+ * Copyright 2009-2012 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.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * -or-
+ * see COPYING.ASL20 in the source distribution
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
-
#include "config.h"
#include <stdlib.h>
#include <assert.h>
@@ -42,22 +39,36 @@
#include "cfsysline.h"
#include "msg.h"
#include "ruleset.h"
-#include "rule.h"
#include "errmsg.h"
#include "parser.h"
#include "batch.h"
#include "unicode-helper.h"
#include "rsconf.h"
+#include "action.h"
+#include "rainerscript.h"
+#include "srUtils.h"
+#include "modules.h"
#include "dirty.h" /* for main ruleset queue creation */
/* static data */
DEFobjStaticHelpers
DEFobjCurrIf(errmsg)
-DEFobjCurrIf(rule)
DEFobjCurrIf(parser)
+/* tables for interfacing with the v6 config system (as far as we need to) */
+static struct cnfparamdescr rspdescr[] = {
+ { "name", eCmdHdlrString, CNFPARAM_REQUIRED },
+ { "parser", eCmdHdlrArray, 0 }
+};
+static struct cnfparamblk rspblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(rspdescr)/sizeof(struct cnfparamdescr),
+ rspdescr
+ };
+
/* forward definitions */
static rsRetVal processBatch(batch_t *pBatch);
+static rsRetVal scriptExec(struct cnfstmt *root, batch_t *pBatch, sbool *active);
/* ---------- linked-list key handling functions (ruleset) ---------- */
@@ -73,45 +84,61 @@ rulesetKeyDestruct(void __attribute__((unused)) *pData)
/* ---------- END linked-list key handling functions (ruleset) ---------- */
+/* iterate over all actions in a script (stmt subtree) */
+static void
+scriptIterateAllActions(struct cnfstmt *root, rsRetVal (*pFunc)(void*, void*), void* pParam)
+{
+ struct cnfstmt *stmt;
+ for(stmt = root ; stmt != NULL ; stmt = stmt->next) {
+ switch(stmt->nodetype) {
+ case S_NOP:
+ case S_STOP:
+ case S_CALL:/* call does not need to do anything - done in called ruleset! */
+ break;
+ case S_ACT:
+ DBGPRINTF("iterateAllActions calling into action %p\n", stmt->d.act);
+ pFunc(stmt->d.act, pParam);
+ break;
+ case S_IF:
+ if(stmt->d.s_if.t_then != NULL)
+ scriptIterateAllActions(stmt->d.s_if.t_then,
+ pFunc, pParam);
+ if(stmt->d.s_if.t_else != NULL)
+ scriptIterateAllActions(stmt->d.s_if.t_else,
+ pFunc, pParam);
+ break;
+ case S_PRIFILT:
+ if(stmt->d.s_prifilt.t_then != NULL)
+ scriptIterateAllActions(stmt->d.s_prifilt.t_then,
+ pFunc, pParam);
+ if(stmt->d.s_prifilt.t_else != NULL)
+ scriptIterateAllActions(stmt->d.s_prifilt.t_else,
+ pFunc, pParam);
+ break;
+ case S_PROPFILT:
+ scriptIterateAllActions(stmt->d.s_propfilt.t_then,
+ pFunc, pParam);
+ break;
+ default:
+ dbgprintf("error: unknown stmt type %u during iterateAll\n",
+ (unsigned) stmt->nodetype);
+ break;
+ }
+ }
+}
/* driver to iterate over all of this ruleset actions */
typedef struct iterateAllActions_s {
rsRetVal (*pFunc)(void*, void*);
void *pParam;
} iterateAllActions_t;
-DEFFUNC_llExecFunc(doIterateRulesetActions)
-{
- DEFiRet;
- rule_t* pRule = (rule_t*) pData;
- iterateAllActions_t *pMyParam = (iterateAllActions_t*) pParam;
- iRet = rule.IterateAllActions(pRule, pMyParam->pFunc, pMyParam->pParam);
- RETiRet;
-}
-/* iterate over all actions of THIS rule set.
- */
-static rsRetVal
-iterateRulesetAllActions(ruleset_t *pThis, rsRetVal (*pFunc)(void*, void*), void* pParam)
-{
- iterateAllActions_t params;
- DEFiRet;
- assert(pFunc != NULL);
-
- params.pFunc = pFunc;
- params.pParam = pParam;
- CHKiRet(llExecFunc(&(pThis->llRules), doIterateRulesetActions, &params));
-
-finalize_it:
- RETiRet;
-}
-
-
/* driver to iterate over all actions */
DEFFUNC_llExecFunc(doIterateAllActions)
{
DEFiRet;
ruleset_t* pThis = (ruleset_t*) pData;
iterateAllActions_t *pMyParam = (iterateAllActions_t*) pParam;
- iRet = iterateRulesetAllActions(pThis, pMyParam->pFunc, pMyParam->pParam);
+ scriptIterateAllActions(pThis->root, pMyParam->pFunc, pMyParam->pParam);
RETiRet;
}
/* iterate over ALL actions present in the WHOLE system.
@@ -134,30 +161,10 @@ finalize_it:
}
-
-/* helper to processBatch(), used to call the configured actions. It is
- * executed from within llExecFunc() of the action list.
- * rgerhards, 2007-08-02
- */
-DEFFUNC_llExecFunc(processBatchDoRules)
-{
- rsRetVal iRet;
- ISOBJ_TYPE_assert(pData, rule);
- dbgprintf("Processing next rule\n");
- iRet = rule.ProcessBatch((rule_t*) pData, (batch_t*) pParam);
-dbgprintf("ruleset: get iRet %d from rule.ProcessMsg()\n", iRet);
- return iRet;
-}
-
-
-
/* This function is similar to processBatch(), but works on a batch that
* contains rules from multiple rulesets. In this case, we can not push
* the whole batch through the ruleset. Instead, we examine it and
* partition it into sub-rulesets which we then push through the system.
- * Note that when we evaluate which message must be processed, we do NOT need
- * to look at bFilterOK, because this value is only set in a later processing
- * stage. Doing so caused a bug during development ;)
* rgerhards, 2010-06-15
*/
static inline rsRetVal
@@ -207,6 +214,326 @@ finalize_it:
RETiRet;
}
+/* return a new "active" structure for the batch. Free with freeActive(). */
+static inline sbool *newActive(batch_t *pBatch)
+{
+ return malloc(sizeof(sbool) * batchNumMsgs(pBatch));
+
+}
+static inline void freeActive(sbool *active) { free(active); }
+
+
+/* for details, see scriptExec() header comment! */
+/* call action for all messages with filter on */
+static rsRetVal
+execAct(struct cnfstmt *stmt, batch_t *pBatch, sbool *active)
+{
+ DEFiRet;
+dbgprintf("RRRR: execAct [%s]: batch of %d elements, active %p\n", modGetName(stmt->d.act->pMod), batchNumMsgs(pBatch), active);
+ pBatch->active = active;
+ stmt->d.act->submitToActQ(stmt->d.act, pBatch);
+ RETiRet;
+}
+
+static rsRetVal
+execSet(struct cnfstmt *stmt, batch_t *pBatch, sbool *active)
+{
+ int i;
+ struct var result;
+ DEFiRet;
+ for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate) ; ++i) {
+ if( pBatch->pElem[i].state != BATCH_STATE_DISC
+ && (active == NULL || active[i])) {
+ cnfexprEval(stmt->d.s_set.expr, &result, pBatch->pElem[i].pUsrp);
+ msgSetJSONFromVar((msg_t*)pBatch->pElem[i].pUsrp, stmt->d.s_set.varname,
+ &result);
+ varDelete(&result);
+ }
+ }
+ RETiRet;
+}
+
+static rsRetVal
+execUnset(struct cnfstmt *stmt, batch_t *pBatch, sbool *active)
+{
+ int i;
+ DEFiRet;
+ for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate) ; ++i) {
+ if( pBatch->pElem[i].state != BATCH_STATE_DISC
+ && (active == NULL || active[i])) {
+ msgUnsetJSON((msg_t*)pBatch->pElem[i].pUsrp, stmt->d.s_unset.varname);
+ }
+ }
+ RETiRet;
+}
+
+/* for details, see scriptExec() header comment! */
+/* "stop" simply discards the filtered items - it's just a (hopefully more intuitive
+ * shortcut for users.
+ */
+static rsRetVal
+execStop(batch_t *pBatch, sbool *active)
+{
+ int i;
+ DEFiRet;
+ for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate) ; ++i) {
+ if( pBatch->pElem[i].state != BATCH_STATE_DISC
+ && (active == NULL || active[i])) {
+ pBatch->pElem[i].state = BATCH_STATE_DISC;
+ }
+ }
+ RETiRet;
+}
+
+/* for details, see scriptExec() header comment! */
+// save current filter, evaluate new one
+// perform then (if any message)
+// if ELSE given:
+// set new filter, inverted
+// perform else (if any messages)
+static rsRetVal
+execIf(struct cnfstmt *stmt, batch_t *pBatch, sbool *active)
+{
+ sbool *newAct;
+ int i;
+ sbool bRet;
+ DEFiRet;
+ newAct = newActive(pBatch);
+ for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate) ; ++i) {
+ if(pBatch->pElem[i].state == BATCH_STATE_DISC)
+ continue; /* will be ignored in any case */
+ if(active == NULL || active[i]) {
+ bRet = cnfexprEvalBool(stmt->d.s_if.expr,
+ (msg_t*)(pBatch->pElem[i].pUsrp));
+ } else
+ bRet = 0;
+ newAct[i] = bRet;
+ DBGPRINTF("batch: item %d: expr eval: %d\n", i, bRet);
+ }
+
+ if(stmt->d.s_if.t_then != NULL) {
+ scriptExec(stmt->d.s_if.t_then, pBatch, newAct);
+ }
+ if(stmt->d.s_if.t_else != NULL) {
+ for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate)
+ ; ++i)
+ if(pBatch->pElem[i].state != BATCH_STATE_DISC)
+ newAct[i] = !newAct[i];
+ scriptExec(stmt->d.s_if.t_else, pBatch, newAct);
+ }
+ freeActive(newAct);
+ RETiRet;
+}
+
+/* for details, see scriptExec() header comment! */
+static void
+execPRIFILT(struct cnfstmt *stmt, batch_t *pBatch, sbool *active)
+{
+ sbool *newAct;
+ msg_t *pMsg;
+ int bRet;
+ int i;
+ newAct = newActive(pBatch);
+ for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate) ; ++i) {
+ if(pBatch->pElem[i].state == BATCH_STATE_DISC)
+ continue; /* will be ignored in any case */
+ pMsg = (msg_t*)(pBatch->pElem[i].pUsrp);
+ if(active == NULL || active[i]) {
+ if( (stmt->d.s_prifilt.pmask[pMsg->iFacility] == TABLE_NOPRI) ||
+ ((stmt->d.s_prifilt.pmask[pMsg->iFacility]
+ & (1<<pMsg->iSeverity)) == 0) )
+ bRet = 0;
+ else
+ bRet = 1;
+ } else
+ bRet = 0;
+ newAct[i] = bRet;
+ DBGPRINTF("batch: item %d PRIFILT %d\n", i, newAct[i]);
+ }
+
+ if(stmt->d.s_prifilt.t_then != NULL) {
+ scriptExec(stmt->d.s_prifilt.t_then, pBatch, newAct);
+ }
+ if(stmt->d.s_prifilt.t_else != NULL) {
+ for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate)
+ ; ++i)
+ if(pBatch->pElem[i].state != BATCH_STATE_DISC)
+ newAct[i] = !newAct[i];
+ scriptExec(stmt->d.s_prifilt.t_else, pBatch, newAct);
+ }
+ freeActive(newAct);
+}
+
+
+/* helper to execPROPFILT(), as the evaluation itself is quite lengthy */
+static int
+evalPROPFILT(struct cnfstmt *stmt, msg_t *pMsg)
+{
+ unsigned short pbMustBeFreed;
+ uchar *pszPropVal;
+ int bRet = 0;
+ rs_size_t propLen;
+
+ if(stmt->d.s_propfilt.propID == PROP_INVALID)
+ goto done;
+
+ pszPropVal = MsgGetProp(pMsg, NULL, stmt->d.s_propfilt.propID,
+ stmt->d.s_propfilt.propName, &propLen, &pbMustBeFreed);
+
+ /* Now do the compares (short list currently ;)) */
+ switch(stmt->d.s_propfilt.operation ) {
+ case FIOP_CONTAINS:
+ if(rsCStrLocateInSzStr(stmt->d.s_propfilt.pCSCompValue, (uchar*) pszPropVal) != -1)
+ bRet = 1;
+ break;
+ case FIOP_ISEMPTY:
+ if(propLen == 0)
+ bRet = 1; /* process message! */
+ break;
+ case FIOP_ISEQUAL:
+ if(rsCStrSzStrCmp(stmt->d.s_propfilt.pCSCompValue,
+ pszPropVal, ustrlen(pszPropVal)) == 0)
+ bRet = 1; /* process message! */
+ break;
+ case FIOP_STARTSWITH:
+ if(rsCStrSzStrStartsWithCStr(stmt->d.s_propfilt.pCSCompValue,
+ pszPropVal, ustrlen(pszPropVal)) == 0)
+ bRet = 1; /* process message! */
+ break;
+ case FIOP_REGEX:
+ if(rsCStrSzStrMatchRegex(stmt->d.s_propfilt.pCSCompValue,
+ (unsigned char*) pszPropVal, 0, &stmt->d.s_propfilt.regex_cache) == RS_RET_OK)
+ bRet = 1;
+ break;
+ case FIOP_EREREGEX:
+ if(rsCStrSzStrMatchRegex(stmt->d.s_propfilt.pCSCompValue,
+ (unsigned char*) pszPropVal, 1, &stmt->d.s_propfilt.regex_cache) == RS_RET_OK)
+ bRet = 1;
+ break;
+ default:
+ /* here, it handles NOP (for performance reasons) */
+ assert(stmt->d.s_propfilt.operation == FIOP_NOP);
+ bRet = 1; /* as good as any other default ;) */
+ break;
+ }
+
+ /* now check if the value must be negated */
+ if(stmt->d.s_propfilt.isNegated)
+ bRet = (bRet == 1) ? 0 : 1;
+
+ if(Debug) {
+ char *cstr;
+ if(stmt->d.s_propfilt.propID == PROP_CEE) {
+ cstr = es_str2cstr(stmt->d.s_propfilt.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(stmt->d.s_propfilt.propID), pszPropVal);
+ }
+ if(stmt->d.s_propfilt.isNegated)
+ DBGPRINTF("NOT ");
+ if(stmt->d.s_propfilt.operation == FIOP_ISEMPTY) {
+ DBGPRINTF("%s : %s\n",
+ getFIOPName(stmt->d.s_propfilt.operation),
+ bRet ? "TRUE" : "FALSE");
+ } else {
+ DBGPRINTF("%s '%s': %s\n",
+ getFIOPName(stmt->d.s_propfilt.operation),
+ rsCStrGetSzStrNoNULL(stmt->d.s_propfilt.pCSCompValue),
+ bRet ? "TRUE" : "FALSE");
+ }
+ }
+
+ /* cleanup */
+ if(pbMustBeFreed)
+ free(pszPropVal);
+done:
+ return bRet;
+}
+
+/* for details, see scriptExec() header comment! */
+static void
+execPROPFILT(struct cnfstmt *stmt, batch_t *pBatch, sbool *active)
+{
+ sbool *thenAct;
+ msg_t *pMsg;
+ sbool bRet;
+ int i;
+ thenAct = newActive(pBatch);
+ for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate) ; ++i) {
+ if(pBatch->pElem[i].state == BATCH_STATE_DISC)
+ continue; /* will be ignored in any case */
+ pMsg = (msg_t*)(pBatch->pElem[i].pUsrp);
+ if(active == NULL || active[i]) {
+ bRet = evalPROPFILT(stmt, (msg_t*)(pBatch->pElem[i].pUsrp));
+ } else
+ bRet = 0;
+ thenAct[i] = bRet;
+ DBGPRINTF("batch: item %d PROPFILT %d\n", i, thenAct[i]);
+ }
+
+ scriptExec(stmt->d.s_propfilt.t_then, pBatch, thenAct);
+ freeActive(thenAct);
+}
+
+/* The rainerscript execution engine. It is debatable if that would be better
+ * contained in grammer/rainerscript.c, HOWEVER, that file focusses primarily
+ * on the parsing and object creation part. So as an actual executor, it is
+ * better suited here.
+ * param active: if NULL, all messages are active (to be processed), if non-null
+ * this is an array of the same size as the batch. If 1, the message
+ * is to be processed, otherwise not.
+ * NOTE: this function must receive batches which contain a single ruleset ONLY!
+ * rgerhards, 2012-09-04
+ */
+static rsRetVal
+scriptExec(struct cnfstmt *root, batch_t *pBatch, sbool *active)
+{
+ DEFiRet;
+ struct cnfstmt *stmt;
+
+ for(stmt = root ; stmt != NULL ; stmt = stmt->next) {
+dbgprintf("RRRR: scriptExec: batch of %d elements, active %p, stmt %p, nodetype %u\n", batchNumMsgs(pBatch), active, stmt, stmt->nodetype);
+ switch(stmt->nodetype) {
+ case S_NOP:
+ break;
+ case S_STOP:
+ execStop(pBatch, active);
+ break;
+ case S_ACT:
+ execAct(stmt, pBatch, active);
+ break;
+ case S_SET:
+ execSet(stmt, pBatch, active);
+ break;
+ case S_UNSET:
+ execUnset(stmt, pBatch, active);
+ break;
+ case S_CALL:
+ DBGPRINTF("calling ruleset\n"); // TODO: add Name
+ scriptExec(stmt->d.s_call.stmt, pBatch, active);
+ break;
+ case S_IF:
+ execIf(stmt, pBatch, active);
+ break;
+ case S_PRIFILT:
+ execPRIFILT(stmt, pBatch, active);
+ break;
+ case S_PROPFILT:
+ execPROPFILT(stmt, pBatch, active);
+ break;
+ default:
+ dbgprintf("error: unknown stmt type %u during exec\n",
+ (unsigned) stmt->nodetype);
+ break;
+ }
+ }
+ RETiRet;
+}
+
+
/* Process (consume) a batch of messages. Calls the actions configured.
* If the whole batch uses a singel ruleset, we can process the batch as
* a whole. Otherwise, we need to process it slower, on a message-by-message
@@ -226,7 +553,7 @@ processBatch(batch_t *pBatch)
if(pThis == NULL)
pThis = ourConf->rulesets.pDflt;
ISOBJ_TYPE_assert(pThis, ruleset);
- CHKiRet(llExecFunc(&pThis->llRules, processBatchDoRules, pBatch));
+ CHKiRet(scriptExec(pThis->root, pBatch, NULL));
} else {
CHKiRet(processBatchMultiRuleset(pBatch));
}
@@ -248,34 +575,21 @@ GetParserList(rsconf_t *conf, msg_t *pMsg)
}
-/* Add a new rule to the end of the current rule set. We do a number
- * of checks and ignore the rule if it does not pass them.
- */
-static rsRetVal
-addRule(ruleset_t *pThis, rule_t **ppRule)
+/* Add a script block to the current ruleset */
+static void
+addScript(ruleset_t *pThis, struct cnfstmt *script)
{
- int iActionCnt;
- DEFiRet;
-
- ISOBJ_TYPE_assert(pThis, ruleset);
- ISOBJ_TYPE_assert(*ppRule, rule);
-
- CHKiRet(llGetNumElts(&(*ppRule)->llActList, &iActionCnt));
- if(iActionCnt == 0) {
- errmsg.LogError(0, NO_ERRCODE, "warning: selector line without actions will be discarded");
- rule.Destruct(ppRule);
- } else {
- CHKiRet(llAppend(&pThis->llRules, NULL, *ppRule));
- dbgprintf("selector line successfully processed, %d actions\n", iActionCnt);
+ if(pThis->last == NULL)
+ pThis->root = pThis->last = script;
+ else {
+ pThis->last->next = script;
+ pThis->last = script;
}
-
-finalize_it:
- RETiRet;
}
/* set name for ruleset */
-static rsRetVal setName(ruleset_t *pThis, uchar *pszName)
+static rsRetVal rulesetSetName(ruleset_t *pThis, uchar *pszName)
{
DEFiRet;
free(pThis->pszName);
@@ -337,15 +651,14 @@ SetDefaultRuleset(rsconf_t *conf, uchar *pszName)
CHKiRet(rulesetGetRuleset(conf, &pRuleset, pszName));
conf->rulesets.pDflt = pRuleset;
- dbgprintf("default rule set changed to %p: '%s'\n", pRuleset, pszName);
+ DBGPRINTF("default rule set changed to %p: '%s'\n", pRuleset, pszName);
finalize_it:
RETiRet;
}
-/* Set a new current rule set. If the ruleset can not be found, no change happens.
- */
+/* Set a new current rule set. If the ruleset can not be found, no change happens */
static rsRetVal
SetCurrRuleset(rsconf_t *conf, uchar *pszName)
{
@@ -355,30 +668,18 @@ SetCurrRuleset(rsconf_t *conf, uchar *pszName)
CHKiRet(rulesetGetRuleset(conf, &pRuleset, pszName));
conf->rulesets.pCurr = pRuleset;
- dbgprintf("current rule set changed to %p: '%s'\n", pRuleset, pszName);
+ DBGPRINTF("current rule set changed to %p: '%s'\n", pRuleset, pszName);
finalize_it:
RETiRet;
}
-/* destructor we need to destruct rules inside our linked list contents.
- */
-static rsRetVal
-doRuleDestruct(void *pData)
-{
- rule_t *pRule = (rule_t *) pData;
- DEFiRet;
- rule.Destruct(&pRule);
- RETiRet;
-}
-
-
/* Standard-Constructor
*/
BEGINobjConstruct(ruleset) /* be sure to specify the object type also in END macro! */
- CHKiRet(llInit(&pThis->llRules, doRuleDestruct, NULL, NULL));
-finalize_it:
+ pThis->root = NULL;
+ pThis->last = NULL;
ENDobjConstruct(ruleset)
@@ -399,9 +700,6 @@ rulesetConstructFinalize(rsconf_t *conf, ruleset_t *pThis)
CHKmalloc(keyName = ustrdup(pThis->pszName));
CHKiRet(llAppend(&(conf->rulesets.llRulesets), keyName, pThis));
- /* this now also is the new current ruleset */
- conf->rulesets.pCurr = pThis;
-
/* and also the default, if so far none has been set */
if(conf->rulesets.pDflt == NULL)
conf->rulesets.pDflt = pThis;
@@ -414,15 +712,15 @@ finalize_it:
/* destructor for the ruleset object */
BEGINobjDestruct(ruleset) /* be sure to specify the object type also in END and CODESTART macros! */
CODESTARTobjDestruct(ruleset)
- dbgprintf("destructing ruleset %p, name %p\n", pThis, pThis->pszName);
+ DBGPRINTF("destructing ruleset %p, name %p\n", pThis, pThis->pszName);
if(pThis->pQueue != NULL) {
qqueueDestruct(&pThis->pQueue);
}
if(pThis->pParserLst != NULL) {
parser.DestructParserList(&pThis->pParserLst);
}
- llDestroy(&pThis->llRules);
free(pThis->pszName);
+ cnfstmtDestruct(pThis->root);
ENDobjDestruct(ruleset)
@@ -456,16 +754,13 @@ rulesetDestructForLinkedList(void *pData)
return rulesetDestruct(&pThis);
}
-/* helper for debugPrint(), initiates rule printing */
-DEFFUNC_llExecFunc(doDebugPrintRule)
-{
- return rule.DebugPrint((rule_t*) pData);
-}
/* debugprint for the ruleset object */
BEGINobjDebugPrint(ruleset) /* be sure to specify the object type also in END and CODESTART macros! */
CODESTARTobjDebugPrint(ruleset)
dbgoprint((obj_t*) pThis, "rsyslog ruleset %s:\n", pThis->pszName);
- llExecFunc(&pThis->llRules, doDebugPrintRule, NULL);
+ cnfstmtPrint(pThis->root, 0);
+ dbgoprint((obj_t*) pThis, "ruleset %s assigned parser list:\n", pThis->pszName);
+ printParserList(pThis->pParserLst);
ENDobjDebugPrint(ruleset)
@@ -486,6 +781,40 @@ debugPrintAll(rsconf_t *conf)
RETiRet;
}
+static inline void
+rulesetOptimize(ruleset_t *pRuleset)
+{
+ if(Debug) {
+ dbgprintf("ruleset '%s' before optimization:\n",
+ pRuleset->pszName);
+ rulesetDebugPrint((ruleset_t*) pRuleset);
+ }
+ cnfstmtOptimize(pRuleset->root);
+ if(Debug) {
+ dbgprintf("ruleset '%s' after optimization:\n",
+ pRuleset->pszName);
+ rulesetDebugPrint((ruleset_t*) pRuleset);
+ }
+}
+
+/* helper for rulsetOptimizeAll(), optimizes a single ruleset */
+DEFFUNC_llExecFunc(doRulesetOptimizeAll)
+{
+ rulesetOptimize((ruleset_t*) pData);
+ return RS_RET_OK;
+}
+/* optimize all rulesets
+ */
+rsRetVal
+rulesetOptimizeAll(rsconf_t *conf)
+{
+ DEFiRet;
+ dbgprintf("begin ruleset optimization phase\n");
+ llExecFunc(&(conf->rulesets.llRulesets), doRulesetOptimizeAll, NULL);
+ dbgprintf("ruleset optimization phase finished.\n");
+ RETiRet;
+}
+
/* Create a ruleset-specific "main" queue for this ruleset. If one is already
* defined, an error message is emitted but nothing else is done.
@@ -539,13 +868,11 @@ rulesetCreateQueue(void __attribute__((unused)) *pVal, int *pNewVal)
* rgerhards, 2009-11-04
*/
static rsRetVal
-doRulesetAddParser(rsconf_t *conf, uchar *pName)
+doRulesetAddParser(ruleset_t *pRuleset, uchar *pName)
{
parser_t *pParser;
DEFiRet;
- assert(conf->rulesets.pCurr != NULL);
-
CHKiRet(objUse(parser, CORE_COMPONENT));
iRet = parser.FindParser(&pParser, pName);
if(iRet == RS_RET_PARSER_NOT_FOUND) {
@@ -557,10 +884,9 @@ doRulesetAddParser(rsconf_t *conf, uchar *pName)
FINALIZE;
}
- CHKiRet(parser.AddParserToList(&conf->rulesets.pCurr->pParserLst, pParser));
+ CHKiRet(parser.AddParserToList(&pRuleset->pParserLst, pParser));
- dbgprintf("added parser '%s' to ruleset '%s'\n", pName, conf->rulesets.pCurr->pszName);
-RUNLOG_VAR("%p", conf->rulesets.pCurr->pParserLst);
+ DBGPRINTF("added parser '%s' to ruleset '%s'\n", pName, pRuleset->pszName);
finalize_it:
d_free(pName); /* no longer needed */
@@ -571,7 +897,63 @@ finalize_it:
static rsRetVal
rulesetAddParser(void __attribute__((unused)) *pVal, uchar *pName)
{
- return doRulesetAddParser(ourConf, pName);
+ return doRulesetAddParser(ourConf->rulesets.pCurr, pName);
+}
+
+
+/* Process ruleset() objects */
+rsRetVal
+rulesetProcessCnf(struct cnfobj *o)
+{
+ struct cnfparamvals *pvals;
+ rsRetVal localRet;
+ uchar *rsName = NULL;
+ uchar *parserName;
+ int nameIdx, parserIdx;
+ ruleset_t *pRuleset;
+ struct cnfarray *ar;
+ int i;
+ DEFiRet;
+
+ pvals = nvlstGetParams(o->nvlst, &rspblk, NULL);
+ if(pvals == NULL) {
+ ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
+ }
+ DBGPRINTF("ruleset param blk after rulesetProcessCnf:\n");
+ cnfparamsPrint(&rspblk, pvals);
+ nameIdx = cnfparamGetIdx(&rspblk, "name");
+ rsName = (uchar*)es_str2cstr(pvals[nameIdx].val.d.estr, NULL);
+ localRet = rulesetGetRuleset(loadConf, &pRuleset, rsName);
+ if(localRet == RS_RET_OK) {
+ errmsg.LogError(0, RS_RET_RULESET_EXISTS,
+ "error: ruleset '%s' specified more than once",
+ rsName);
+ cnfstmtDestruct(o->script);
+ ABORT_FINALIZE(RS_RET_RULESET_EXISTS);
+ } else if(localRet != RS_RET_NOT_FOUND) {
+ ABORT_FINALIZE(localRet);
+ }
+ CHKiRet(rulesetConstruct(&pRuleset));
+ CHKiRet(rulesetSetName(pRuleset, rsName));
+ CHKiRet(rulesetConstructFinalize(loadConf, pRuleset));
+ addScript(pRuleset, o->script);
+
+ /* we have only two params, so we do NOT do the usual param loop */
+ parserIdx = cnfparamGetIdx(&rspblk, "parser");
+ if(parserIdx == -1 || !pvals[parserIdx].bUsed)
+ FINALIZE;
+
+ ar = pvals[parserIdx].val.d.ar;
+ for(i = 0 ; i < ar->nmemb ; ++i) {
+ parserName = (uchar*)es_str2cstr(ar->arr[i], NULL);
+ doRulesetAddParser(pRuleset, parserName);
+ free(parserName);
+ }
+
+finalize_it:
+ free(rsName);
+ cnfparamvalsDestruct(pvals, &rspblk);
+ RETiRet;
}
@@ -596,9 +978,9 @@ CODESTARTobjQueryInterface(ruleset)
pIf->IterateAllActions = iterateAllActions;
pIf->DestructAllActions = destructAllActions;
- pIf->AddRule = addRule;
+ pIf->AddScript = addScript;
pIf->ProcessBatch = processBatch;
- pIf->SetName = setName;
+ pIf->SetName = rulesetSetName;
pIf->DebugPrintAll = debugPrintAll;
pIf->GetCurrent = GetCurrent;
pIf->GetRuleset = rulesetGetRuleset;
@@ -615,7 +997,6 @@ ENDobjQueryInterface(ruleset)
*/
BEGINObjClassExit(ruleset, OBJ_IS_CORE_MODULE) /* class, version */
objRelease(errmsg, CORE_COMPONENT);
- objRelease(rule, CORE_COMPONENT);
objRelease(parser, CORE_COMPONENT);
ENDObjClassExit(ruleset)
@@ -627,7 +1008,6 @@ ENDObjClassExit(ruleset)
BEGINObjClassInit(ruleset, 1, OBJ_IS_CORE_MODULE) /* class, version */
/* request objects we use */
CHKiRet(objUse(errmsg, CORE_COMPONENT));
- CHKiRet(objUse(rule, CORE_COMPONENT));
/* set our own handlers */
OBJSetMethodHandler(objMethod_DEBUGPRINT, rulesetDebugPrint);
diff --git a/runtime/ruleset.h b/runtime/ruleset.h
index f4443e18..cbf8243b 100644
--- a/runtime/ruleset.h
+++ b/runtime/ruleset.h
@@ -25,13 +25,15 @@
#include "queue.h"
#include "linkedlist.h"
+#include "rsconf.h"
/* the ruleset object */
struct ruleset_s {
BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */
- linkedList_t llRules; /* this is NOT a pointer - no typo here ;) */
uchar *pszName; /* name of our ruleset */
qqueue_t *pQueue; /* "main" message queue, if the ruleset has its own (else NULL) */
+ struct cnfstmt *root;
+ struct cnfstmt *last;
parserList_t *pParserLst;/* list of parsers to use for this ruleset */
};
@@ -42,9 +44,7 @@ BEGINinterface(ruleset) /* name must also be changed in ENDinterface macro! */
rsRetVal (*Construct)(ruleset_t **ppThis);
rsRetVal (*ConstructFinalize)(rsconf_t *conf, ruleset_t __attribute__((unused)) *pThis);
rsRetVal (*Destruct)(ruleset_t **ppThis);
- rsRetVal (*IterateAllActions)(rsconf_t *conf, rsRetVal (*pFunc)(void*, void*), void* pParam);
rsRetVal (*DestructAllActions)(rsconf_t *conf);
- rsRetVal (*AddRule)(ruleset_t *pThis, rule_t **ppRule);
rsRetVal (*SetName)(ruleset_t *pThis, uchar *pszName);
rsRetVal (*ProcessBatch)(batch_t*);
rsRetVal (*GetRuleset)(rsconf_t *conf, ruleset_t **ppThis, uchar*);
@@ -60,8 +60,12 @@ BEGINinterface(ruleset) /* name must also be changed in ENDinterface macro! */
* removed conf ptr from SetName, AddRule as the flex/bison based
* system uses globals in any case.
*/
+ /* v7, 2012-09-04 */
+ /* AddRule() removed */
+ /*TODO:REMOVE*/rsRetVal (*IterateAllActions)(rsconf_t *conf, rsRetVal (*pFunc)(void*, void*), void* pParam);
+ void (*AddScript)(ruleset_t *pThis, struct cnfstmt *script);
ENDinterface(ruleset)
-#define rulesetCURR_IF_VERSION 6 /* increment whenever you change the interface structure! */
+#define rulesetCURR_IF_VERSION 7 /* increment whenever you change the interface structure! */
/* prototypes */
@@ -87,5 +91,16 @@ rulesetGetName(ruleset_t *pRuleset)
}
+/* we will most probably convert this module back to traditional C
+ * calling sequence, so here we go...
+ */
rsRetVal rulesetGetRuleset(rsconf_t *conf, ruleset_t **ppRuleset, uchar *pszName);
+rsRetVal rulesetOptimizeAll(rsconf_t *conf);
+rsRetVal rulesetProcessCnf(struct cnfobj *o);
+
+/* Set a current rule set to already-known pointer */
+static inline void
+rulesetSetCurrRulesetPtr(ruleset_t *pRuleset) {
+ loadConf->rulesets.pCurr = pRuleset;
+}
#endif /* #ifndef INCLUDED_RULESET_H */
diff --git a/runtime/statsobj.c b/runtime/statsobj.c
index a21614f6..25275616 100644
--- a/runtime/statsobj.c
+++ b/runtime/statsobj.c
@@ -168,15 +168,18 @@ finalize_it:
/* get all the object's countes together as CEE. */
static rsRetVal
-getStatsLineCEE(statsobj_t *pThis, cstr_t **ppcstr)
+getStatsLineCEE(statsobj_t *pThis, cstr_t **ppcstr, int cee_cookie)
{
cstr_t *pcstr;
ctr_t *pCtr;
DEFiRet;
CHKiRet(cstrConstruct(&pcstr));
- rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT("@cee: {"), 7);
+ if (cee_cookie == 1)
+ rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT("@cee: "), 6);
+
+ rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT("{"), 1);
rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT("\""), 1);
rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT("name"), 4);
rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT("\""), 1);
@@ -273,8 +276,11 @@ getAllStatsLines(rsRetVal(*cb)(void*, cstr_t*), void *usrptr, statsFmtType_t fmt
case statsFmt_Legacy:
CHKiRet(getStatsLine(o, &cstr));
break;
+ case statsFmt_CEE:
+ CHKiRet(getStatsLineCEE(o, &cstr, 1));
+ break;
case statsFmt_JSON:
- CHKiRet(getStatsLineCEE(o, &cstr));
+ CHKiRet(getStatsLineCEE(o, &cstr, 0));
break;
}
CHKiRet(cb(usrptr, cstr));
diff --git a/runtime/statsobj.h b/runtime/statsobj.h
index f7de68ee..14b33215 100644
--- a/runtime/statsobj.h
+++ b/runtime/statsobj.h
@@ -46,7 +46,8 @@ typedef enum statsCtrType_e {
/* stats line format types */
typedef enum statsFmtType_e {
statsFmt_Legacy,
- statsFmt_JSON
+ statsFmt_JSON,
+ statsFmt_CEE
} statsFmtType_t;
diff --git a/runtime/typedefs.h b/runtime/typedefs.h
index f994cbc4..ccae08b2 100644
--- a/runtime/typedefs.h
+++ b/runtime/typedefs.h
@@ -92,6 +92,8 @@ typedef struct cfgmodules_etry_s cfgmodules_etry_t;
typedef struct outchannels_s outchannels_t;
typedef struct modConfData_s modConfData_t;
typedef struct instanceConf_s instanceConf_t;
+typedef int rs_size_t; /* we do never need more than 2Gig strings, signed permits to
+ * use -1 as a special flag. */
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 */
@@ -154,12 +156,15 @@ typedef enum cslCmdHdlrType {
eCmdHdlrBinary,
eCmdHdlrFileCreateMode,
eCmdHdlrInt,
+ eCmdHdlrNonNegInt,
+ eCmdHdlrPositiveInt,
eCmdHdlrSize,
eCmdHdlrGetChar,
eCmdHdlrFacility,
eCmdHdlrSeverity,
eCmdHdlrGetWord,
eCmdHdlrString,
+ eCmdHdlrArray,
eCmdHdlrQueueType,
eCmdHdlrGoneAway /* statment existed, but is no longer supported */
} ecslCmdHdrlType;
diff --git a/runtime/wti.c b/runtime/wti.c
index 7b88c3eb..f91fb5a9 100644
--- a/runtime/wti.c
+++ b/runtime/wti.c
@@ -121,7 +121,7 @@ wtiWakeupThrd(wti_t *pThis)
if(wtiGetState(pThis)) {
/* we first try the cooperative "cancel" interface */
pthread_kill(pThis->thrdID, SIGTTIN);
- dbgprintf("sent SIGTTIN to worker thread 0x%x\n", (unsigned) pThis->thrdID);
+ DBGPRINTF("sent SIGTTIN to worker thread 0x%x\n", (unsigned) pThis->thrdID);
}
RETiRet;
@@ -148,13 +148,13 @@ wtiCancelThrd(wti_t *pThis)
if(wtiGetState(pThis)) {
/* we first try the cooperative "cancel" interface */
pthread_kill(pThis->thrdID, SIGTTIN);
- dbgprintf("sent SIGTTIN to worker thread 0x%x, giving it a chance to terminate\n", (unsigned) pThis->thrdID);
+ DBGPRINTF("sent SIGTTIN to worker thread 0x%x, giving it a chance to terminate\n", (unsigned) pThis->thrdID);
srSleep(0, 10000);
}
if(wtiGetState(pThis)) {
- dbgprintf("cooperative worker termination failed, using cancellation...\n");
- dbgoprint((obj_t*) pThis, "canceling worker thread\n");
+ DBGPRINTF("cooperative worker termination failed, using cancellation...\n");
+ DBGOPRINT((obj_t*) pThis, "canceling worker thread\n");
pthread_cancel(pThis->thrdID);
/* now wait until the thread terminates... */
while(wtiGetState(pThis)) {
@@ -195,7 +195,7 @@ wtiConstructFinalize(wti_t *pThis)
ISOBJ_TYPE_assert(pThis, wti);
- dbgprintf("%s: finalizing construction of worker instance data\n", wtiGetDbgHdr(pThis));
+ DBGPRINTF("%s: finalizing construction of worker instance data\n", wtiGetDbgHdr(pThis));
/* initialize our thread instance descriptor (no concurrency here) */
pThis->bIsRunning = RSFALSE;
@@ -257,7 +257,7 @@ doIdleProcessing(wti_t *pThis, wtp_t *pWtp, int *pbInactivityTOOccured)
*pbInactivityTOOccured = 1; /* indicate we had a timeout */
}
}
- dbgoprint((obj_t*) pThis, "worker awoke from idle processing\n");
+ DBGOPRINT((obj_t*) pThis, "worker awoke from idle processing\n");
ENDfunc
}
@@ -300,7 +300,7 @@ wtiWorker(wti_t *pThis)
if(terminateRet == RS_RET_TERMINATE_NOW) {
/* we now need to free the old batch */
localRet = pWtp->pfObjProcessed(pWtp->pUsr, pThis);
- dbgoprint((obj_t*) pThis, "terminating worker because of TERMINATE_NOW mode, del iRet %d\n",
+ DBGOPRINT((obj_t*) pThis, "terminating worker because of TERMINATE_NOW mode, del iRet %d\n",
localRet);
d_pthread_mutex_unlock(pWtp->pmutUsr);
break;
@@ -318,7 +318,7 @@ wtiWorker(wti_t *pThis)
} else if(localRet == RS_RET_IDLE) {
if(terminateRet == RS_RET_TERMINATE_WHEN_IDLE || bInactivityTOOccured) {
d_pthread_mutex_unlock(pWtp->pmutUsr);
- dbgoprint((obj_t*) pThis, "terminating worker terminateRet=%d, bInactivityTOOccured=%d\n",
+ DBGOPRINT((obj_t*) pThis, "terminating worker terminateRet=%d, bInactivityTOOccured=%d\n",
terminateRet, bInactivityTOOccured);
break; /* end of loop */
}