From e34ca1e7d952906fd2593850e3be47252211649c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 15 Sep 2005 15:05:11 +0000 Subject: on the way to adding property-based filters - right before changing cfline() --- NEWS | 2 + linux/Makefile | 7 +++ master.make | 2 +- parse.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ parse.h | 87 ++++++++++++++++++++++++++++++++ rsyslog.h | 17 +++++-- stringbuf.c | 62 +++++++++++++++++++---- stringbuf.h | 39 +++++++++------ syslogd.c | 65 +++++++++++++++--------- 9 files changed, 383 insertions(+), 52 deletions(-) create mode 100644 parse.c create mode 100644 parse.h diff --git a/NEWS b/NEWS index 2bc1c2e3..9f7f0cb0 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,8 @@ Version 1.10.0 (RGer), 2005-09-?? previously not be obtained. Thanks to Cristian Testa for pointing this out and even providing a fix. - added display of compile-time options to -v output +- performance improvement for production build - made some checks + to happen only during debug mode --------------------------------------------------------------------------- Version 1.0.0 (RGer), 2005-09-12 - changed install doc to cover daily cron scripts - a trouble source diff --git a/linux/Makefile b/linux/Makefile index 06047ed0..7b1c99e5 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -30,6 +30,9 @@ FEATURE_DB=0 # Enable regular expressions FEATURE_REGEXP=1 +# Enable debug mode (much slower code) +FEATURE_DEBUG=1 + ############################################################# # END OF USER SETTINGS # # -------------------- # @@ -53,6 +56,10 @@ ifeq ($(strip $(FEATURE_REGEXP)), 1) F_REGEXP=-DFEATURE_REGEXP endif +ifeq ($(strip $(FEATURE_DEBUG)), 0) + DBG=-DNDEBUG +endif + # Include MySQL client lib if DB is selected ifdef WITHDB LIBS = -lmysqlclient -L/usr/local/lib/mysql diff --git a/master.make b/master.make index da51843f..6b42d26c 100644 --- a/master.make +++ b/master.make @@ -11,7 +11,7 @@ #LDFLAGS= -g -Wall -fno-omit-frame-pointer #CFLAGS= -DSYSV -g -Wall -fno-omit-frame-pointer -CFLAGS= $(RPM_OPT_FLAGS) -O3 -DSYSV -fomit-frame-pointer -Wall -fno-strength-reduce -I/usr/local/include $(NOLARGEFILE) $(WITHDB) $(F_REGEXP) +CFLAGS= $(RPM_OPT_FLAGS) -O3 -DSYSV -fomit-frame-pointer -Wall -fno-strength-reduce -I/usr/local/include $(NOLARGEFILE) $(WITHDB) $(F_REGEXP) $(DBG) LDFLAGS= -s # There is one report that under an all ELF system there may be a need to diff --git a/parse.c b/parse.c new file mode 100644 index 00000000..bcf0895b --- /dev/null +++ b/parse.c @@ -0,0 +1,154 @@ +/* parsing routines for the counted string class. for generic + * informaton see parse.h. + * + * begun 2005-09-15 rgerhards + * + * Copyright 2005 + * Rainer Gerhards and Adiscon GmbH. All Rights Reserved. + * This code is placed under the GPL. + */ +#include +#include +#include +#include "rsyslog.h" +#include "parse.h" + +/* ################################################################# * + * private members * + * ################################################################# */ + + + +/* ################################################################# * + * public members * + * ################################################################# */ + + +/** + * Construct a rsPars object. + */ +rsRetVal rsParsConstruct(rsParsObj **ppThis) +{ + rsParsObj *pThis; + + assert(ppThis != NULL); + + if((pThis = (rsParsObj*) calloc(1, sizeof(rsParsObj))) == NULL) + return RS_RET_OUT_OF_MEMORY; + + rsSETOBJTYPE(pThis, OIDrsPars); + + *ppThis = pThis; + return RS_RET_OK; +} + +/** + * Assign the to-be-parsed string. + */ +rsRetVal rsParsAssignString(rsParsObj *pThis, rsCStrObj *pCStr) +{ + rsCHECKVALIDOBJECT(pThis, OIDrsPars); + rsCHECKVALIDOBJECT(pCStr, OIDrsCStr); + + pThis->pCStr = pCStr; + pThis->iCurrPos = 0; + + return RS_RET_OK; +} + +/* parse an integer. The parse pointer is advanced */ +rsRetVal parsInt(rsParsObj *pThis, int* pInt) +{ + rsCHECKVALIDOBJECT(pThis, OIDrsPars); + assert(pInt != NULL); + + return RS_RET_OK; +} + +/* Skip whitespace. Often used to trim parsable entries. + * Returns with ParsePointer set to first non-whitespace + * character (or at end of string). + */ +rsRetVal parsSkipWhitespace(rsParsObj *pThis) +{ + register char *pC; + + rsCHECKVALIDOBJECT(pThis, OIDrsPars); + + pC = rsCStrGetBufBeg(pThis->pCStr); + + while(pThis->iCurrPos >= rsCStrLen(pThis->pCStr)) { + if(!isspace(*(pC+pThis->iCurrPos))) + break; + ++pThis->iCurrPos; + } + + return RS_RET_OK; +} + +/* Parse string up to a delimiter. + * + * Input: + * cDelim - the delimiter + * The following two are for whitespace stripping, + * 0 means "no", 1 "yes" + * - bTrimLeading + * - bTrimTrailing + * + * Output: + * ppCStr Pointer to the parsed string - must be freed by caller! + */ +rsRetVal parsDelimCStr(rsParsObj *pThis, rsCStrObj **ppCStr, char cDelim, int bTrimLeading, int bTrimTrailing) +{ + register char *pC; + rsCStrObj *pCStr; + rsRetVal iRet; + + rsCHECKVALIDOBJECT(pThis, OIDrsPars); + + if((pCStr = rsCStrConstruct()) == NULL) + return RS_RET_OUT_OF_MEMORY; + + pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; + + if(bTrimLeading) + parsSkipWhitespace(pThis); + + while(pThis->iCurrPos >= rsCStrLen(pThis->pCStr) + && *pC != cDelim) { + if((iRet = rsCStrAppendChar(pCStr, *pC)) != RS_RET_OK) { + RSFREEOBJ(pCStr); + return(iRet); + } + ++pThis->iCurrPos; + } + + /* We got the string, now take it and see if we need to + * remove anything at its end. + */ + if((iRet = rsCStrFinish(pCStr)) != RS_RET_OK) { + RSFREEOBJ(pCStr); + return(iRet); + } + + if(bTrimTrailing) { + if((iRet = rsCStrTrimTrailingWhiteSpace(pCStr)) + != RS_RET_OK) { + RSFREEOBJ(pCStr); + return iRet; + } + } + + /* done! */ + *ppCStr = pCStr; + return RS_RET_OK; +} + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + * vi:set ai: + */ diff --git a/parse.h b/parse.h new file mode 100644 index 00000000..201c1a64 --- /dev/null +++ b/parse.h @@ -0,0 +1,87 @@ +/* parsing routines for the counted string class. These + * routines provide generic parsing aid as well some fairly + * complex routines targeted toward specific needs. + * + * General information - read this: + * All routines work on a single CStr object, which must be supplied + * during construction. The parse class keeps an internal pointer of + * where the next parse operation is to start (you could also say + * this is where the last parse operation stopped). + * + * Each parse operation carried out by this package starts from the + * parse pointer, parses the caller-requested element (e.g. an + * integer or delemited string) and the update the parse pointer. If + * the caller tries to parse beyond the end of the original string, + * an error is returned. In general, all functions return a parsRet + * error code and all require the parseObj to be the first parameter. + * The to-be-parsed string provided to the parse object MUST NOT be + * freed or modified by the caller during the lifetime of the parse + * object. However, the caller must free it when it is no longer needed. + * Optinally, the parse object can be instructed to do that. All objects + * returned by the parse routines must be freed by the caller. For + * simpler data types (like integers), the caller must provide the + * necessary buffer space. + * + * begun 2005-09-09 rgerhards + */ +#ifndef _PARSE_H_INCLUDED__ +#define _PARSE_H_INCLUDED__ 1 + +#include "stringbuf.h" + +/** + * The parse object + */ +struct rsParsObject +{ +#ifndef NDEBUG + rsObjID OID; /**< object ID */ +#endif + rsCStrObj *pCStr; /**< pointer to the string object we are parsing */ + int iCurrPos; /**< current parsing position (char offset) */ +}; +typedef struct rsParsObject rsParsObj; + +/** + * Construct a rsPars object. + */ +rsRetVal rsParsConstruct(rsParsObj **ppThis); + +/* parse an integer. The parse pointer is advanced */ +rsRetVal parsInt(rsParsObj *pThis, int* pInt); + +/* Skip whitespace. Often used to trim parsable entries. */ +rsRetVal parsSkipWhitespace(rsParsObj *pThis); + +/* Parse string up to a delimiter. + * + * Input: + * cDelim - the delimiter + * The following two are for whitespace stripping, + * 0 means "no", 1 "yes" + * - bTrimLeading + * - bTrimTrailing + * + * Output: + * ppCStr Pointer to the parsed string + */ +rsRetVal parsDelimCStr(rsParsObj *pThis, rsCStrObj **ppCStr, char cDelim, int bTrimLeading, int bTrimTrailing); + +#if 0 /* later! */ +/* Parse a property + * This is a complex parsing routine. It parses an property + * entry suitable for use in the property replacer. It is currently + * just an idea if this should be a parser function. + */ +parsRet parsProp(parseObj *pThis, ?? **pPropEtry); +#endif + +#endif +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + * vi:set ai: + */ diff --git a/rsyslog.h b/rsyslog.h index 85e68d56..95138e79 100644 --- a/rsyslog.h +++ b/rsyslog.h @@ -31,7 +31,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth { RS_RET_OUT_OF_MEMORY = -6, /**< memory allocation failed */ RS_RET_PROVIDED_BUFFER_TOO_SMALL = -50,/**< the caller provided a buffer, but the called function sees the size of this buffer is too small - operation not carried out */ - /* start next error at -3000 */ + RS_TRUNCAT_TOO_LARGE = -3000, /**< truncation operation where too many chars should be truncated */ RS_RET_OK = 0 /**< operation successful */ }; typedef enum rsRetVal_ rsRetVal; /**< friendly type for global return value */ @@ -61,13 +61,22 @@ enum rsObjectID }; typedef enum rsObjectID rsObjID; +/* support to set object types */ +#ifdef NDEBUG +#define rsSETOBJTYPE(pObj, type) +#define rsCHECKVALIDOBJECT(x, type) +#else +#define rsSETOBJTYPE(pObj, type) pObj->OID = type; +#define rsCHECKVALIDOBJECT(x, type) {assert(x != NULL); assert(x->OID == type);} +#endif + /** * This macro should be used to free objects. * It aids in interpreting dumps during debugging. */ -#if DEBUGLEVEL > 0 -#define RSFREEOBJ(x) {(x)->OID = OID_Freed; free(x);} -#else +#ifdef NDEBUG #define RSFREEOBJ(x) free(x) +#else +#define RSFREEOBJ(x) {(x)->OID = OID_Freed; free(x);} #endif #endif diff --git a/stringbuf.c b/stringbuf.c index e75b4698..aa35a6c7 100755 --- a/stringbuf.c +++ b/stringbuf.c @@ -11,6 +11,7 @@ #include #include #include +#include #include "rsyslog.h" #include "stringbuf.h" #include "srUtils.h" @@ -33,7 +34,7 @@ rsCStrObj *rsCStrConstruct(void) if((pThis = (rsCStrObj*) calloc(1, sizeof(rsCStrObj))) == NULL) return NULL; - pThis->OID = OIDrsCStr; + rsSETOBJTYPE(pThis, OIDrsCStr); pThis->pBuf = NULL; pThis->pszBuf = NULL; pThis->iBufSize = 0; @@ -93,7 +94,7 @@ rsRetVal rsCStrAppendStr(rsCStrObj *pThis, char* psz) { rsRetVal iRet; - sbSTRBCHECKVALIDOBJECT(pThis); + rsCHECKVALIDOBJECT(pThis, OIDrsCStr); assert(psz != NULL); while(*psz) @@ -109,7 +110,7 @@ rsRetVal rsCStrAppendInt(rsCStrObj *pThis, int i) rsRetVal iRet; char szBuf[32]; - sbSTRBCHECKVALIDOBJECT(pThis); + rsCHECKVALIDOBJECT(pThis, OIDrsCStr); if((iRet = srUtilItoA(szBuf, sizeof(szBuf), i)) != RS_RET_OK) return iRet; @@ -122,7 +123,7 @@ rsRetVal rsCStrAppendChar(rsCStrObj *pThis, char c) { char* pNewBuf; - sbSTRBCHECKVALIDOBJECT(pThis); + rsCHECKVALIDOBJECT(pThis, OIDrsCStr); if(pThis->iBufPtr >= pThis->iBufSize) { /* need more memory! */ @@ -163,7 +164,7 @@ char* rsCStrConvSzStrAndDestruct(rsCStrObj *pThis) char* pRetBuf; int i; - sbSTRBCHECKVALIDOBJECT(pThis); + rsCHECKVALIDOBJECT(pThis, OIDrsCStr); if(pThis->pszBuf == NULL) { /* we do not yet have a usable sz version - so create it... */ @@ -203,9 +204,9 @@ char* rsCStrConvSzStrAndDestruct(rsCStrObj *pThis) } -void rsCStrFinish(rsCStrObj *pThis) +rsRetVal rsCStrFinish(rsCStrObj *pThis) { - sbSTRBCHECKVALIDOBJECT(pThis); + rsCHECKVALIDOBJECT(pThis, OIDrsCStr); # if STRINGBUF_TRIM_ALLOCSIZE == 1 /* in this mode, we need to trim the string. To do @@ -228,24 +229,67 @@ void rsCStrFinish(rsCStrObj *pThis) /* here, we need to do ... nothing ;) */ # endif + + return RS_RET_OK; } void rsCStrSetAllocIncrement(rsCStrObj *pThis, int iNewIncrement) { - sbSTRBCHECKVALIDOBJECT(pThis); + rsCHECKVALIDOBJECT(pThis, OIDrsCStr); assert(iNewIncrement > 0); pThis->iAllocIncrement = iNewIncrement; } + /* return the length of the current string * 2005-09-09 rgerhards + * Please note: this is only a function in a debug build. + * For release builds, it is a macro defined in stringbuf.h. + * This is due to performance reasons. */ +#ifndef NDEBUG int rsCStrLen(rsCStrObj *pThis) { - sbSTRBCHECKVALIDOBJECT(pThis); + rsCHECKVALIDOBJECT(pThis, OIDrsCStr); return(pThis->iStrLen); } +#endif + +/* Truncate characters from the end of the string. + * rgerhards 2005-09-15 + */ +rsRetVal rsCStrTruncate(rsCStrObj *pThis, int nTrunc) +{ + rsCHECKVALIDOBJECT(pThis, OIDrsCStr); + + if(pThis->iStrLen < nTrunc) + return RS_TRUNCAT_TOO_LARGE; + + pThis->iStrLen -= nTrunc; + + return RS_RET_OK; +} + +/* Trim trailing whitespace from a given string + */ +rsRetVal rsCStrTrimTrailingWhiteSpace(rsCStrObj *pThis) +{ + register int i; + register char *pC; + rsCHECKVALIDOBJECT(pThis, OIDrsCStr); + + i = pThis->iStrLen; + pC = pThis->pBuf + i - 1; + while(i > 0 && !isspace(*pC)) { + --pC; + --i; + } + /* i now is the new string length! */ + pThis->iStrLen = i; + + return RS_RET_OK; +} /* * Local variables: diff --git a/stringbuf.h b/stringbuf.h index a38a0997..1e2f5515 100755 --- a/stringbuf.h +++ b/stringbuf.h @@ -19,14 +19,14 @@ #ifndef _STRINGBUF_H_INCLUDED__ #define _STRINGBUF_H_INCLUDED__ 1 -#define sbSTRBCHECKVALIDOBJECT(x) {assert(x != NULL); assert(x->OID == OIDrsCStr);} - /** * The dynamic string buffer object. */ struct rsCStrObject { +#ifndef NDEBUG rsObjID OID; /**< object ID */ +#endif char *pBuf; /**< pointer to the string buffer, may be NULL if string is empty */ char *pszBuf; /**< pointer to the sz version of the string (after it has been created )*/ int iBufSize; /**< current maximum size of the string buffer */ @@ -57,19 +57,19 @@ void rsCStrDestruct(rsCStrObj *pThis); rsRetVal rsCStrAppendChar(rsCStrObj *pThis, char c); /** - * Finish the string buffer. That means, the string - * is returned to the caller and then the string - * buffer is destroyed. The caller is reponsible for - * freeing the returned string pointer. - * - * After calling this method, the string buffer object - * is destroyed and thus the provided handle (pThis) - * can no longer be used. - * - * \retval pointer to \0 terminated string. May be NULL - * (empty string) and MUST be free()ed by caller. + * Finish the string buffer dynamic allocation. */ -void rsCStrFinish(rsCStrObj *pThis); +rsRetVal rsCStrFinish(rsCStrObj *pThis); + +/** + * Truncate "n" number of characters from the end of the + * string. The buffer remains unchanged, just the + * string length is manipulated. This is for performance + * reasons. + */ +rsRetVal rsCStrTruncate(rsCStrObj *pThis, int nTrunc); + +rsRetVal rsCStrTrimTrailingWhiteSpace(rsCStrObj *pThis); /** * Append a string to the buffer. @@ -102,5 +102,14 @@ rsRetVal rsCStrAppendInt(rsCStrObj *pThis, int i); char* rsCStrConvSzStrAndDestruct(rsCStrObj *pThis); -int rsCStrLen(rsCStrObj *pThis); + +/* now come inline-like functions */ +#ifdef NDEBUG +# define rsCStrLen(x) ((x)->iStrLen) +#else + int rsCStrLen(rsCStrObj *pThis); #endif + +#define rsCStrGetBufBeg(x) ((x)->pBuf) + +#endif /* single include */ diff --git a/syslogd.c b/syslogd.c index 2118ae15..0fca256d 100644 --- a/syslogd.c +++ b/syslogd.c @@ -425,7 +425,22 @@ struct filed { int f_iLastDBErrNo; /* Last db error number. 0 = no error */ #endif time_t f_time; /* time this was last written */ - u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ + /* filter properties */ + enum { + FILTER_PRI = 0, /* traditional PRI based filer */ + FILTER_PROP = 1 /* extended filter, property based */ + } f_filter_type; + union { + u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ + struct { + rsCStrObj pCSPropName; + enum { + FIOP_NOP = 0, /* do not use - No Operation */ + FIOP_CONTAINS = 1, /* contains string? */ + } operation; + rsCStrObj pCSCompValue; /* value to "compare" against */ + } prop; + } f_filterData; union { char f_uname[MAXUNAMES][UNAMESZ+1]; struct { @@ -2328,7 +2343,7 @@ int main(argc, argv) TCPLstnPort = atoi(optarg); break; case 'v': - printf("rsyslogd %s.%s\n", VERSION, PATCHLEVEL); + printf("rsyslogd %s.%s, ", VERSION, PATCHLEVEL); printf("compiled with:\n"); #ifdef FEATURE_REGEXP printf("\tFEATURE_REGEXP\n"); @@ -2339,6 +2354,10 @@ int main(argc, argv) #ifndef NOLARGEFILE printf("\tFEATURE_LARGEFILE\n"); #endif +#ifndef NDEBUG + printf("\tFEATURE_DEBUG (debug build, slow code)\n"); +#endif + printf("\nSee http://www.rsyslog.com for more information.\n"); exit(0); case '?': default: @@ -3404,8 +3423,8 @@ void logmsg(pri, pMsg, flags) * 2005-09-09 rgerhards */ /* skip messages that are incorrect priority */ - if ( (f->f_pmask[fac] == TABLE_NOPRI) || \ - ((f->f_pmask[fac] & (1<f_filterData.f_pmask[fac] == TABLE_NOPRI) || \ + ((f->f_filterData.f_pmask[fac] & (1<f_next) { if (f->f_type != F_UNUSED) { for (i = 0; i <= LOG_NFACILITIES; i++) - if (f->f_pmask[i] == TABLE_NOPRI) + if (f->f_filterData.f_pmask[i] == TABLE_NOPRI) printf(" X "); else - printf("%2X ", f->f_pmask[i]); + printf("%2X ", f->f_filterData.f_pmask[i]); printf("%s: ", TypeNames[f->f_type]); switch (f->f_type) { case F_FILE: @@ -5002,7 +5021,7 @@ void cfline(line, f) * created with calloc()! */ for (i = 0; i <= LOG_NFACILITIES; i++) { - f->f_pmask[i] = TABLE_NOPRI; + f->f_filterData.f_pmask[i] = TABLE_NOPRI; f->f_flags = 0; } @@ -5057,32 +5076,32 @@ void cfline(line, f) for (i = 0; i <= LOG_NFACILITIES; i++) { if ( pri == INTERNAL_NOPRI ) { if ( ignorepri ) - f->f_pmask[i] = TABLE_ALLPRI; + f->f_filterData.f_pmask[i] = TABLE_ALLPRI; else - f->f_pmask[i] = TABLE_NOPRI; + f->f_filterData.f_pmask[i] = TABLE_NOPRI; } else if ( singlpri ) { if ( ignorepri ) - f->f_pmask[i] &= ~(1<f_filterData.f_pmask[i] &= ~(1<f_pmask[i] |= (1<f_filterData.f_pmask[i] |= (1<f_pmask[i] = TABLE_NOPRI; + f->f_filterData.f_pmask[i] = TABLE_NOPRI; else - f->f_pmask[i] = TABLE_ALLPRI; + f->f_filterData.f_pmask[i] = TABLE_ALLPRI; } else { if ( ignorepri ) for (i2= 0; i2 <= pri; ++i2) - f->f_pmask[i] &= ~(1<f_filterData.f_pmask[i] &= ~(1<f_pmask[i] |= (1<f_filterData.f_pmask[i] |= (1<f_pmask[i >> 3] = TABLE_ALLPRI; + f->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI; else - f->f_pmask[i >> 3] = TABLE_NOPRI; + f->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI; } else if ( singlpri ) { if ( ignorepri ) - f->f_pmask[i >> 3] &= ~(1<f_filterData.f_pmask[i >> 3] &= ~(1<f_pmask[i >> 3] |= (1<f_filterData.f_pmask[i >> 3] |= (1<f_pmask[i >> 3] = TABLE_NOPRI; + f->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI; else - f->f_pmask[i >> 3] = TABLE_ALLPRI; + f->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI; } else { if ( ignorepri ) for (i2= 0; i2 <= pri; ++i2) - f->f_pmask[i >> 3] &= ~(1<f_filterData.f_pmask[i >> 3] &= ~(1<f_pmask[i >> 3] |= (1<f_filterData.f_pmask[i >> 3] |= (1<