summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--action.c1
-rw-r--r--doc/rsyslog_conf_filter.html7
-rw-r--r--parse.c7
-rw-r--r--plugins/mmnormalize/mmnormalize.c6
-rw-r--r--runtime/conf.c27
-rw-r--r--runtime/msg.c17
-rw-r--r--runtime/msg.h3
-rw-r--r--runtime/rule.c53
-rw-r--r--runtime/rule.h2
-rw-r--r--runtime/typedefs.h3
-rw-r--r--template.c6
11 files changed, 99 insertions, 33 deletions
diff --git a/action.c b/action.c
index 8ad72975..74b4456b 100644
--- a/action.c
+++ b/action.c
@@ -775,7 +775,6 @@ finalize_it:
*/
switch(pThis->eParamPassing) {
case ACT_STRING_PASSING:
- /* nothing to do in that case */
break;
case ACT_ARRAY_PASSING:
cleanupDoActionParams(pThis, actParams); /* iRet ignored! */
diff --git a/doc/rsyslog_conf_filter.html b/doc/rsyslog_conf_filter.html
index 63c29817..27f4a8a6 100644
--- a/doc/rsyslog_conf_filter.html
+++ b/doc/rsyslog_conf_filter.html
@@ -117,6 +117,13 @@ currently supported:</p>
the property. There must be an exact match, wildcards are not supported.</td>
</tr>
<tr>
+<td>isempty</td>
+<td>Checks if the property is empty. The value is discarded. This is
+especially useful when working with normalized data, where some fields
+may be populated based on normalization result.
+Available since 6.6.2.
+</tr>
+<tr>
<td>isequal</td>
<td>Compares the "value" string provided and the property
contents. These two values must be exactly equal to match. The
diff --git a/parse.c b/parse.c
index e335d423..a156b317 100644
--- a/parse.c
+++ b/parse.c
@@ -231,7 +231,8 @@ rsRetVal parsSkipWhitespace(rsParsObj *pThis)
/* Parse string up to a delimiter.
*
* Input:
- * cDelim - the delimiter
+ * cDelim - the delimiter. Note that SP within a value always is a delimiter,
+ * so cDelim is actually an *additional* delimiter.
* The following two are for whitespace stripping,
* 0 means "no", 1 "yes"
* - bTrimLeading
@@ -256,13 +257,13 @@ rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrim
pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
- while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && *pC != cDelim) {
+ while(pThis->iCurrPos < rsCStrLen(pThis->pCStr) && *pC != cDelim && *pC != ' ') {
CHKiRet(cstrAppendChar(pCStr, bConvLower ? tolower(*pC) : *pC));
++pThis->iCurrPos;
++pC;
}
- if(*pC == cDelim) {
+ if(pThis->iCurrPos < cstrLen(pThis->pCStr)) { //BUGFIX!!
++pThis->iCurrPos; /* eat delimiter */
}
diff --git a/plugins/mmnormalize/mmnormalize.c b/plugins/mmnormalize/mmnormalize.c
index d9d64687..8c4efd81 100644
--- a/plugins/mmnormalize/mmnormalize.c
+++ b/plugins/mmnormalize/mmnormalize.c
@@ -126,18 +126,17 @@ CODESTARTdoAction
if(r != 0) {
DBGPRINTF("error %d during ln_normalize\n", r);
}
+ es_deleteStr(str);
/***DEBUG***/ // TODO: remove after initial testing - 2010-12-01
{
- dbgprintf("mmnormalize: event ptr now is %p\n", pMsg->event);
char *cstr;
- es_emptyStr(str);
ee_fmtEventToJSON(pMsg->event, &str);
cstr = es_str2cstr(str, NULL);
dbgprintf("mmnormalize generated: %s\n", cstr);
free(cstr);
+ es_deleteStr(str);
}
/***END DEBUG***/
- es_deleteStr(str);
ENDdoAction
@@ -192,6 +191,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1)
/* all config vars auto-reset! */
cs.bUseRawMsg = 0;
+ free(cs.sampdb);
cs.sampdb = NULL;
CODE_STD_FINALIZERparseSelectorAct
ENDparseSelectorAct
diff --git a/runtime/conf.c b/runtime/conf.c
index 1f0badcb..e12cf82b 100644
--- a/runtime/conf.c
+++ b/runtime/conf.c
@@ -874,6 +874,14 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
rsParsDestruct(pPars);
return(iRet);
}
+ if(f->f_filterData.prop.propID == PROP_CEE) {
+ /* in CEE case, we need to preserve the actual property name */
+ if((f->f_filterData.prop.propName =
+ es_newStrFromBuf((char*)cstrGetSzStrNoNULL(pCSPropName)+2, cstrLen(pCSPropName)-2)) == NULL) {
+ cstrDestruct(&pCSPropName);
+ return(RS_RET_ERR);
+ }
+ }
cstrDestruct(&pCSPropName);
/* read operation */
@@ -902,10 +910,13 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
iOffset = 0;
}
+dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSCompOp));
if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) {
f->f_filterData.prop.operation = FIOP_CONTAINS;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) {
f->f_filterData.prop.operation = FIOP_ISEQUAL;
+ } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isempty", 7)) {
+ f->f_filterData.prop.operation = FIOP_ISEMPTY;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "startswith", 10)) {
f->f_filterData.prop.operation = FIOP_STARTSWITH;
} else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) {
@@ -918,12 +929,15 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f)
}
rsCStrDestruct(&pCSCompOp); /* no longer needed */
- /* read compare value */
- iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue);
- if(iRet != RS_RET_OK) {
- errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet);
- rsParsDestruct(pPars);
- return(iRet);
+dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation);
+ if(f->f_filterData.prop.operation != FIOP_ISEMPTY) {
+ /* read compare value */
+ iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue);
+ if(iRet != RS_RET_OK) {
+ errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet);
+ rsParsDestruct(pPars);
+ return(iRet);
+ }
}
/* skip to action part */
@@ -1065,7 +1079,6 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f)
* and, if so, we copy them over. rgerhards, 2005-10-18
*/
if(pDfltProgNameCmp != NULL) {
-RUNLOG_STR("dflt ProgNameCmp != NULL, setting opCSProgNameComp");
CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp));
}
diff --git a/runtime/msg.c b/runtime/msg.c
index 7299b5bf..cca9d5f6 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -530,6 +530,10 @@ uchar *propIDToName(propid_t propID)
return UCHAR_CONSTANT("$MINUTE");
case PROP_SYS_MYHOSTNAME:
return UCHAR_CONSTANT("$MYHOSTNAME");
+ case PROP_CEE:
+ return UCHAR_CONSTANT("*CEE-based property*");
+ case PROP_CEE_ALL_JSON:
+ return UCHAR_CONSTANT("$!all-json");
default:
return UCHAR_CONSTANT("*invalid property id*");
}
@@ -2233,7 +2237,7 @@ static uchar *getNOW(eNOWType eNow)
* function here, as the context seems good enough. -- rgerhards, 2010-12-01
*/
static inline void
-getCEEPropVal(msg_t *pMsg, struct templateEntry *pTpe, uchar **pRes, unsigned short *pbMustBeFreed)
+getCEEPropVal(msg_t *pMsg, es_str_t *propName, uchar **pRes, int *buflen, unsigned short *pbMustBeFreed)
{
struct ee_field *field;
es_str_t *str;
@@ -2243,7 +2247,7 @@ getCEEPropVal(msg_t *pMsg, struct templateEntry *pTpe, uchar **pRes, unsigned sh
*pRes = NULL;
if(pMsg->event == NULL) goto finalize_it;
- if((field = ee_getEventField(pMsg->event, pTpe->data.field.propName)) == NULL)
+ if((field = ee_getEventField(pMsg->event, propName)) == NULL)
goto finalize_it;
/* right now, we always extract data from the first field value. A reason for this
* is that as of now (2010-12-01) liblognorm never populates more than one ;)
@@ -2251,6 +2255,7 @@ getCEEPropVal(msg_t *pMsg, struct templateEntry *pTpe, uchar **pRes, unsigned sh
if((str = ee_getFieldValueAsStr(field, 0)) == NULL) goto finalize_it;
*pRes = (unsigned char*) es_str2cstr(str, "#000");
es_deleteStr(str);
+ *buflen = (int) ustrlen(*pRes);
*pbMustBeFreed = 1;
finalize_it:
@@ -2303,7 +2308,7 @@ 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, size_t *pPropLen,
+ propid_t propid, es_str_t *propName, size_t *pPropLen,
unsigned short *pbMustBeFreed)
{
uchar *pRes; /* result pointer */
@@ -2460,14 +2465,13 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
pRes = glbl.GetLocalHostName();
break;
case PROP_CEE_ALL_JSON:
- str = es_newStr(512);
ee_fmtEventToJSON(pMsg->event, &str);
pRes = (uchar*) es_str2cstr(str, "#000");
es_deleteStr(str);
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
break;
case PROP_CEE:
- getCEEPropVal(pMsg, pTpe, &pRes, pbMustBeFreed);
+ getCEEPropVal(pMsg, propName, &pRes, &bufLen, pbMustBeFreed);
break;
default:
/* there is no point in continuing, we may even otherwise render the
@@ -2481,6 +2485,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
/* If we did not receive a template pointer, we are already done... */
if(pTpe == NULL) {
+ *pPropLen = (bufLen == -1) ? ustrlen(pRes) : bufLen;
return pRes;
}
@@ -3096,7 +3101,7 @@ msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar)
/* always call MsgGetProp() without a template specifier */
/* TODO: optimize propNameToID() call -- rgerhards, 2009-06-26 */
propNameToID(pstrPropName, &propid);
- pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, &propLen, &bMustBeFreed);
+ pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, NULL, &propLen, &bMustBeFreed);
/* now create a string object out of it and hand that over to the var */
CHKiRet(rsCStrConstructFromszStr(&pstrProp, pszProp));
diff --git a/runtime/msg.h b/runtime/msg.h
index 6a680da6..9d9df8d0 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -164,7 +164,8 @@ void MsgSetRawMsgWOSize(msg_t *pMsg, char* pszRawMsg);
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, size_t *pPropLen, unsigned short *pbMustBeFreed);
+ propid_t propid, es_str_t *propName,
+ 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);
rsRetVal MsgEnableThreadSafety(void);
diff --git a/runtime/rule.c b/runtime/rule.c
index 42773768..fc1ee17c 100644
--- a/runtime/rule.c
+++ b/runtime/rule.c
@@ -70,6 +70,12 @@ getFIOPName(unsigned iFIOP)
case FIOP_REGEX:
pRet = "regex";
break;
+ case FIOP_EREREGEX:
+ pRet = "ereregex";
+ break;
+ case FIOP_ISEMPTY:
+ pRet = "isempty";
+ break;
default:
pRet = "NOP";
break;
@@ -190,7 +196,8 @@ dbgprintf("testing filter, f_pmask %d\n", pRule->f_filterData.f_pmask[pMsg->iFac
bRet = (pResult->val.num) ? 1 : 0;
} else {
assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */
- pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID, &propLen, &pbMustBeFreed);
+ 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 ) {
@@ -198,6 +205,10 @@ dbgprintf("testing filter, f_pmask %d\n", pRule->f_filterData.f_pmask[pMsg->iFac
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)
@@ -230,14 +241,28 @@ dbgprintf("testing filter, f_pmask %d\n", pRule->f_filterData.f_pmask[pMsg->iFac
bRet = (bRet == 1) ? 0 : 1;
if(Debug) {
- dbgprintf("Filter: check for property '%s' (value '%s') ",
- propIDToName(pRule->f_filterData.prop.propID), pszPropVal);
+ 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 ");
- dbgprintf("%s '%s': %s\n",
- getFIOPName(pRule->f_filterData.prop.operation),
- rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSCompValue),
- bRet ? "TRUE" : "FALSE");
+ 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 */
@@ -324,6 +349,8 @@ CODESTARTobjDestruct(rule)
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);
} else if(pThis->f_filter_type == FILTER_EXPR) {
if(pThis->f_filterData.f_expr != NULL)
expr.Destruct(&pThis->f_filterData.f_expr);
@@ -368,6 +395,7 @@ DEFFUNC_llExecFunc(dbgPrintInitInfoAction)
/* 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)
@@ -388,12 +416,19 @@ CODESTARTobjDebugPrint(rule)
} else {
dbgprintf("PROPERTY-BASED Filter:\n");
dbgprintf("\tProperty.: '%s'\n", propIDToName(pThis->f_filterData.prop.propID));
+ 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));
+ if(pThis->f_filterData.prop.pCSCompValue != NULL) {
+ dbgprintf("\tValue....: '%s'\n",
+ rsCStrGetSzStrNoNULL(pThis->f_filterData.prop.pCSCompValue));
+ }
dbgprintf("\tAction...: ");
}
diff --git a/runtime/rule.h b/runtime/rule.h
index 309a2ed8..3b34e11a 100644
--- a/runtime/rule.h
+++ b/runtime/rule.h
@@ -25,6 +25,7 @@
#ifndef INCLUDED_RULE_H
#define INCLUDED_RULE_H
+#include "libestr.h"
#include "linkedlist.h"
#include "regexp.h"
#include "expr.h"
@@ -49,6 +50,7 @@ struct rule_s {
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;
expr_t *f_expr; /* expression object */
} f_filterData;
diff --git a/runtime/typedefs.h b/runtime/typedefs.h
index 38bc02d5..1f624f7a 100644
--- a/runtime/typedefs.h
+++ b/runtime/typedefs.h
@@ -127,7 +127,8 @@ typedef enum {
FIOP_ISEQUAL = 2, /* is (exactly) equal? */
FIOP_STARTSWITH = 3, /* starts with a string? */
FIOP_REGEX = 4, /* matches a (BRE) regular expression? */
- FIOP_EREREGEX = 5 /* matches a ERE regular expression? */
+ FIOP_EREREGEX = 5, /* matches a ERE regular expression? */
+ FIOP_ISEMPTY = 6 /* string empty <=> strlen(s) == 0 ?*/
} fiop_t;
/* types of configuration handlers
diff --git a/template.c b/template.c
index 4a15966b..1ea2575a 100644
--- a/template.c
+++ b/template.c
@@ -113,7 +113,8 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar **ppBuf, size_t *
iLenVal = pTpe->data.constant.iLenConstant;
bMustBeFreed = 0;
} else if(pTpe->eEntryType == FIELD) {
- pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, &iLenVal, &bMustBeFreed);
+ pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid,
+ pTpe->data.field.propName, &iLenVal, &bMustBeFreed);
/* we now need to check if we should use SQL option. In this case,
* we must go over the generated string and escape '\'' characters.
* rgerhards, 2005-09-22: the option values below look somewhat misplaced,
@@ -192,7 +193,8 @@ rsRetVal tplToArray(struct template *pTpl, msg_t *pMsg, uchar*** ppArr)
if(pTpe->eEntryType == CONSTANT) {
CHKmalloc(pArr[iArr] = (uchar*)strdup((char*) pTpe->data.constant.pConstant));
} else if(pTpe->eEntryType == FIELD) {
- pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, &propLen, &bMustBeFreed);
+ pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid,
+ pTpe->data.field.propName, &propLen, &bMustBeFreed);
if(bMustBeFreed) { /* if it must be freed, it is our own private copy... */
pArr[iArr] = pVal; /* ... so we can use it! */
} else {