diff options
-rw-r--r-- | Makefile.am | 11 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | modules.c | 1 | ||||
-rw-r--r-- | msg.c | 69 | ||||
-rw-r--r-- | obj-types.h | 6 | ||||
-rw-r--r-- | obj.c | 22 | ||||
-rw-r--r-- | regexp.c | 100 | ||||
-rw-r--r-- | regexp.h | 42 | ||||
-rw-r--r-- | rsyslog.h | 2 | ||||
-rwxr-xr-x | stringbuf.c | 44 | ||||
-rw-r--r-- | syslogd.c | 1 | ||||
-rw-r--r-- | template.c | 16 | ||||
-rw-r--r-- | template.h | 7 |
13 files changed, 271 insertions, 51 deletions
diff --git a/Makefile.am b/Makefile.am index c4fc4b68..1fc48c18 100644 --- a/Makefile.am +++ b/Makefile.am @@ -120,6 +120,17 @@ net_la_LIBADD = endif # +# regular expression support +# +if ENABLE_REGEXP +pkglib_LTLIBRARIES += regexp.la +regexp_la_SOURCES = regexp.c regexp.h +regexp_la_CPPFLAGS = $(pthreads_cflags) +regexp_la_LDFLAGS = -module -avoid-version +regexp_la_LIBADD = +endif + +# # gssapi support # if ENABLE_GSSAPI diff --git a/configure.ac b/configure.ac index c7050772..eece80b9 100644 --- a/configure.ac +++ b/configure.ac @@ -109,6 +109,7 @@ AC_ARG_ENABLE(regexp, esac], [enable_regexp=yes] ) +AM_CONDITIONAL(ENABLE_REGEXP, test x$enable_regexp = xyes) if test "$enable_regexp" = "yes"; then AC_DEFINE(FEATURE_REGEXP, 1, [Regular expressions support enabled.]) fi @@ -486,7 +486,6 @@ Load(uchar *pModName) } free(pModNameDup); - /* complete load path constructed, so ... GO! */ dbgprintf("loading module '%s'\n", szPath); if(!(pModHdlr = dlopen((char *) szPath, RTLD_NOW))) { @@ -42,11 +42,13 @@ #include "msg.h" #include "var.h" #include "datetime.h" +#include "regexp.h" /* static data */ DEFobjStaticHelpers DEFobjCurrIf(var) DEFobjCurrIf(datetime) +DEFobjCurrIf(regexp) static syslogCODE rs_prioritynames[] = { @@ -1765,40 +1767,55 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, if (pTpe->data.field.has_regex != 0) { if (pTpe->data.field.has_regex == 2) /* Could not compile regex before! */ - return - "**NO MATCH** **BAD REGULAR EXPRESSION**"; + return "**NO MATCH** **BAD REGULAR EXPRESSION**"; - dbgprintf("debug: String to match for regex is: %s\n", - pRes); + dbgprintf("debug: String to match for regex is: %s\n", pRes); - if (0 != regexec(&pTpe->data.field.re, pRes, nmatch, - pmatch, 0)) { - /* we got no match! */ - return "**NO MATCH**"; - } else { - /* Match! */ - /* I need to malloc pB */ - int iLenBuf; - char *pB; + if(objUse(regexp, "regexp") == RS_RET_OK) { + if (0 != regexp.regexec(&pTpe->data.field.re, pRes, nmatch, + pmatch, 0)) { + /* we got no match! */ + if (*pbMustBeFreed == 1) { + free(pRes); + *pbMustBeFreed = 0; + } + return "**NO MATCH**"; + } else { + /* Match! */ + /* I need to malloc pB */ + int iLenBuf; + char *pB; + + iLenBuf = pmatch[1].rm_eo - pmatch[1].rm_so; + pB = (char *) malloc((iLenBuf + 1) * sizeof(char)); + + if (pB == NULL) { + if (*pbMustBeFreed == 1) + free(pRes); + *pbMustBeFreed = 0; + return "**OUT OF MEMORY ALLOCATING pBuf**"; + } - iLenBuf = pmatch[1].rm_eo - pmatch[1].rm_so; - pB = (char *) malloc((iLenBuf + 1) * sizeof(char)); + /* Lets copy the matched substring to the buffer */ + memcpy(pB, pRes + pmatch[1].rm_so, iLenBuf); + pB[iLenBuf] = '\0';/* terminate string, did not happen before */ - if (pB == NULL) { if (*pbMustBeFreed == 1) free(pRes); - *pbMustBeFreed = 0; - return "**OUT OF MEMORY ALLOCATING pBuf**"; + pRes = pB; + *pbMustBeFreed = 1; } - - /* Lets copy the matched substring to the buffer */ - memcpy(pB, pRes + pmatch[1].rm_so, iLenBuf); - pB[iLenBuf] = '\0';/* terminate string, did not happen before */ - - if (*pbMustBeFreed == 1) + } else { + /* we could not load regular expression support. This is quite unexpected at + * this stage of processing (after all, the config parser found it), but so + * it is. We return an error in that case. -- rgerhards, 2008-03-07 + */ + dbgprintf("could not get regexp object pointer, so regexp can not be evaluated\n"); + if (*pbMustBeFreed == 1) { free(pRes); - pRes = pB; - *pbMustBeFreed = 1; + *pbMustBeFreed = 0; + } + return "***REGEXP NOT AVAILABLE***"; } } #endif /* #ifdef FEATURE_REGEXP */ diff --git a/obj-types.h b/obj-types.h index b2f89f9e..dda9b364 100644 --- a/obj-types.h +++ b/obj-types.h @@ -65,7 +65,7 @@ typedef enum { /* IDs of base methods supported by all objects - used for jump t */ typedef struct interface_s { int ifVersion; /* must be set to version requested */ - int ifIsLoaded; /* is the interface loaded? (0-no, 1-yes; if no, functions can NOT be called! */ + int ifIsLoaded; /* is the interface loaded? (0-no, 1-yes, 2-load failed; if not 1, functions can NOT be called! */ } interface_t; @@ -351,14 +351,14 @@ finalize_it: \ /* defines data that must always be present at the very begin of the interface structure */ #define ifBEGIN \ int ifVersion; /* must be set to version requested */ \ - objID_t oID; /* our object ID (later dynamically assigned) */ + int ifIsLoaded; /* is the interface loaded? (0-no, 1-yes; if no, functions can NOT be called! */ /* use the following define some place in your static data (suggested right at * the beginning */ #define DEFobjCurrIf(obj) \ - static obj##_if_t obj = { .ifVersion = obj##CURR_IF_VERSION }; + static obj##_if_t obj = { .ifVersion = obj##CURR_IF_VERSION, .ifIsLoaded = 0 }; /* define the prototypes for a class - when we use interfaces, we just have few * functions that actually need to be non-static. @@ -1052,7 +1052,7 @@ RUNLOG_VAR("%p", errmsg.LogError); * rgerhards, 2008-02-29 */ static rsRetVal -UseObj(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *ppIf) +UseObj(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *pIf) { DEFiRet; cstr_t *pStr = NULL; @@ -1061,13 +1061,29 @@ UseObj(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *ppIf) CHKiRet(rsCStrConstructFromszStr(&pStr, pObjName)); iRet = FindObjInfo(pStr, &pObjInfo); - dbgprintf("source file %s requests object '%s'\n", srcFile, pObjName); + dbgprintf("source file %s requests object '%s', ifIsLoaded %d\n", srcFile, pObjName, pIf->ifIsLoaded); + + if(pIf->ifIsLoaded == 1) { + ABORT_FINALIZE(RS_RET_OK); /* we are already set */ + } + if(pIf->ifIsLoaded == 2) { + ABORT_FINALIZE(RS_RET_LOAD_ERROR); /* we had a load error and can not continue */ + } + + /* we must be careful that we do not enter in infinite loop if an error occurs during + * loading a module. ModLoad emits an error message in such cases and that potentially + * can trigger the same code here. So we initially set the module state to "load error" + * and set it to "fully initialized" when the load succeeded. It's a bit hackish, but + * looks like a good solution. -- rgerhards, 2008-03-07 + */ + pIf->ifIsLoaded = 2; if(iRet == RS_RET_NOT_FOUND) { /* in this case, we need to see if we can dynamically load the object */ if(pObjFile == NULL) { FINALIZE; /* no chance, we have lost... */ } else { CHKiRet(module.Load(pObjFile)); + pIf->ifIsLoaded = 1; /* all went well! */ /* NOW, we must find it or we have a problem... */ CHKiRet(FindObjInfo(pStr, &pObjInfo)); } @@ -1075,7 +1091,7 @@ UseObj(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *ppIf) FINALIZE; /* give up */ } - pObjInfo->QueryIF(ppIf); + pObjInfo->QueryIF(pIf); finalize_it: if(pStr != NULL) diff --git a/regexp.c b/regexp.c new file mode 100644 index 00000000..a1a9e1cd --- /dev/null +++ b/regexp.c @@ -0,0 +1,100 @@ +/* The regexp object. + * + * Module begun 2008-03-05 by Rainer Gerhards, based on some code + * from syslogd.c + * + * Copyright 2008 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Rsyslog 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ + +#include "config.h" +#include <regex.h> +#include <assert.h> + +#include "rsyslog.h" +#include "module-template.h" +#include "obj.h" +#include "regexp.h" + +MODULE_TYPE_LIB + +/* static data */ +DEFobjStaticHelpers + + +/* ------------------------------ methods ------------------------------ */ + + + +/* queryInterface function + * rgerhards, 2008-03-05 + */ +BEGINobjQueryInterface(regexp) +CODESTARTobjQueryInterface(regexp) + if(pIf->ifVersion != regexpCURR_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->regcomp = regcomp; + pIf->regexec = regexec; + pIf->regerror = regerror; + pIf->regfree = regfree; +finalize_it: +ENDobjQueryInterface(regexp) + + +/* Initialize the regexp class. Must be called as the very first method + * before anything else is called inside this class. + * rgerhards, 2008-02-19 + */ +BEGINAbstractObjClassInit(regexp, 1, OBJ_IS_LOADABLE_MODULE) /* class, version */ + /* request objects we use */ + + /* set our own handlers */ +ENDObjClassInit(regexp) + + +/* --------------- here now comes the plumbing that makes as a library module --------------- */ + + +BEGINmodExit +CODESTARTmodExit +ENDmodExit + + +BEGINqueryEtryPt +CODESTARTqueryEtryPt +CODEqueryEtryPt_STD_LIB_QUERIES +ENDqueryEtryPt + + +BEGINmodInit() +CODESTARTmodInit + *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ + + CHKiRet(regexpClassInit()); /* must be done after tcps_sess, as we use it */ + /* Initialize all classes that are in our module - this includes ourselfs */ +ENDmodInit +/* vi:set ai: + */ diff --git a/regexp.h b/regexp.h new file mode 100644 index 00000000..2ff00ae7 --- /dev/null +++ b/regexp.h @@ -0,0 +1,42 @@ +/* The regexp object. It encapsulates the C regexp functionality. The primary + * purpose of this wrapper class is to enable rsyslogd core to be build without + * regexp libraries. + * + * Copyright 2008 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Rsyslog 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see <http://www.gnu.org/licenses/>. + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#ifndef INCLUDED_REGEXP_H +#define INCLUDED_REGEXP_H + +#include <regex.h> + +/* interfaces */ +BEGINinterface(regexp) /* name must also be changed in ENDinterface macro! */ + int (*regcomp)(regex_t *preg, const char *regex, int cflags); + int (*regexec)(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags); + size_t (*regerror)(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size); + void (*regfree)(regex_t *preg); +ENDinterface(regexp) +#define regexpCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ + + +/* prototypes */ +PROTOTYPEObj(regexp); + +#endif /* #ifndef INCLUDED_REGEXP_H */ @@ -80,6 +80,8 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_INVALID_CORE_INTERFACE = -1002,/**< interface provided by host invalid, can not be used */ RS_RET_ENTRY_POINT_NOT_FOUND = -1003,/**< a requested entry point was not found */ RS_RET_MODULE_ENTRY_POINT_NOT_FOUND = -1004,/**< a entry point requested from a module was not present in it */ + RS_RET_OBJ_NOT_AVAILABLE = -1005,/**< something could not be completed because the required object is not available*/ + RS_RET_LOAD_ERROR = -1006,/**< we had an error loading the object/interface and can not continue */ /* return states for config file processing */ RS_RET_NONE = -2000, /**< some value is not available - not necessarily an error */ RS_RET_CONFLINE_UNPROCESSED = -2001,/**< config line was not processed, pass to other module */ diff --git a/stringbuf.c b/stringbuf.c index b95892ad..d5b77d99 100755 --- a/stringbuf.c +++ b/stringbuf.c @@ -33,17 +33,20 @@ #include <string.h> #include <ctype.h> #include <sys/types.h> -#include <regex.h> #include "rsyslog.h" #include "stringbuf.h" #include "srUtils.h" +#include "regexp.h" +#include "obj.h" /* ################################################################# * * private members * * ################################################################# */ - +/* static data */ +DEFobjCurrIf(obj) +DEFobjCurrIf(regexp) /* ################################################################# * * public members * @@ -696,18 +699,29 @@ int rsCStrCaseInsensitveStartsWithSzStr(cstr_t *pCS1, uchar *psz, size_t iLenSz) * bug: doesn't work for CStr containing \0 * rgerhards, 2007-07-16: bug is no real bug, because rsyslogd ensures there * never is a \0 *inside* a property string. + * Note that the function returns -1 if regexp functionality is not available. + * TODO: change calling interface! -- rgerhards, 2008-03-07 */ int rsCStrSzStrMatchRegex(cstr_t *pCS1, uchar *psz) { - regex_t preq; - BEGINfunc - regcomp(&preq, (char*) rsCStrGetSzStr(pCS1), 0); - int ret = regexec(&preq, (char*) psz, 0, NULL, 0); - regfree(&preq); - ENDfunc - return ret; + regex_t preq; + int ret; + + BEGINfunc + + if(objUse(regexp, "regexp") == RS_RET_OK) { + regexp.regcomp(&preq, (char*) rsCStrGetSzStr(pCS1), 0); + ret = regexp.regexec(&preq, (char*) psz, 0, NULL, 0); + regexp.regfree(&preq); + } else { + ret = 1; /* simulate "not found" */ + } + + ENDfunc + return ret; } + /* compare a rsCStr object with a classical sz string. This function * is almost identical to rsCStrZsStrCmp(), but it also takes an offset * to the CStr object from where the comparison is to start. @@ -1032,6 +1046,18 @@ int rsCStrLocateSzStr(cstr_t *pThis, uchar *sz) #endif /* end comment out */ +/* our init function. TODO: remove once converted to a class + */ +rsRetVal strInit() +{ + DEFiRet; + CHKiRet(objGetObjInterface(&obj)); + +finalize_it: + RETiRet; +} + + /* * Local variables: * c-indent-level: 8 @@ -2907,6 +2907,7 @@ static rsRetVal InitGlobalClasses(void) /* dummy "classes" */ CHKiRet(actionClassInit()); CHKiRet(templateInit()); + CHKiRet(strInit()); /* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */ CHKiRet(objUse(net, "net")); @@ -40,6 +40,7 @@ /* static data */ DEFobjCurrIf(obj) DEFobjCurrIf(errmsg) +DEFobjCurrIf(regexp) static struct template *tplRoot = NULL; /* the root of the template list */ static struct template *tplLast = NULL; /* points to the last element of the template list */ @@ -482,6 +483,7 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) cstr_t *pStrB; struct templateEntry *pTpe; int iNum; /* to compute numbers */ + rsRetVal iRetLocal; #ifdef FEATURE_REGEXP /* APR: variables for regex */ @@ -625,8 +627,17 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) /* Now i compile the regex */ /* Remember that the re is an attribute of the Template entry */ - if(regcomp(&(pTpe->data.field.re), (char*) regex_char, 0) != 0) { - dbgprintf("error: can not compile regex: '%s'\n", regex_char); + if((iRetLocal = objUse(regexp, "regexp")) == RS_RET_OK) { + if(regexp.regcomp(&(pTpe->data.field.re), (char*) regex_char, 0) != 0) { + dbgprintf("error: can not compile regex: '%s'\n", regex_char); + pTpe->data.field.has_regex = 2; + } + } else { + /* regexp object could not be loaded */ + dbgprintf("error %d trying to load regexp library - this may be desired and thus OK", + iRetLocal); + errmsg.LogError(NO_ERRCODE, "regexp libraray could not be loaded (error %d), regexp" + "ignored", iRetLocal); pTpe->data.field.has_regex = 2; } @@ -664,7 +675,6 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) #endif /* #ifdef FEATURE_REGEXP */ } - /* TODO: add more sanity checks. For now, we do the bare minimum */ if((pTpe->data.field.has_fields == 0) && (pTpe->data.field.iToPos < pTpe->data.field.iFromPos)) { iNum = pTpe->data.field.iToPos; pTpe->data.field.iToPos = pTpe->data.field.iFromPos; @@ -25,14 +25,9 @@ #ifndef TEMPLATE_H_INCLUDED #define TEMPLATE_H_INCLUDED 1 - +#include "regexp.h" #include "stringbuf.h" -#ifdef FEATURE_REGEXP -/* Include regular expressions */ -#include <regex.h> -#endif - struct template { struct template *pNext; char *pszName; |