diff options
Diffstat (limited to 'runtime')
-rw-r--r-- | runtime/Makefile.am | 4 | ||||
-rw-r--r-- | runtime/atomic.h | 23 | ||||
-rw-r--r-- | runtime/conf.c | 58 | ||||
-rw-r--r-- | runtime/conf.h | 4 | ||||
-rw-r--r-- | runtime/datetime.c | 268 | ||||
-rw-r--r-- | runtime/datetime.h | 4 | ||||
-rw-r--r-- | runtime/debug.c | 233 | ||||
-rw-r--r-- | runtime/debug.h | 3 | ||||
-rw-r--r-- | runtime/glbl.c | 3 | ||||
-rw-r--r-- | runtime/glbl.h | 1 | ||||
-rw-r--r-- | runtime/modules.c | 108 | ||||
-rw-r--r-- | runtime/msg.c | 65 | ||||
-rw-r--r-- | runtime/msg.h | 5 | ||||
-rw-r--r-- | runtime/net.c | 1 | ||||
-rw-r--r-- | runtime/obj.c | 2 | ||||
-rw-r--r-- | runtime/queue.c | 20 | ||||
-rw-r--r-- | runtime/rsyslog.h | 8 | ||||
-rw-r--r-- | runtime/var.c | 40 | ||||
-rw-r--r-- | runtime/var.h | 1 | ||||
-rw-r--r-- | runtime/vmop.c | 37 | ||||
-rw-r--r-- | runtime/vmop.h | 2 | ||||
-rw-r--r-- | runtime/vmprg.c | 39 | ||||
-rw-r--r-- | runtime/vmprg.h | 3 | ||||
-rw-r--r-- | runtime/wti.c | 9 | ||||
-rw-r--r-- | runtime/wti.h | 1 | ||||
-rw-r--r-- | runtime/wtp.c | 7 |
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 c8dbf2c2..3073fc5f 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; } } @@ -2371,6 +2423,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")) { @@ -2433,6 +2487,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;*/ |