From 6c2956163de3be527cc34387ee0bbfdd64a5c4ef Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 Sep 2005 15:52:43 +0000 Subject: added capability to filter on any property in selector lines --- NEWS | 2 + master.make | 2 +- parse.c | 19 +++++++--- parse.h | 6 +++ stringbuf.c | 88 +++++++++++++++++++++++++++++++++++++++++++ stringbuf.h | 2 + syslogd.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++----------- 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 @@ -3226,6 +3232,54 @@ void logmsgInternal(pri, msg, from, flags) MsgDestruct(pMsg); } +/* + * 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<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. @@ -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<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 */ -- cgit