summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2005-09-19 15:52:43 +0000
committerRainer Gerhards <rgerhards@adiscon.com>2005-09-19 15:52:43 +0000
commit6c2956163de3be527cc34387ee0bbfdd64a5c4ef (patch)
tree010cfb576af5217ed8138f737c740b2d798769c3
parent3e8ba29e5cf041b9056b7a14f0000a9c1557fed0 (diff)
downloadrsyslog-6c2956163de3be527cc34387ee0bbfdd64a5c4ef.tar.gz
rsyslog-6c2956163de3be527cc34387ee0bbfdd64a5c4ef.tar.xz
rsyslog-6c2956163de3be527cc34387ee0bbfdd64a5c4ef.zip
added capability to filter on any property in selector lines
-rw-r--r--NEWS2
-rw-r--r--master.make2
-rw-r--r--parse.c19
-rw-r--r--parse.h6
-rwxr-xr-xstringbuf.c88
-rwxr-xr-xstringbuf.h2
-rw-r--r--syslogd.c123
7 files changed, 214 insertions, 28 deletions
diff --git a/NEWS b/NEWS
index 9f7f0cb0..38de71fc 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
---------------------------------------------------------------------------
Version 1.10.0 (RGer), 2005-09-??
REMINDER: 1.10 is the first unstable version if the 1.x series!
+- added the capability to filter on any property in selector lines
+ (not just facility and priority)
- changed stringbuf into a new counted string class
- added support for a "discard" action. If a selector line with
discard (~ character) is found, no selector lines *after* that
diff --git a/master.make b/master.make
index f8f2b55f..39530d72 100644
--- a/master.make
+++ b/master.make
@@ -50,7 +50,7 @@ parse.o: parse.c parse.h rsyslog.h
template.o: template.c template.h stringbuf.h rsyslog.h
outchannel.o: outchannel.c outchannel.h stringbuf.h syslogd.h rsyslog.h
-syslogd.o: syslogd.c version.h template.h outchannel.h syslogd.h rsyslog.h
+syslogd.o: syslogd.c version.h parse.h template.h stringbuf.h outchannel.h syslogd.h rsyslog.h
${CC} ${CFLAGS} ${SYSLOGD_FLAGS} -c $(VPATH)syslogd.c
syslog.o: syslog.c
diff --git a/parse.c b/parse.c
index 4fb0a66b..51737278 100644
--- a/parse.c
+++ b/parse.c
@@ -152,11 +152,8 @@ rsRetVal parsDelimCStr(rsParsObj *pThis, rsCStrObj **ppCStr, char cDelim, int bT
pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos;
-printf("after trim leading, len %d - %d, pC: %c, Delim '%c'\n", pThis->iCurrPos, rsCStrLen(pThis->pCStr),
- *pC, cDelim);
while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)
&& *pC != cDelim) {
- printf("parse[%d,%d]: %c\n", pThis->iCurrPos, rsCStrLen(pThis->pCStr), *pC);
if((iRet = rsCStrAppendChar(pCStr, *pC)) != RS_RET_OK) {
RSFREEOBJ(pCStr);
return(iRet);
@@ -221,10 +218,7 @@ rsRetVal parsQuotedCStr(rsParsObj *pThis, rsCStrObj **ppCStr)
if((pCStr = rsCStrConstruct()) == NULL)
return RS_RET_OUT_OF_MEMORY;
-printf("at start of quoted string, len %d - %d, pC: '%c'\n", pThis->iCurrPos, rsCStrLen(pThis->pCStr),
- *pC);
while(pThis->iCurrPos < rsCStrLen(pThis->pCStr)) {
- printf("parse[%d,%d]: '%c'\n", pThis->iCurrPos, rsCStrLen(pThis->pCStr), *pC);
if(*pC == '"') {
break; /* we are done! */
} else if(*pC == '\\') {
@@ -269,6 +263,19 @@ printf("at start of quoted string, len %d - %d, pC: '%c'\n", pThis->iCurrPos, rs
return RS_RET_OK;
}
+/* return the position of the parse pointer
+ */
+int rsParsGetParsePointer(rsParsObj *pThis)
+{
+ rsCHECKVALIDOBJECT(pThis, OIDrsPars);
+
+ if(pThis->iCurrPos < rsCStrLen(pThis->pCStr))
+ return pThis->iCurrPos;
+ else
+ return rsCStrLen(pThis->pCStr) - 1;
+}
+
+
/*
* Local variables:
* c-indent-level: 8
diff --git a/parse.h b/parse.h
index f5207d42..6bbc4afd 100644
--- a/parse.h
+++ b/parse.h
@@ -42,6 +42,12 @@ struct rsParsObject
};
typedef struct rsParsObject rsParsObj;
+
+/* BEGIN "inline"-like functions */
+/* END "inline"-like functions */
+
+int rsParsGetParsePointer(rsParsObj *pThis);
+
/**
* Construct a rsPars object.
*/
diff --git a/stringbuf.c b/stringbuf.c
index ccd2c184..c3e0fee0 100755
--- a/stringbuf.c
+++ b/stringbuf.c
@@ -366,6 +366,94 @@ int rsCStrSzCmp(rsCStrObj *pCStr, char *sz)
}
+/* Locate the first occurence of this rsCStr object inside a standard sz string.
+ * Returns the offset (0-bound) of this first occurrence. If not found, -1 is
+ * returned. Both parameters MUST be given (NULL is not allowed).
+ * rgerhards 2005-09-19
+ */
+int rsCStrLocateInSzStr(rsCStrObj *pThis, char *sz)
+{
+ int i;
+ int iMax;
+ int bFound;
+ rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
+ assert(sz != NULL);
+
+ if(pThis->iStrLen == 0)
+ return 0;
+
+ /* compute the largest index where a match could occur - after all,
+ * the to-be-located string must be able to be present in the
+ * searched string (it needs its size ;)).
+ */
+ iMax = strlen(sz) - pThis->iStrLen;
+
+ bFound = 0;
+ i = 0;
+ while(i <= iMax && !bFound) {
+ int iCheck;
+ char *pComp = sz + i;
+ for(iCheck = 0 ; iCheck < pThis->iStrLen ; ++iCheck)
+ if(*(pComp + iCheck) != *(pThis->pBuf + iCheck))
+ break;
+ if(iCheck == pThis->iStrLen)
+ bFound = 1; /* found! - else it wouldn't be equal */
+ else
+ ++i; /* on to the next try */
+ }
+
+ return(bFound ? i : -1);
+}
+
+
+/* locate the first occurence of a standard sz string inside a rsCStr object.
+ * Returns the offset (0-bound) of this first occurrence. If not found, -1 is
+ * returned.
+ * rgerhards 2005-09-19
+ * WARNING: i accidently created this function (I later noticed I didn't relly
+ * need it... I will not remove the function, as it probably is useful
+ * some time later. However, it is not fully tested, so start with testing
+ * it before you put it to first use).
+ */
+int rsCStrLocateSzStr(rsCStrObj *pThis, char *sz)
+{
+ int iLenSz;
+ int i;
+ int iMax;
+ int bFound;
+ rsCHECKVALIDOBJECT(pThis, OIDrsCStr);
+
+ if(sz == NULL)
+ return 0;
+
+ iLenSz = strlen(sz);
+ if(iLenSz == 0)
+ return 0;
+
+ /* compute the largest index where a match could occur - after all,
+ * the to-be-located string must be able to be present in the
+ * searched string (it needs its size ;)).
+ */
+ iMax = pThis->iStrLen - iLenSz;
+
+ bFound = 0;
+ i = 0;
+ while(i < iMax && !bFound) {
+ int iCheck;
+ char *pComp = pThis->pBuf + i;
+ for(iCheck = 0 ; iCheck < iLenSz ; ++iCheck)
+ if(*(pComp + iCheck) != *(sz + iCheck))
+ break;
+ if(iCheck == iLenSz)
+ bFound = 1; /* found! - else it wouldn't be equal */
+ else
+ ++i; /* on to the next try */
+ }
+
+ return(bFound ? i : -1);
+}
+
+
/*
* Local variables:
* c-indent-level: 8
diff --git a/stringbuf.h b/stringbuf.h
index 80eff56d..053f10c7 100755
--- a/stringbuf.h
+++ b/stringbuf.h
@@ -104,6 +104,8 @@ char* rsCStrGetSzStr(rsCStrObj *pThis);
char* rsCStrConvSzStrAndDestruct(rsCStrObj *pThis);
int rsCStrCStrCmp(rsCStrObj *pCS1, rsCStrObj *pCS2);
int rsCStrSzCmp(rsCStrObj *pCStr, char *sz);
+int rsCStrLocateSzStr(rsCStrObj *pCStr, char *sz);
+int rsCStrLocateInSzStr(rsCStrObj *pThis, char *sz);
/* now come inline-like functions */
#ifdef NDEBUG
diff --git a/syslogd.c b/syslogd.c
index 01ba77ee..1e93e1c4 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -2025,7 +2025,8 @@ int MsgSetRawMsg(struct msg *pMsg, char* pszRawMsg)
* be used in selector line processing.
* rgerhards 2005-09-15
*/
-char *MsgGetProp(struct msg *pMsg, struct templateEntry *pTpe, unsigned short *pbMustBeFreed)
+char *MsgGetProp(struct msg *pMsg, struct templateEntry *pTpe,
+ rsCStrObj *pCSPropName, unsigned short *pbMustBeFreed)
{
char *pName;
char *pRes; /* result pointer */
@@ -2034,12 +2035,17 @@ char *MsgGetProp(struct msg *pMsg, struct templateEntry *pTpe, unsigned short *p
/* Variables necessary for regular expression matching */
size_t nmatch = 2;
regmatch_t pmatch[2];
-#endif
+#endif
assert(pMsg != NULL);
assert(pbMustBeFreed != NULL);
- pName = pTpe->data.field.pPropRepl;
+ if(pCSPropName == NULL) {
+ assert(pTpe != NULL);
+ pName = pTpe->data.field.pPropRepl;
+ } else {
+ pName = rsCStrGetSzStr(pCSPropName);
+ }
*pbMustBeFreed = 0;
/* sometimes there are aliases to the original MonitoWare
@@ -3227,6 +3233,54 @@ void logmsgInternal(pri, msg, from, flags)
}
/*
+ * This functions looks at the given message and checks if it matches the
+ * provided filter condition. If so, it returns true, else it returns
+ * false. This is a helper to logmsg() and meant to drive the decision
+ * process if a message is to be processed or not. As I expect this
+ * decision code to grow more complex over time AND logmsg() is already
+ * a very lengthe function, I thought a separate function is more appropriate.
+ * 2005-09-19 rgerhards
+ */
+int shouldProcessThisMessage(struct filed *f, struct msg *pMsg)
+{
+ unsigned short pbMustBeFreed;
+ char *pszPropVal;
+ int iRet = 0;
+
+ assert(f != NULL);
+ assert(pMsg != NULL);
+
+ if(f->f_filter_type == FILTER_PRI) {
+ /* skip messages that are incorrect priority */
+ if ( (f->f_filterData.f_pmask[pMsg->iFacility] == TABLE_NOPRI) || \
+ ((f->f_filterData.f_pmask[pMsg->iFacility] & (1<<pMsg->iSeverity)) == 0) )
+ iRet = 0;
+ else
+ iRet = 1;
+ } else {
+ assert(f->f_filter_type == FILTER_PROP); /* assert() just in case... */
+ pszPropVal = MsgGetProp(pMsg, NULL,
+ f->f_filterData.prop.pCSPropName, &pbMustBeFreed);
+
+ /* Now do the compares (short list currently ;)) */
+ if(f->f_filterData.prop.operation == FIOP_CONTAINS) {
+ if(rsCStrLocateInSzStr(f->f_filterData.prop.pCSCompValue, pszPropVal) != -1)
+ iRet = 1;
+ } else { /* here, it handles NOP (for performance reasons) */
+ assert(f->f_filterData.prop.operation == FIOP_NOP);
+ iRet = 1; /* as good as any other default ;) */
+ }
+
+ /* cleanup */
+ if(pbMustBeFreed)
+ free(pszPropVal);
+ }
+
+ return(iRet);
+}
+
+
+/*
* Log a message to the appropriate log files, users, etc. based on
* the priority.
* rgerhards 2004-11-08: actually, this also decodes all but the PRI part.
@@ -3246,10 +3300,7 @@ void logmsgInternal(pri, msg, from, flags)
* circumstances given.
*/
-void logmsg(pri, pMsg, flags)
- int pri;
- struct msg *pMsg;
- int flags;
+void logmsg(int pri, struct msg *pMsg, int flags)
{
register struct filed *f;
@@ -3425,11 +3476,12 @@ void logmsg(pri, pMsg, flags)
* won't do that for now, but at least we now know where
* to look at.
* 2005-09-09 rgerhards
+ * ok, we are now ready to move to something more advanced. Because
+ * of this, I am moving the actual decision code to outside this function.
+ * 2005-09-19 rgerhards
*/
- /* skip messages that are incorrect priority */
- if ( (f->f_filterData.f_pmask[fac] == TABLE_NOPRI) || \
- ((f->f_filterData.f_pmask[fac] & (1<<prilev)) == 0) )
- continue;
+ if(!shouldProcessThisMessage(f, pMsg))
+ continue;
/* We now need to check a special case - F_DISCARD. If that
* action is specified in the selector line, no futher processing
@@ -3685,7 +3737,7 @@ void iovCreate(struct filed *f)
++v;
++iIOVused;
} else if(pTpe->eEntryType == FIELD) {
- v->iov_base = MsgGetProp(pMsg, pTpe, f->f_bMustBeFreed + iIOVused);
+ v->iov_base = MsgGetProp(pMsg, pTpe, NULL, f->f_bMustBeFreed + iIOVused);
v->iov_len = strlen(v->iov_base);
/* TODO: performance optimize - can we obtain the length? */
/* we now need to check if we should use SQL option. In this case,
@@ -4749,13 +4801,31 @@ void init()
Initialized = 1;
if ( Debug ) {
+ printf("Active selectors:\n");
for (f = Files; f; f = f->f_next) {
if (f->f_type != F_UNUSED) {
- for (i = 0; i <= LOG_NFACILITIES; i++)
- if (f->f_filterData.f_pmask[i] == TABLE_NOPRI)
- printf(" X ");
+ if(f->f_filter_type == FILTER_PRI) {
+ for (i = 0; i <= LOG_NFACILITIES; i++)
+ if (f->f_filterData.f_pmask[i] == TABLE_NOPRI)
+ printf(" X ");
+ else
+ printf("%2X ", f->f_filterData.f_pmask[i]);
+ } else {
+ printf("PROPERTY-BASED Filter:\n");
+ printf("\tProperty.: '%s'\n",
+ rsCStrGetSzStr(f->f_filterData.prop.pCSPropName));
+ printf("\tOperation: ");
+ if(f->f_filterData.prop.operation == FIOP_NOP)
+ printf("'NOP'");
+ else if(f->f_filterData.prop.operation == FIOP_CONTAINS)
+ printf("'contains'");
else
- printf("%2X ", f->f_filterData.f_pmask[i]);
+ printf("'ERROR - invalid filter type!'");
+ printf("\n");
+ printf("\tValue....: '%s'\n",
+ rsCStrGetSzStr(f->f_filterData.prop.pCSCompValue));
+ printf("\tAction...: ");
+ }
printf("%s: ", TypeNames[f->f_type]);
switch (f->f_type) {
case F_FILE:
@@ -4781,6 +4851,7 @@ void init()
printf("\n");
}
}
+ printf("\n");
tplPrintList();
ochPrintList();
}
@@ -5229,7 +5300,6 @@ rsRetVal cflineProcessPropFilter(char **pline, register struct filed *f)
RSFREEOBJ(pCSLine);
return(iRet);
}
- printf("after read prop, prop name '%s'\n", rsCStrGetSzStr(f->f_filterData.prop.pCSPropName));
/* read operation */
iRet = parsDelimCStr(pPars, &pCSCompOp, ',', 1, 1);
@@ -5239,14 +5309,13 @@ rsRetVal cflineProcessPropFilter(char **pline, register struct filed *f)
RSFREEOBJ(pCSLine);
return(iRet);
}
- printf("after read CompOp, prop name '%s'\n", rsCStrGetSzStr(pCSCompOp));
if(!rsCStrSzCmp(pCSCompOp, "contains")) {
f->f_filterData.prop.operation = FIOP_CONTAINS;
-dprintf("Contains filter!\n");
} else {
logerrorSz("error: invalid compare operation '%s' - ignoring selector",
rsCStrGetSzStr(pCSCompOp));
}
+ RSFREEOBJ(pCSCompOp); /* no longer needed */
/* read compare value */
iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue);
@@ -5259,8 +5328,20 @@ dprintf("Contains filter!\n");
printf("after read CompVal, prop name '%s'\n", rsCStrGetSzStr(f->f_filterData.prop.pCSCompValue));
/* skip to action part */
+ if((iRet = parsSkipWhitespace(pPars)) != RS_RET_OK) {
+ logerrorInt("error %d skipping to action part - ignoring selector", iRet);
+ RSFREEOBJ(pPars);
+ RSFREEOBJ(pCSLine);
+ return(iRet);
+ }
+
+ /* cleanup */
+ *pline = *pline + rsParsGetParsePointer(pPars) + 1;
+ /* we are adding one for the skipped initial ":" */
+
+ RSFREEOBJ(pPars);
+ RSFREEOBJ(pCSLine);
- /**pline = p;*/
return RS_RET_OK;
}
@@ -5569,8 +5650,8 @@ rsRetVal cfline(char *line, register struct filed *f)
else {
initMySQL(f);
}
- break;
#endif /* #ifdef WITH_DB */
+ break;
default:
dprintf ("users: %s\n", p); /* ASP */