summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am11
-rw-r--r--configure.ac1
-rw-r--r--modules.c1
-rw-r--r--msg.c69
-rw-r--r--obj-types.h6
-rw-r--r--obj.c22
-rw-r--r--regexp.c100
-rw-r--r--regexp.h42
-rw-r--r--rsyslog.h2
-rwxr-xr-xstringbuf.c44
-rw-r--r--syslogd.c1
-rw-r--r--template.c16
-rw-r--r--template.h7
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
diff --git a/modules.c b/modules.c
index d9c1f983..4a7b2e19 100644
--- a/modules.c
+++ b/modules.c
@@ -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))) {
diff --git a/msg.c b/msg.c
index 8e235919..1076feae 100644
--- a/msg.c
+++ b/msg.c
@@ -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.
diff --git a/obj.c b/obj.c
index 2bbbe4bb..5a144727 100644
--- a/obj.c
+++ b/obj.c
@@ -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 */
diff --git a/rsyslog.h b/rsyslog.h
index de97e1b8..e06ae7d2 100644
--- a/rsyslog.h
+++ b/rsyslog.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
diff --git a/syslogd.c b/syslogd.c
index 09b9bb7b..62c44a96 100644
--- a/syslogd.c
+++ b/syslogd.c
@@ -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"));
diff --git a/template.c b/template.c
index 01f6452c..5d13fd08 100644
--- a/template.c
+++ b/template.c
@@ -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;
diff --git a/template.h b/template.h
index 1179fe06..eb9f3045 100644
--- a/template.h
+++ b/template.h
@@ -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;