summaryrefslogtreecommitdiffstats
path: root/runtime
diff options
context:
space:
mode:
authorRainer Gerhards <rgerhards@adiscon.com>2008-11-11 12:54:44 +0100
committerRainer Gerhards <rgerhards@adiscon.com>2008-11-11 12:54:44 +0100
commit05bd696ebb7766f33b3ae176b841bcecb0bfedfc (patch)
tree99437759863ee4b25174f49aa69807c207176a76 /runtime
parent9048c16d90177a0dfa4131266ae73f029a5923c8 (diff)
parentba201a941435bc5fec2c333155e1a8e16c4a9c05 (diff)
downloadrsyslog-05bd696ebb7766f33b3ae176b841bcecb0bfedfc.tar.gz
rsyslog-05bd696ebb7766f33b3ae176b841bcecb0bfedfc.tar.xz
rsyslog-05bd696ebb7766f33b3ae176b841bcecb0bfedfc.zip
Merge branch 'master' into beta
Conflicts: ChangeLog configure.ac doc/manual.html
Diffstat (limited to 'runtime')
-rw-r--r--runtime/Makefile.am4
-rw-r--r--runtime/atomic.h23
-rw-r--r--runtime/conf.c58
-rw-r--r--runtime/conf.h4
-rw-r--r--runtime/datetime.c268
-rw-r--r--runtime/datetime.h4
-rw-r--r--runtime/debug.c233
-rw-r--r--runtime/debug.h3
-rw-r--r--runtime/glbl.c3
-rw-r--r--runtime/glbl.h1
-rw-r--r--runtime/modules.c108
-rw-r--r--runtime/msg.c65
-rw-r--r--runtime/msg.h5
-rw-r--r--runtime/net.c1
-rw-r--r--runtime/obj.c2
-rw-r--r--runtime/queue.c20
-rw-r--r--runtime/rsyslog.h8
-rw-r--r--runtime/var.c40
-rw-r--r--runtime/var.h1
-rw-r--r--runtime/vmop.c37
-rw-r--r--runtime/vmop.h2
-rw-r--r--runtime/vmprg.c39
-rw-r--r--runtime/vmprg.h3
-rw-r--r--runtime/wti.c9
-rw-r--r--runtime/wti.h1
-rw-r--r--runtime/wtp.c7
26 files changed, 622 insertions, 327 deletions
diff --git a/runtime/Makefile.am b/runtime/Makefile.am
index 81a9d5bd..8dd8ad12 100644
--- a/runtime/Makefile.am
+++ b/runtime/Makefile.am
@@ -83,7 +83,11 @@ librsyslog_la_SOURCES = \
# the files with ../ we need to work on - so that they either become part of the
# runtime or will no longer be needed. -- rgerhards, 2008-06-13
+if WITH_MODDIRS
+librsyslog_la_CPPFLAGS = -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(pthreads_cflags)
+else
librsyslog_la_CPPFLAGS = -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(pthreads_cflags)
+endif
#librsyslog_la_LDFLAGS = -module -avoid-version
librsyslog_la_LIBADD = $(dl_libs) $(rt_libs)
diff --git a/runtime/atomic.h b/runtime/atomic.h
index 430ae7f0..2dbe7f52 100644
--- a/runtime/atomic.h
+++ b/runtime/atomic.h
@@ -1,6 +1,6 @@
/* This header supplies atomic operations. So far, we rely on GCC's
- * atomic builtins. I have no idea if we can check them via autotools,
- * but I am making the necessary provisioning to live without them if
+ * atomic builtins. During configure, we check if atomic operatons are
+ * available. If they are not, I am making the necessary provisioning to live without them if
* they are not available. Please note that you should only use the macros
* here if you think you can actually live WITHOUT an explicit atomic operation,
* because in the non-presence of them, we simply do it without atomicitiy.
@@ -36,16 +36,21 @@
#ifndef INCLUDED_ATOMIC_H
#define INCLUDED_ATOMIC_H
-/* set the following to 1 if we have atomic operations (and #undef it otherwise) */
-/* #define DO_HAVE_ATOMICS 1 */
/* for this release, we disable atomic calls because there seem to be some
* portability problems and we can not fix that without destabilizing the build.
* They simply came in too late. -- rgerhards, 2008-04-02
*/
-/* make sure they are not used!
-#define ATOMIC_INC(data) ((void) __sync_fetch_and_add(&data, 1))
-#define ATOMIC_DEC_AND_FETCH(data) __sync_sub_and_fetch(&data, 1)
-*/
-#define ATOMIC_INC(data) (++(data))
+#ifdef HAVE_ATOMIC_BUILTINS
+# define ATOMIC_INC(data) ((void) __sync_fetch_and_add(&(data), 1))
+# define ATOMIC_DEC_AND_FETCH(data) __sync_sub_and_fetch(&(data), 1)
+# define ATOMIC_FETCH_32BIT(data) ((unsigned) __sync_fetch_and_and(&(data), 0xffffffff))
+# define ATOMIC_STORE_1_TO_32BIT(data) __sync_lock_test_and_set(&(data), 1)
+#else
+# warning "atomic builtins not available, using nul operations"
+# define ATOMIC_INC(data) (++(data))
+# define ATOMIC_DEC_AND_FETCH(data) (--(data))
+# define ATOMIC_FETCH_32BIT(data) (data)
+# define ATOMIC_STORE_1_TO_32BIT(data) (data) = 1
+#endif
#endif /* #ifndef INCLUDED_ATOMIC_H */
diff --git a/runtime/conf.c b/runtime/conf.c
index 75276a00..f71d5669 100644
--- a/runtime/conf.c
+++ b/runtime/conf.c
@@ -83,6 +83,8 @@ DEFobjCurrIf(module)
DEFobjCurrIf(errmsg)
DEFobjCurrIf(net)
+static int iNbrActions; /* number of actions the running config has. Needs to be init on ReInitConf() */
+
/* The following global variables are used for building
* tag and host selector lines during startup and config reload.
* This is stored as a global variable pool because of its ease. It is
@@ -188,6 +190,7 @@ doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal)
char pattern[MAXFNAME];
uchar *cfgFile;
glob_t cfgFiles;
+ int result;
size_t i = 0;
struct stat fileInfo;
@@ -195,14 +198,21 @@ doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal)
ASSERT(*pp != NULL);
if(getSubString(pp, (char*) pattern, sizeof(pattern) / sizeof(char), ' ') != 0) {
- errmsg.LogError(0, RS_RET_NOT_FOUND, "could not extract group name");
+ errmsg.LogError(0, RS_RET_NOT_FOUND, "could not parse config file name");
ABORT_FINALIZE(RS_RET_NOT_FOUND);
}
/* Use GLOB_MARK to append a trailing slash for directories.
* Required by doIncludeDirectory().
*/
- glob(pattern, GLOB_MARK, NULL, &cfgFiles);
+ result = glob(pattern, GLOB_MARK, NULL, &cfgFiles);
+ if(result != 0) {
+ char errStr[1024];
+ rs_strerror_r(errno, errStr, sizeof(errStr));
+ errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s",
+ pattern, errStr);
+ ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND);
+ }
for(i = 0; i < cfgFiles.gl_pathc; i++) {
cfgFile = (uchar*) cfgFiles.gl_pathv[i];
@@ -560,8 +570,7 @@ cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int
}
-/*
- * Helper to cfline(). This function takes the filter part of a traditional, PRI
+/* Helper to cfline(). This function takes the filter part of a traditional, PRI
* based line and decodes the PRIs given in the selector line. It processed the
* line up to the beginning of the action part. A pointer to that beginnig is
* passed back to the caller.
@@ -577,8 +586,9 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
int pri;
int singlpri = 0;
int ignorepri = 0;
- uchar buf[MAXLINE];
+ uchar buf[2048]; /* buffer for facility and priority names */
uchar xbuf[200];
+ DEFiRet;
ASSERT(pline != NULL);
ASSERT(*pline != NULL);
@@ -603,7 +613,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
continue;
/* collect priority name */
- for (bp = buf; *q && !strchr("\t ,;", *q); )
+ for (bp = buf; *q && !strchr("\t ,;", *q) && bp < buf+sizeof(buf)-1 ; )
*bp++ = *q++;
*bp = '\0';
@@ -614,6 +624,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
/* decode priority name */
if ( *buf == '!' ) {
ignorepri = 1;
+ /* copy below is ok, we can NOT go off the allocated area */
for (bp=buf; *(bp+1); bp++)
*bp=*(bp+1);
*bp='\0';
@@ -639,7 +650,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
/* scan facilities */
while (*p && !strchr("\t .;", *p)) {
- for (bp = buf; *p && !strchr("\t ,;.", *p); )
+ for (bp = buf; *p && !strchr("\t ,;.", *p) && bp < buf+sizeof(buf)-1 ; )
*bp++ = *p++;
*bp = '\0';
if (*buf == '*') {
@@ -722,7 +733,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register selector_t *f
p++;
*pline = p;
- return RS_RET_OK;
+ RETiRet;
}
@@ -1060,6 +1071,7 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction)
pAction->f_ReduceRepeated = 0;
}
pAction->bEnabled = 1; /* action is enabled */
+ iNbrActions++; /* one more active action! */
}
break;
}
@@ -1159,6 +1171,34 @@ cfline(uchar *line, selector_t **pfCurr)
}
+/* Reinitialize the configuration subsystem. This is a "work-around" to the fact
+ * that we do not yet have actual config objects. This method is to be called
+ * whenever a totally new config is started (which means on startup and HUP).
+ * Note that it MUST NOT be called for an included config file.
+ * rgerhards, 2008-07-28
+ */
+static rsRetVal
+ReInitConf(void)
+{
+ DEFiRet;
+ iNbrActions = 0; /* this is what we created the function for ;) - action count is reset */
+ RETiRet;
+}
+
+
+/* return the current number of active actions
+ * rgerhards, 2008-07-28
+ */
+static rsRetVal
+GetNbrActActions(int *piNbrActions)
+{
+ DEFiRet;
+ assert(piNbrActions != NULL);
+ *piNbrActions = iNbrActions;
+ RETiRet;
+}
+
+
/* queryInterface function
* rgerhards, 2008-02-29
*/
@@ -1179,6 +1219,8 @@ CODESTARTobjQueryInterface(conf)
pIf->doIncludeLine = doIncludeLine;
pIf->cfline = cfline;
pIf->processConfFile = processConfFile;
+ pIf->ReInitConf = ReInitConf;
+ pIf->GetNbrActActions = GetNbrActActions;
finalize_it:
ENDobjQueryInterface(conf)
diff --git a/runtime/conf.h b/runtime/conf.h
index 31ca27b3..2494d4dc 100644
--- a/runtime/conf.h
+++ b/runtime/conf.h
@@ -37,8 +37,10 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */
rsRetVal (*doIncludeLine)(uchar **pp, __attribute__((unused)) void* pVal);
rsRetVal (*cfline)(uchar *line, selector_t **pfCurr);
rsRetVal (*processConfFile)(uchar *pConfFile);
+ rsRetVal (*ReInitConf)(void);
+ rsRetVal (*GetNbrActActions)(int *);
ENDinterface(conf)
-#define confCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
+#define confCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */
/* prototypes */
diff --git a/runtime/datetime.c b/runtime/datetime.c
index aeb5fac5..20ca6191 100644
--- a/runtime/datetime.c
+++ b/runtime/datetime.c
@@ -159,18 +159,34 @@ static int srSLMGParseInt32(char** ppsz)
/**
* Parse a TIMESTAMP-3339.
- * updates the parse pointer position.
+ * updates the parse pointer position. The pTime parameter
+ * is guranteed to be updated only if a new valid timestamp
+ * could be obtained (restriction added 2008-09-16 by rgerhards).
*/
-static int
+static rsRetVal
ParseTIMESTAMP3339(struct syslogTime *pTime, char** ppszTS)
{
char *pszTS = *ppszTS;
+ /* variables to temporarily hold time information while we parse */
+ int year;
+ int month;
+ int day;
+ int hour; /* 24 hour clock */
+ int minute;
+ int second;
+ int secfrac; /* fractional seconds (must be 32 bit!) */
+ int secfracPrecision;
+ char OffsetMode; /* UTC offset + or - */
+ char OffsetHour; /* UTC offset in hours */
+ int OffsetMinute; /* UTC offset in minutes */
+ /* end variables to temporarily hold time information while we parse */
+ DEFiRet;
assert(pTime != NULL);
assert(ppszTS != NULL);
assert(pszTS != NULL);
- pTime->year = srSLMGParseInt32(&pszTS);
+ year = srSLMGParseInt32(&pszTS);
/* We take the liberty to accept slightly malformed timestamps e.g. in
* the format of 2003-9-1T1:0:0. This doesn't hurt on receiving. Of course,
@@ -178,105 +194,128 @@ ParseTIMESTAMP3339(struct syslogTime *pTime, char** ppszTS)
* here because at postion 11, there is no "T" in such cases ;)
*/
if(*pszTS++ != '-')
- return FALSE;
- pTime->month = srSLMGParseInt32(&pszTS);
- if(pTime->month < 1 || pTime->month > 12)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ month = srSLMGParseInt32(&pszTS);
+ if(month < 1 || month > 12)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != '-')
- return FALSE;
- pTime->day = srSLMGParseInt32(&pszTS);
- if(pTime->day < 1 || pTime->day > 31)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ day = srSLMGParseInt32(&pszTS);
+ if(day < 1 || day > 31)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != 'T')
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
- pTime->hour = srSLMGParseInt32(&pszTS);
- if(pTime->hour < 0 || pTime->hour > 23)
- return FALSE;
+ hour = srSLMGParseInt32(&pszTS);
+ if(hour < 0 || hour > 23)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != ':')
- return FALSE;
- pTime->minute = srSLMGParseInt32(&pszTS);
- if(pTime->minute < 0 || pTime->minute > 59)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ minute = srSLMGParseInt32(&pszTS);
+ if(minute < 0 || minute > 59)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != ':')
- return FALSE;
- pTime->second = srSLMGParseInt32(&pszTS);
- if(pTime->second < 0 || pTime->second > 60)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ second = srSLMGParseInt32(&pszTS);
+ if(second < 0 || second > 60)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
/* Now let's see if we have secfrac */
- if(*pszTS == '.')
- {
+ if(*pszTS == '.') {
char *pszStart = ++pszTS;
- pTime->secfrac = srSLMGParseInt32(&pszTS);
- pTime->secfracPrecision = (int) (pszTS - pszStart);
- }
- else
- {
- pTime->secfracPrecision = 0;
- pTime->secfrac = 0;
+ secfrac = srSLMGParseInt32(&pszTS);
+ secfracPrecision = (int) (pszTS - pszStart);
+ } else {
+ secfracPrecision = 0;
+ secfrac = 0;
}
/* check the timezone */
if(*pszTS == 'Z')
{
pszTS++; /* eat Z */
- pTime->OffsetMode = 'Z';
- pTime->OffsetHour = 0;
- pTime->OffsetMinute = 0;
- }
- else if((*pszTS == '+') || (*pszTS == '-'))
- {
- pTime->OffsetMode = *pszTS;
+ OffsetMode = 'Z';
+ OffsetHour = 0;
+ OffsetMinute = 0;
+ } else if((*pszTS == '+') || (*pszTS == '-')) {
+ OffsetMode = *pszTS;
pszTS++;
- pTime->OffsetHour = srSLMGParseInt32(&pszTS);
- if(pTime->OffsetHour < 0 || pTime->OffsetHour > 23)
- return FALSE;
+ OffsetHour = srSLMGParseInt32(&pszTS);
+ if(OffsetHour < 0 || OffsetHour > 23)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != ':')
- return FALSE;
- pTime->OffsetMinute = srSLMGParseInt32(&pszTS);
- if(pTime->OffsetMinute < 0 || pTime->OffsetMinute > 59)
- return FALSE;
- }
- else
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ OffsetMinute = srSLMGParseInt32(&pszTS);
+ if(OffsetMinute < 0 || OffsetMinute > 59)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ } else {
/* there MUST be TZ information */
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ }
/* OK, we actually have a 3339 timestamp, so let's indicated this */
if(*pszTS == ' ')
++pszTS;
else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
- /* update parse pointer */
+ /* we had success, so update parse pointer and caller-provided timestamp */
*ppszTS = pszTS;
+ pTime->timeType = 2;
+ pTime->year = year;
+ pTime->month = month;
+ pTime->day = day;
+ pTime->hour = hour;
+ pTime->minute = minute;
+ pTime->second = second;
+ pTime->secfrac = secfrac;
+ pTime->secfracPrecision = secfracPrecision;
+ pTime->OffsetMode = OffsetMode;
+ pTime->OffsetHour = OffsetHour;
+ pTime->OffsetMinute = OffsetMinute;
- return TRUE;
+finalize_it:
+ RETiRet;
}
/**
- * Parse a TIMESTAMP-3164.
- * Returns TRUE on parse OK, FALSE on parse error.
+ * Parse a TIMESTAMP-3164. The pTime parameter
+ * is guranteed to be updated only if a new valid timestamp
+ * could be obtained (restriction added 2008-09-16 by rgerhards). This
+ * also means the caller *must* provide a valid (probably current)
+ * timstamp in pTime when calling this function. a 3164 timestamp contains
+ * only partial information and only that partial information is updated.
+ * So the "output timestamp" is a valid timestamp only if the "input
+ * timestamp" was valid, too. The is actually an optimization, as it
+ * permits us to use a pre-aquired timestamp and thus avoids to do
+ * a (costly) time() call. Thanks to David Lang for insisting on
+ * time() call reduction ;).
*/
-static int
+static rsRetVal
ParseTIMESTAMP3164(struct syslogTime *pTime, char** ppszTS)
{
+ /* variables to temporarily hold time information while we parse */
+ int month;
+ int day;
+ int hour; /* 24 hour clock */
+ int minute;
+ int second;
+ /* end variables to temporarily hold time information while we parse */
char *pszTS;
+ DEFiRet;
assert(ppszTS != NULL);
pszTS = *ppszTS;
assert(pszTS != NULL);
assert(pTime != NULL);
- getCurrTime(pTime); /* obtain the current year and UTC offsets! */
-
/* If we look at the month (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec),
* we may see the following character sequences occur:
*
@@ -301,117 +340,117 @@ ParseTIMESTAMP3164(struct syslogTime *pTime, char** ppszTS)
++pszTS;
if(*pszTS == 'n') {
++pszTS;
- pTime->month = 1;
+ month = 1;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else if(*pszTS == 'u') {
++pszTS;
if(*pszTS == 'n') {
++pszTS;
- pTime->month = 6;
+ month = 6;
} else if(*pszTS == 'l') {
++pszTS;
- pTime->month = 7;
+ month = 7;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'F':
if(*pszTS == 'e') {
++pszTS;
if(*pszTS == 'b') {
++pszTS;
- pTime->month = 2;
+ month = 2;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'M':
if(*pszTS == 'a') {
++pszTS;
if(*pszTS == 'r') {
++pszTS;
- pTime->month = 3;
+ month = 3;
} else if(*pszTS == 'y') {
++pszTS;
- pTime->month = 5;
+ month = 5;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'A':
if(*pszTS == 'p') {
++pszTS;
if(*pszTS == 'r') {
++pszTS;
- pTime->month = 4;
+ month = 4;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else if(*pszTS == 'u') {
++pszTS;
if(*pszTS == 'g') {
++pszTS;
- pTime->month = 8;
+ month = 8;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'S':
if(*pszTS == 'e') {
++pszTS;
if(*pszTS == 'p') {
++pszTS;
- pTime->month = 9;
+ month = 9;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'O':
if(*pszTS == 'c') {
++pszTS;
if(*pszTS == 't') {
++pszTS;
- pTime->month = 10;
+ month = 10;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'N':
if(*pszTS == 'o') {
++pszTS;
if(*pszTS == 'v') {
++pszTS;
- pTime->month = 11;
+ month = 11;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
case 'D':
if(*pszTS == 'e') {
++pszTS;
if(*pszTS == 'c') {
++pszTS;
- pTime->month = 12;
+ month = 12;
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
} else
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
break;
default:
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
}
/* done month */
if(*pszTS++ != ' ')
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
/* we accept a slightly malformed timestamp when receiving. This is
* we accept one-digit days
@@ -419,42 +458,51 @@ ParseTIMESTAMP3164(struct syslogTime *pTime, char** ppszTS)
if(*pszTS == ' ')
++pszTS;
- pTime->day = srSLMGParseInt32(&pszTS);
- if(pTime->day < 1 || pTime->day > 31)
- return FALSE;
+ day = srSLMGParseInt32(&pszTS);
+ if(day < 1 || day > 31)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != ' ')
- return FALSE;
- pTime->hour = srSLMGParseInt32(&pszTS);
- if(pTime->hour < 0 || pTime->hour > 23)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ hour = srSLMGParseInt32(&pszTS);
+ if(hour < 0 || hour > 23)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != ':')
- return FALSE;
- pTime->minute = srSLMGParseInt32(&pszTS);
- if(pTime->minute < 0 || pTime->minute > 59)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ minute = srSLMGParseInt32(&pszTS);
+ if(minute < 0 || minute > 59)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
if(*pszTS++ != ':')
- return FALSE;
- pTime->second = srSLMGParseInt32(&pszTS);
- if(pTime->second < 0 || pTime->second > 60)
- return FALSE;
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
+ second = srSLMGParseInt32(&pszTS);
+ if(second < 0 || second > 60)
+ ABORT_FINALIZE(RS_RET_INVLD_TIME);
- /* we provide support for an exter ":" after the date. While this is an
+ /* we provide support for an extra ":" after the date. While this is an
* invalid format, it occurs frequently enough (e.g. with Cisco devices)
* to permit it as a valid case. -- rgerhards, 2008-09-12
*/
if(*pszTS++ == ':')
- ++pszTS;
+ ++pszTS; /* just skip past it */
- /* OK, we actually have a 3164 timestamp, so let's indicate this
- * and fill the rest of the properties. */
+ /* we had success, so update parse pointer and caller-provided timestamp
+ * fields we do not have are not updated in the caller's timestamp. This
+ * is the reason why the caller must pass in a correct timestamp.
+ */
+ *ppszTS = pszTS; /* provide updated parse position back to caller */
pTime->timeType = 1;
+ pTime->month = month;
+ pTime->day = day;
+ pTime->hour = hour;
+ pTime->minute = minute;
+ pTime->second = second;
pTime->secfracPrecision = 0;
pTime->secfrac = 0;
- *ppszTS = pszTS; /* provide updated parse position back to caller */
- return TRUE;
+
+finalize_it:
+ RETiRet;
}
/*******************************************************************
diff --git a/runtime/datetime.h b/runtime/datetime.h
index 755cc0ed..2210af02 100644
--- a/runtime/datetime.h
+++ b/runtime/datetime.h
@@ -36,8 +36,8 @@ typedef struct datetime_s {
/* interfaces */
BEGINinterface(datetime) /* name must also be changed in ENDinterface macro! */
void (*getCurrTime)(struct syslogTime *t);
- int (*ParseTIMESTAMP3339)(struct syslogTime *pTime, char** ppszTS);
- int (*ParseTIMESTAMP3164)(struct syslogTime *pTime, char** pszTS);
+ rsRetVal (*ParseTIMESTAMP3339)(struct syslogTime *pTime, char** ppszTS);
+ rsRetVal (*ParseTIMESTAMP3164)(struct syslogTime *pTime, char** pszTS);
int (*formatTimestampToMySQL)(struct syslogTime *ts, char* pDst, size_t iLenDst);
int (*formatTimestampToPgSQL)(struct syslogTime *ts, char *pDst, size_t iLenDst);
int (*formatTimestamp3339)(struct syslogTime *ts, char* pBuf, size_t iLenBuf);
diff --git a/runtime/debug.c b/runtime/debug.c
index 1450d029..b0bf76ea 100644
--- a/runtime/debug.c
+++ b/runtime/debug.c
@@ -43,6 +43,9 @@
#include <pthread.h>
#include <ctype.h>
#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
#include "rsyslog.h"
#include "debug.h"
@@ -62,8 +65,8 @@ static int bPrintTime = 1; /* print a timestamp together with debug message */
static int bPrintAllDebugOnExit = 0;
static int bAbortTrace = 1; /* print a trace after SIGABRT or SIGSEGV */
static char *pszAltDbgFileName = NULL; /* if set, debug output is *also* sent to here */
-static FILE *altdbg = NULL; /* and the handle for alternate debug output */
-static FILE *stddbg;
+static int altdbg = -1; /* and the handle for alternate debug output */
+static int stddbg;
/* list of files/objects that should be printed */
typedef struct dbgPrintName_s {
@@ -113,8 +116,7 @@ static dbgThrdInfo_t *dbgCallStackListRoot = NULL;
static dbgThrdInfo_t *dbgCallStackListLast = NULL;
static pthread_mutex_t mutCallStack;
-static pthread_mutex_t mutdbgprintf;
-static pthread_mutex_t mutdbgoprint;
+static pthread_mutex_t mutdbgprint;
static pthread_key_t keyCallStack;
@@ -480,7 +482,23 @@ static inline void dbgMutexUnlockLog(pthread_mutex_t *pmut, dbgFuncDB_t *pFuncDB
pthread_mutex_lock(&mutMutLog);
pLog = dbgMutLogFindSpecific(pmut, MUTOP_LOCK, NULL);
+#if 0 /* toggle for testing */
assert(pLog != NULL);
+#else
+/* the change below seems not to work - the problem seems to be a real race... I keep this code in just in case
+ * I need to re-use it. It should be removed once we are finished analyzing this problem. -- rgerhards, 2008-09-17
+ */
+if(pLog == NULL) {
+ /* this may happen due to some races. We do not try to avoid
+ * this, as it would complicate the "real" code. This is not justified
+ * just to keep the debug info system up. -- rgerhards, 2008-09-17
+ */
+ pthread_mutex_unlock(&mutMutLog);
+ dbgprintf("%s:%d:%s: mutex %p UNlocked [but we did not yet know this mutex!]\n",
+ pFuncDB->file, unlockLn, pFuncDB->func, (void*)pmut);
+ return; /* if we don't know it yet, we can not clean up... */
+}
+#endif
/* we found the last lock entry. We now need to see from which FuncDB we need to
* remove it. This is recorded inside the mutex log entry.
@@ -732,8 +750,6 @@ sigsegvHdlr(int signum)
}
dbgprintf("\n\nTo submit bug reports, visit http://www.rsyslog.com/bugs\n\n");
- if(stddbg != NULL) fflush(stddbg);
- if(altdbg != NULL) fflush(altdbg);
/* and finally abort... */
/* TODO: think about restarting rsyslog in this case: may be a good idea,
@@ -742,56 +758,47 @@ sigsegvHdlr(int signum)
abort();
}
-
+#if 1
#pragma GCC diagnostic ignored "-Wempty-body"
-/* print some debug output when an object is given
- * This is mostly a copy of dbgprintf, but I do not know how to combine it
- * into a single function as we have variable arguments and I don't know how to call
- * from one vararg function into another. I don't dig in this, it is OK for the
- * time being. -- rgerhards, 2008-01-29
+/* write the debug message. This is a helper to dbgprintf and dbgoprint which
+ * contains common code. added 2008-09-26 rgerhards
*/
-void
-dbgoprint(obj_t *pObj, char *fmt, ...)
+static void
+dbgprint(obj_t *pObj, char *pszMsg, size_t lenMsg)
{
static pthread_t ptLastThrdID = 0;
static int bWasNL = 0;
- va_list ap;
- static char pszThrdName[64]; /* 64 is to be on the safe side, anything over 20 is bad... */
- static char pszWriteBuf[1024];
+ char pszThrdName[64]; /* 64 is to be on the safe side, anything over 20 is bad... */
+ char pszWriteBuf[1024];
size_t lenWriteBuf;
struct timespec t;
+ uchar *pszObjName = NULL;
- if(!(Debug && debugging_on))
- return;
-
- /* a quick and very dirty hack to enable us to display just from those objects
- * that we are interested in. So far, this must be changed at compile time (and
- * chances are great it is commented out while you read it. Later, this shall
- * be selectable via the environment. -- rgerhards, 2008-02-20
+ /* we must get the object name before we lock the mutex, because the object
+ * potentially calls back into us. If we locked the mutex, we would deadlock
+ * ourselfs. On the other hand, the GetName call needs not to be protected, as
+ * this thread has a valid reference. If such an object is deleted by another
+ * thread, we are in much more trouble than just for dbgprint(). -- rgerhards, 2008-09-26
*/
-#if 0
- if(objGetObjID(pObj) != OBJexpr)
- return;
-#endif
-
+ if(pObj != NULL) {
+ pszObjName = obj.GetName(pObj);
+ }
- pthread_mutex_lock(&mutdbgoprint);
- pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgoprint);
+ pthread_mutex_lock(&mutdbgprint);
+ pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprint);
/* The bWasNL handler does not really work. It works if no thread
* switching occurs during non-NL messages. Else, things are messed
* up. Anyhow, it works well enough to provide useful help during
* getting this up and running. It is questionable if the extra effort
- * is worth fixing it, giving the limited appliability.
- * rgerhards, 2005-10-25
+ * is worth fixing it, giving the limited appliability. -- rgerhards, 2005-10-25
* I have decided that it is not worth fixing it - especially as it works
- * pretty well.
- * rgerhards, 2007-06-15
+ * pretty well. -- rgerhards, 2007-06-15
*/
if(ptLastThrdID != pthread_self()) {
if(!bWasNL) {
- if(stddbg != NULL) fprintf(stddbg, "\n");
- if(altdbg != NULL) fprintf(altdbg, "\n");
+ if(stddbg != -1) write(stddbg, "\n", 1);
+ if(altdbg != -1) write(altdbg, "\n", 1);
bWasNL = 1;
}
ptLastThrdID = pthread_self();
@@ -805,113 +812,82 @@ dbgoprint(obj_t *pObj, char *fmt, ...)
if(bWasNL) {
if(bPrintTime) {
clock_gettime(CLOCK_REALTIME, &t);
- if(stddbg != NULL) fprintf(stddbg, "%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
- if(altdbg != NULL) fprintf(altdbg, "%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
+ lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf),
+ "%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
+ if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
+ if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf);
}
- if(stddbg != NULL) fprintf(stddbg, "%s: ", pszThrdName);
- if(altdbg != NULL) fprintf(altdbg, "%s: ", pszThrdName);
+ lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "%s: ", pszThrdName);
+ if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
+ if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf);
/* print object name header if we have an object */
- if(pObj != NULL) {
- if(stddbg != NULL) fprintf(stddbg, "%s: ", obj.GetName(pObj));
- if(altdbg != NULL) fprintf(altdbg, "%s: ", obj.GetName(pObj));
+ if(pszObjName != NULL) {
+ lenWriteBuf = snprintf(pszWriteBuf, sizeof(pszWriteBuf), "%s: ", pszObjName);
+ if(stddbg != -1) write(stddbg, pszWriteBuf, lenWriteBuf);
+ if(altdbg != -1) write(altdbg, pszWriteBuf, lenWriteBuf);
}
}
- bWasNL = (*(fmt + strlen(fmt) - 1) == '\n') ? 1 : 0;
+ if(stddbg != -1) write(stddbg, pszMsg, lenMsg);
+ if(altdbg != -1) write(altdbg, pszMsg, lenMsg);
+
+ bWasNL = (pszMsg[lenMsg - 1] == '\n') ? 1 : 0;
+
+ pthread_cleanup_pop(1);
+}
+#pragma GCC diagnostic warning "-Wempty-body"
+#endif
+
+/* print some debug output when an object is given
+ * This is mostly a copy of dbgprintf, but I do not know how to combine it
+ * into a single function as we have variable arguments and I don't know how to call
+ * from one vararg function into another. I don't dig in this, it is OK for the
+ * time being. -- rgerhards, 2008-01-29
+ */
+void
+dbgoprint(obj_t *pObj, char *fmt, ...)
+{
+ va_list ap;
+ char pszWriteBuf[1024];
+ size_t lenWriteBuf;
+
+ if(!(Debug && debugging_on))
+ return;
+
+ /* a quick and very dirty hack to enable us to display just from those objects
+ * that we are interested in. So far, this must be changed at compile time (and
+ * chances are great it is commented out while you read it. Later, this shall
+ * be selectable via the environment. -- rgerhards, 2008-02-20
+ */
+#if 0
+ if(objGetObjID(pObj) != OBJexpr)
+ return;
+#endif
+
va_start(ap, fmt);
lenWriteBuf = vsnprintf(pszWriteBuf, sizeof(pszWriteBuf), fmt, ap);
- if(lenWriteBuf >= sizeof(pszWriteBuf)) {
- /* if our buffer was too small, we simply truncate. TODO: maybe something better? */
- lenWriteBuf = sizeof(pszWriteBuf) - 1;
- }
va_end(ap);
- /*
- if(stddbg != NULL) fprintf(stddbg, "%s", pszWriteBuf);
- if(altdbg != NULL) fprintf(altdbg, "%s", pszWriteBuf);
- */
- if(stddbg != NULL) fwrite(pszWriteBuf, lenWriteBuf, 1, stddbg);
- if(altdbg != NULL) fwrite(pszWriteBuf, lenWriteBuf, 1, altdbg);
-
- if(stddbg != NULL) fflush(stddbg);
- if(altdbg != NULL) fflush(altdbg);
- pthread_cleanup_pop(1);
+ dbgprint(pObj, pszWriteBuf, lenWriteBuf);
}
-#pragma GCC diagnostic warning "-Wempty-body"
-#pragma GCC diagnostic ignored "-Wempty-body"
/* print some debug output when no object is given
* WARNING: duplicate code, see dbgoprin above!
*/
void
dbgprintf(char *fmt, ...)
{
- static pthread_t ptLastThrdID = 0;
- static int bWasNL = 0;
va_list ap;
- static char pszThrdName[64]; /* 64 is to be on the safe side, anything over 20 is bad... */
- static char pszWriteBuf[1024];
+ char pszWriteBuf[1024];
size_t lenWriteBuf;
- struct timespec t;
if(!(Debug && debugging_on))
return;
- pthread_mutex_lock(&mutdbgprintf);
- pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprintf);
-
- /* The bWasNL handler does not really work. It works if no thread
- * switching occurs during non-NL messages. Else, things are messed
- * up. Anyhow, it works well enough to provide useful help during
- * getting this up and running. It is questionable if the extra effort
- * is worth fixing it, giving the limited appliability.
- * rgerhards, 2005-10-25
- * I have decided that it is not worth fixing it - especially as it works
- * pretty well.
- * rgerhards, 2007-06-15
- */
- if(ptLastThrdID != pthread_self()) {
- if(!bWasNL) {
- if(stddbg != NULL) fprintf(stddbg, "\n");
- if(altdbg != NULL) fprintf(altdbg, "\n");
- bWasNL = 1;
- }
- ptLastThrdID = pthread_self();
- }
-
- /* do not cache the thread name, as the caller might have changed it
- * TODO: optimized, invalidate cache when new name is set
- */
- dbgGetThrdName(pszThrdName, sizeof(pszThrdName), ptLastThrdID, 0);
-
- if(bWasNL) {
- if(bPrintTime) {
- clock_gettime(CLOCK_REALTIME, &t);
- if(stddbg != NULL) fprintf(stddbg, "%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
- if(altdbg != NULL) fprintf(altdbg, "%4.4ld.%9.9ld:", (long) (t.tv_sec % 10000), t.tv_nsec);
- }
- if(stddbg != NULL) fprintf(stddbg, "%s: ", pszThrdName);
- if(altdbg != NULL) fprintf(altdbg, "%s: ", pszThrdName);
- }
- bWasNL = (*(fmt + strlen(fmt) - 1) == '\n') ? 1 : 0;
va_start(ap, fmt);
lenWriteBuf = vsnprintf(pszWriteBuf, sizeof(pszWriteBuf), fmt, ap);
- if(lenWriteBuf >= sizeof(pszWriteBuf)) {
- /* if our buffer was too small, we simply truncate. TODO: maybe something better? */
- lenWriteBuf = sizeof(pszWriteBuf) - 1;
- }
va_end(ap);
- /*
- if(stddbg != NULL) fprintf(stddbg, "%s", pszWriteBuf);
- if(altdbg != NULL) fprintf(altdbg, "%s", pszWriteBuf);
- */
- if(stddbg != NULL) fwrite(pszWriteBuf, lenWriteBuf, 1, stddbg);
- if(altdbg != NULL) fwrite(pszWriteBuf, lenWriteBuf, 1, altdbg);
-
- if(stddbg != NULL) fflush(stddbg);
- if(altdbg != NULL) fflush(altdbg);
- pthread_cleanup_pop(1);
+ dbgprint(NULL, pszWriteBuf, lenWriteBuf);
}
-#pragma GCC diagnostic warning "-Wempty-body"
void tester(void)
{
@@ -925,7 +901,7 @@ ENDfunc
int dbgEntrFunc(dbgFuncDB_t **ppFuncDB, const char *file, const char *func, int line)
{
int iStackPtr = 0; /* TODO: find some better default, this one hurts the least, but it is not clean */
- dbgThrdInfo_t *pThrd = dbgGetThrdInfo();
+ dbgThrdInfo_t *pThrd;
dbgFuncDBListEntry_t *pFuncDBListEntry;
unsigned int i;
dbgFuncDB_t *pFuncDB;
@@ -936,6 +912,8 @@ int dbgEntrFunc(dbgFuncDB_t **ppFuncDB, const char *file, const char *func, int
pFuncDB = *ppFuncDB;
assert((pFuncDB == NULL) || (pFuncDB->magic == dbgFUNCDB_MAGIC));
+ pThrd = dbgGetThrdInfo(); /* we must do this AFTER the mutexes are initialized! */
+
if(pFuncDB == NULL) {
/* we do not yet have a funcDB and need to create a new one. We also add it
* to the linked list of funcDBs. Please note that when a module is unloaded and
@@ -1190,7 +1168,7 @@ dbgGetRuntimeOptions(void)
uchar *optname;
/* set some defaults */
- stddbg = stdout;
+ stddbg = 1;
if((pszOpts = (uchar*) getenv("RSYSLOG_DEBUG")) != NULL) {
/* we have options set, so let's process them */
@@ -1232,7 +1210,7 @@ dbgGetRuntimeOptions(void)
} else if(!strcasecmp((char*)optname, "nologtimestamp")) {
bPrintTime = 0;
} else if(!strcasecmp((char*)optname, "nostdout")) {
- stddbg = NULL;
+ stddbg = -1;
} else if(!strcasecmp((char*)optname, "noaborttrace")) {
bAbortTrace = 0;
} else if(!strcasecmp((char*)optname, "filetrace")) {
@@ -1257,7 +1235,7 @@ dbgGetRuntimeOptions(void)
rsRetVal dbgClassInit(void)
{
- DEFiRet;
+ rsRetVal iRet; /* do not use DEFiRet, as this makes calls into the debug system! */
struct sigaction sigAct;
sigset_t sigSet;
@@ -1271,8 +1249,7 @@ rsRetVal dbgClassInit(void)
pthread_mutex_init(&mutFuncDBList, NULL);
pthread_mutex_init(&mutMutLog, NULL);
pthread_mutex_init(&mutCallStack, NULL);
- pthread_mutex_init(&mutdbgprintf, NULL);
- pthread_mutex_init(&mutdbgoprint, NULL);
+ pthread_mutex_init(&mutdbgprint, NULL);
/* while we try not to use any of the real rsyslog code (to avoid infinite loops), we
* need to have the ability to query object names. Thus, we need to obtain a pointer to
@@ -1294,7 +1271,7 @@ rsRetVal dbgClassInit(void)
if(pszAltDbgFileName != NULL) {
/* we have a secondary file, so let's open it) */
- if((altdbg = fopen(pszAltDbgFileName, "w")) == NULL) {
+ if((altdbg = open(pszAltDbgFileName, O_WRONLY|O_CREAT|O_TRUNC|O_NOCTTY, S_IRUSR|S_IWUSR)) == -1) {
fprintf(stderr, "alternate debug file could not be opened, ignoring. Error: %s\n", strerror(errno));
}
}
@@ -1302,7 +1279,7 @@ rsRetVal dbgClassInit(void)
dbgSetThrdName((uchar*)"main thread");
finalize_it:
- RETiRet;
+ return(iRet);
}
@@ -1314,8 +1291,8 @@ rsRetVal dbgClassExit(void)
if(bPrintAllDebugOnExit)
dbgPrintAllDebugInfo();
- if(altdbg != NULL)
- fclose(altdbg);
+ if(altdbg != -1)
+ close(altdbg);
/* now free all of our memory to make the memory debugger happy... */
pFuncDBListEtry = pFuncDBListRoot;
diff --git a/runtime/debug.h b/runtime/debug.h
index 214b7c05..d9d576b5 100644
--- a/runtime/debug.h
+++ b/runtime/debug.h
@@ -130,7 +130,8 @@ void dbgPrintAllDebugInfo(void);
/* debug aides */
-#ifdef RTINST
+//#ifdef RTINST
+#if 0 // temporarily removed for helgrind
#define d_pthread_mutex_lock(x) dbgMutexLock(x, pdbgFuncDB, __LINE__, dbgCALLStaCK_POP_POINT )
#define d_pthread_mutex_unlock(x) dbgMutexUnlock(x, pdbgFuncDB, __LINE__, dbgCALLStaCK_POP_POINT )
#define d_pthread_cond_wait(cond, mut) dbgCondWait(cond, mut, pdbgFuncDB, __LINE__, dbgCALLStaCK_POP_POINT )
diff --git a/runtime/glbl.c b/runtime/glbl.c
index 11a664f8..1114fcd3 100644
--- a/runtime/glbl.c
+++ b/runtime/glbl.c
@@ -51,6 +51,7 @@ DEFobjStaticHelpers
* class...
*/
static uchar *pszWorkDir = NULL;
+static int iMaxLine = 2048; /* maximum length of a syslog message */
static int iDefPFFamily = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */
static int bDropMalPTRMsgs = 0;/* Drop messages which have malicious PTR records during DNS lookup */
static int option_DisallowWarning = 1; /* complain if message from disallowed sender is received */
@@ -84,6 +85,7 @@ static dataType Get##nameFunc(void) \
return(nameVar); \
}
+SIMP_PROP(MaxLine, iMaxLine, int)
SIMP_PROP(DefPFFamily, iDefPFFamily, int) /* note that in the future we may check the family argument */
SIMP_PROP(DropMalPTRMsgs, bDropMalPTRMsgs, int)
SIMP_PROP(Option_DisallowWarning, option_DisallowWarning, int)
@@ -170,6 +172,7 @@ CODESTARTobjQueryInterface(glbl)
#define SIMP_PROP(name) \
pIf->Get##name = Get##name; \
pIf->Set##name = Set##name;
+ SIMP_PROP(MaxLine);
SIMP_PROP(DefPFFamily);
SIMP_PROP(DropMalPTRMsgs);
SIMP_PROP(Option_DisallowWarning);
diff --git a/runtime/glbl.h b/runtime/glbl.h
index 90436319..0c83bdd5 100644
--- a/runtime/glbl.h
+++ b/runtime/glbl.h
@@ -40,6 +40,7 @@ BEGINinterface(glbl) /* name must also be changed in ENDinterface macro! */
#define SIMP_PROP(name, dataType) \
dataType (*Get##name)(void); \
rsRetVal (*Set##name)(dataType);
+ SIMP_PROP(MaxLine, int)
SIMP_PROP(DefPFFamily, int)
SIMP_PROP(DropMalPTRMsgs, int)
SIMP_PROP(Option_DisallowWarning, int)
diff --git a/runtime/modules.c b/runtime/modules.c
index ceb4768c..d5730ede 100644
--- a/runtime/modules.c
+++ b/runtime/modules.c
@@ -570,6 +570,8 @@ Load(uchar *pModName)
int bHasExtension;
void *pModHdlr, *pModInit;
modInfo_t *pModInfo;
+ uchar *pModDirCurr, *pModDirNext;
+ int iLoadCnt;
assert(pModName != NULL);
dbgprintf("Requested to load module '%s'\n", pModName);
@@ -591,48 +593,84 @@ Load(uchar *pModName)
pModInfo = GetNxt(pModInfo);
}
- /* now build our load module name */
- if(*pModName == '/') {
- *szPath = '\0'; /* we do not need to append the path - its already in the module name */
- iPathLen = 0;
- } else {
- *szPath = '\0';
- strncat((char *) szPath, (pModDir == NULL) ? _PATH_MODDIR : (char*) pModDir, sizeof(szPath) - 1);
- iPathLen = strlen((char*) szPath);
- if((szPath[iPathLen - 1] != '/')) {
- if((iPathLen <= sizeof(szPath) - 2)) {
- szPath[iPathLen++] = '/';
- szPath[iPathLen] = '\0';
- } else {
- errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName);
+ pModDirCurr = (uchar *)((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir);
+ pModDirNext = NULL;
+ pModHdlr = NULL;
+ iLoadCnt = 0;
+ do {
+ /* now build our load module name */
+ if(*pModName == '/') {
+ *szPath = '\0'; /* we do not need to append the path - its already in the module name */
+ iPathLen = 0;
+ } else {
+ *szPath = '\0';
+
+ iPathLen = strlen((char *)pModDirCurr);
+ pModDirNext = (uchar *)strchr((char *)pModDirCurr, ':');
+ if(pModDirNext)
+ iPathLen = (size_t)(pModDirNext - pModDirCurr);
+
+ if(iPathLen == 0) {
+ if(pModDirNext) {
+ pModDirCurr = pModDirNext + 1;
+ continue;
+ }
+ break;
+ } else if(iPathLen > sizeof(szPath) - 1) {
+ errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', module path too long\n", pModName);
ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN);
}
+
+ strncat((char *) szPath, (char *)pModDirCurr, iPathLen);
+ iPathLen = strlen((char*) szPath);
+
+ if(pModDirNext)
+ pModDirCurr = pModDirNext + 1;
+
+ if((szPath[iPathLen - 1] != '/')) {
+ if((iPathLen <= sizeof(szPath) - 2)) {
+ szPath[iPathLen++] = '/';
+ szPath[iPathLen] = '\0';
+ } else {
+ errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName);
+ ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN);
+ }
+ }
}
- }
- /* ... add actual name ... */
- strncat((char *) szPath, (char *) pModName, sizeof(szPath) - iPathLen - 1);
+ /* ... add actual name ... */
+ strncat((char *) szPath, (char *) pModName, sizeof(szPath) - iPathLen - 1);
+
+ /* now see if we have an extension and, if not, append ".so" */
+ if(!bHasExtension) {
+ /* we do not have an extension and so need to add ".so"
+ * TODO: I guess this is highly importable, so we should change the
+ * algo over time... -- rgerhards, 2008-03-05
+ */
+ /* ... so now add the extension */
+ strncat((char *) szPath, ".so", sizeof(szPath) - strlen((char*) szPath) - 1);
+ iPathLen += 3;
+ }
- /* now see if we have an extension and, if not, append ".so" */
- if(!bHasExtension) {
- /* we do not have an extension and so need to add ".so"
- * TODO: I guess this is highly importable, so we should change the
- * algo over time... -- rgerhards, 2008-03-05
- */
- /* ... so now add the extension */
- strncat((char *) szPath, ".so", sizeof(szPath) - strlen((char*) szPath) - 1);
- iPathLen += 3;
- }
+ if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) {
+ errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName);
+ ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN);
+ }
- if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) {
- errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName);
- ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN);
- }
+ /* complete load path constructed, so ... GO! */
+ dbgprintf("loading module '%s'\n", szPath);
+ pModHdlr = dlopen((char *) szPath, RTLD_NOW);
+ iLoadCnt++;
+
+ } while(pModHdlr == NULL && *pModName != '/' && pModDirNext);
- /* complete load path constructed, so ... GO! */
- dbgprintf("loading module '%s'\n", szPath);
- if(!(pModHdlr = dlopen((char *) szPath, RTLD_NOW))) {
- errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", szPath, dlerror());
+ if(!pModHdlr) {
+ if(iLoadCnt) {
+ errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", szPath, dlerror());
+ } else {
+ errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', ModDir was '%s'\n", szPath,
+ ((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir));
+ }
ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_DLOPEN);
}
if(!(pModInit = dlsym(pModHdlr, "modInit"))) {
diff --git a/runtime/msg.c b/runtime/msg.c
index fdeae077..9c2e3f17 100644
--- a/runtime/msg.c
+++ b/runtime/msg.c
@@ -42,6 +42,7 @@
#include "msg.h"
#include "var.h"
#include "datetime.h"
+#include "glbl.h"
#include "regexp.h"
#include "atomic.h"
@@ -49,6 +50,7 @@
DEFobjStaticHelpers
DEFobjCurrIf(var)
DEFobjCurrIf(datetime)
+DEFobjCurrIf(glbl)
DEFobjCurrIf(regexp)
static syslogCODE rs_prioritynames[] =
@@ -255,7 +257,16 @@ rsRetVal msgConstruct(msg_t **ppThis)
pM->iRefCount = 1;
pM->iSeverity = -1;
pM->iFacility = -1;
+
+ /* we initialize both timestamps to contain the current time, so that they
+ * are consistent. Also, this saves us from doing any further time calls just
+ * to obtain a timestamp. The memcpy() should not really make a difference,
+ * especially as I think there is no codepath currently where it would not be
+ * required (after I have cleaned up the pathes ;)). -- rgerhards, 2008-10-02
+ */
datetime.getCurrTime(&(pM->tRcvdAt));
+ memcpy(&pM->tTIMESTAMP, &pM->tRcvdAt, sizeof(struct syslogTime));
+
objConstructSetObjInfo(pM);
/* DEV debugging only! dbgprintf("msgConstruct\t0x%x, ref 1\n", (int)pM);*/
@@ -271,11 +282,13 @@ BEGINobjDestruct(msg) /* be sure to specify the object type also in END and CODE
int currRefCount;
CODESTARTobjDestruct(msg)
/* DEV Debugging only ! dbgprintf("msgDestruct\t0x%lx, Ref now: %d\n", (unsigned long)pM, pM->iRefCount - 1); */
-# ifdef DO_HAVE_ATOMICS
- currRefCount = ATOMIC_DEC_AND_FETCH(pThis->iRefCount);
-# else
+//# ifdef DO_HAVE_ATOMICS
+// currRefCount = ATOMIC_DEC_AND_FETCH(pThis->iRefCount);
+//# else
+ MsgLock(pThis);
currRefCount = --pThis->iRefCount;
-# endif
+//# endif
+// we need a mutex, because we may be suspended after getting the refcount but before
if(currRefCount == 0)
{
/* DEV Debugging Only! dbgprintf("msgDestruct\t0x%lx, RefCount now 0, doing DESTROY\n", (unsigned long)pThis); */
@@ -287,6 +300,8 @@ CODESTARTobjDestruct(msg)
free(pThis->pszTAG);
if(pThis->pszHOSTNAME != NULL)
free(pThis->pszHOSTNAME);
+ if(pThis->pszInputName != NULL)
+ free(pThis->pszInputName);
if(pThis->pszRcvFrom != NULL)
free(pThis->pszRcvFrom);
if(pThis->pszRcvFromIP != NULL)
@@ -333,8 +348,10 @@ CODESTARTobjDestruct(msg)
rsCStrDestruct(&pThis->pCSPROCID);
if(pThis->pCSMSGID != NULL)
rsCStrDestruct(&pThis->pCSMSGID);
+ MsgUnlock(pThis);
funcDeleteMutex(pThis);
} else {
+ MsgUnlock(pThis);
pThis = NULL; /* tell framework not to destructing the object! */
}
ENDobjDestruct(msg)
@@ -453,6 +470,7 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm)
objSerializePTR(pStrm, pszUxTradMsg, PSZ);
objSerializePTR(pStrm, pszTAG, PSZ);
objSerializePTR(pStrm, pszHOSTNAME, PSZ);
+ objSerializePTR(pStrm, pszInputName, PSZ);
objSerializePTR(pStrm, pszRcvFrom, PSZ);
objSerializePTR(pStrm, pszRcvFromIP, PSZ);
@@ -478,7 +496,7 @@ finalize_it:
msg_t *MsgAddRef(msg_t *pM)
{
assert(pM != NULL);
-# ifdef DO_HAVE_ATOMICS
+# ifdef HAVE_ATOMIC_BUILTINS
ATOMIC_INC(pM->iRefCount);
# else
MsgLock(pM);
@@ -1219,6 +1237,18 @@ char *getHOSTNAME(msg_t *pM)
}
+uchar *getInputName(msg_t *pM)
+{
+ if(pM == NULL)
+ return (uchar*) "";
+ else
+ if(pM->pszInputName == NULL)
+ return (uchar*) "";
+ else
+ return pM->pszInputName;
+}
+
+
char *getRcvFrom(msg_t *pM)
{
if(pM == NULL)
@@ -1399,6 +1429,19 @@ static int getAPPNAMELen(msg_t *pM)
return (pM->pCSAPPNAME == NULL) ? 0 : rsCStrLen(pM->pCSAPPNAME);
}
+/* rgerhards 2008-09-10: set pszInputName in msg object
+ */
+void MsgSetInputName(msg_t *pMsg, char* pszInputName)
+{
+ assert(pMsg != NULL);
+ if(pMsg->pszInputName != NULL)
+ free(pMsg->pszInputName);
+
+ pMsg->iLenInputName = strlen(pszInputName);
+ if((pMsg->pszInputName = malloc(pMsg->iLenInputName + 1)) != NULL) {
+ memcpy(pMsg->pszInputName, pszInputName, pMsg->iLenInputName + 1);
+ }
+}
/* rgerhards 2004-11-16: set pszRcvFrom in msg object
*/
@@ -1685,6 +1728,8 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
pRes = getRawMsg(pMsg);
} else if(!strcmp((char*) pName, "uxtradmsg")) {
pRes = getUxTradMsg(pMsg);
+ } else if(!strcmp((char*) pName, "inputname")) {
+ pRes = (char*) getInputName(pMsg);
} else if(!strcmp((char*) pName, "fromhost")) {
pRes = getRcvFrom(pMsg);
} else if(!strcmp((char*) pName, "fromhost-ip")) {
@@ -1772,6 +1817,8 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
return "***OUT OF MEMORY***";
} else
*pbMustBeFreed = 1; /* all of these functions allocate dyn. memory */
+ } else if(!strcmp((char*) pName, "$myhostname")) {
+ pRes = (char*) glbl.GetLocalHostName();
} else {
/* there is no point in continuing, we may even otherwise render the
* error message unreadable. rgerhards, 2007-07-10
@@ -1809,6 +1856,11 @@ char *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe,
++pFld; /* skip to field terminator */
if(*pFld == pTpe->data.field.field_delim) {
++pFld; /* eat it */
+ if (pTpe->data.field.field_expand != 0) {
+ while (*pFld == pTpe->data.field.field_delim) {
+ ++pFld;
+ }
+ }
++iCurrFld;
}
}
@@ -2363,6 +2415,8 @@ rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp)
MsgSetUxTradMsg(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
} else if(isProp("pszTAG")) {
MsgSetTAG(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
+ } else if(isProp("pszInputName")) {
+ MsgSetInputName(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr));
} else if(isProp("pszRcvFromIP")) {
MsgSetRcvFromIP(pThis, rsCStrGetSzStrNoNULL(pProp->val.pStr));
} else if(isProp("pszRcvFrom")) {
@@ -2425,6 +2479,7 @@ BEGINObjClassInit(msg, 1, OBJ_IS_CORE_MODULE)
/* request objects we use */
CHKiRet(objUse(var, CORE_COMPONENT));
CHKiRet(objUse(datetime, CORE_COMPONENT));
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
/* set our own handlers */
OBJSetMethodHandler(objMethod_SERIALIZE, MsgSerialize);
diff --git a/runtime/msg.h b/runtime/msg.h
index c428237a..21cb2c64 100644
--- a/runtime/msg.h
+++ b/runtime/msg.h
@@ -91,9 +91,11 @@ struct msg {
int iLenRcvFrom; /* Length of pszRcvFrom */
uchar *pszRcvFromIP; /* IP of system message was received from */
int iLenRcvFromIP; /* Length of pszRcvFromIP */
+ uchar *pszInputName; /* name of the input module that submitted this message */
+ int iLenInputName; /* Length of pszInputName */
short iProtocolVersion;/* protocol version of message received 0 - legacy, 1 syslog-protocol) */
cstr_t *pCSProgName; /* the (BSD) program name */
- cstr_t *pCSStrucData;/* STRUCTURED-DATA */
+ cstr_t *pCSStrucData; /* STRUCTURED-DATA */
cstr_t *pCSAPPNAME; /* APP-NAME */
cstr_t *pCSPROCID; /* PROCID */
cstr_t *pCSMSGID; /* MSGID */
@@ -135,6 +137,7 @@ char *getSeverity(msg_t *pM);
char *getSeverityStr(msg_t *pM);
char *getFacility(msg_t *pM);
char *getFacilityStr(msg_t *pM);
+void MsgSetInputName(msg_t *pMsg, char*);
rsRetVal MsgSetAPPNAME(msg_t *pMsg, char* pszAPPNAME);
char *getAPPNAME(msg_t *pM);
rsRetVal MsgSetPROCID(msg_t *pMsg, char* pszPROCID);
diff --git a/runtime/net.c b/runtime/net.c
index b9af700c..44c9008a 100644
--- a/runtime/net.c
+++ b/runtime/net.c
@@ -977,7 +977,6 @@ should_use_so_bsdcompat(void)
#define SO_BSDCOMPAT 0
#endif
-
/* get the hostname of the message source. This was originally in cvthname()
* but has been moved out of it because of clarity and fuctional separation.
* It must be provided by the socket we received the message on as well as
diff --git a/runtime/obj.c b/runtime/obj.c
index 082aa691..2a9df9ed 100644
--- a/runtime/obj.c
+++ b/runtime/obj.c
@@ -780,7 +780,7 @@ Deserialize(void *ppObj, uchar *pszTypeExpected, strm_t *pStrm, rsRetVal (*fFixu
DEFiRet;
rsRetVal iRetLocal;
obj_t *pObj = NULL;
- int oVers = 0; /* after all, it is totally useless but takes up some execution time... */
+ int oVers = 0; /* keep compiler happy, but it is totally useless but takes up some execution time... */
cstr_t *pstrID = NULL;
objInfo_t *pObjInfo;
diff --git a/runtime/queue.c b/runtime/queue.c
index 9f9943bc..93b33967 100644
--- a/runtime/queue.c
+++ b/runtime/queue.c
@@ -1449,8 +1449,13 @@ queueDequeueConsumable(queue_t *pThis, wti_t *pWti, int iCancelStateSave)
pthread_cond_broadcast(&pThis->belowLightDlyWtrMrk);
}
- d_pthread_mutex_unlock(pThis->mut);
+ /* rgerhards, 2008-09-30: I reversed the order of cond_signal und mutex_unlock
+ * as of the pthreads recommendation on predictable scheduling behaviour. I don't see
+ * any problems caused by this, but I add this comment in case some will be seen
+ * in the next time.
+ */
pthread_cond_signal(&pThis->notFull);
+ d_pthread_mutex_unlock(pThis->mut);
pthread_setcancelstate(iCancelStateSave, NULL);
/* WE ARE NO LONGER PROTECTED BY THE MUTEX */
@@ -2111,7 +2116,6 @@ queueEnqObj(queue_t *pThis, flowControl_t flowCtlType, void *pUsr)
{
DEFiRet;
int iCancelStateSave;
- int i;
struct timespec t;
ISOBJ_TYPE_assert(pThis, queue);
@@ -2134,7 +2138,6 @@ queueEnqObj(queue_t *pThis, flowControl_t flowCtlType, void *pUsr)
if(pThis->bIsDA)
CHKiRet(queueChkStrtDA(pThis));
-
/* handle flow control
* There are two different flow control mechanisms: basic and advanced flow control.
* Basic flow control has always been implemented and protects the queue structures
@@ -2191,17 +2194,14 @@ queueEnqObj(queue_t *pThis, flowControl_t flowCtlType, void *pUsr)
finalize_it:
if(pThis->qType != QUEUETYPE_DIRECT) {
+ /* make sure at least one worker is running. */
+ queueAdviseMaxWorkers(pThis);
+ dbgoprint((obj_t*) pThis, "EnqueueMsg advised worker start\n");
+ /* and release the mutex */
d_pthread_mutex_unlock(pThis->mut);
- i = pthread_cond_signal(&pThis->notEmpty);
- dbgoprint((obj_t*) pThis, "EnqueueMsg signaled condition (%d)\n", i);
pthread_setcancelstate(iCancelStateSave, NULL);
}
- /* make sure at least one worker is running. */
- if(pThis->qType != QUEUETYPE_DIRECT) {
- queueAdviseMaxWorkers(pThis);
- }
-
RETiRet;
}
diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h
index 7927af3a..361bfb47 100644
--- a/runtime/rsyslog.h
+++ b/runtime/rsyslog.h
@@ -123,6 +123,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_TRUE = -3, /**< to indicate a true state (can be used as TRUE, legacy) */
RS_RET_FALSE = -2, /**< to indicate a false state (can be used as FALSE, legacy) */
RS_RET_NO_IRET = -8, /**< This is a trick for the debuging system - it means no iRet is provided */
+ RS_RET_VALIDATION_RUN = -9, /**< indicates a (config) validation run, processing not carried out */
RS_RET_ERR = -3000, /**< generic failure */
RS_TRUNCAT_TOO_LARGE = -3001, /**< truncation operation where too many chars should be truncated */
RS_RET_FOUND_AT_STRING_END = -3002, /**< some value found, but at the last pos of string */
@@ -246,8 +247,11 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth
RS_RET_RETRY = -2100, /**< call should be retried (e.g. EGAIN on recv) */
RS_RET_GSS_ERR = -2101, /**< generic error occured in GSSAPI subsystem */
RS_RET_CERTLESS = -2102, /**< state: we run without machine cert (this may be OK) */
- RS_RET_QUEUE_FULL = -2103, /**< queue is full, operation could not be completed */
- RS_RET_ACCEPT_ERR = -2104, /**< error during accept() system call */
+ RS_RET_NO_ACTIONS = -2103, /**< no active actions are configured (no output will be created) */
+ RS_RET_CONF_FILE_NOT_FOUND = -2104, /**< config file or directory not found */
+ RS_RET_QUEUE_FULL = -2105, /**< queue is full, operation could not be completed */
+ RS_RET_ACCEPT_ERR = -2106, /**< error during accept() system call */
+ RS_RET_INVLD_TIME = -2107, /**< invalid timestamp (e.g. could not be parsed) */
/* RainerScript error messages (range 1000.. 1999) */
RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */
diff --git a/runtime/var.c b/runtime/var.c
index 7e51fc6d..559bc56c 100644
--- a/runtime/var.c
+++ b/runtime/var.c
@@ -29,6 +29,7 @@
*/
#include "config.h"
+#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
@@ -89,6 +90,44 @@ CODESTARTobjDebugPrint(var)
ENDobjDebugPrint(var)
+/* This function is similar to DebugPrint, but does not send its output to
+ * the debug log but instead to a caller-provided string. The idea here is that
+ * we can use this string to get a textual representation of a variable.
+ * Among others, this is useful for creating testbenches, our first use case for
+ * it. Here, it enables simple comparison of the resulting program to a
+ * reference program by simple string compare.
+ * Note that the caller must initialize the string object. We always add
+ * data to it. So, it can be easily combined into a chain of methods
+ * to generate the final string.
+ * rgerhards, 2008-07-07
+ */
+static rsRetVal
+Obj2Str(var_t *pThis, cstr_t *pstrPrg)
+{
+ DEFiRet;
+ size_t lenBuf;
+ uchar szBuf[2048];
+
+ ISOBJ_TYPE_assert(pThis, var);
+ assert(pstrPrg != NULL);
+ switch(pThis->varType) {
+ case VARTYPE_STR:
+ lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%s[cstr]", rsCStrGetSzStr(pThis->val.pStr));
+ break;
+ case VARTYPE_NUMBER:
+ lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%lld[nbr]", pThis->val.num);
+ break;
+ default:
+ lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "**UNKNOWN**[%d]", pThis->varType);
+ break;
+ }
+ CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szBuf, lenBuf));
+
+finalize_it:
+ RETiRet;
+}
+
+
/* duplicates a var instance
* rgerhards, 2008-02-25
*/
@@ -387,6 +426,7 @@ CODESTARTobjQueryInterface(var)
pIf->ConstructFinalize = varConstructFinalize;
pIf->Destruct = varDestruct;
pIf->DebugPrint = varDebugPrint;
+ pIf->Obj2Str = Obj2Str;
pIf->SetNumber = varSetNumber;
pIf->SetString = varSetString;
pIf->ConvForOperation = ConvForOperation;
diff --git a/runtime/var.h b/runtime/var.h
index bbe7ba33..6d890ec9 100644
--- a/runtime/var.h
+++ b/runtime/var.h
@@ -59,6 +59,7 @@ BEGINinterface(var) /* name must also be changed in ENDinterface macro! */
rsRetVal (*ConvToNumber)(var_t *pThis);
rsRetVal (*ConvToBool)(var_t *pThis);
rsRetVal (*ConvToString)(var_t *pThis);
+ rsRetVal (*Obj2Str)(var_t *pThis, cstr_t*);
rsRetVal (*Duplicate)(var_t *pThis, var_t **ppNew);
ENDinterface(var)
#define varCURR_IF_VERSION 1 /* increment whenever you change the interface above! */
diff --git a/runtime/vmop.c b/runtime/vmop.c
index 219315c4..fcacb15b 100644
--- a/runtime/vmop.c
+++ b/runtime/vmop.c
@@ -25,6 +25,7 @@
*/
#include "config.h"
+#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
@@ -81,6 +82,39 @@ CODESTARTobjDebugPrint(vmop)
ENDobjDebugPrint(vmop)
+/* This function is similar to DebugPrint, but does not send its output to
+ * the debug log but instead to a caller-provided string. The idea here is that
+ * we can use this string to get a textual representation of an operation.
+ * Among others, this is useful for creating testbenches, our first use case for
+ * it. Here, it enables simple comparison of the resulting program to a
+ * reference program by simple string compare.
+ * Note that the caller must initialize the string object. We always add
+ * data to it. So, it can be easily combined into a chain of methods
+ * to generate the final string.
+ * rgerhards, 2008-07-04
+ */
+static rsRetVal
+Obj2Str(vmop_t *pThis, cstr_t *pstrPrg)
+{
+ uchar *pOpcodeName;
+ uchar szBuf[2048];
+ size_t lenBuf;
+ DEFiRet;
+
+ ISOBJ_TYPE_assert(pThis, vmop);
+ assert(pstrPrg != NULL);
+ vmopOpcode2Str(pThis, &pOpcodeName);
+ lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%s\t", pOpcodeName);
+ CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szBuf, lenBuf));
+ if(pThis->operand.pVar != NULL)
+ CHKiRet(var.Obj2Str(pThis->operand.pVar, pstrPrg));
+ CHKiRet(rsCStrAppendChar(pstrPrg, '\n'));
+
+finalize_it:
+ RETiRet;
+}
+
+
/* set operand (variant case)
* rgerhards, 2008-02-20
*/
@@ -206,8 +240,6 @@ CODESTARTobjQueryInterface(vmop)
* work here (if we can support an older interface version - that,
* of course, also affects the "if" above).
*/
- //xxxpIf->oID = OBJvmop;
-
pIf->Construct = vmopConstruct;
pIf->ConstructFinalize = vmopConstructFinalize;
pIf->Destruct = vmopDestruct;
@@ -215,6 +247,7 @@ CODESTARTobjQueryInterface(vmop)
pIf->SetOpcode = vmopSetOpcode;
pIf->SetVar = vmopSetVar;
pIf->Opcode2Str = vmopOpcode2Str;
+ pIf->Obj2Str = Obj2Str;
finalize_it:
ENDobjQueryInterface(vmop)
diff --git a/runtime/vmop.h b/runtime/vmop.h
index 97f924d7..c3d5d5f4 100644
--- a/runtime/vmop.h
+++ b/runtime/vmop.h
@@ -26,6 +26,7 @@
#define INCLUDED_VMOP_H
#include "ctok_token.h"
+#include "stringbuf.h"
/* machine instructions types */
typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc() */
@@ -83,6 +84,7 @@ BEGINinterface(vmop) /* name must also be changed in ENDinterface macro! */
rsRetVal (*SetOpcode)(vmop_t *pThis, opcode_t opcode);
rsRetVal (*SetVar)(vmop_t *pThis, var_t *pVar);
rsRetVal (*Opcode2Str)(vmop_t *pThis, uchar **ppName);
+ rsRetVal (*Obj2Str)(vmop_t *pThis, cstr_t *pstr);
ENDinterface(vmop)
#define vmopCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
diff --git a/runtime/vmprg.c b/runtime/vmprg.c
index a2b744d7..705e6948 100644
--- a/runtime/vmprg.c
+++ b/runtime/vmprg.c
@@ -24,12 +24,14 @@
*/
#include "config.h"
+#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "rsyslog.h"
#include "obj.h"
#include "vmprg.h"
+#include "stringbuf.h"
/* static data */
DEFobjStaticHelpers
@@ -79,6 +81,40 @@ CODESTARTobjDebugPrint(vmprg)
ENDobjDebugPrint(vmprg)
+/* This function is similar to DebugPrint, but does not send its output to
+ * the debug log but instead to a caller-provided string. The idea here is that
+ * we can use this string to get a textual representation of a bytecode program.
+ * Among others, this is useful for creating testbenches, our first use case for
+ * it. Here, it enables simple comparison of the resulting program to a
+ * reference program by simple string compare.
+ * Note that the caller must initialize the string object. We always add
+ * data to it. So, it can be easily combined into a chain of methods
+ * to generate the final string.
+ * rgerhards, 2008-07-04
+ */
+static rsRetVal
+Obj2Str(vmprg_t *pThis, cstr_t *pstrPrg)
+{
+ uchar szAddr[12];
+ vmop_t *pOp;
+ int i;
+ int lenAddr;
+ DEFiRet;
+
+ ISOBJ_TYPE_assert(pThis, vmprg);
+ assert(pstrPrg != NULL);
+ i = 0; /* "program counter" */
+ for(pOp = pThis->vmopRoot ; pOp != NULL ; pOp = pOp->pNext) {
+ lenAddr = snprintf((char*)szAddr, sizeof(szAddr), "%8.8d: ", i++);
+ CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szAddr, lenAddr));
+ vmop.Obj2Str(pOp, pstrPrg);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
/* add an operation (instruction) to the end of the current program. This
* function is expected to be called while creating the program, but never
* again after this is done and it is being executed. Results are undefined if
@@ -146,12 +182,11 @@ CODESTARTobjQueryInterface(vmprg)
* work here (if we can support an older interface version - that,
* of course, also affects the "if" above).
*/
- //xxxpIf->oID = OBJvmprg;
-
pIf->Construct = vmprgConstruct;
pIf->ConstructFinalize = vmprgConstructFinalize;
pIf->Destruct = vmprgDestruct;
pIf->DebugPrint = vmprgDebugPrint;
+ pIf->Obj2Str = Obj2Str;
pIf->AddOperation = vmprgAddOperation;
pIf->AddVarOperation = vmprgAddVarOperation;
finalize_it:
diff --git a/runtime/vmprg.h b/runtime/vmprg.h
index db1f62f0..c1042f7d 100644
--- a/runtime/vmprg.h
+++ b/runtime/vmprg.h
@@ -38,7 +38,7 @@
#define INCLUDED_VMPRG_H
#include "vmop.h"
-
+#include "stringbuf.h"
/* the vmprg object */
typedef struct vmprg_s {
@@ -56,6 +56,7 @@ BEGINinterface(vmprg) /* name must also be changed in ENDinterface macro! */
rsRetVal (*Destruct)(vmprg_t **ppThis);
rsRetVal (*AddOperation)(vmprg_t *pThis, vmop_t *pOp);
rsRetVal (*AddVarOperation)(vmprg_t *pThis, opcode_t opcode, var_t *pVar);
+ rsRetVal (*Obj2Str)(vmprg_t *pThis, cstr_t *pstr);
ENDinterface(vmprg)
#define vmprgCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */
diff --git a/runtime/wti.c b/runtime/wti.c
index 13554232..365b25d5 100644
--- a/runtime/wti.c
+++ b/runtime/wti.c
@@ -113,6 +113,9 @@ wtiSetState(wti_t *pThis, qWrkCmd_t tCmd, int bActiveOnly, int bLockMutex)
wtiGetDbgHdr(pThis), tCmd, pThis->tCurrCmd);
} else {
dbgprintf("%s: receiving command %d\n", wtiGetDbgHdr(pThis), tCmd);
+ /* we could replace this with a simple if, but we leave the switch in in case we need
+ * to add something at a later stage. -- rgerhards, 2008-09-30
+ */
switch(tCmd) {
case eWRKTHRD_TERMINATING:
/* TODO: re-enable meaningful debug msg! (via function callback?)
@@ -123,10 +126,8 @@ wtiSetState(wti_t *pThis, qWrkCmd_t tCmd, int bActiveOnly, int bLockMutex)
pthread_cond_signal(&pThis->condExitDone);
dbgprintf("%s: worker terminating\n", wtiGetDbgHdr(pThis));
break;
- case eWRKTHRD_RUNNING:
- pthread_cond_signal(&pThis->condInitDone);
- break;
/* these cases just to satisfy the compiler, we do (yet) not act an them: */
+ case eWRKTHRD_RUNNING:
case eWRKTHRD_STOPPED:
case eWRKTHRD_RUN_CREATED:
case eWRKTHRD_RUN_INIT:
@@ -190,7 +191,6 @@ CODESTARTobjDestruct(wti)
d_pthread_mutex_unlock(&pThis->mut);
/* actual destruction */
- pthread_cond_destroy(&pThis->condInitDone);
pthread_cond_destroy(&pThis->condExitDone);
pthread_mutex_destroy(&pThis->mut);
@@ -202,7 +202,6 @@ ENDobjDestruct(wti)
/* Standard-Constructor for the wti object
*/
BEGINobjConstruct(wti) /* be sure to specify the object type also in END macro! */
- pthread_cond_init(&pThis->condInitDone, NULL);
pthread_cond_init(&pThis->condExitDone, NULL);
pthread_mutex_init(&pThis->mut, NULL);
ENDobjConstruct(wti)
diff --git a/runtime/wti.h b/runtime/wti.h
index b3d92473..0cd6744e 100644
--- a/runtime/wti.h
+++ b/runtime/wti.h
@@ -35,7 +35,6 @@ typedef struct wti_s {
qWrkCmd_t tCurrCmd; /* current command to be carried out by worker */
obj_t *pUsrp; /* pointer to an object meaningful for current user pointer (e.g. queue pUsr data elemt) */
wtp_t *pWtp; /* my worker thread pool (important if only the work thread instance is passed! */
- pthread_cond_t condInitDone; /* signaled when the thread startup is done (once per thread existance) */
pthread_cond_t condExitDone; /* signaled when the thread exit is done (once per thread existance) */
pthread_mutex_t mut;
int bShutdownRqtd; /* shutdown for this thread requested? 0 - no , 1 - yes */
diff --git a/runtime/wtp.c b/runtime/wtp.c
index 8b041ea2..734c8d57 100644
--- a/runtime/wtp.c
+++ b/runtime/wtp.c
@@ -169,7 +169,9 @@ wtpWakeupAllWrkr(wtp_t *pThis)
DEFiRet;
ISOBJ_TYPE_assert(pThis, wtp);
+ d_pthread_mutex_lock(pThis->pmutUsr);
pthread_cond_broadcast(pThis->pcondBusy);
+ d_pthread_mutex_unlock(pThis->pmutUsr);
RETiRet;
}
@@ -302,11 +304,12 @@ wtpShutdownAll(wtp_t *pThis, wtpState_t tShutdownCmd, struct timespec *ptTimeout
rsRetVal wtpSignalWrkrTermination(wtp_t *pThis)
{
DEFiRet;
- /* I leave the mutex code here out as it give as deadlocks. I think it is not really
+ /* I leave the mutex code here out as it gives us deadlocks. I think it is not really
* needed and we are on the safe side. I leave this comment in if practice proves us
- * wrong. The whole thing should be removed after half a your or year if we see there
+ * wrong. The whole thing should be removed after half a year or year if we see there
* actually is no issue (or revisit it from a theoretical POV).
* rgerhards, 2008-01-28
+ * revisited 2008-09-30, still a bit unclear, leave in
*/
/*TODO: mutex or not mutex, that's the question ;)DEFVARS_mutexProtection;*/