From db350988f0ab0b57f6a4aed0da20b5f41499690f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 29 May 2012 10:45:44 +0200 Subject: first experiments with regexp'es in RainerScript --- grammar/rainerscript.c | 17 ++++++++++++++++- grammar/rainerscript.h | 3 ++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 320e66d0..ce0298fb 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -839,6 +839,11 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) } ret->datatype = 'N'; break; + case CNFFUNC_RE_MATCH: + dbgprintf("TODO: implement re_match()\n"); + ret->d.n = 1; + ret->datatype = 'N'; + break; default: if(Debug) { fname = es_str2cstr(func->fname, NULL); @@ -892,7 +897,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) int bMustFree, bMustFree2; long long n_r, n_l; - //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { /* note: comparison operations are extremely similar. The code can be copyied, only * places flagged with "CMP" need to be changed. @@ -1450,6 +1455,9 @@ cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) static inline enum cnffuncid funcName2ID(es_str_t *fname, unsigned short nParams) { +{ char *s;s=es_str2cstr(fname, NULL); +dbgprintf("ZZZZ: func: '%s', nParams: %d\n", s, nParams); +free(s);} if(!es_strbufcmp(fname, (unsigned char*)"strlen", sizeof("strlen") - 1)) { if(nParams != 1) { parser_errmsg("number of parameters for strlen() must be one " @@ -1485,6 +1493,13 @@ funcName2ID(es_str_t *fname, unsigned short nParams) return CNFFUNC_INVALID; } return CNFFUNC_CNUM; + } else if(!es_strbufcmp(fname, (unsigned char*)"re_match", sizeof("re_match") - 1)) { + if(nParams != 2) { + parser_errmsg("number of parameters for re_match() must be two " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } + return CNFFUNC_RE_MATCH; } else { return CNFFUNC_INVALID; } diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index e11ae62f..07e6af0b 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -163,7 +163,8 @@ enum cnffuncid { CNFFUNC_GETENV, CNFFUNC_TOLOWER, CNFFUNC_CSTR, - CNFFUNC_CNUM + CNFFUNC_CNUM, + CNFFUNC_RE_MATCH }; struct cnffunc { -- cgit v1.2.3 From 04399f5ebe22d4f0c228fceb6766f33a49892e38 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 29 May 2012 12:01:07 +0200 Subject: added --enable-debugless configure option for very high demanding environments This actually at compile time disables a lot of debug code, resulting in some speedup (but serious loss of debugging capabilities) --- ChangeLog | 5 +++++ configure.ac | 19 ++++++++++++++++++- plugins/imuxsock/imuxsock.c | 18 ++++++++---------- runtime/debug.h | 9 +++++++-- runtime/queue.c | 12 ++++++------ runtime/rule.c | 20 ++++++++++---------- runtime/ruleset.c | 17 ++++++++--------- runtime/wti.c | 16 ++++++++-------- tools/omfile.c | 2 +- tools/syslogd.c | 1 - 10 files changed, 71 insertions(+), 48 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2846a59d..4679d263 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,9 @@ --------------------------------------------------------------------------- +Version 6.5.0 [devel] 2012-0?-?? +- added --enable-debugless configure option for very high demanding envs + This actually at compile time disables a lot of debug code, resulting + in some speedup (but serious loss of debugging capabilities) +--------------------------------------------------------------------------- Version 6.3.10 [BETA] 2012-0?-?? - bugfix: if debug message could end up in log file when forking if rsyslog was set to auto-background (thus fork, the default) and debug diff --git a/configure.ac b/configure.ac index 0c6fe35c..0d41572c 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[6.3.9],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[6.3.8],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) @@ -445,6 +445,22 @@ if test "$enable_rtinst" = "yes"; then fi +# total debugless: highest performance, but no way at all to enable debug +# logging +AC_ARG_ENABLE(debugless, + [AS_HELP_STRING([--enable-debugless],[Enable runtime instrumentation mode @<:@default=no@:>@])], + [case "${enableval}" in + yes) enable_debugless="yes" ;; + no) enable_debugless="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-debugless) ;; + esac], + [enable_debugless="no"] +) +if test "$enable_debugless" = "yes"; then + AC_DEFINE(DEBUGLESS, 1, [Defined if debugless mode is enabled.]) +fi + + # valgrind AC_ARG_ENABLE(valgrind, [AS_HELP_STRING([--enable-valgrind],[Enable valgrind support settings @<:@default=no@:>@])], @@ -1394,6 +1410,7 @@ echo " Extended Testbench enabled: $enable_extended_tests" echo " MySQL Tests enabled: $enable_mysql_tests" echo " Debug mode enabled: $enable_debug" echo " Runtime Instrumentation enabled: $enable_rtinst" +echo " (total) debugless mode enabled: $enable_debugless" echo " Diagnostic tools enabled: $enable_diagtools" echo " Enhanced memory checking enabled: $enable_memcheck" echo " Valgrind support settings enabled: $enable_valgrind" diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 2d26e652..19028470 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -388,7 +388,7 @@ addListner(instanceConf_t *inst) if(inst->ratelimitInterval > 0) { if((listeners[nfd].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn, NULL)) == NULL) { /* in this case, we simply turn off rate-limiting */ - dbgprintf("imuxsock: turning off rate limiting because we could not " + DBGPRINTF("imuxsock: turning off rate limiting because we could not " "create hash table\n"); inst->ratelimitInterval = 0; } @@ -458,7 +458,7 @@ createLogSocket(lstn_t *pLstn) if(pLstn->fd < 0 || bind(pLstn->fd, (struct sockaddr *) &sunx, SUN_LEN(&sunx)) < 0 || chmod((char*)pLstn->sockName, 0666) < 0) { errmsg.LogError(errno, NO_ERRCODE, "cannot create '%s'", pLstn->sockName); - dbgprintf("cannot create %s (%d).\n", pLstn->sockName, errno); + DBGPRINTF("cannot create %s (%d).\n", pLstn->sockName, errno); if(pLstn->fd != -1) close(pLstn->fd); pLstn->fd = -1; @@ -491,7 +491,7 @@ openLogSocket(lstn_t *pLstn) /* ok, it matches -- just use as is */ pLstn->fd = fd; - dbgprintf("imuxsock: Acquired UNIX socket '%s' (fd %d) from systemd.\n", + DBGPRINTF("imuxsock: Acquired UNIX socket '%s' (fd %d) from systemd.\n", pLstn->sockName, pLstn->fd); break; } @@ -563,7 +563,7 @@ findRatelimiter(lstn_t *pLstn, struct ucred *cred, rs_ratelimit_state_t **prl) rl = hashtable_search(pLstn->ht, &cred->pid); if(rl == NULL) { /* we need to add a new ratelimiter, process not seen before! */ - dbgprintf("imuxsock: no ratelimiter for pid %lu, creating one\n", + DBGPRINTF("imuxsock: no ratelimiter for pid %lu, creating one\n", (unsigned long) cred->pid); STATSCOUNTER_INC(ctrNumRatelimiters, mutCtrNumRatelimiters); CHKmalloc(rl = malloc(sizeof(rs_ratelimit_state_t))); @@ -931,7 +931,7 @@ static rsRetVal readSocket(lstn_t *pLstn) msgh.msg_iovlen = 1; iRcvd = recvmsg(pLstn->fd, &msgh, MSG_DONTWAIT); - dbgprintf("Message from UNIX socket: #%d\n", pLstn->fd); + DBGPRINTF("Message from UNIX socket: #%d\n", pLstn->fd); if(iRcvd > 0) { cred = NULL; ts = NULL; @@ -948,8 +948,6 @@ static rsRetVal readSocket(lstn_t *pLstn) if( pLstn->bUseSysTimeStamp && cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SO_TIMESTAMP) { ts = (struct timeval *)CMSG_DATA(cm); - dbgprintf("XXX: got timestamp %ld.%ld\n", - (long) ts->tv_sec, (long) ts->tv_usec); break; } # endif /* HAVE_SO_TIMESTAMP */ @@ -959,7 +957,7 @@ static rsRetVal readSocket(lstn_t *pLstn) } else if(iRcvd < 0 && errno != EINTR) { char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); - dbgprintf("UNIX socket error: %d = %s.\n", errno, errStr); + DBGPRINTF("UNIX socket error: %d = %s.\n", errno, errStr); errmsg.LogError(errno, NO_ERRCODE, "imuxsock: recvfrom UNIX"); } @@ -1025,7 +1023,7 @@ activateListeners() for (i = startIndexUxLocalSockets ; i < nfd ; i++) { if(openLogSocket(&(listeners[i])) == RS_RET_OK) { ++actSocks; - dbgprintf("imuxsock: Opened UNIX socket '%s' (fd %d).\n", + DBGPRINTF("imuxsock: Opened UNIX socket '%s' (fd %d).\n", listeners[i].sockName, listeners[i].fd); } } @@ -1263,7 +1261,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(parser, CORE_COMPONENT)); - dbgprintf("imuxsock version %s initializing\n", PACKAGE_VERSION); + DBGPRINTF("imuxsock version %s initializing\n", PACKAGE_VERSION); /* init legacy config vars */ cs.pLogSockName = NULL; diff --git a/runtime/debug.h b/runtime/debug.h index 26672c3e..5bd26bd8 100644 --- a/runtime/debug.h +++ b/runtime/debug.h @@ -106,8 +106,13 @@ void dbgPrintAllDebugInfo(void); void *dbgmalloc(size_t size); /* macros */ -#define DBGPRINTF(...) if(Debug) { dbgprintf(__VA_ARGS__); } -#define DBGOPRINT(...) if(Debug) { dbgoprint(__VA_ARGS__); } +#ifdef DEBUGLESS +# define DBGPRINTF(...) {} +# define DBGOPRINT(...) {} +#else +# define DBGPRINTF(...) if(Debug) { dbgprintf(__VA_ARGS__); } +# define DBGOPRINT(...) if(Debug) { dbgoprint(__VA_ARGS__); } +#endif #ifdef RTINST # define BEGINfunc static dbgFuncDB_t *pdbgFuncDB; int dbgCALLStaCK_POP_POINT = dbgEntrFunc(&pdbgFuncDB, __FILE__, __func__, __LINE__); # define ENDfunc dbgExitFunc(pdbgFuncDB, dbgCALLStaCK_POP_POINT, RS_RET_NO_IRET); diff --git a/runtime/queue.c b/runtime/queue.c index 2b017747..05399278 100644 --- a/runtime/queue.c +++ b/runtime/queue.c @@ -131,7 +131,7 @@ static void displayBatchState(batch_t *pBatch) { int i; for(i = 0 ; i < pBatch->nElem ; ++i) { - dbgprintf("XXXXX: displayBatchState %p[%d]: %d\n", pBatch, i, pBatch->pElem[i].state); + DBGPRINTF("displayBatchState %p[%d]: %d\n", pBatch, i, pBatch->pElem[i].state); } } @@ -1418,7 +1418,8 @@ DoDeleteBatchFromQStore(qqueue_t *pThis, int nElem) /* iQueueSize is not decremented by qDel(), so we need to do it ourselves */ ATOMIC_SUB(&pThis->iQueueSize, nElem, &pThis->mutQueueSize); ATOMIC_SUB(&pThis->nLogDeq, nElem, &pThis->mutLogDeq); -dbgprintf("delete batch from store, new sizes: log %d, phys %d\n", getLogicalQueueSize(pThis), getPhysicalQueueSize(pThis)); + DBGPRINTF("delete batch from store, new sizes: log %d, phys %d\n", + getLogicalQueueSize(pThis), getPhysicalQueueSize(pThis)); ++pThis->deqIDDel; /* one more batch dequeued */ RETiRet; @@ -1454,7 +1455,7 @@ DeleteBatchFromQStore(qqueue_t *pThis, batch_t *pBatch) DoDeleteBatchFromQStore(pThis, pBatch->nElem); } else { /* can not delete, insert into to-delete list */ - dbgprintf("not at head of to-delete list, enqueue %d\n", (int) pBatch->deqID); + DBGPRINTF("not at head of to-delete list, enqueue %d\n", (int) pBatch->deqID); CHKiRet(tdlAdd(pThis, pBatch->deqID, pBatch->nElem)); } @@ -1484,7 +1485,6 @@ DeleteProcessedBatch(qqueue_t *pThis, batch_t *pBatch) pUsr = pBatch->pElem[i].pUsrp; if( pBatch->pElem[i].state == BATCH_STATE_RDY || pBatch->pElem[i].state == BATCH_STATE_SUB) { -dbgprintf("XXX: DeleteProcessedBatch re-enqueue %d of %d, state %d\n", i, pBatch->nElem, pBatch->pElem[i].state); localRet = doEnqSingleObj(pThis, eFLOWCTL_NO_DELAY, (obj_t*)MsgAddRef((msg_t*) pUsr)); ++nEnqueued; @@ -1495,7 +1495,7 @@ dbgprintf("XXX: DeleteProcessedBatch re-enqueue %d of %d, state %d\n", i, pBatch objDestruct(pUsr); } - dbgprintf("we deleted %d objects and enqueued %d objects\n", i-nEnqueued, nEnqueued); + DBGPRINTF("we deleted %d objects and enqueued %d objects\n", i-nEnqueued, nEnqueued); if(nEnqueued > 0) qqueueChkPersist(pThis, nEnqueued); @@ -2674,7 +2674,7 @@ qqueueApplyCnfParam(qqueue_t *pThis, struct cnfparamvals *pvals) } else if(!strcmp(pblk.descr[i].name, "queuedequeuetimend.")) { pThis->iDeqtWinToHr = pvals[i].val.d.n; } else { - dbgprintf("queue: program error, non-handled " + DBGPRINTF("queue: program error, non-handled " "param '%s'\n", pblk.descr[i].name); } } diff --git a/runtime/rule.c b/runtime/rule.c index 18199230..41cc9e4e 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -132,14 +132,14 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) } else if(pRule->eHostnameCmpMode == HN_COMP_MATCH) { if(rsCStrSzStrCmp(pRule->pCSHostnameComp, (uchar*) getHOSTNAME(pMsg), getHOSTNAMELen(pMsg))) { /* not equal, so we are already done... */ - dbgprintf("hostname filter '+%s' does not match '%s'\n", + DBGPRINTF("hostname filter '+%s' does not match '%s'\n", rsCStrGetSzStrNoNULL(pRule->pCSHostnameComp), getHOSTNAME(pMsg)); FINALIZE; } } else { /* must be -hostname */ if(!rsCStrSzStrCmp(pRule->pCSHostnameComp, (uchar*) getHOSTNAME(pMsg), getHOSTNAMELen(pMsg))) { - /* not equal, so we are already done... */ - dbgprintf("hostname filter '-%s' does not match '%s'\n", + /* not equal, SO WE ARe already done... */ + DBGPRINTF("hostname filter '-%s' does not match '%s'\n", rsCStrGetSzStrNoNULL(pRule->pCSHostnameComp), getHOSTNAME(pMsg)); FINALIZE; } @@ -171,7 +171,7 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) if(pRule->f_filter_type == FILTER_PRI) { /* skip messages that are incorrect priority */ - dbgprintf("testing filter, f_pmask %d\n", pRule->f_filterData.f_pmask[pMsg->iFacility]); + DBGPRINTF("testing filter, f_pmask %d\n", pRule->f_filterData.f_pmask[pMsg->iFacility]); if ( (pRule->f_filterData.f_pmask[pMsg->iFacility] == TABLE_NOPRI) || \ ((pRule->f_filterData.f_pmask[pMsg->iFacility] & (1<iSeverity)) == 0) ) bRet = 0; @@ -179,7 +179,7 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) bRet = 1; } else if(pRule->f_filter_type == FILTER_EXPR) { bRet = cnfexprEvalBool(pRule->f_filterData.expr, pMsg); - dbgprintf("result of rainerscript filter evaluation: %d\n", bRet); + DBGPRINTF("result of rainerscript filter evaluation: %d\n", bRet); } else { assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */ pszPropVal = MsgGetProp(pMsg, NULL, pRule->f_filterData.prop.propID, @@ -230,21 +230,21 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) char *cstr; if(pRule->f_filterData.prop.propID == PROP_CEE) { cstr = es_str2cstr(pRule->f_filterData.prop.propName, NULL); - dbgprintf("Filter: check for CEE property '%s' (value '%s') ", + DBGPRINTF("Filter: check for CEE property '%s' (value '%s') ", cstr, pszPropVal); free(cstr); } else { - dbgprintf("Filter: check for property '%s' (value '%s') ", + DBGPRINTF("Filter: check for property '%s' (value '%s') ", propIDToName(pRule->f_filterData.prop.propID), pszPropVal); } if(pRule->f_filterData.prop.isNegated) - dbgprintf("NOT "); + DBGPRINTF("NOT "); if(pRule->f_filterData.prop.operation == FIOP_ISEMPTY) { - dbgprintf("%s : %s\n", + DBGPRINTF("%s : %s\n", getFIOPName(pRule->f_filterData.prop.operation), bRet ? "TRUE" : "FALSE"); } else { - dbgprintf("%s '%s': %s\n", + DBGPRINTF("%s '%s': %s\n", getFIOPName(pRule->f_filterData.prop.operation), rsCStrGetSzStrNoNULL(pRule->f_filterData.prop.pCSCompValue), bRet ? "TRUE" : "FALSE"); diff --git a/runtime/ruleset.c b/runtime/ruleset.c index c384663a..ecded4a3 100644 --- a/runtime/ruleset.c +++ b/runtime/ruleset.c @@ -143,9 +143,9 @@ DEFFUNC_llExecFunc(processBatchDoRules) { rsRetVal iRet; ISOBJ_TYPE_assert(pData, rule); - dbgprintf("Processing next rule\n"); + DBGPRINTF("Processing next rule\n"); iRet = rule.ProcessBatch((rule_t*) pData, (batch_t*) pParam); -dbgprintf("ruleset: get iRet %d from rule.ProcessMsg()\n", iRet); + DBGPRINTF("ruleset: get iRet %d from rule.ProcessMsg()\n", iRet); return iRet; } @@ -266,7 +266,7 @@ addRule(ruleset_t *pThis, rule_t **ppRule) rule.Destruct(ppRule); } else { CHKiRet(llAppend(&pThis->llRules, NULL, *ppRule)); - dbgprintf("selector line successfully processed, %d actions\n", iActionCnt); + DBGPRINTF("selector line successfully processed, %d actions\n", iActionCnt); } finalize_it: @@ -337,7 +337,7 @@ SetDefaultRuleset(rsconf_t *conf, uchar *pszName) CHKiRet(rulesetGetRuleset(conf, &pRuleset, pszName)); conf->rulesets.pDflt = pRuleset; - dbgprintf("default rule set changed to %p: '%s'\n", pRuleset, pszName); + DBGPRINTF("default rule set changed to %p: '%s'\n", pRuleset, pszName); finalize_it: RETiRet; @@ -355,7 +355,7 @@ SetCurrRuleset(rsconf_t *conf, uchar *pszName) CHKiRet(rulesetGetRuleset(conf, &pRuleset, pszName)); conf->rulesets.pCurr = pRuleset; - dbgprintf("current rule set changed to %p: '%s'\n", pRuleset, pszName); + DBGPRINTF("current rule set changed to %p: '%s'\n", pRuleset, pszName); finalize_it: RETiRet; @@ -414,7 +414,7 @@ finalize_it: /* destructor for the ruleset object */ BEGINobjDestruct(ruleset) /* be sure to specify the object type also in END and CODESTART macros! */ CODESTARTobjDestruct(ruleset) - dbgprintf("destructing ruleset %p, name %p\n", pThis, pThis->pszName); + DBGPRINTF("destructing ruleset %p, name %p\n", pThis, pThis->pszName); if(pThis->pQueue != NULL) { qqueueDestruct(&pThis->pQueue); } @@ -515,7 +515,7 @@ doRulesetCreateQueue(rsconf_t *conf, int *pNewVal) if(pNewVal == 0) FINALIZE; /* if it is turned off, we do not need to change anything ;) */ - dbgprintf("adding a ruleset-specific \"main\" queue"); + DBGPRINTF("adding a ruleset-specific \"main\" queue"); rulesetMainQName = (conf->rulesets.pCurr->pszName == NULL)? UCHAR_CONSTANT("ruleset") : conf->rulesets.pCurr->pszName; CHKiRet(createMainQueue(&conf->rulesets.pCurr->pQueue, rulesetMainQName)); @@ -560,8 +560,7 @@ doRulesetAddParser(rsconf_t *conf, uchar *pName) CHKiRet(parser.AddParserToList(&conf->rulesets.pCurr->pParserLst, pParser)); - dbgprintf("added parser '%s' to ruleset '%s'\n", pName, conf->rulesets.pCurr->pszName); -RUNLOG_VAR("%p", conf->rulesets.pCurr->pParserLst); + DBGPRINTF("added parser '%s' to ruleset '%s'\n", pName, conf->rulesets.pCurr->pszName); finalize_it: d_free(pName); /* no longer needed */ diff --git a/runtime/wti.c b/runtime/wti.c index e44086af..382f3668 100644 --- a/runtime/wti.c +++ b/runtime/wti.c @@ -121,7 +121,7 @@ wtiWakeupThrd(wti_t *pThis) if(wtiGetState(pThis)) { /* we first try the cooperative "cancel" interface */ pthread_kill(pThis->thrdID, SIGTTIN); - dbgprintf("sent SIGTTIN to worker thread 0x%x\n", (unsigned) pThis->thrdID); + DBGPRINTF("sent SIGTTIN to worker thread 0x%x\n", (unsigned) pThis->thrdID); } RETiRet; @@ -148,13 +148,13 @@ wtiCancelThrd(wti_t *pThis) if(wtiGetState(pThis)) { /* we first try the cooperative "cancel" interface */ pthread_kill(pThis->thrdID, SIGTTIN); - dbgprintf("sent SIGTTIN to worker thread 0x%x, giving it a chance to terminate\n", (unsigned) pThis->thrdID); + DBGPRINTF("sent SIGTTIN to worker thread 0x%x, giving it a chance to terminate\n", (unsigned) pThis->thrdID); srSleep(0, 10000); } if(wtiGetState(pThis)) { - dbgprintf("cooperative worker termination failed, using cancellation...\n"); - dbgoprint((obj_t*) pThis, "canceling worker thread\n"); + DBGPRINTF("cooperative worker termination failed, using cancellation...\n"); + DBGOPRINT((obj_t*) pThis, "canceling worker thread\n"); pthread_cancel(pThis->thrdID); /* now wait until the thread terminates... */ while(wtiGetState(pThis)) { @@ -195,7 +195,7 @@ wtiConstructFinalize(wti_t *pThis) ISOBJ_TYPE_assert(pThis, wti); - dbgprintf("%s: finalizing construction of worker instance data\n", wtiGetDbgHdr(pThis)); + DBGPRINTF("%s: finalizing construction of worker instance data\n", wtiGetDbgHdr(pThis)); /* initialize our thread instance descriptor (no concurrency here) */ pThis->bIsRunning = FALSE; @@ -257,7 +257,7 @@ doIdleProcessing(wti_t *pThis, wtp_t *pWtp, int *pbInactivityTOOccured) *pbInactivityTOOccured = 1; /* indicate we had a timeout */ } } - dbgoprint((obj_t*) pThis, "worker awoke from idle processing\n"); + DBGOPRINT((obj_t*) pThis, "worker awoke from idle processing\n"); ENDfunc } @@ -300,7 +300,7 @@ wtiWorker(wti_t *pThis) if(terminateRet == RS_RET_TERMINATE_NOW) { /* we now need to free the old batch */ localRet = pWtp->pfObjProcessed(pWtp->pUsr, pThis); - dbgoprint((obj_t*) pThis, "terminating worker because of TERMINATE_NOW mode, del iRet %d\n", + DBGOPRINT((obj_t*) pThis, "terminating worker because of TERMINATE_NOW mode, del iRet %d\n", localRet); d_pthread_mutex_unlock(pWtp->pmutUsr); break; @@ -318,7 +318,7 @@ wtiWorker(wti_t *pThis) } else if(localRet == RS_RET_IDLE) { if(terminateRet == RS_RET_TERMINATE_WHEN_IDLE || bInactivityTOOccured) { d_pthread_mutex_unlock(pWtp->pmutUsr); - dbgoprint((obj_t*) pThis, "terminating worker terminateRet=%d, bInactivityTOOccured=%d\n", + DBGOPRINT((obj_t*) pThis, "terminating worker terminateRet=%d, bInactivityTOOccured=%d\n", terminateRet, bInactivityTOOccured); break; /* end of loop */ } diff --git a/tools/omfile.c b/tools/omfile.c index 68222883..0b20b1f6 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -647,7 +647,7 @@ doWrite(instanceData *pData, uchar *pszBuf, int lenBuf) ASSERT(pData != NULL); ASSERT(pszBuf != NULL); -dbgprintf("write to stream, pData->pStrm %p, lenBuf %d\n", pData->pStrm, lenBuf); + DBGPRINTF("write to stream, pData->pStrm %p, lenBuf %d\n", pData->pStrm, lenBuf); if(pData->pStrm != NULL){ CHKiRet(strm.Write(pData->pStrm, pszBuf, lenBuf)); FINALIZE; diff --git a/tools/syslogd.c b/tools/syslogd.c index 7d995cc2..930920b7 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -448,7 +448,6 @@ logmsgInternal(int iErr, int pri, uchar *msg, int flags) MsgSetRawMsgWOSize(pMsg, (char*)msg); MsgSetHOSTNAME(pMsg, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName())); MsgSetRcvFrom(pMsg, glbl.GetLocalHostNameProp()); -dbgprintf("ZZZZ: pLocalHostIPIF used!\n"); MsgSetRcvFromIP(pMsg, glbl.GetLocalHostIP()); MsgSetMSGoffs(pMsg, 0); /* check if we have an error code associated and, if so, -- cgit v1.2.3 From 439a5b70f2216616e9d55072be43658d5a7fe5d7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 29 May 2012 12:42:46 +0200 Subject: improved support for --enable-debugless Now it's probably time to prove the effect in practice... --- runtime/parser.c | 6 +++--- tcps_sess.c | 10 +++++----- tcpsrv.c | 13 ++++++------- tools/pmrfc3164.c | 4 ++-- 4 files changed, 16 insertions(+), 17 deletions(-) diff --git a/runtime/parser.c b/runtime/parser.c index a79f2ce8..f0515484 100644 --- a/runtime/parser.c +++ b/runtime/parser.c @@ -180,7 +180,7 @@ AddDfltParser(uchar *pName) CHKiRet(FindParser(&pParser, pName)); CHKiRet(AddParserToList(&pDfltParsLst, pParser)); - dbgprintf("Parser '%s' added to default parser set.\n", pName); + DBGPRINTF("Parser '%s' added to default parser set.\n", pName); finalize_it: RETiRet; @@ -209,7 +209,7 @@ finalize_it: BEGINobjDestruct(parser) /* be sure to specify the object type also in END and CODESTART macros! */ CODESTARTobjDestruct(parser) - dbgprintf("destructing parser '%s'\n", pThis->pName); + DBGPRINTF("destructing parser '%s'\n", pThis->pName); free(pThis->pName); ENDobjDestruct(parser) @@ -521,7 +521,7 @@ ParseMsg(msg_t *pMsg) bIsSanitized = TRUE; } localRet = pParser->pModule->mod.pm.parse(pMsg); - dbgprintf("Parser '%s' returned %d\n", pParser->pName, localRet); + DBGPRINTF("Parser '%s' returned %d\n", pParser->pName, localRet); if(localRet != RS_RET_COULD_NOT_PARSE) break; pParserList = pParserList->pNext; diff --git a/tcps_sess.c b/tcps_sess.c index eb3740e4..e7149cb7 100644 --- a/tcps_sess.c +++ b/tcps_sess.c @@ -323,7 +323,7 @@ PrepareClose(tcps_sess_t *pThis) * of message may occur. As such, we process the message in * this case. */ - dbgprintf("Extra data at end of stream in legacy syslog/tcp message - processing\n"); + DBGPRINTF("Extra data at end of stream in legacy syslog/tcp message - processing\n"); datetime.getCurrTime(&stTime, &ttGenTime); defaultDoSubmitMessage(pThis, &stTime, ttGenTime, NULL); } @@ -382,21 +382,21 @@ processDataRcvd(tcps_sess_t *pThis, char c, struct syslogTime *stTime, time_t tt if(isdigit(c)) { pThis->iOctetsRemain = pThis->iOctetsRemain * 10 + c - '0'; } else { /* done with the octet count, so this must be the SP terminator */ - dbgprintf("TCP Message with octet-counter, size %d.\n", pThis->iOctetsRemain); + DBGPRINTF("TCP Message with octet-counter, size %d.\n", pThis->iOctetsRemain); if(c != ' ') { errmsg.LogError(0, NO_ERRCODE, "Framing Error in received TCP message: " "delimiter is not SP but has ASCII value %d.\n", c); } if(pThis->iOctetsRemain < 1) { /* TODO: handle the case where the octet count is 0! */ - dbgprintf("Framing Error: invalid octet count\n"); + DBGPRINTF("Framing Error: invalid octet count\n"); errmsg.LogError(0, NO_ERRCODE, "Framing Error in received TCP message: " "invalid octet count %d.\n", pThis->iOctetsRemain); } else if(pThis->iOctetsRemain > iMaxLine) { /* while we can not do anything against it, we can at least log an indication * that something went wrong) -- rgerhards, 2008-03-14 */ - dbgprintf("truncating message with %d octets - max msg size is %d\n", + DBGPRINTF("truncating message with %d octets - max msg size is %d\n", pThis->iOctetsRemain, iMaxLine); errmsg.LogError(0, NO_ERRCODE, "received oversize message: size is %d bytes, " "max msg size is %d, truncating...\n", pThis->iOctetsRemain, iMaxLine); @@ -407,7 +407,7 @@ processDataRcvd(tcps_sess_t *pThis, char c, struct syslogTime *stTime, time_t tt assert(pThis->inputState == eInMsg); if(pThis->iMsg >= iMaxLine) { /* emergency, we now need to flush, no matter if we are at end of message or not... */ - dbgprintf("error: message received is larger than max msg size, we split it\n"); + DBGPRINTF("error: message received is larger than max msg size, we split it\n"); defaultDoSubmitMessage(pThis, stTime, ttGenTime, pMultiSub); /* we might think if it is better to ignore the rest of the * message than to treat it as a new one. Maybe this is a good diff --git a/tcpsrv.c b/tcpsrv.c index 0e6e13d2..df5f2a5f 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -596,7 +596,6 @@ processWorksetItem(tcpsrv_t *pThis, nspoll_t *pPoll, int idx, void *pUsr) iRet = SessAccept(pThis, pThis->ppLstnPort[idx], &pNewSess, pThis->ppLstn[idx]); if(iRet == RS_RET_OK) { if(pPoll != NULL) { - dbgprintf("XXXXXX: processWorksetItem trying nspoll.ctl\n"); CHKiRet(nspoll.Ctl(pPoll, pNewSess->pStrm, 0, pNewSess, NSDPOLL_IN, NSDPOLL_ADD)); } DBGPRINTF("New session created with NSD %p.\n", pNewSess); @@ -661,7 +660,7 @@ processWorkset(tcpsrv_t *pThis, nspoll_t *pPoll, int numEntries, nsd_epworkset_t int origEntries = numEntries; DEFiRet; - dbgprintf("tcpsrv: ready to process %d event entries\n", numEntries); + DBGPRINTF("tcpsrv: ready to process %d event entries\n", numEntries); while(numEntries > 0) { if(glbl.GetGlobalInputTermState() == 1) @@ -862,21 +861,21 @@ Run(tcpsrv_t *pThis) } if(localRet != RS_RET_OK) { /* fall back to select */ - dbgprintf("tcpsrv could not use epoll() interface, iRet=%d, using select()\n", localRet); + DBGPRINTF("tcpsrv could not use epoll() interface, iRet=%d, using select()\n", localRet); iRet = RunSelect(pThis, workset, sizeof(workset)/sizeof(nsd_epworkset_t)); FINALIZE; } - dbgprintf("tcpsrv uses epoll() interface, nsdpoll driver found\n"); + DBGPRINTF("tcpsrv uses epoll() interface, nsdpoll driver found\n"); /* flag that we are in epoll mode */ pThis->bUsingEPoll = TRUE; /* Add the TCP listen sockets to the list of sockets to monitor */ for(i = 0 ; i < pThis->iLstnCurr ; ++i) { - dbgprintf("Trying to add listener %d, pUsr=%p\n", i, pThis->ppLstn); + DBGPRINTF("Trying to add listener %d, pUsr=%p\n", i, pThis->ppLstn); CHKiRet(nspoll.Ctl(pPoll, pThis->ppLstn[i], i, pThis->ppLstn, NSDPOLL_IN, NSDPOLL_ADD)); - dbgprintf("Added listener %d\n", i); + DBGPRINTF("Added listener %d\n", i); } while(1) { @@ -1064,7 +1063,7 @@ static rsRetVal SetKeepAlive(tcpsrv_t *pThis, int iVal) { DEFiRet; - dbgprintf("tcpsrv: keep-alive set to %d\n", iVal); + DBGPRINTF("tcpsrv: keep-alive set to %d\n", iVal); pThis->bUseKeepAlive = iVal; RETiRet; } diff --git a/tools/pmrfc3164.c b/tools/pmrfc3164.c index 2657780d..bcded428 100644 --- a/tools/pmrfc3164.c +++ b/tools/pmrfc3164.c @@ -79,7 +79,7 @@ BEGINparse uchar bufParseTAG[CONF_TAG_MAXSIZE]; uchar bufParseHOSTNAME[CONF_HOSTNAME_MAXSIZE]; CODESTARTparse - dbgprintf("Message will now be parsed by the legacy syslog parser (one size fits all... ;)).\n"); + DBGPRINTF("Message will now be parsed by the legacy syslog parser (one size fits all... ;)).\n"); assert(pMsg != NULL); assert(pMsg->pszRawMsg != NULL); lenMsg = pMsg->iLenRawMsg - pMsg->offAfterPRI; /* note: offAfterPRI is already the number of PRI chars (do not add one!) */ @@ -229,7 +229,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(parser, CORE_COMPONENT)); CHKiRet(objUse(datetime, CORE_COMPONENT)); - dbgprintf("rfc3164 parser init called\n"); + DBGPRINTF("rfc3164 parser init called\n"); bParseHOSTNAMEandTAG = glbl.GetParseHOSTNAMEandTAG(); /* cache value, is set only during rsyslogd option processing */ -- cgit v1.2.3 From cbff73d94c3a86ed74294fe1265dc5242f9317be Mon Sep 17 00:00:00 2001 From: David Kelly Date: Tue, 29 May 2012 13:05:59 +0200 Subject: added new-style zeromq plugins, based on czmq api and rsyslog v6 conf --- Makefile.am | 8 + configure.ac | 42 +++ plugins/impstats/impstats.c | 11 +- plugins/imzmq3/Makefile.am | 8 + plugins/imzmq3/imzmq3.c | 651 ++++++++++++++++++++++++++++++++++++++++++++ plugins/omzmq3/Makefile.am | 8 + plugins/omzmq3/omzmq3.c | 460 +++++++++++++++++++++++++++++++ runtime/statsobj.c | 12 +- runtime/statsobj.h | 3 +- 9 files changed, 1198 insertions(+), 5 deletions(-) create mode 100644 plugins/imzmq3/Makefile.am create mode 100644 plugins/imzmq3/imzmq3.c create mode 100644 plugins/omzmq3/Makefile.am create mode 100644 plugins/omzmq3/omzmq3.c diff --git a/Makefile.am b/Makefile.am index 999404e7..4cefb756 100644 --- a/Makefile.am +++ b/Makefile.am @@ -158,6 +158,14 @@ if ENABLE_OMHIREDIS SUBDIRS += plugins/omhiredis endif +if ENABLE_OMZMQ3 +SUBDIRS += plugins/omzmq3 +endif + +if ENABLE_IMZMQ3 +SUBDIRS += plugins/imzmq3 +endif + if ENABLE_OMUXSOCK SUBDIRS += plugins/omuxsock endif diff --git a/configure.ac b/configure.ac index 0d41572c..cee453db 100644 --- a/configure.ac +++ b/configure.ac @@ -1269,6 +1269,44 @@ fi AM_CONDITIONAL(ENABLE_OMMONGODB, test x$enable_ommongodb = xyes) # end of mongodb code +# BEGIN ZMQ3 INPUT SUPPORT +AC_ARG_ENABLE(imzmq3, + [AS_HELP_STRING([--enable-imzmq3],[Compiles imzmq3 output module @<:@default=no@:>@])], + [case "${enableval}" in + yes) enable_imzmq3="yes" ;; + no) enable_imzmq3="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-imzmq3) ;; + esac], + [enable_imzmq3=no] +) +if test "x$enable_imzmq3" = "xyes"; then + PKG_CHECK_MODULES(CZMQ, libczmq >= 1.1.0) + AC_SUBST(CZMQ_CFLAGS) + AC_SUBST(CZMQ_LIBS) +fi +AM_CONDITIONAL(ENABLE_IMZMQ3, test x$enable_imzmq3 = xyes) + +# END ZMQ3 INPUT SUPPORT + +# BEGIN ZMQ3 OUTPUT SUPPORT +AC_ARG_ENABLE(omzmq3, + [AS_HELP_STRING([--enable-omzmq3],[Compiles omzmq3 output module @<:@default=no@:>@])], + [case "${enableval}" in + yes) enable_omzmq3="yes" ;; + no) enable_omzmq3="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-omzmq3) ;; + esac], + [enable_omzmq3=no] +) +if test "x$enable_omzmq3" = "xyes"; then + PKG_CHECK_MODULES(CZMQ, libczmq >= 1.1.0) + AC_SUBST(CZMQ_CFLAGS) + AC_SUBST(CZMQ_LIBS) +fi +AM_CONDITIONAL(ENABLE_OMZMQ3, test x$enable_omzmq3 = xyes) + +# END ZMQ3 SUPPORT + # HIREDIS SUPPORT AC_ARG_ENABLE(omhiredis, @@ -1319,6 +1357,7 @@ AC_CONFIG_FILES([Makefile \ plugins/impstats/Makefile \ plugins/imrelp/Makefile \ plugins/imdiag/Makefile \ + plugins/imzmq3/Makefile \ plugins/omtesting/Makefile \ plugins/omgssapi/Makefile \ plugins/ommysql/Makefile \ @@ -1331,6 +1370,7 @@ AC_CONFIG_FILES([Makefile \ plugins/omudpspoof/Makefile \ plugins/ommongodb/Makefile \ plugins/omhiredis/Makefile \ + plugins/omzmq3/Makefile \ plugins/mmnormalize/Makefile \ plugins/mmjsonparse/Makefile \ plugins/mmaudit/Makefile \ @@ -1363,6 +1403,7 @@ echo " imdiag enabled: $enable_imdiag" echo " file input module enabled: $enable_imfile" echo " Solaris input module enabled: $enable_imsolaris" echo " periodic statistics module enabled: $enable_impstats" +echo " imzmq3 input module enabled: $enable_imzmq3" echo echo "---{ output plugins }---" echo " Mail support enabled: $enable_mail" @@ -1373,6 +1414,7 @@ echo " omelasticsearch module will be compiled: $enable_elasticsearch" echo " omruleset module will be compiled: $enable_omruleset" echo " omudpspoof module will be compiled: $enable_omudpspoof" echo " omuxsock module will be compiled: $enable_omuxsock" +echo " omzmq3 module will be compiled: $enable_omzmq3" echo echo "---{ parser modules }---" echo " pmrfc3164sd module will be compiled: $enable_pmrfc3164sd" diff --git a/plugins/impstats/impstats.c b/plugins/impstats/impstats.c index 4fec8e70..0abde84a 100644 --- a/plugins/impstats/impstats.c +++ b/plugins/impstats/impstats.c @@ -59,6 +59,7 @@ typedef struct configSettings_s { int iFacility; int iSeverity; int bJSON; + int bCEE; } configSettings_t; struct modConfData_s { @@ -89,6 +90,7 @@ initConfigSettings(void) cs.iFacility = DEFAULT_FACILITY; cs.iSeverity = DEFAULT_SEVERITY; cs.bJSON = 0; + cs.bCEE = 0; } @@ -157,7 +159,13 @@ CODESTARTendCnfLoad loadModConf->iStatsInterval = cs.iStatsInterval; loadModConf->iFacility = cs.iFacility; loadModConf->iSeverity = cs.iSeverity; - loadModConf->statsFmt = cs.bJSON ? statsFmt_JSON : statsFmt_Legacy; + if (cs.bCEE == 1) { + loadModConf->statsFmt = statsFmt_CEE; + } else if (cs.bJSON == 1) { + loadModConf->statsFmt = statsFmt_JSON; + } else { + loadModConf->statsFmt = statsFmt_Legacy; + } ENDendCnfLoad @@ -259,6 +267,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatfacility", 0, eCmdHdlrInt, NULL, &cs.iFacility, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatseverity", 0, eCmdHdlrInt, NULL, &cs.iSeverity, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatjson", 0, eCmdHdlrBinary, NULL, &cs.bJSON, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatcee", 0, eCmdHdlrBinary, NULL, &cs.bCEE, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(prop.Construct(&pInputName)); diff --git a/plugins/imzmq3/Makefile.am b/plugins/imzmq3/Makefile.am new file mode 100644 index 00000000..f9c84e5d --- /dev/null +++ b/plugins/imzmq3/Makefile.am @@ -0,0 +1,8 @@ +pkglib_LTLIBRARIES = imzmq3.la + +imzmq3_la_SOURCES = imzmq3.c +imzmq3_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(CZMQ_CFLAGS) +imzmq3_la_LDFLAGS = -module -avoid-version +imzmq3_la_LIBADD = $(CZMQ_LIBS) + +EXTRA_DIST = diff --git a/plugins/imzmq3/imzmq3.c b/plugins/imzmq3/imzmq3.c new file mode 100644 index 00000000..0195fd20 --- /dev/null +++ b/plugins/imzmq3/imzmq3.c @@ -0,0 +1,651 @@ +/* imzmq3.c + * + * This input plugin enables rsyslog to read messages from a ZeroMQ + * queue. + * + * Copyright 2012 Talksum, Inc. + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program. If not, see + * . + * + * Author: David Kelly + * + */ + +#include +#include +#include +#include +#include + +#include "rsyslog.h" + +#include "cfsysline.h" +#include "config.h" +#include "dirty.h" +#include "errmsg.h" +#include "glbl.h" +#include "module-template.h" +#include "msg.h" +#include "net.h" +#include "parser.h" +#include "prop.h" +#include "ruleset.h" +#include "srUtils.h" +#include "unicode-helper.h" + +#include + +MODULE_TYPE_INPUT +MODULE_TYPE_NOKEEP + +/* convienent symbols to denote a socket we want to bind + * vs one we want to just connect to + */ +#define ACTION_CONNECT 1 +#define ACTION_BIND 2 + +/* Module static data */ +DEF_IMOD_STATIC_DATA +DEFobjCurrIf(errmsg) +DEFobjCurrIf(glbl) +DEFobjCurrIf(prop) +DEFobjCurrIf(ruleset) + + +/* ---------------------------------------------------------------------------- + * structs to describe sockets + */ +typedef struct _socket_type { + char* name; + int type; +} socket_type; + +// more overkill, but seems nice to be consistent. +typedef struct _socket_action { + char* name; + int action; +} socket_action; + +typedef struct _poller_data { + ruleset_t* ruleset; + thrdInfo_t* thread; +} poller_data; + +typedef struct _socket_info { + int type; + int action; + char* description; + int sndHWM; // if you want more than 2^32 messages, + int rcvHWM; // then pass in 0 (the default). + char* identity; + char** subscriptions; + ruleset_t* ruleset; + int sndBuf; + int rcvBuf; + int linger; + int backlog; + int sndTimeout; + int rcvTimeout; + int maxMsgSize; + int rate; + int recoveryIVL; + int multicastHops; + int reconnectIVL; + int reconnectIVLMax; + int ipv4Only; + int affinity; + +} socket_info; + + +/* ---------------------------------------------------------------------------- + * Static definitions/initializations. + */ +static socket_info* s_socketInfo = NULL; +static size_t s_nitems = 0; +static prop_t * s_namep = NULL; +static zloop_t* s_zloop = NULL; +static int s_io_threads = 1; +static zctx_t* s_context = NULL; +static ruleset_t* s_ruleset = NULL; +static socket_type socketTypes[] = { + {"SUB", ZMQ_SUB }, + {"PULL", ZMQ_PULL }, + {"XSUB", ZMQ_XSUB } +}; + +static socket_action socketActions[] = { + {"BIND", ACTION_BIND}, + {"CONNECT", ACTION_CONNECT}, +}; + + +/* ---------------------------------------------------------------------------- + * Helper functions + */ + +// get the name of a socket type, return the ZMQ_XXX type +// or -1 if not a supported type (see above) +static int getSocketType(char* name) { + int type = -1; + uint i; + + // match name with known socket type + for(i=0; itype = ZMQ_SUB; + info->action = ACTION_BIND; + info->description = NULL; + info->sndHWM = 0; + info->rcvHWM = 0; + info->identity = NULL; + info->subscriptions = NULL; + info->ruleset = NULL; + info->sndBuf = -1; + info->rcvBuf = -1; + info->linger = -1; + info->backlog = -1; + info->sndTimeout = -1; + info->rcvTimeout = -1; + info->maxMsgSize = -1; + info->rate = -1; + info->recoveryIVL = -1; + info->multicastHops = -1; + info->reconnectIVL = -1; + info->reconnectIVLMax = -1; + info->ipv4Only = -1; + info->affinity = -1; + +}; + + +/* The config string should look like: + * "action=AAA,type=TTT,description=DDD,sndHWM=SSS,rcvHWM=RRR,subscribe='xxx',subscribe='yyy'" + * + */ +static rsRetVal parseConfig(char* config, socket_info* info) { + int nsubs = 0; + + char* binding; + char* ptr1; + for (binding = strtok_r(config, ",", &ptr1); + binding != NULL; + binding = strtok_r(NULL, ",", &ptr1)) { + + // Each binding looks like foo=bar + char * sep = strchr(binding, '='); + if (sep == NULL) + { + errmsg.LogError(0, NO_ERRCODE, + "Invalid argument format %s, ignoring ...", + binding); + continue; + } + + // Replace '=' with '\0'. + *sep = '\0'; + + char * val = sep + 1; + + if (strcmp(binding, "action") == 0) { + info->action = getSocketAction(val); + } else if (strcmp(binding, "type") == 0) { + info->type = getSocketType(val); + } else if (strcmp(binding, "description") == 0) { + info->description = strdup(val); + } else if (strcmp(binding, "sndHWM") == 0) { + info->sndHWM = atoi(val); + } else if (strcmp(binding, "rcvHWM") == 0) { + info->sndHWM = atoi(val); + } else if (strcmp(binding, "subscribe") == 0) { + // Add the subscription value to the list. + char * substr = NULL; + substr = strdup(val); + info->subscriptions = realloc(info->subscriptions, sizeof(char *) * nsubs + 1); + info->subscriptions[nsubs] = substr; + ++nsubs; + } else if (strcmp(binding, "sndBuf") == 0) { + info->sndBuf = atoi(val); + } else if (strcmp(binding, "rcvBuf") == 0) { + info->rcvBuf = atoi(val); + } else if (strcmp(binding, "linger") == 0) { + info->linger = atoi(val); + } else if (strcmp(binding, "backlog") == 0) { + info->backlog = atoi(val); + } else if (strcmp(binding, "sndTimeout") == 0) { + info->sndTimeout = atoi(val); + } else if (strcmp(binding, "rcvTimeout") == 0) { + info->rcvTimeout = atoi(val); + } else if (strcmp(binding, "maxMsgSize") == 0) { + info->maxMsgSize = atoi(val); + } else if (strcmp(binding, "rate") == 0) { + info->rate = atoi(val); + } else if (strcmp(binding, "recoveryIVL") == 0) { + info->recoveryIVL = atoi(val); + } else if (strcmp(binding, "multicastHops") == 0) { + info->multicastHops = atoi(val); + } else if (strcmp(binding, "reconnectIVL") == 0) { + info->reconnectIVL = atoi(val); + } else if (strcmp(binding, "reconnectIVLMax") == 0) { + info->reconnectIVLMax = atoi(val); + } else if (strcmp(binding, "ipv4Only") == 0) { + info->ipv4Only = atoi(val); + } else if (strcmp(binding, "affinity") == 0) { + info->affinity = atoi(val); + } else { + errmsg.LogError(0, NO_ERRCODE, "Unknown argument %s", binding); + return RS_RET_INVALID_PARAMS; + } + } + + return RS_RET_OK; +} + +static rsRetVal validateConfig(socket_info* info) { + + if (info->type == -1) { + errmsg.LogError(0, RS_RET_INVALID_PARAMS, + "you entered an invalid type"); + return RS_RET_INVALID_PARAMS; + } + if (info->action == -1) { + errmsg.LogError(0, RS_RET_INVALID_PARAMS, + "you entered an invalid action"); + return RS_RET_INVALID_PARAMS; + } + if (info->description == NULL) { + errmsg.LogError(0, RS_RET_INVALID_PARAMS, + "you didn't enter a description"); + return RS_RET_INVALID_PARAMS; + } + if(info->type == ZMQ_SUB && info->subscriptions == NULL) { + errmsg.LogError(0, RS_RET_INVALID_PARAMS, + "SUB sockets need at least one subscription"); + return RS_RET_INVALID_PARAMS; + } + if(info->type != ZMQ_SUB && info->subscriptions != NULL) { + errmsg.LogError(0, RS_RET_INVALID_PARAMS, + "only SUB sockets can have subscriptions"); + return RS_RET_INVALID_PARAMS; + } + return RS_RET_OK; +} + +static rsRetVal createContext() { + if (s_context == NULL) { + errmsg.LogError(0, NO_ERRCODE, "creating zctx."); + s_context = zctx_new(); + + if (s_context == NULL) { + errmsg.LogError(0, RS_RET_INVALID_PARAMS, + "zctx_new failed: %s", + strerror(errno)); + // DK: really should do better than invalid params... + return RS_RET_INVALID_PARAMS; + } + + if (s_io_threads > 1) { + errmsg.LogError(0, NO_ERRCODE, "setting io worker threads to %d", s_io_threads); + zctx_set_iothreads(s_context, s_io_threads); + } + } + return RS_RET_OK; +} + +static rsRetVal createSocket(socket_info* info, void** sock) { + size_t ii; + int rv; + + *sock = zsocket_new(s_context, info->type); + if (!sock) { + errmsg.LogError(0, + RS_RET_INVALID_PARAMS, + "zsocket_new failed: %s, for type %d", + strerror(errno),info->type); + // DK: invalid params seems right here. + return RS_RET_INVALID_PARAMS; + } + + // Set options *before* the connect/bind. + if (info->identity) zsocket_set_identity(*sock, info->identity); + if (info->sndBuf > -1) zsocket_set_sndbuf(*sock, info->sndBuf); + if (info->rcvBuf > -1) zsocket_set_rcvbuf(*sock, info->rcvBuf); + if (info->linger > -1) zsocket_set_linger(*sock, info->linger); + if (info->backlog > -1) zsocket_set_backlog(*sock, info->backlog); + if (info->sndTimeout > -1) zsocket_set_sndtimeo(*sock, info->sndTimeout); + if (info->rcvTimeout > -1) zsocket_set_rcvtimeo(*sock, info->rcvTimeout); + if (info->maxMsgSize > -1) zsocket_set_maxmsgsize(*sock, info->maxMsgSize); + if (info->rate > -1) zsocket_set_rate(*sock, info->rate); + if (info->recoveryIVL > -1) zsocket_set_recovery_ivl(*sock, info->recoveryIVL); + if (info->multicastHops > -1) zsocket_set_multicast_hops(*sock, info->multicastHops); + if (info->reconnectIVL > -1) zsocket_set_reconnect_ivl(*sock, info->reconnectIVL); + if (info->reconnectIVLMax > -1) zsocket_set_reconnect_ivl_max(*sock, info->reconnectIVLMax); + if (info->ipv4Only > -1) zsocket_set_ipv4only(*sock, info->ipv4Only); + if (info->affinity > -1) zsocket_set_affinity(*sock, info->affinity); + + // since HWM have defaults, we always set them. No return codes to check, either. + zsocket_set_sndhwm(*sock, info->sndHWM); + zsocket_set_rcvhwm(*sock, info->rcvHWM); + + // Set subscriptions. + for (ii = 0; ii < sizeof(info->subscriptions)/sizeof(char*); ++ii) + zsocket_set_subscribe(*sock, info->subscriptions[ii]); + + + + // Do the bind/connect... + if (info->action==ACTION_CONNECT) { + rv = zsocket_connect(*sock, info->description); + if (rv < 0) { + errmsg.LogError(0, + RS_RET_INVALID_PARAMS, + "zmq_connect using %s failed: %s", + info->description, strerror(errno)); + return RS_RET_INVALID_PARAMS; + } + } else { + rv = zsocket_bind(*sock, info->description); + if (rv <= 0) { + errmsg.LogError(0, + RS_RET_INVALID_PARAMS, + "zmq_bind using %s failed: %s", + info->description, strerror(errno)); + return RS_RET_INVALID_PARAMS; + } + } + return RS_RET_OK; +} + +/* ---------------------------------------------------------------------------- + * Module endpoints + */ + +/* accept a new ruleset to bind. Checks if it exists and complains, if not. Note + * that this makes the assumption that after the bind ruleset is called in the config, + * another call will be made to add an endpoint. +*/ +static rsRetVal +set_ruleset(void __attribute__((unused)) *pVal, uchar *pszName) { + ruleset_t* ruleset_ptr; + rsRetVal localRet; + DEFiRet; + + localRet = ruleset.GetRuleset(ourConf, &ruleset_ptr, pszName); + if(localRet == RS_RET_NOT_FOUND) { + errmsg.LogError(0, NO_ERRCODE, "error: " + "ruleset '%s' not found - ignored", pszName); + } + CHKiRet(localRet); + s_ruleset = ruleset_ptr; + DBGPRINTF("imzmq3 current bind ruleset '%s'\n", pszName); + +finalize_it: + free(pszName); /* no longer needed */ + RETiRet; +} + +/* add an actual endpoint + */ +static rsRetVal add_endpoint(void __attribute__((unused)) * oldp, uchar * valp) { + DEFiRet; + + // increment number of items and store old num items, as it will be handy. + size_t idx = s_nitems++; + + // allocate a new socket_info array to accomidate this new endpoint + socket_info* tmpSocketInfo; + CHKmalloc(tmpSocketInfo = (socket_info*)MALLOC(sizeof(socket_info) * s_nitems)); + + // copy existing socket_info across into new array, if any, and free old storage + if(idx) { + memcpy(tmpSocketInfo, s_socketInfo, sizeof(socket_info) * idx); + free(s_socketInfo); + } + + // set the static to hold the new array + s_socketInfo = tmpSocketInfo; + + // point to the new one + socket_info* sockInfo = &s_socketInfo[idx]; + + // set defaults for the new socket info + setDefaults(sockInfo); + + // Make a writeable copy of the string so we can use strtok + // in the parseConfig call + char * copy = NULL; + CHKmalloc(copy = strdup((char *) valp)); + + // parse the config string + CHKiRet(parseConfig(copy, sockInfo)); + + // validate it + CHKiRet(validateConfig(sockInfo)); + + // bind to the current ruleset (if any) + sockInfo->ruleset = s_ruleset; + +finalize_it: + free(valp); /* in any case, this is no longer needed */ + RETiRet; +} + + +static int handlePoll(zloop_t __attribute__((unused)) * loop, zmq_pollitem_t *poller, void* pd) { + msg_t* logmsg; + poller_data* pollerData = (poller_data*)pd; + + char* buf = zstr_recv(poller->socket); + if (msgConstruct(&logmsg) == RS_RET_OK) { + MsgSetRawMsg(logmsg, buf, strlen(buf)); + MsgSetInputName(logmsg, s_namep); + MsgSetFlowControlType(logmsg, eFLOWCTL_NO_DELAY); + MsgSetRuleset(logmsg, pollerData->ruleset); + logmsg->msgFlags = NEEDS_PARSING; + submitMsg(logmsg); + } + + if( pollerData->thread->bShallStop == TRUE) { + // a handler that returns -1 will terminate the + // czmq reactor loop + return -1; + } + + return 0; +} + +/* called when runInput is called by rsyslog + */ +static rsRetVal rcv_loop(thrdInfo_t* pThrd){ + size_t i; + int rv; + zmq_pollitem_t* items; + poller_data* pollerData; + + DEFiRet; + + // create the context + CHKiRet(createContext()); + + // create the poll items + CHKmalloc(items = (zmq_pollitem_t*)MALLOC(sizeof(zmq_pollitem_t)*s_nitems)); + + // create poller data (stuff to pass into the zmq closure called when we get a message) + CHKmalloc(pollerData = (poller_data*)MALLOC(sizeof(poller_data)*s_nitems)); + + // loop through and initialize the poll items and poller_data arrays... + for(i=0; i. +* +* Author: David Kelly +* +*/ + + +#include "config.h" +#include "rsyslog.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "conf.h" +#include "syslogd-types.h" +#include "srUtils.h" +#include "template.h" +#include "module-template.h" +#include "errmsg.h" +#include "cfsysline.h" + +#include + +MODULE_TYPE_OUTPUT +MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omzmq3") + +DEF_OMOD_STATIC_DATA +DEFobjCurrIf(errmsg) + +/* convienent symbols to denote a socket we want to bind +p * vs one we want to just connect to + */ +#define ACTION_CONNECT 1 +#define ACTION_BIND 2 + + +/* ---------------------------------------------------------------------------- + * structs to describe sockets + */ +struct socket_type { + char* name; + int type; +}; + +// more overkill, but seems nice to be consistent. +struct socket_action { + char* name; + int action; +}; + +typedef struct _instanceData { + void* socket; + uchar* description; + int type; + int action; + int sndHWM; + int rcvHWM; + uchar* identity; + int sndBuf; + int rcvBuf; + int linger; + int backlog; + int sndTimeout; + int rcvTimeout; + int maxMsgSize; + int rate; + int recoveryIVL; + int multicastHops; + int reconnectIVL; + int reconnectIVLMax; + int ipv4Only; + int affinity; + uchar* tplName; +} instanceData; + + +/* ---------------------------------------------------------------------------- + * Static definitions/initializations + */ + +// only 1 zctx for all the sockets, with an adjustable number of +// worker threads which may be useful if we use affinity in particular +// sockets +static zctx_t* s_context = NULL; +static int s_workerThreads = -1; + +static struct socket_type types[] = { + {"PUB", ZMQ_PUB }, + {"PUSH", ZMQ_PUSH }, + {"XPUB", ZMQ_XPUB } +}; + +static struct socket_action actions[] = { + {"BIND", ACTION_BIND}, + {"CONNECT", ACTION_CONNECT}, +}; + +static struct cnfparamdescr actpdescr[] = { + { "description", eCmdHdlrGetWord, 0 }, + { "sockType", eCmdHdlrGetWord, 0 }, + { "action", eCmdHdlrGetWord, 0 }, + { "sndHWM", eCmdHdlrInt, 0 }, + { "rcvHWM", eCmdHdlrInt, 0 }, + { "identity", eCmdHdlrGetWord, 0 }, + { "sndBuf", eCmdHdlrInt, 0 }, + { "rcvBuf", eCmdHdlrInt, 0 }, + { "linger", eCmdHdlrInt, 0 }, + { "backlog", eCmdHdlrInt, 0 }, + { "sndTimeout", eCmdHdlrInt, 0 }, + { "rcvTimeout", eCmdHdlrInt, 0 }, + { "maxMsgSize", eCmdHdlrInt, 0 }, + { "rate", eCmdHdlrInt, 0 }, + { "recoveryIVL", eCmdHdlrInt, 0 }, + { "multicastHops", eCmdHdlrInt, 0 }, + { "reconnectIVL", eCmdHdlrInt, 0 }, + { "reconnectIVLMax", eCmdHdlrInt, 0 }, + { "ipv4Only", eCmdHdlrInt, 0 }, + { "affinity", eCmdHdlrInt, 0 }, + { "globalWorkerThreads", eCmdHdlrInt, 0 }, + { "template", eCmdHdlrGetWord, 1 } +}; + +static struct cnfparamblk actpblk = { + CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr +}; + +/* ---------------------------------------------------------------------------- + * Helper Functions + */ + +// get the name of a socket type, return the ZMQ_XXX type +// or -1 if not a supported type (see above) +int getSocketType(char* name) { + int type = -1; + uint i; + for(i=0; isocket) { + if(pData->socket != NULL) { + zsocket_destroy(s_context, pData->socket); + } + } +} + + +static rsRetVal initZMQ(instanceData* pData) { + DEFiRet; + + // create the context if necessary. + if (NULL == s_context) { + s_context = zctx_new(); + if (s_workerThreads > 0) zctx_set_iothreads(s_context, s_workerThreads); + } + + pData->socket = zsocket_new(s_context, pData->type); + + // ALWAYS set the HWM as the zmq3 default is 1000 and we default + // to 0 (infinity) + zsocket_set_rcvhwm(pData->socket, pData->rcvHWM); + zsocket_set_sndhwm(pData->socket, pData->sndHWM); + + // use czmq defaults for these, unless set to non-default values + if(pData->identity) zsocket_set_identity(pData->socket, (char*)pData->identity); + if(pData->sndBuf > -1) zsocket_set_sndbuf(pData->socket, pData->sndBuf); + if(pData->rcvBuf > -1) zsocket_set_sndbuf(pData->socket, pData->rcvBuf); + if(pData->linger > -1) zsocket_set_linger(pData->socket, pData->linger); + if(pData->backlog > -1) zsocket_set_backlog(pData->socket, pData->backlog); + if(pData->sndTimeout > -1) zsocket_set_sndtimeo(pData->socket, pData->sndTimeout); + if(pData->rcvTimeout > -1) zsocket_set_rcvtimeo(pData->socket, pData->rcvTimeout); + if(pData->maxMsgSize > -1) zsocket_set_maxmsgsize(pData->socket, pData->maxMsgSize); + if(pData->rate > -1) zsocket_set_rate(pData->socket, pData->rate); + if(pData->recoveryIVL > -1) zsocket_set_recovery_ivl(pData->socket, pData->recoveryIVL); + if(pData->multicastHops > -1) zsocket_set_multicast_hops(pData->socket, pData->multicastHops); + if(pData->reconnectIVL > -1) zsocket_set_reconnect_ivl(pData->socket, pData->reconnectIVL); + if(pData->reconnectIVLMax > -1) zsocket_set_reconnect_ivl_max(pData->socket, pData->reconnectIVLMax); + if(pData->ipv4Only > -1) zsocket_set_ipv4only(pData->socket, pData->ipv4Only); + if(pData->affinity != 1) zsocket_set_affinity(pData->socket, pData->affinity); + + // bind or connect to it + if (pData->action == ACTION_BIND) { + // bind asserts, so no need to test return val here + // which isn't the greatest api -- oh well + zsocket_bind(pData->socket, (char*)pData->description); + } else { + if(zsocket_connect(pData->socket, (char*)pData->description) == -1) { + errmsg.LogError(0, RS_RET_SUSPENDED, "omzmq3: connect failed!"); + ABORT_FINALIZE(RS_RET_SUSPENDED); + } + } + finalize_it: + RETiRet; +} + +rsRetVal writeZMQ(uchar* msg, instanceData* pData) { + DEFiRet; + + // initialize if necessary + if(NULL == pData->socket) + CHKiRet(initZMQ(pData)); + + // send the shit... + int result = zstr_send(pData->socket, (char*)msg); + + // whine if shit went wrong + if (result == -1) { + errmsg.LogError(0, NO_ERRCODE, "omzmq3: send of %s failed with return %d", msg, result); + ABORT_FINALIZE(RS_RET_ERR); + } + finalize_it: + RETiRet; +} + +static inline void +setInstParamDefaults(instanceData* pData) { + pData->description = (uchar*)"tcp://*:7171"; + pData->socket = NULL; + pData->tplName = NULL; + pData->type = ZMQ_PUB; + pData->action = ACTION_BIND; + pData->sndHWM = 0; // unlimited + pData->rcvHWM = 0; // unlimited + pData->identity = NULL; + pData->sndBuf = -1; + pData->rcvBuf = -1; + pData->linger = -1; + pData->backlog = -1; + pData->sndTimeout = -1; + pData->rcvTimeout = -1; + pData->maxMsgSize = -1; + pData->rate = -1; + pData->recoveryIVL = -1; + pData->multicastHops = -1; + pData->reconnectIVL = -1; + pData->reconnectIVLMax = -1; + pData->ipv4Only = -1; + pData->affinity = 1; +} + + +/* ---------------------------------------------------------------------------- + * Output Module Functions + */ + +BEGINcreateInstance +CODESTARTcreateInstance +ENDcreateInstance + +BEGINisCompatibleWithFeature +CODESTARTisCompatibleWithFeature + if(eFeat == sFEATURERepeatedMsgReduction) + iRet = RS_RET_OK; +ENDisCompatibleWithFeature + + +BEGINdbgPrintInstInfo +CODESTARTdbgPrintInstInfo +ENDdbgPrintInstInfo + +BEGINfreeInstance +CODESTARTfreeInstance + closeZMQ(pData); + free(pData->description); + free(pData->tplName); +ENDfreeInstance + +BEGINtryResume +CODESTARTtryResume + if(NULL == pData->socket) + iRet = initZMQ(pData); +ENDtryResume + +BEGINdoAction +CODESTARTdoAction +iRet = writeZMQ(ppString[0], pData); +ENDdoAction + + +BEGINnewActInst + struct cnfparamvals *pvals; + int i; +CODESTARTnewActInst +if((pvals = nvlstGetParams(lst, &actpblk, NULL)) == NULL) { + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + +CHKiRet(createInstance(&pData)); +setInstParamDefaults(pData); + +CODE_STD_STRING_REQUESTparseSelectorAct(1) +for(i = 0 ; i < actpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(actpblk.descr[i].name, "description")) { + pData->description = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "template")) { + pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "sockType")){ + pData->type = getSocketType(es_str2cstr(pvals[i].val.d.estr, NULL)); + } else if(!strcmp(actpblk.descr[i].name, "action")){ + pData->action = getSocketAction(es_str2cstr(pvals[i].val.d.estr, NULL)); + } else if(!strcmp(actpblk.descr[i].name, "sndHWM")) { + pData->sndHWM = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "rcvHWM")) { + pData->rcvHWM = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "identity")){ + pData->identity = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "sndBuf")) { + pData->sndBuf = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "rcvBuf")) { + pData->rcvBuf = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "linger")) { + pData->linger = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "backlog")) { + pData->backlog = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "sndTimeout")) { + pData->sndTimeout = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "rcvTimeout")) { + pData->rcvTimeout = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "maxMsgSize")) { + pData->maxMsgSize = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "rate")) { + pData->rate = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "recoveryIVL")) { + pData->recoveryIVL = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "multicastHops")) { + pData->multicastHops = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "reconnectIVL")) { + pData->reconnectIVL = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "reconnectIVLMax")) { + pData->reconnectIVLMax = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "ipv4Only")) { + pData->ipv4Only = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "affinity")) { + pData->affinity = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "globalWorkerThreads")) { + s_workerThreads = (int) pvals[i].val.d.n, NULL; + } else { + errmsg.LogError(0, NO_ERRCODE, "omzmq3: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + +if(pData->tplName == NULL) { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, NULL, OMSR_TPL_AS_MSG)); + } else { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, (uchar*)pData->tplName, OMSR_NO_RQD_TPL_OPTS)); + } + +if(pData->type == -1) { + errmsg.LogError(0, RS_RET_CONFIG_ERROR, "omzmq3: unknown socket type."); + ABORT_FINALIZE(RS_RET_CONFIG_ERROR); + } +if(pData->action == -1) { + errmsg.LogError(0, RS_RET_CONFIG_ERROR, "omzmq3: unknown socket action"); + ABORT_FINALIZE(RS_RET_CONFIG_ERROR); + } + + +CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + +BEGINparseSelectorAct +CODESTARTparseSelectorAct + +/* tell the engine we only want one template string */ +CODE_STD_STRING_REQUESTparseSelectorAct(1) + if(!strncmp((char*) p, ":omzmq3:", sizeof(":omzmq3:") - 1)) + errmsg.LogError(0, RS_RET_LEGA_ACT_NOT_SUPPORTED, + "omzmq3 supports only v6 config format, use: " + "action(type=\"omzmq3\" serverport=...)"); + ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); +CODE_STD_FINALIZERparseSelectorAct +ENDparseSelectorAct + +BEGINinitConfVars /* (re)set config variables to defaults */ +CODESTARTinitConfVars +s_workerThreads = -1; +ENDinitConfVars + +BEGINmodExit +CODESTARTmodExit +if(NULL != s_context) { + zctx_destroy(&s_context); + s_context=NULL; + } +ENDmodExit + + +BEGINqueryEtryPt +CODESTARTqueryEtryPt +CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES +ENDqueryEtryPt + +BEGINmodInit() +CODESTARTmodInit + *ipIFVersProvided = CURR_MOD_IF_VERSION; /* only supports rsyslog 6 configs */ +CODEmodInit_QueryRegCFSLineHdlr + CHKiRet(objUse(errmsg, CORE_COMPONENT)); + INITChkCoreFeature(bCoreSupportsBatching, CORE_FEATURE_BATCHING); + DBGPRINTF("omzmq3: module compiled with rsyslog version %s.\n", VERSION); + +INITLegCnfVars +CHKiRet(omsdRegCFSLineHdlr((uchar *)"omzmq3workerthreads", 0, eCmdHdlrInt, NULL, &s_workerThreads, STD_LOADABLE_MODULE_ID)); +ENDmodInit + + + diff --git a/runtime/statsobj.c b/runtime/statsobj.c index a21614f6..25275616 100644 --- a/runtime/statsobj.c +++ b/runtime/statsobj.c @@ -168,15 +168,18 @@ finalize_it: /* get all the object's countes together as CEE. */ static rsRetVal -getStatsLineCEE(statsobj_t *pThis, cstr_t **ppcstr) +getStatsLineCEE(statsobj_t *pThis, cstr_t **ppcstr, int cee_cookie) { cstr_t *pcstr; ctr_t *pCtr; DEFiRet; CHKiRet(cstrConstruct(&pcstr)); - rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT("@cee: {"), 7); + if (cee_cookie == 1) + rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT("@cee: "), 6); + + rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT("{"), 1); rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT("\""), 1); rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT("name"), 4); rsCStrAppendStrWithLen(pcstr, UCHAR_CONSTANT("\""), 1); @@ -273,8 +276,11 @@ getAllStatsLines(rsRetVal(*cb)(void*, cstr_t*), void *usrptr, statsFmtType_t fmt case statsFmt_Legacy: CHKiRet(getStatsLine(o, &cstr)); break; + case statsFmt_CEE: + CHKiRet(getStatsLineCEE(o, &cstr, 1)); + break; case statsFmt_JSON: - CHKiRet(getStatsLineCEE(o, &cstr)); + CHKiRet(getStatsLineCEE(o, &cstr, 0)); break; } CHKiRet(cb(usrptr, cstr)); diff --git a/runtime/statsobj.h b/runtime/statsobj.h index f7de68ee..14b33215 100644 --- a/runtime/statsobj.h +++ b/runtime/statsobj.h @@ -46,7 +46,8 @@ typedef enum statsCtrType_e { /* stats line format types */ typedef enum statsFmtType_e { statsFmt_Legacy, - statsFmt_JSON + statsFmt_JSON, + statsFmt_CEE } statsFmtType_t; -- cgit v1.2.3 From 09c96a4f4ccb077fd49139980bf6962f162c680b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 31 May 2012 18:02:10 +0200 Subject: imrelp now supports non-cancel thread termination (but now requires at least librelp 1.0.1) --- ChangeLog | 2 ++ configure.ac | 2 +- plugins/imrelp/imrelp.c | 39 ++++++++++++++++++++++++++++++++++++--- runtime/rsconf.c | 3 ++- 4 files changed, 41 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 01268200..8403d549 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ --------------------------------------------------------------------------- Version 6.5.0 [devel] 2012-0?-?? +- imrelp now supports non-cancel thread termination + (but now requires at least librelp 1.0.1) - added --enable-debugless configure option for very high demanding envs This actually at compile time disables a lot of debug code, resulting in some speedup (but serious loss of debugging capabilities) diff --git a/configure.ac b/configure.ac index 0d41572c..952d64cd 100644 --- a/configure.ac +++ b/configure.ac @@ -916,7 +916,7 @@ AC_ARG_ENABLE(relp, [enable_relp=no] ) if test "x$enable_relp" = "xyes"; then - PKG_CHECK_MODULES(RELP, relp >= 0.1.1) + PKG_CHECK_MODULES(RELP, relp >= 1.0.1) fi AM_CONDITIONAL(ENABLE_RELP, test x$enable_relp = xyes) AC_SUBST(RELP_CFLAGS) diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c index 99fabd18..f6040b21 100644 --- a/plugins/imrelp/imrelp.c +++ b/plugins/imrelp/imrelp.c @@ -22,7 +22,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "config.h" #include #include @@ -35,6 +34,7 @@ #include #include #include +#include #include #include "rsyslog.h" #include "dirty.h" @@ -236,13 +236,39 @@ BEGINfreeCnf CODESTARTfreeCnf ENDfreeCnf +/* This is used to terminate the plugin. Note that the signal handler blocks + * other activity on the thread. As such, it is safe to request the stop. When + * we terminate, relpEngine is called, and it's select() loop interrupted. But + * only *after this function is done*. So we do not have a race! + */ +static void +doSIGTTIN(int __attribute__((unused)) sig) +{ + DBGPRINTF("imrelp: termination requested via SIGTTIN - telling RELP engine\n"); + relpEngineSetStop(pRelpEngine); +} + + /* This function is called to gather input. */ BEGINrunInput + sigset_t sigSet; + struct sigaction sigAct; CODESTARTrunInput - /* TODO: we must be careful to start the listener here. Currently, tcpsrv.c seems to - * do that in ConstructFinalize + /* we want to support non-cancel input termination. To do so, we must signal librelp + * when to stop. As we run on the same thread, we need to register as SIGTTIN handler, + * which will be used to put the terminating condition into librelp. */ + sigfillset(&sigSet); + pthread_sigmask(SIG_BLOCK, &sigSet, NULL); + sigemptyset(&sigSet); + sigaddset(&sigSet, SIGTTIN); + pthread_sigmask(SIG_UNBLOCK, &sigSet, NULL); + memset(&sigAct, 0, sizeof (sigAct)); + sigemptyset(&sigAct.sa_mask); + sigAct.sa_handler = doSIGTTIN; + sigaction(SIGTTIN, &sigAct, NULL); + iRet = relpEngineRun(pRelpEngine); ENDrunInput @@ -284,12 +310,19 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus } +BEGINisCompatibleWithFeature +CODESTARTisCompatibleWithFeature + if(eFeat == sFEATURENonCancelInputTermination) + iRet = RS_RET_OK; +ENDisCompatibleWithFeature + BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES +CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 460e69d6..fca4f9b8 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -685,9 +685,10 @@ runInputModules(void) node = module.GetNxtCnfType(runConf, NULL, eMOD_IN); while(node != NULL) { if(node->canRun) { - DBGPRINTF("running module %s with config %p\n", node->pMod->pszName, node); bNeedsCancel = (node->pMod->isCompatibleWithFeature(sFEATURENonCancelInputTermination) == RS_RET_OK) ? 0 : 1; + DBGPRINTF("running module %s with config %p, term mode: %s\n", node->pMod->pszName, node, + bNeedsCancel ? "cancel" : "cooperative/SIGTTIN"); thrdCreate(node->pMod->mod.im.runInput, node->pMod->mod.im.afterRun, bNeedsCancel, (node->pMod->cnfName == NULL) ? node->pMod->pszName : node->pMod->cnfName); } -- cgit v1.2.3 From 1498c2701301fadc6f902208068fc959c8673322 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 1 Jun 2012 17:36:11 +0200 Subject: change action queue default enqueue timeout from 2000ms to 50ms --- action.c | 2 +- doc/v6compatibility.html | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/action.c b/action.c index bcefe9e9..652c0259 100644 --- a/action.c +++ b/action.c @@ -262,7 +262,7 @@ actionResetQueueParams(void) cs.bActionQSyncQeueFiles = 0; cs.iActionQtoQShutdown = 0; /* queue shutdown */ cs.iActionQtoActShutdown = 1000; /* action shutdown (in phase 2) */ - cs.iActionQtoEnq = 2000; /* timeout for queue enque */ + cs.iActionQtoEnq = 50; /* timeout for queue enque */ cs.iActionQtoWrkShutdown = 60000; /* timeout for worker thread shutdown */ cs.iActionQWrkMinMsgs = 100; /* minimum messages per worker needed to start a new one */ cs.bActionQSaveOnShutdown = 1; /* save queue on shutdown (when DA enabled)? */ diff --git a/doc/v6compatibility.html b/doc/v6compatibility.html index 1f830854..058ab4f1 100644 --- a/doc/v6compatibility.html +++ b/doc/v6compatibility.html @@ -112,6 +112,15 @@ to spot why things went wrong (and if at all).

Due to their positive effect on performance and comparatively low overhead, default batch sizes have been increased. Starting with 6.3.4, the action queues have a default batch size of 128 messages. +

Default action queue enqueue timeout

+

This timeout previously was 2seconds, and has been reduced to 50ms (starting with 6.5.0). This change +was made as a long timeout will caused delays in the associated main queue, something +that was quite unexpected to users. Now, this can still happen, but the effect is much +less harsh (but still considerable on a busy system). Also, 50ms should be fairly enough +for most output sources, except when they are really broken (like network disconnect). If +they are really broken, even a 2second timeout does not help, so we hopefully get the best +of both worlds with the new timeout. A specific timeout can of course still be configured, +it is just the timeout that changed.

outchannels

Outchannels are a to-be-removed feature of rsyslog, at least as far as the config syntax is concerned. Nevertheless, v6 still supports it, but a new syntax is required -- cgit v1.2.3 From d886dd979ebc94b45eb31255a24d49316dfcf6d0 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 31 May 2012 15:25:00 -0700 Subject: Minor updates * C++ style comments converted to c-style * copy/paste error (benign I believe) in omzmq3 fixed * added readme files for both imzmq3 and omzmq3 --- plugins/imzmq3/README | 24 +++++++++++++++ plugins/imzmq3/imzmq3.c | 78 +++++++++++++++++++++++++------------------------ plugins/omzmq3/README | 25 ++++++++++++++++ plugins/omzmq3/omzmq3.c | 76 ++++++++++++++++++++++++----------------------- 4 files changed, 128 insertions(+), 75 deletions(-) create mode 100644 plugins/imzmq3/README create mode 100644 plugins/omzmq3/README diff --git a/plugins/imzmq3/README b/plugins/imzmq3/README new file mode 100644 index 00000000..88653b83 --- /dev/null +++ b/plugins/imzmq3/README @@ -0,0 +1,24 @@ +ZeroMQ 3.x Input Plugin + +Building this plugin: +Requires libzmq and libczmq. First, install libzmq from the HEAD on github: +http://github.com/zeromq/libzmq. You can clone the repository, build, then +install it. The directions for doing so are there in the readme. Then, do +the same for libczmq: http://github.com/zeromq/czmq. At some point, the 3.1 +version of libzmq will be released, and a supporting version of libczmq. +At that time, you could simply download and install the tarballs instead of +using git to clone the repositories. Those tarballs (when available) can +be found at http://download.zeromq.org. As of this writing (5/31/2012), the +most recent version of czmq (1.1.0) and libzmq (3.1.0-beta) will not compile +properly. + +Imzmq3 allows you to push data into rsyslog from a zeromq socket. The example +below binds a SUB socket to port 7172, and then any messages with the topic +"foo" will be pushed into rsyslog. + +Example Rsyslog.conf snippet: +------------------------------------------------------------------------------- + +$InputZmq3ServerRun action=BIND,type=SUB,description=tcp://*:7172,subscribe=foo + +------------------------------------------------------------------------------- diff --git a/plugins/imzmq3/imzmq3.c b/plugins/imzmq3/imzmq3.c index 0195fd20..78eee887 100644 --- a/plugins/imzmq3/imzmq3.c +++ b/plugins/imzmq3/imzmq3.c @@ -72,7 +72,7 @@ typedef struct _socket_type { int type; } socket_type; -// more overkill, but seems nice to be consistent. +/* more overkill, but seems nice to be consistent.*/ typedef struct _socket_action { char* name; int action; @@ -87,8 +87,8 @@ typedef struct _socket_info { int type; int action; char* description; - int sndHWM; // if you want more than 2^32 messages, - int rcvHWM; // then pass in 0 (the default). + int sndHWM; /* if you want more than 2^32 messages, */ + int rcvHWM; /* then pass in 0 (the default). */ char* identity; char** subscriptions; ruleset_t* ruleset; @@ -136,13 +136,14 @@ static socket_action socketActions[] = { * Helper functions */ -// get the name of a socket type, return the ZMQ_XXX type -// or -1 if not a supported type (see above) +/* get the name of a socket type, return the ZMQ_XXX type + or -1 if not a supported type (see above) +*/ static int getSocketType(char* name) { int type = -1; uint i; - // match name with known socket type + /* match name with known socket type */ for(i=0; isndHWM = atoi(val); } else if (strcmp(binding, "subscribe") == 0) { - // Add the subscription value to the list. + /* Add the subscription value to the list.*/ char * substr = NULL; substr = strdup(val); info->subscriptions = realloc(info->subscriptions, sizeof(char *) * nsubs + 1); @@ -326,7 +327,7 @@ static rsRetVal createContext() { errmsg.LogError(0, RS_RET_INVALID_PARAMS, "zctx_new failed: %s", strerror(errno)); - // DK: really should do better than invalid params... + /* DK: really should do better than invalid params...*/ return RS_RET_INVALID_PARAMS; } @@ -348,11 +349,11 @@ static rsRetVal createSocket(socket_info* info, void** sock) { RS_RET_INVALID_PARAMS, "zsocket_new failed: %s, for type %d", strerror(errno),info->type); - // DK: invalid params seems right here. + /* DK: invalid params seems right here */ return RS_RET_INVALID_PARAMS; } - // Set options *before* the connect/bind. + /* Set options *before* the connect/bind. */ if (info->identity) zsocket_set_identity(*sock, info->identity); if (info->sndBuf > -1) zsocket_set_sndbuf(*sock, info->sndBuf); if (info->rcvBuf > -1) zsocket_set_rcvbuf(*sock, info->rcvBuf); @@ -369,17 +370,17 @@ static rsRetVal createSocket(socket_info* info, void** sock) { if (info->ipv4Only > -1) zsocket_set_ipv4only(*sock, info->ipv4Only); if (info->affinity > -1) zsocket_set_affinity(*sock, info->affinity); - // since HWM have defaults, we always set them. No return codes to check, either. + /* since HWM have defaults, we always set them. No return codes to check, either.*/ zsocket_set_sndhwm(*sock, info->sndHWM); zsocket_set_rcvhwm(*sock, info->rcvHWM); - // Set subscriptions. + /* Set subscriptions.*/ for (ii = 0; ii < sizeof(info->subscriptions)/sizeof(char*); ++ii) zsocket_set_subscribe(*sock, info->subscriptions[ii]); - // Do the bind/connect... + /* Do the bind/connect... */ if (info->action==ACTION_CONNECT) { rv = zsocket_connect(*sock, info->description); if (rv < 0) { @@ -435,40 +436,40 @@ finalize_it: static rsRetVal add_endpoint(void __attribute__((unused)) * oldp, uchar * valp) { DEFiRet; - // increment number of items and store old num items, as it will be handy. + /* increment number of items and store old num items, as it will be handy.*/ size_t idx = s_nitems++; - // allocate a new socket_info array to accomidate this new endpoint + /* allocate a new socket_info array to accomidate this new endpoint*/ socket_info* tmpSocketInfo; CHKmalloc(tmpSocketInfo = (socket_info*)MALLOC(sizeof(socket_info) * s_nitems)); - // copy existing socket_info across into new array, if any, and free old storage + /* copy existing socket_info across into new array, if any, and free old storage*/ if(idx) { memcpy(tmpSocketInfo, s_socketInfo, sizeof(socket_info) * idx); free(s_socketInfo); } - // set the static to hold the new array + /* set the static to hold the new array */ s_socketInfo = tmpSocketInfo; - // point to the new one + /* point to the new one */ socket_info* sockInfo = &s_socketInfo[idx]; - // set defaults for the new socket info + /* set defaults for the new socket info */ setDefaults(sockInfo); - // Make a writeable copy of the string so we can use strtok - // in the parseConfig call + /* Make a writeable copy of the string so we can use strtok + in the parseConfig call */ char * copy = NULL; CHKmalloc(copy = strdup((char *) valp)); - // parse the config string + /* parse the config string */ CHKiRet(parseConfig(copy, sockInfo)); - // validate it + /* validate it */ CHKiRet(validateConfig(sockInfo)); - // bind to the current ruleset (if any) + /* bind to the current ruleset (if any)*/ sockInfo->ruleset = s_ruleset; finalize_it: @@ -492,8 +493,9 @@ static int handlePoll(zloop_t __attribute__((unused)) * loop, zmq_pollitem_t *po } if( pollerData->thread->bShallStop == TRUE) { - // a handler that returns -1 will terminate the - // czmq reactor loop + /* a handler that returns -1 will terminate the + czmq reactor loop + */ return -1; } @@ -510,22 +512,22 @@ static rsRetVal rcv_loop(thrdInfo_t* pThrd){ DEFiRet; - // create the context + /* create the context*/ CHKiRet(createContext()); - // create the poll items + /* create the poll items*/ CHKmalloc(items = (zmq_pollitem_t*)MALLOC(sizeof(zmq_pollitem_t)*s_nitems)); - // create poller data (stuff to pass into the zmq closure called when we get a message) + /* create poller data (stuff to pass into the zmq closure called when we get a message)*/ CHKmalloc(pollerData = (poller_data*)MALLOC(sizeof(poller_data)*s_nitems)); - // loop through and initialize the poll items and poller_data arrays... + /* loop through and initialize the poll items and poller_data arrays...*/ for(i=0; itplName = NULL; pData->type = ZMQ_PUB; pData->action = ACTION_BIND; - pData->sndHWM = 0; // unlimited - pData->rcvHWM = 0; // unlimited + pData->sndHWM = 0; /*unlimited*/ + pData->rcvHWM = 0; /*unlimited*/ pData->identity = NULL; pData->sndBuf = -1; pData->rcvBuf = -1; @@ -350,41 +352,41 @@ for(i = 0 ; i < actpblk.nParams ; ++i) { } else if(!strcmp(actpblk.descr[i].name, "action")){ pData->action = getSocketAction(es_str2cstr(pvals[i].val.d.estr, NULL)); } else if(!strcmp(actpblk.descr[i].name, "sndHWM")) { - pData->sndHWM = (int) pvals[i].val.d.n, NULL; + pData->sndHWM = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "rcvHWM")) { - pData->rcvHWM = (int) pvals[i].val.d.n, NULL; + pData->rcvHWM = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "identity")){ pData->identity = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); } else if(!strcmp(actpblk.descr[i].name, "sndBuf")) { - pData->sndBuf = (int) pvals[i].val.d.n, NULL; + pData->sndBuf = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "rcvBuf")) { - pData->rcvBuf = (int) pvals[i].val.d.n, NULL; + pData->rcvBuf = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "linger")) { - pData->linger = (int) pvals[i].val.d.n, NULL; + pData->linger = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "backlog")) { - pData->backlog = (int) pvals[i].val.d.n, NULL; + pData->backlog = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "sndTimeout")) { - pData->sndTimeout = (int) pvals[i].val.d.n, NULL; + pData->sndTimeout = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "rcvTimeout")) { - pData->rcvTimeout = (int) pvals[i].val.d.n, NULL; + pData->rcvTimeout = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "maxMsgSize")) { - pData->maxMsgSize = (int) pvals[i].val.d.n, NULL; + pData->maxMsgSize = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "rate")) { - pData->rate = (int) pvals[i].val.d.n, NULL; + pData->rate = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "recoveryIVL")) { - pData->recoveryIVL = (int) pvals[i].val.d.n, NULL; + pData->recoveryIVL = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "multicastHops")) { - pData->multicastHops = (int) pvals[i].val.d.n, NULL; + pData->multicastHops = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "reconnectIVL")) { - pData->reconnectIVL = (int) pvals[i].val.d.n, NULL; + pData->reconnectIVL = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "reconnectIVLMax")) { - pData->reconnectIVLMax = (int) pvals[i].val.d.n, NULL; + pData->reconnectIVLMax = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "ipv4Only")) { - pData->ipv4Only = (int) pvals[i].val.d.n, NULL; + pData->ipv4Only = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "affinity")) { - pData->affinity = (int) pvals[i].val.d.n, NULL; + pData->affinity = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "globalWorkerThreads")) { - s_workerThreads = (int) pvals[i].val.d.n, NULL; + s_workerThreads = (int) pvals[i].val.d.n; } else { errmsg.LogError(0, NO_ERRCODE, "omzmq3: program error, non-handled " "param '%s'\n", actpblk.descr[i].name); -- cgit v1.2.3 From 4224ee66376f1a8e914e63f402c71de29180e21c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jun 2012 11:53:41 +0200 Subject: cosmetic: updated ChangeLog to mention new 0mq plugins --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index a855bb1e..262a4f74 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,8 @@ Version 6.5.0 [devel] 2012-0?-?? - added --enable-debugless configure option for very high demanding envs This actually at compile time disables a lot of debug code, resulting in some speedup (but serious loss of debugging capabilities) +- added new 0mq plugins (via czmq lib) + Thanks to David Kelly for contributing these modules --------------------------------------------------------------------------- Version 6.3.10 [BETA] 2012-06-04 - bugfix: delayble source could block action queue, even if there was -- cgit v1.2.3 From 6dd21d2d633f5cc33bfcc4c101def87e14555d99 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 12 Jun 2012 16:02:26 +0200 Subject: cosmetic: merge remains in ChangeLog cleared up --- ChangeLog | 3 --- 1 file changed, 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index f528c771..61131c42 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,4 @@ --------------------------------------------------------------------------- -<<<<<<< HEAD Version 6.5.0 [devel] 2012-0?-?? - imrelp now supports non-cancel thread termination (but now requires at least librelp 1.0.1) @@ -507,8 +506,6 @@ expected that interfaces, even new ones, break during the initial syslog plain tcp input plugin (NOT supporting TLS!) [ported from v4] --------------------------------------------------------------------------- -======= ->>>>>>> 0620fc5780fabdfb160524197fd4aa6bb22613e9 Version 5.9.8 [V5-BETA], 2012-05-?? - bugfix: delayble source could block action queue, even if there was a disk queue associated with it. The root cause of this problem was -- cgit v1.2.3 From c8324b3460a85d57ca1bcfa481168d566069a0d1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 12 Jun 2012 18:52:32 +0200 Subject: milestone: regex is compiled from script based filter --- grammar/rainerscript.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++--- grammar/rainerscript.h | 2 ++ runtime/rule.c | 1 + tools/syslogd.c | 2 ++ 4 files changed, 63 insertions(+), 3 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index bcdbdf3b..dfaff869 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -41,6 +41,11 @@ #include "grammar.h" #include "queue.h" #include "srUtils.h" +#include "regexp.h" +#include "obj.h" + +DEFobjCurrIf(obj) +DEFobjCurrIf(regexp) void readConfFile(FILE *fp, es_str_t **str) @@ -1458,9 +1463,6 @@ cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) static inline enum cnffuncid funcName2ID(es_str_t *fname, unsigned short nParams) { -{ char *s;s=es_str2cstr(fname, NULL); -dbgprintf("ZZZZ: func: '%s', nParams: %d\n", s, nParams); -free(s);} if(!es_strbufcmp(fname, (unsigned char*)"strlen", sizeof("strlen") - 1)) { if(nParams != 1) { parser_errmsg("number of parameters for strlen() must be one " @@ -1508,6 +1510,41 @@ free(s);} } } + +static inline rsRetVal +initFunc_re_match(struct cnffunc *func) +{ + rsRetVal localRet; + char *regex = NULL; + regex_t *re; + DEFiRet; + + func->funcdata = NULL; + if(func->expr[1]->nodetype != 'S') { + parser_errmsg("param 2 of re_match() must be a constant string"); + FINALIZE; + } + + CHKmalloc(re = malloc(sizeof(regex_t))); + func->funcdata = re; + + regex = es_str2cstr(((struct cnfstringval*) func->expr[1])->estr, NULL); + + if((localRet = objUse(regexp, LM_REGEXP_FILENAME)) == RS_RET_OK) { + if(regexp.regcomp(re, (char*) regex, REG_EXTENDED) != 0) { + parser_errmsg("cannot compile regex '%s'", regex); + ABORT_FINALIZE(RS_RET_ERR); + } + } else { /* regexp object could not be loaded */ + parser_errmsg("could not load regex support - regex ignored"); + ABORT_FINALIZE(RS_RET_ERR); + } + +finalize_it: + free(regex); + RETiRet; +} + struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) { @@ -1534,6 +1571,14 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) param = param->next; free(toDel); } + /* some functions require special initialization */ + switch(func->fID) { + case CNFFUNC_RE_MATCH: + /* need to compile the regexp in param 2, so this MUST be a constant */ + initFunc_re_match(func); + break; + default:break; + } } return func; } @@ -1631,3 +1676,13 @@ cstrPrint(char *text, es_str_t *estr) dbgprintf("%s%s", text, str); free(str); } + +/* init must be called once before any parsing of the script files start */ +rsRetVal +initRainerscript(void) +{ + DEFiRet; + CHKiRet(objGetObjInterface(&obj)); +finalize_it: + RETiRet; +} diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 07e6af0b..b8d6e772 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -172,6 +172,7 @@ struct cnffunc { es_str_t *fname; unsigned short nParams; enum cnffuncid fID; /* function ID for built-ins, 0 means use name */ + void *funcdata; /* global data for function-specific use (e.g. compiled regex) */ struct cnfexpr *expr[]; }; @@ -250,6 +251,7 @@ void cnfparamsPrint(struct cnfparamblk *params, struct cnfparamvals *vals); void varDelete(struct var *v); void cnfparamvalsDestruct(struct cnfparamvals *paramvals, struct cnfparamblk *blk); void cnfcfsyslinelstDestruct(struct cnfcfsyslinelst *cfslst); +rsRetVal initRainerscript(void); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); diff --git a/runtime/rule.c b/runtime/rule.c index 41cc9e4e..96bf2c2f 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -336,6 +336,7 @@ CODESTARTobjDestruct(rule) if(pThis->f_filterData.prop.propName != NULL) es_deleteStr(pThis->f_filterData.prop.propName); } +#warning: need to destroy expression based filter! llDestroy(&pThis->llActList); ENDobjDestruct(rule) diff --git a/tools/syslogd.c b/tools/syslogd.c index 82ad79b9..b84aae22 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -125,6 +125,7 @@ #include "rsconf.h" #include "dnscache.h" #include "sd-daemon.h" +#include "rainerscript.h" /* definitions for objects we access */ DEFobjCurrIf(obj) @@ -1445,6 +1446,7 @@ InitGlobalClasses(void) pErrObj = "net"; CHKiRet(objUse(net, LM_NET_FILENAME)); dnscacheInit(); + initRainerscript(); finalize_it: if(iRet != RS_RET_OK) { -- cgit v1.2.3 From ba00396eee5b8f8717639da396b010631ad5baa7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 13 Jun 2012 17:51:22 +0200 Subject: re_match() function now also executes things now basically work. however, there is at least a (small) memory leak and the code needs to be further reviewed --- grammar/rainerscript.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index dfaff869..2f7057c5 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -754,8 +754,7 @@ var2Number(struct var *r, int *bSuccess) return n; } -/* ensure that retval is a string; if string is no number, - * emit error message and set number to 0. +/* ensure that retval is a string */ static inline es_str_t * var2String(struct var *r, int *bMustFree) @@ -779,6 +778,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) int bMustFree; es_str_t *estr; char *str; + int retval; struct var r[CNFFUNC_MAX_ARGS]; dbgprintf("rainerscript: executing function id %d\n", func->fID); @@ -844,9 +844,21 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) ret->datatype = 'N'; break; case CNFFUNC_RE_MATCH: - dbgprintf("TODO: implement re_match()\n"); - ret->d.n = 1; + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = var2String(&r[0], &bMustFree); + str = es_str2cstr(estr, NULL); + retval = regexp.regexec(func->funcdata, str, 0, NULL, 0); + if(retval == 0) + ret->d.n = 1; + else { + ret->d.n = 0; + if(retval != REG_NOMATCH) { + DBGPRINTF("re_match: regexec returned error %d\n", retval); + } + } ret->datatype = 'N'; + if(bMustFree) es_deleteStr(estr); + free(str); break; default: if(Debug) { -- cgit v1.2.3 From 488d0aaaa2a6d55e016d6b5b097cb3e20e49e191 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 14 Jun 2012 18:18:53 +0200 Subject: fixing memory leaks in expression-based filters most recently added by re_match() function --- grammar/rainerscript.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rainerscript.h | 1 + runtime/rule.c | 2 ++ 3 files changed, 77 insertions(+) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 2f7057c5..be8272b4 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -821,6 +821,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) es_tolower(estr); ret->datatype = 'S'; ret->d.estr = estr; + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); break; case CNFFUNC_CSTR: cnfexprEval(func->expr[0], &r[0], usrptr); @@ -829,6 +830,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) estr = es_strdup(estr); ret->datatype = 'S'; ret->d.estr = estr; + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); break; case CNFFUNC_CNUM: if(func->expr[0]->nodetype == 'N') { @@ -859,6 +861,7 @@ doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) ret->datatype = 'N'; if(bMustFree) es_deleteStr(estr); free(str); + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); break; default: if(Debug) { @@ -1221,6 +1224,77 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) } } +//--------------------------------------------------------- + +static inline void +cnffuncDestruct(struct cnffunc *func) +{ + unsigned short i; + + for(i = 0 ; i < func->nParams ; ++i) { + cnfexprDestruct(func->expr[i]); + } + /* some functions require special destruction */ + switch(func->fID) { + case CNFFUNC_RE_MATCH: + regexp.regfree(func->funcdata); + free(func->funcdata); + break; + default:break; + } +} + +/* Destruct an expression and all sub-expressions contained in it. + */ +void +cnfexprDestruct(struct cnfexpr *expr) +{ + + dbgprintf("cnfexprDestruct expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + switch(expr->nodetype) { + case CMP_NE: + case CMP_EQ: + case CMP_LE: + case CMP_GE: + case CMP_LT: + case CMP_GT: + case CMP_STARTSWITH: + case CMP_STARTSWITHI: + case CMP_CONTAINS: + case CMP_CONTAINSI: + case OR: + case AND: + case '+': + case '-': + case '*': + case '/': + case '%': /* binary */ + cnfexprDestruct(expr->l); + cnfexprDestruct(expr->r); + break; + case NOT: + case 'M': /* unary */ + cnfexprDestruct(expr->r); + break; + case 'N': + break; + case 'S': + es_deleteStr(((struct cnfstringval*)expr)->estr); + break; + case 'V': + free(((struct cnfvar*)expr)->name); + break; + case 'F': + cnffuncDestruct((struct cnffunc*)expr); + break; + default:break; + } + free(expr); +} + +//---- END + + /* Evaluate an expression as a bool. This is added because expressions are * mostly used inside filters, and so this function is quite common and * important. diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index b8d6e772..5ff71bee 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -235,6 +235,7 @@ struct cnfexpr* cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr void cnfexprPrint(struct cnfexpr *expr, int indent); void cnfexprEval(struct cnfexpr *expr, struct var *ret, void *pusr); int cnfexprEvalBool(struct cnfexpr *expr, void *usrptr); +void cnfexprDestruct(struct cnfexpr *expr); struct cnfnumval* cnfnumvalNew(long long val); struct cnfstringval* cnfstringvalNew(es_str_t *estr); struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst); diff --git a/runtime/rule.c b/runtime/rule.c index 96bf2c2f..254f2f10 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -335,6 +335,8 @@ CODESTARTobjDestruct(rule) rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache); if(pThis->f_filterData.prop.propName != NULL) es_deleteStr(pThis->f_filterData.prop.propName); + } else if(pThis->f_filter_type == FILTER_EXPR) { + cnfexprDestruct(pThis->f_filterData.expr); } #warning: need to destroy expression based filter! -- cgit v1.2.3 From 459b5d8c688f0448c0f34f7356456fdbe70f277a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 14 Jun 2012 18:27:17 +0200 Subject: bump default omfile iobuffer size to 4k (should originally have this value; larger value makes limited sense giving current batch sizes) --- tools/omfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/omfile.c b/tools/omfile.c index 0b20b1f6..f88ffce4 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -121,7 +121,7 @@ struct s_dynaFileCacheEntry { typedef struct s_dynaFileCacheEntry dynaFileCacheEntry; -#define IOBUF_DFLT_SIZE 1024 /* default size for io buffers */ +#define IOBUF_DFLT_SIZE 4096 /* default size for io buffers */ #define FLUSH_INTRVL_DFLT 1 /* default buffer flush interval (in seconds) */ #define USE_ASYNCWRITER_DFLT 0 /* default buffer use async writer */ #define FLUSHONTX_DFLT 1 /* default for flush on TX end */ -- cgit v1.2.3 From 3da62eee866a1edeb133c1c50fbffdebd261c8e6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 14 Jun 2012 18:59:06 +0200 Subject: bugfix: small static memory leak in expression based filters function names were not freed upon config shutdown --- grammar/rainerscript.c | 1 + 1 file changed, 1 insertion(+) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index be8272b4..f542b7f2 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -1239,6 +1239,7 @@ cnffuncDestruct(struct cnffunc *func) case CNFFUNC_RE_MATCH: regexp.regfree(func->funcdata); free(func->funcdata); + free(func->fname); break; default:break; } -- cgit v1.2.3 From 46ccc9e77f5e2ee3ded1ca79e973fafdc37e4c0f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 20 Jun 2012 09:34:31 +0200 Subject: milestone: module() can load module in legacy mode --- grammar/rainerscript.c | 1 - runtime/conf.c | 9 +++------ runtime/modules.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++--- runtime/modules.h | 11 +++++++++-- runtime/obj.c | 2 +- runtime/rsconf.c | 3 +++ 6 files changed, 65 insertions(+), 13 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index f542b7f2..3bfb2e07 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -682,7 +682,6 @@ cnfactlstReverse(struct cnfactlst *actlst) prev = NULL; while(actlst != NULL) { - //dbgprintf("reversing: %s\n", actlst->data.legActLine); curr = actlst; actlst = actlst->next; curr->syslines = cnfcfsyslinelstReverse(curr->syslines); diff --git a/runtime/conf.c b/runtime/conf.c index eec04df8..488d1b86 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -116,18 +116,15 @@ doModLoad(uchar **pp, __attribute__((unused)) void* pVal) skipWhiteSpace(pp); /* skip over any whitespace */ /* this below is a quick and dirty hack to provide compatibility with the - * $ModLoad MySQL forward compatibility statement. TODO: clean this up - * For the time being, it is clean enough, it just needs to be done - * differently when we have a full design for loadable plug-ins. For the - * time being, we just mangle the names a bit. - * rgerhards, 2007-08-14 + * $ModLoad MySQL forward compatibility statement. This needs to be supported + * for legacy format. */ if(!strcmp((char*) szName, "MySQL")) pModName = (uchar*) "ommysql.so"; else pModName = szName; - CHKiRet(module.Load(pModName, 1)); + CHKiRet(module.Load(pModName, 1, NULL)); finalize_it: RETiRet; diff --git a/runtime/modules.c b/runtime/modules.c index dac3bd95..4ab5b206 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -11,7 +11,7 @@ * * File begun on 2007-07-22 by RGerhards * - * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2012 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -75,6 +75,18 @@ static struct dlhandle_s *pHandles = NULL; static uchar *pModDir; /* directory where loadable modules are found */ +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "load", eCmdHdlrGetWord, 1 } +}; +static struct cnfparamblk pblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + + /* we provide a set of dummy functions for modules that do not support the * some interfaces. * On the commit feature: As the modules do not support it, they commit each message they @@ -931,9 +943,10 @@ findModule(uchar *pModName, int iModNameLen, modInfo_t **pMod) * the system loads a module for internal reasons, this is not directly tied to a * configuration. We could also think if it would be useful to add only certain types * of modules, but the current implementation at least looks simpler. + * Note: pvals = NULL means legacy config system */ static rsRetVal -Load(uchar *pModName, sbool bConfLoad) +Load(uchar *pModName, sbool bConfLoad, struct cnfparamvals *pvals) { DEFiRet; @@ -954,7 +967,7 @@ Load(uchar *pModName, sbool bConfLoad) size_t lenPathBuf = sizeof(pathBuf); assert(pModName != NULL); - dbgprintf("Requested to load module '%s'\n", pModName); + DBGPRINTF("Requested to load module '%s'\n", pModName); iModNameLen = strlen((char*)pModName); /* overhead for a full path is potentially 1 byte for a slash, @@ -1093,6 +1106,39 @@ finalize_it: } +/* the v6+ way of loading modules: process a "module(...)" directive. + * rgerhards, 2012-06-20 + */ +rsRetVal +modulesProcessCnf(struct cnfobj *o) +{ + struct cnfparamvals *pvals; + uchar *cnfModName = NULL; + int typeIdx; + DEFiRet; + + pvals = nvlstGetParams(o->nvlst, &pblk, NULL); + if(pvals == NULL) { + ABORT_FINALIZE(RS_RET_ERR); + } + DBGPRINTF("modulesProcessCnf params:\n"); + cnfparamsPrint(&pblk, pvals); + typeIdx = cnfparamGetIdx(&pblk, "load"); + if(pvals[typeIdx].bUsed == 0) { + errmsg.LogError(0, RS_RET_CONF_RQRD_PARAM_MISSING, "module type missing"); + ABORT_FINALIZE(RS_RET_CONF_RQRD_PARAM_MISSING); + } + + cnfModName = (uchar*)es_str2cstr(pvals[typeIdx].val.d.estr, NULL); + iRet = Load(cnfModName, 1, pvals); + +finalize_it: + free(cnfModName); + cnfparamvalsDestruct(pvals, &pblk); + RETiRet; +} + + /* set the default module load directory. A NULL value may be provided, in * which case any previous value is deleted but no new one set. The caller-provided * string is duplicated. If it needs to be freed, that's the caller's duty. diff --git a/runtime/modules.h b/runtime/modules.h index 6c5a2cba..5a293352 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -171,19 +171,26 @@ BEGINinterface(module) /* name must also be changed in ENDinterface macro! */ void (*PrintList)(void); rsRetVal (*UnloadAndDestructAll)(eModLinkType_t modLinkTypesToUnload); rsRetVal (*doModInit)(rsRetVal (*modInit)(), uchar *name, void *pModHdlr, modInfo_t **pNew); - rsRetVal (*Load)(uchar *name, sbool bConfLoad); + rsRetVal (*Load)(uchar *name, sbool bConfLoad, struct cnfparamvals *pvals); rsRetVal (*SetModDir)(uchar *name); modInfo_t *(*FindWithCnfName)(rsconf_t *cnf, uchar *name, eModType_t rqtdType); /* added v3, 2011-07-19 */ ENDinterface(module) -#define moduleCURR_IF_VERSION 3 /* increment whenever you change the interface structure! */ +#define moduleCURR_IF_VERSION 4 /* increment whenever you change the interface structure! */ /* Changes: * v2 * - added param bCondLoad to Load call - 2011-04-27 * - removed GetNxtType, added GetNxtCnfType - 2011-04-27 + * v3 (see above) + * v4 + * - added thrid parameter to Load() - 2012-06-20 */ /* prototypes */ PROTOTYPEObj(module); +/* in v6, we go back to in-core static link for core objects, at least those + * that are not called from plugins. + */ +rsRetVal modulesProcessCnf(struct cnfobj *o); /* TODO: remove "dirty" calls! */ rsRetVal addModToCnfList(modInfo_t *pThis); diff --git a/runtime/obj.c b/runtime/obj.c index b2739c58..99621124 100644 --- a/runtime/obj.c +++ b/runtime/obj.c @@ -1151,7 +1151,7 @@ UseObj(char *srcFile, uchar *pObjName, uchar *pObjFile, interface_t *pIf) if(pObjFile == NULL) { FINALIZE; /* no chance, we have lost... */ } else { - CHKiRet(module.Load(pObjFile, 0)); + CHKiRet(module.Load(pObjFile, 0, NULL)); /* NOW, we must find it or we have a problem... */ CHKiRet(FindObjInfo(pStr, &pObjInfo)); } diff --git a/runtime/rsconf.c b/runtime/rsconf.c index c1af7d22..ea0eaa0d 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -368,6 +368,9 @@ void cnfDoObj(struct cnfobj *o) case CNFOBJ_GLOBAL: glblProcessCnf(o); break; + case CNFOBJ_MODULE: + modulesProcessCnf(o); + break; case CNFOBJ_ACTION: actionProcessCnf(o); break; -- cgit v1.2.3 From 4b150db338ae885ea3a3bb7cc5b5f84e2fc96e89 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Jun 2012 16:19:20 +0200 Subject: milestone: module() config statement basically works some nits to iron out, only omfile actually support module params --- action.h | 1 + runtime/glbl.c | 2 + runtime/module-template.h | 32 ++++++++++- runtime/modules.c | 49 ++++++++++++---- runtime/modules.h | 10 ++-- runtime/rsconf.c | 22 +++---- runtime/rsyslog.h | 3 + tools/omfile.c | 142 ++++++++++++++++++++++++++++++++++++++++++---- 8 files changed, 220 insertions(+), 41 deletions(-) diff --git a/action.h b/action.h index 4da0be24..fdebdc36 100644 --- a/action.h +++ b/action.h @@ -111,5 +111,6 @@ rsRetVal actionNewScope(void); rsRetVal actionRestoreScope(void); rsRetVal activateActions(void); rsRetVal actionNewInst(struct nvlst *lst, action_t **ppAction); +rsRetVal actionProcessCnf(struct cnfobj *o); #endif /* #ifndef ACTION_H_INCLUDED */ diff --git a/runtime/glbl.c b/runtime/glbl.c index 537b7b4f..18993eef 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -553,10 +553,12 @@ glblProcessCnf(struct cnfobj *o) cnfparamsPrint(¶mblk, cnfparamvals); } +#if 0 /* TODO: finally remove? rgerhards, 2012-06-20 */ rsRetVal glblCheckCnf() { } +#endif void glblDoneLoadCnf(void) diff --git a/runtime/module-template.h b/runtime/module-template.h index 75bf7312..5d32b909 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -4,7 +4,7 @@ * * File begun on 2007-07-25 by RGerhards * - * Copyright 2007 Adiscon GmbH. This is Adiscon-exclusive code without any other + * Copyright 2007-2012 Adiscon GmbH. This is Adiscon-exclusive code without any other * contributions. *** GPLv3 *** * * This file is part of the rsyslog runtime library. @@ -503,6 +503,14 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\ } \ CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES +/* the following block is to be added for modules that support v2 + * module global parameters [module(...)] + */ +#define CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES \ + else if(!strcmp((char*) name, "setModCnf")) {\ + *pEtryPoint = setModCnf;\ + } \ + /* the following block is to be added for output modules that support the v2 * config system. The config name is also provided. */ @@ -693,6 +701,28 @@ static rsRetVal beginCnfLoad(modConfData_t **ptr, __attribute__((unused)) rsconf } +/* setModCnf() + * This function permits to set module global parameters via the v2 config + * interface. It may be called multiple times, but parameters must not be + * set in a conflicting way. The module must use its current config load + * context when processing the directives. + * Note that lst may be NULL, especially if the module is loaded via the + * legacy config system. The module must check for this. + * NOTE: This entry point must only be implemented if module global + * parameters are actually required. + */ +#define BEGINsetModCnf \ +static rsRetVal setModCnf(struct nvlst *lst)\ +{\ + DEFiRet; + +#define CODESTARTsetModCnf + +#define ENDsetModCnf \ + RETiRet;\ +} + + /* endCnfLoad() * This is a function tells an input module that the current config load ended. * It gets a last chance to make changes to its in-memory config object. After diff --git a/runtime/modules.c b/runtime/modules.c index 4ab5b206..e7ae72cc 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -349,7 +349,8 @@ addModToGlblList(modInfo_t *pThis) } -/* Add a module to the config module list for current loadConf +/* Add a module to the config module list for current loadConf and + * provide its config params to it. */ rsRetVal addModToCnfList(modInfo_t *pThis) @@ -370,11 +371,16 @@ addModToCnfList(modInfo_t *pThis) while(1) { /* loop broken inside */ if(pLast->pMod == pThis) { DBGPRINTF("module '%s' already in this config\n", modGetName(pThis)); + if(strncmp((char*)modGetName(pThis), "builtin:", sizeof("builtin:")-1)) { + errmsg.LogError(0, RS_RET_MODULE_ALREADY_IN_CONF, + "module '%s' already in this config, cannot be added\n", modGetName(pThis)); + ABORT_FINALIZE(RS_RET_MODULE_ALREADY_IN_CONF); + } FINALIZE; } if(pLast->next == NULL) break; - pLast = pLast -> next; + pLast = pLast->next; } } @@ -547,7 +553,7 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*modGetType)(&pNew->eType)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getKeepType", &modGetKeepType)); CHKiRet((*modGetKeepType)(&pNew->eKeepType)); - dbgprintf("module %s of type %d being loaded.\n", name, pNew->eType); + dbgprintf("module %s of type %d being loaded (keepType=%d).\n", name, pNew->eType, pNew->eKeepType); /* OK, we know we can successfully work with the module. So we now fill the * rest of the data elements. First we load the interfaces common to all @@ -560,6 +566,11 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ pNew->isCompatibleWithFeature = dummyIsCompatibleWithFeature; else if(localRet != RS_RET_OK) ABORT_FINALIZE(localRet); + localRet = (*pNew->modQueryEtryPt)((uchar*)"setModCnf", &pNew->setModCnf); + if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) + pNew->setModCnf = NULL; + else if(localRet != RS_RET_OK) + ABORT_FINALIZE(localRet); /* optional calls for new config system */ localRet = (*pNew->modQueryEtryPt)((uchar*)"getModCnfName", &getModCnfName); @@ -766,6 +777,7 @@ static void modPrintList(void) dbgprintf("\tdbgPrintInstInfo: 0x%lx\n", (unsigned long) pMod->dbgPrintInstInfo); dbgprintf("\tfreeInstance: 0x%lx\n", (unsigned long) pMod->freeInstance); dbgprintf("\tbeginCnfLoad: 0x%lx\n", (unsigned long) pMod->beginCnfLoad); + dbgprintf("\tSetModCnf: 0x%lx\n", (unsigned long) pMod->setModCnf); dbgprintf("\tcheckCnf: 0x%lx\n", (unsigned long) pMod->checkCnf); dbgprintf("\tactivateCnfPrePrivDrop: 0x%lx\n", (unsigned long) pMod->activateCnfPrePrivDrop); dbgprintf("\tactivateCnf: 0x%lx\n", (unsigned long) pMod->activateCnf); @@ -946,12 +958,9 @@ findModule(uchar *pModName, int iModNameLen, modInfo_t **pMod) * Note: pvals = NULL means legacy config system */ static rsRetVal -Load(uchar *pModName, sbool bConfLoad, struct cnfparamvals *pvals) +Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) { - DEFiRet; - size_t iPathLen, iModNameLen; - uchar *pModNameCmp; int bHasExtension; void *pModHdlr, *pModInit; modInfo_t *pModInfo; @@ -965,6 +974,8 @@ Load(uchar *pModName, sbool bConfLoad, struct cnfparamvals *pvals) # endif uchar *pPathBuf = pathBuf; size_t lenPathBuf = sizeof(pathBuf); + rsRetVal localRet; + DEFiRet; assert(pModName != NULL); DBGPRINTF("Requested to load module '%s'\n", pModName); @@ -985,9 +996,19 @@ Load(uchar *pModName, sbool bConfLoad, struct cnfparamvals *pvals) CHKiRet(findModule(pModName, iModNameLen, &pModInfo)); if(pModInfo != NULL) { - if(bConfLoad) - addModToCnfList(pModInfo); - dbgprintf("Module '%s' already loaded\n", pModName); + DBGPRINTF("Module '%s' already loaded\n", pModName); + if(bConfLoad) { + localRet = addModToCnfList(pModInfo); + if(pModInfo->setModCnf != NULL && localRet == RS_RET_OK) { + if(!strncmp((char*)pModName, "builtin:", sizeof("builtin:")-1)) { + /* for built-in moules, we need to call setModConf, + * because there is no way to set parameters at load + * time for obvious reasons... + */ + pModInfo->setModCnf(lst); + } + } + } FINALIZE; } @@ -1095,8 +1116,12 @@ Load(uchar *pModName, sbool bConfLoad, struct cnfparamvals *pvals) dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_INIT_FAILED); } - if(bConfLoad) + + if(bConfLoad) { addModToCnfList(pModInfo); + if(pModInfo->setModCnf != NULL) + pModInfo->setModCnf(lst); + } finalize_it: if(pPathBuf != pathBuf) /* used malloc()ed memory? */ @@ -1130,7 +1155,7 @@ modulesProcessCnf(struct cnfobj *o) } cnfModName = (uchar*)es_str2cstr(pvals[typeIdx].val.d.estr, NULL); - iRet = Load(cnfModName, 1, pvals); + iRet = Load(cnfModName, 1, o->nvlst); finalize_it: free(cnfModName); diff --git a/runtime/modules.h b/runtime/modules.h index 5a293352..b0f7100f 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -12,7 +12,7 @@ * * File begun on 2007-07-22 by RGerhards * - * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2012 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -114,6 +114,7 @@ struct modInfo_s { rsRetVal (*doHUP)(void *); /* non-restart type HUP handler */ /* v2 config system specific */ rsRetVal (*beginCnfLoad)(void*newCnf, rsconf_t *pConf); + rsRetVal (*setModCnf)(struct nvlst *lst); rsRetVal (*endCnfLoad)(void*Cnf); rsRetVal (*checkCnf)(void*Cnf); rsRetVal (*activateCnfPrePrivDrop)(void*Cnf); @@ -152,9 +153,7 @@ struct modInfo_s { } mod; void *pModHdlr; /* handler to the dynamic library holding the module */ # ifdef DEBUG - /* we add some home-grown support to track our users (and detect who does not free us). In - * the long term, this should probably be migrated into debug.c (TODO). -- rgerhards, 2008-03-11 - */ + /* we add some home-grown support to track our users (and detect who does not free us). */ modUsr_t *pModUsrRoot; # endif }; @@ -171,7 +170,7 @@ BEGINinterface(module) /* name must also be changed in ENDinterface macro! */ void (*PrintList)(void); rsRetVal (*UnloadAndDestructAll)(eModLinkType_t modLinkTypesToUnload); rsRetVal (*doModInit)(rsRetVal (*modInit)(), uchar *name, void *pModHdlr, modInfo_t **pNew); - rsRetVal (*Load)(uchar *name, sbool bConfLoad, struct cnfparamvals *pvals); + rsRetVal (*Load)(uchar *name, sbool bConfLoad, struct nvlst *lst); rsRetVal (*SetModDir)(uchar *name); modInfo_t *(*FindWithCnfName)(rsconf_t *cnf, uchar *name, eModType_t rqtdType); /* added v3, 2011-07-19 */ ENDinterface(module) @@ -192,6 +191,5 @@ PROTOTYPEObj(module); */ rsRetVal modulesProcessCnf(struct cnfobj *o); -/* TODO: remove "dirty" calls! */ rsRetVal addModToCnfList(modInfo_t *pThis); #endif /* #ifndef MODULES_H_INCLUDED */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index ea0eaa0d..fecd4f29 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -996,12 +996,12 @@ loadBuildInModules() { DEFiRet; - CHKiRet(regBuildInModule(modInitFile, UCHAR_CONSTANT("builtin-file"), NULL)); - CHKiRet(regBuildInModule(modInitPipe, UCHAR_CONSTANT("builtin-pipe"), NULL)); + CHKiRet(regBuildInModule(modInitFile, UCHAR_CONSTANT("builtin:omfile"), NULL)); + CHKiRet(regBuildInModule(modInitPipe, UCHAR_CONSTANT("builtin:ompipe"), NULL)); CHKiRet(regBuildInModule(modInitShell, UCHAR_CONSTANT("builtin-shell"), NULL)); - CHKiRet(regBuildInModule(modInitDiscard, UCHAR_CONSTANT("builtin-discard"), NULL)); + CHKiRet(regBuildInModule(modInitDiscard, UCHAR_CONSTANT("builtin:omdiscard"), NULL)); # ifdef SYSLOG_INET - CHKiRet(regBuildInModule(modInitFwd, UCHAR_CONSTANT("builtin-fwd"), NULL)); + CHKiRet(regBuildInModule(modInitFwd, UCHAR_CONSTANT("builtin:omfwd"), NULL)); # endif /* dirty, but this must be for the time being: the usrmsg module must always be @@ -1013,11 +1013,11 @@ loadBuildInModules() * User names now must begin with: * [a-zA-Z0-9_.] */ - CHKiRet(regBuildInModule(modInitUsrMsg, (uchar*) "builtin-usrmsg", NULL)); + CHKiRet(regBuildInModule(modInitUsrMsg, (uchar*) "builtin:omusrmsg", NULL)); /* load build-in parser modules */ - CHKiRet(regBuildInModule(modInitpmrfc5424, UCHAR_CONSTANT("builtin-pmrfc5424"), NULL)); - CHKiRet(regBuildInModule(modInitpmrfc3164, UCHAR_CONSTANT("builtin-pmrfc3164"), NULL)); + CHKiRet(regBuildInModule(modInitpmrfc5424, UCHAR_CONSTANT("builtin:pmrfc5424"), NULL)); + CHKiRet(regBuildInModule(modInitpmrfc3164, UCHAR_CONSTANT("builtin:pmrfc3164"), NULL)); /* and set default parser modules. Order is *very* important, legacy * (3164) parser needs to go last! */ @@ -1025,10 +1025,10 @@ loadBuildInModules() CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc3164"))); /* load build-in strgen modules */ - CHKiRet(regBuildInModule(modInitsmfile, UCHAR_CONSTANT("builtin-smfile"), NULL)); - CHKiRet(regBuildInModule(modInitsmtradfile, UCHAR_CONSTANT("builtin-smtradfile"), NULL)); - CHKiRet(regBuildInModule(modInitsmfwd, UCHAR_CONSTANT("builtin-smfwd"), NULL)); - CHKiRet(regBuildInModule(modInitsmtradfwd, UCHAR_CONSTANT("builtin-smtradfwd"), NULL)); + CHKiRet(regBuildInModule(modInitsmfile, UCHAR_CONSTANT("builtin:smfile"), NULL)); + CHKiRet(regBuildInModule(modInitsmtradfile, UCHAR_CONSTANT("builtin:smtradfile"), NULL)); + CHKiRet(regBuildInModule(modInitsmfwd, UCHAR_CONSTANT("builtin:smfwd"), NULL)); + CHKiRet(regBuildInModule(modInitsmtradfwd, UCHAR_CONSTANT("builtin:smtradfwd"), NULL)); finalize_it: if(iRet != RS_RET_OK) { diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 058322bd..f75b07ab 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -374,6 +374,9 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_CNF_INVLD_FRAMING = -2214, /**< invalid framing specified in config file */ RS_RET_LEGA_ACT_NOT_SUPPORTED = -2215, /**< the module (no longer) supports legacy action syntax */ RS_RET_MAX_OMSR_REACHED = -2216, /**< max nbr of string requests reached, not supported by core */ + /* reserved for pre-v6.5 */ + RS_RET_DUP_PARAM = -2220, /**< config parameter is given more than once */ + RS_RET_MODULE_ALREADY_IN_CONF = -2221, /**< module already in current configuration */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/tools/omfile.c b/tools/omfile.c index f88ffce4..e9f4cba8 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -180,7 +180,26 @@ typedef struct configSettings_s { static configSettings_t cs; uchar *pszFileDfltTplName; /* name of the default template to use */ +struct modConfData_s { + rsconf_t *pConf; /* our overall config object */ + struct cnfparamvals* vals; /* vals kept to detect re-set options */ + uchar *tplName; /* default template */ +}; + +static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ +static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current exec process */ + /* tables for interfacing with the v6 config system */ +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "template", eCmdHdlrGetWord, 0 }, +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + /* action (instance) parameters */ static struct cnfparamdescr actpdescr[] = { { "dynafilecachesize", eCmdHdlrInt, 0 }, /* legacy: dynafilecachesize */ @@ -201,7 +220,6 @@ static struct cnfparamdescr actpdescr[] = { { "file", eCmdHdlrString, 0 }, /* either "file" or ... */ { "dynafile", eCmdHdlrString, 0 }, /* "dynafile" MUST be present */ { "template", eCmdHdlrGetWord, 0 }, - //{ "", eCmdHdlrGetWord, 0 }, /* legacy: */ }; static struct cnfparamblk actpblk = { CNFPARAMBLK_VERSION, @@ -210,6 +228,21 @@ static struct cnfparamblk actpblk = }; +/* this function gets the default template. It coordinates action between + * old-style and new-style configuration parts. + */ +static inline uchar* +getDfltTpl(void) +{ + if(loadModConf != NULL && loadModConf->tplName != NULL) + return loadModConf->tplName; + else if(pszFileDfltTplName == NULL) + return (uchar*)"RSYSLOG_FileFormat"; + else + return pszFileDfltTplName; +} + + BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars pszFileDfltTplName = NULL; /* make sure this can be free'ed! */ @@ -246,6 +279,30 @@ CODESTARTdbgPrintInstInfo ENDdbgPrintInstInfo + +/* set the default template to be used + * This is a module-global parameter, and as such needs special handling. It needs to + * be coordinated with values set via the v2 config system (rsyslog v6+). What we do + * is we do not permit this directive after the v2 config system has been used to set + * the parameter. + */ +rsRetVal +setLegacyDfltTpl(void __attribute__((unused)) *pVal, uchar* newVal) +{ + DEFiRet; + + if(loadModConf != NULL && loadModConf->tplName != NULL) { + errmsg.LogError(0, RS_RET_ERR, "omfile default template already set via module " + "global parameter - can no longer be changed"); + ABORT_FINALIZE(RS_RET_ERR); + } + free(pszFileDfltTplName); + pszFileDfltTplName = newVal; +finalize_it: + RETiRet; +} + + /* set the dynaFile cache size. Does some limit checking. * rgerhards, 2007-07-31 */ @@ -333,8 +390,7 @@ static rsRetVal cflineParseOutchannel(instanceData *pData, uchar* p, omodStringR */ pData->pszSizeLimitCmd = pOch->cmdOnSizeLimit; - iRet = cflineParseTemplateName(&p, pOMSR, iEntry, iTplOpts, - (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName); + iRet = cflineParseTemplateName(&p, pOMSR, iEntry, iTplOpts, getDfltTpl()); finalize_it: RETiRet; @@ -690,6 +746,72 @@ finalize_it: } +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + pModConf->tplName = NULL; +ENDbeginCnfLoad + +BEGINsetModCnf + struct cnfparamvals *pvals; + int i; +CODESTARTsetModCnf + loadModConf->vals = nvlstGetParams(lst, &modpblk, loadModConf->vals); + if(loadModConf->vals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + pvals = loadModConf->vals; + + if(Debug) { + dbgprintf("module (global) param blk for omfile:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "template")) { + loadModConf->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + if(pszFileDfltTplName != NULL) { + errmsg.LogError(0, RS_RET_DUP_PARAM, "omfile: warning: default template " + "was already set via legacy directive - may lead to inconsistent " + "results."); + } + } else { + dbgprintf("omfile: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } +finalize_it: +ENDsetModCnf + +BEGINendCnfLoad +CODESTARTendCnfLoad + /* persist module-specific settings from legacy config system */ + //... + + loadModConf = NULL; /* done loading */ + /* free legacy config vars */ + //... +ENDendCnfLoad + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + +BEGINactivateCnf +CODESTARTactivateCnf + runModConf = pModConf; +ENDactivateCnf + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + + BEGINcreateInstance CODESTARTcreateInstance pData->pStrm = NULL; @@ -837,9 +959,7 @@ CODESTARTnewActInst ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); } - CHKiRet(OMSRsetEntry(*ppOMSR, 0, ustrdup((pData->tplName == NULL) ? - (uchar*)"RSYSLOG_FileFormat" : pData->tplName), - OMSR_NO_RQD_TPL_OPTS)); + CHKiRet(OMSRsetEntry(*ppOMSR, 0, ustrdup(getDfltTpl()), OMSR_NO_RQD_TPL_OPTS)); if(pData->bDynamicName) { /* "filename" is actually a template name, we need this as string 1. So let's add it @@ -902,8 +1022,7 @@ CODESTARTparseSelectorAct */ CODE_STD_STRING_REQUESTparseSelectorAct(2) ++p; /* eat '?' */ - CHKiRet(cflineParseFileName(p, fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, - (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); + CHKiRet(cflineParseFileName(p, fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, getDfltTpl())); pData->f_fname = ustrdup(fname); pData->bDynamicName = 1; pData->iCurrElt = -1; /* no current element */ @@ -919,8 +1038,7 @@ CODESTARTparseSelectorAct case '/': case '.': CODE_STD_STRING_REQUESTparseSelectorAct(1) - CHKiRet(cflineParseFileName(p, fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, - (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); + CHKiRet(cflineParseFileName(p, fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, getDfltTpl())); pData->f_fname = ustrdup(fname); pData->bDynamicName = 0; break; @@ -999,6 +1117,8 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */ CODEqueryEtryPt_doHUP @@ -1033,7 +1153,7 @@ INITLegCnfVars CHKiRet(omsdRegCFSLineHdlr((uchar *)"failonchownfailure", 0, eCmdHdlrBinary, NULL, &cs.bFailOnChown, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileforcechown", 0, eCmdHdlrGoneAway, NULL, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionfileenablesync", 0, eCmdHdlrBinary, NULL, &cs.bEnableSync, STD_LOADABLE_MODULE_ID)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionfiledefaulttemplate", 0, eCmdHdlrGetWord, NULL, &pszFileDfltTplName, NULL)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionfiledefaulttemplate", 0, eCmdHdlrGetWord, setLegacyDfltTpl, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit /* vi:set ai: -- cgit v1.2.3 From bf85d81790a26945e404c6fdfdddad5eadbaa371 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 Jun 2012 12:35:46 +0200 Subject: implemented freeCnf() module interface & fixed some mem leaks The interface was actually not present in older versions, even though some modules already used it. The implementation was now done, and not in 6.3/6.4 because the resulting memory leak was ultra-slim and the new interface handling has some potential to seriously break things. Not the kind of thing you want to add in late beta state, if avoidable. --- ChangeLog | 6 ++++++ plugins/imtcp/imtcp.c | 9 +++++++++ plugins/imudp/imudp.c | 9 +++++++++ plugins/imuxsock/imuxsock.c | 8 ++++++++ runtime/modules.c | 22 ++++++++++++++++------ runtime/modules.h | 3 ++- runtime/rsconf.c | 26 ++++++++++++++++++++++++++ runtime/rsconf.h | 2 +- runtime/rule.c | 1 - tcpsrv.c | 2 +- tools/omfile.c | 12 +++++++----- tools/syslogd.c | 27 +++++---------------------- 12 files changed, 90 insertions(+), 37 deletions(-) diff --git a/ChangeLog b/ChangeLog index 08aad36b..c4361d3a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,12 @@ Version 6.5.0 [devel] 2012-0?-?? - imrelp now supports non-cancel thread termination (but now requires at least librelp 1.0.1) +- implemented freeCnf() module interface + This was actually not present in older versions, even though some modules + already used it. The implementation was now done, and not in 6.3/6.4 + because the resulting memory leak was ultra-slim and the new interface + handling has some potential to seriously break things. Not the kind of + thing you want to add in late beta state, if avoidable. - added --enable-debugless configure option for very high demanding envs This actually at compile time disables a lot of debug code, resulting in some speedup (but serious loss of debugging capabilities) diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index 33404fee..a3365d44 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -366,7 +366,16 @@ ENDactivateCnf BEGINfreeCnf + instanceConf_t *inst, *del; CODESTARTfreeCnf + for(inst = pModConf->root ; inst != NULL ; ) { + free(inst->pszBindPort); + free(inst->pBindRuleset); + free(inst->pszInputName); + del = inst; + inst = inst->next; + free(del); + } ENDfreeCnf /* This function is called to gather input. diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 6abeab07..165b6680 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -751,7 +751,16 @@ ENDactivateCnf BEGINfreeCnf + instanceConf_t *inst, *del; CODESTARTfreeCnf + for(inst = pModConf->root ; inst != NULL ; ) { + free(inst->pszBindPort); + free(inst->pszBindAddr); + free(inst->pBindRuleset); + del = inst; + inst = inst->next; + free(del); + } ENDfreeCnf /* This function is called to gather input. diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 19028470..eeb18fd2 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -1085,8 +1085,16 @@ ENDactivateCnf BEGINfreeCnf + instanceConf_t *inst, *del; CODESTARTfreeCnf free(pModConf->pLogSockName); + for(inst = pModConf->root ; inst != NULL ; ) { + free(inst->sockName); + free(inst->pLogHostName); + del = inst; + inst = inst->next; + free(del); + } ENDfreeCnf diff --git a/runtime/modules.c b/runtime/modules.c index e7ae72cc..6417cecd 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -1001,11 +1001,19 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) localRet = addModToCnfList(pModInfo); if(pModInfo->setModCnf != NULL && localRet == RS_RET_OK) { if(!strncmp((char*)pModName, "builtin:", sizeof("builtin:")-1)) { - /* for built-in moules, we need to call setModConf, - * because there is no way to set parameters at load - * time for obvious reasons... - */ - pModInfo->setModCnf(lst); + if(pModInfo->bSetModCnfCalled) { + errmsg.LogError(0, RS_RET_DUP_PARAM, + "parameters for built-in module %s already set - ignored\n", + pModName); + ABORT_FINALIZE(RS_RET_DUP_PARAM); + } else { + /* for built-in moules, we need to call setModConf, + * because there is no way to set parameters at load + * time for obvious reasons... + */ + pModInfo->setModCnf(lst); + pModInfo->bSetModCnfCalled = 1; + } } } } @@ -1119,8 +1127,10 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) if(bConfLoad) { addModToCnfList(pModInfo); - if(pModInfo->setModCnf != NULL) + if(pModInfo->setModCnf != NULL) { pModInfo->setModCnf(lst); + pModInfo->bSetModCnfCalled = 1; + } } finalize_it: diff --git a/runtime/modules.h b/runtime/modules.h index b0f7100f..6a143ae3 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -101,6 +101,7 @@ struct modInfo_s { uchar* pszName; /* printable module name, e.g. for dbgprintf */ uchar* cnfName; /* name to be used in config statements (e.g. 'name="omusrmsg"') */ unsigned uRefCnt; /* reference count for this module; 0 -> may be unloaded */ + sbool bSetModCnfCalled;/* is setModCnf already called? Needed for built-in modules */ /* functions supported by all types of modules */ rsRetVal (*modInit)(int, int*, rsRetVal(**)()); /* initialize the module */ /* be sure to support version handshake! */ @@ -181,7 +182,7 @@ ENDinterface(module) * - removed GetNxtType, added GetNxtCnfType - 2011-04-27 * v3 (see above) * v4 - * - added thrid parameter to Load() - 2012-06-20 + * - added third parameter to Load() - 2012-06-20 */ /* prototypes */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index fecd4f29..affa2dd5 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -64,6 +64,7 @@ #include "threads.h" #include "datetime.h" #include "parserif.h" +#include "modules.h" #include "dirty.h" /* static data */ @@ -151,11 +152,36 @@ rsRetVal rsconfConstructFinalize(rsconf_t __attribute__((unused)) *pThis) } +/* call freeCnf() module entry points AND free the module entries themselfes. + */ +static inline void +freeCnf(rsconf_t *pThis) +{ + cfgmodules_etry_t *etry, *del; + etry = pThis->modules.root; + while(etry != NULL) { + if(etry->pMod->beginCnfLoad != NULL) { + dbgprintf("calling freeCnf(%p) for module '%s'\n", + etry->modCnf, (char*) module.GetName(etry->pMod)); + etry->pMod->freeCnf(etry->modCnf); + } + del = etry; + etry = etry->next; + free(del); + } +} + + /* destructor for the rsconf object */ BEGINobjDestruct(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */ CODESTARTobjDestruct(rsconf) +dbgprintf("AAA: rsconfObjDesctruct called\n"); + freeCnf(pThis); + tplDeleteAll(pThis); free(pThis->globals.mainQ.pszMainMsgQFName); + free(pThis->globals.pszConfDAGFile); llDestroy(&(pThis->rulesets.llRulesets)); +dbgprintf("AAA: rsconfObjDesctruct exit\n"); ENDobjDestruct(rsconf) diff --git a/runtime/rsconf.h b/runtime/rsconf.h index 8715cf1b..484fec8c 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -97,8 +97,8 @@ struct defaults_s { struct cfgmodules_etry_s { cfgmodules_etry_t *next; modInfo_t *pMod; - /* the following data is input module specific */ void *modCnf; /* pointer to the input module conf */ + /* the following data is input module specific */ sbool canActivate; /* OK to activate this config? */ sbool canRun; /* OK to run this config? */ }; diff --git a/runtime/rule.c b/runtime/rule.c index 254f2f10..6d14199b 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -338,7 +338,6 @@ CODESTARTobjDestruct(rule) } else if(pThis->f_filter_type == FILTER_EXPR) { cnfexprDestruct(pThis->f_filterData.expr); } -#warning: need to destroy expression based filter! llDestroy(&pThis->llActList); ENDobjDestruct(rule) diff --git a/tcpsrv.c b/tcpsrv.c index df5f2a5f..c5a26322 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -132,7 +132,7 @@ addNewLstnPort(tcpsrv_t *pThis, uchar *pszPort, int bSuppOctetFram) /* create entry */ CHKmalloc(pEntry = MALLOC(sizeof(tcpLstnPortList_t))); - pEntry->pszPort = pszPort; + CHKmalloc(pEntry->pszPort = ustrdup(pszPort)); pEntry->pSrv = pThis; pEntry->pRuleset = pThis->pRuleset; pEntry->bSuppOctetFram = bSuppOctetFram; diff --git a/tools/omfile.c b/tools/omfile.c index e9f4cba8..446e1b32 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -182,7 +182,6 @@ uchar *pszFileDfltTplName; /* name of the default template to use */ struct modConfData_s { rsconf_t *pConf; /* our overall config object */ - struct cnfparamvals* vals; /* vals kept to detect re-set options */ uchar *tplName; /* default template */ }; @@ -292,6 +291,7 @@ setLegacyDfltTpl(void __attribute__((unused)) *pVal, uchar* newVal) DEFiRet; if(loadModConf != NULL && loadModConf->tplName != NULL) { + free(newVal); errmsg.LogError(0, RS_RET_ERR, "omfile default template already set via module " "global parameter - can no longer be changed"); ABORT_FINALIZE(RS_RET_ERR); @@ -754,16 +754,15 @@ CODESTARTbeginCnfLoad ENDbeginCnfLoad BEGINsetModCnf - struct cnfparamvals *pvals; + struct cnfparamvals *pvals = NULL; int i; CODESTARTsetModCnf - loadModConf->vals = nvlstGetParams(lst, &modpblk, loadModConf->vals); - if(loadModConf->vals == NULL) { + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " "config parameters [module(...)]"); ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); } - pvals = loadModConf->vals; if(Debug) { dbgprintf("module (global) param blk for omfile:\n"); @@ -786,6 +785,8 @@ CODESTARTsetModCnf } } finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); ENDsetModCnf BEGINendCnfLoad @@ -809,6 +810,7 @@ ENDactivateCnf BEGINfreeCnf CODESTARTfreeCnf + free(pModConf->tplName); ENDfreeCnf diff --git a/tools/syslogd.c b/tools/syslogd.c index b84aae22..20a4aa12 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -786,18 +786,6 @@ static void doDie(int sig) } -/* This function frees all dynamically allocated memory for program termination. - * It must be called only immediately before exit(). It is primarily an aid - * for memory debuggers, which prevents cluttered outupt. - * rgerhards, 2008-03-20 - */ -static void -freeAllDynMemForTermination(void) -{ - free(ourConf->globals.pszConfDAGFile); -} - - /* Finalize and destruct all actions. */ static inline void @@ -867,14 +855,16 @@ die(int sig) destructAllActions(); DBGPRINTF("all primary multi-thread sources have been terminated - now doing aux cleanup...\n"); + + DBGPRINTF("destructing current config...\n"); + rsconf.Destruct(&runConf); + /* rger 2005-02-22 * now clean up the in-memory structures. OK, the OS * would also take care of that, but if we do it * ourselfs, this makes finding memory leaks a lot * easier. */ - tplDeleteAll(runConf); - /* de-init some modules */ modExitIminternal(); @@ -898,15 +888,8 @@ die(int sig) /* dbgClassExit MUST be the last one, because it de-inits the debug system */ dbgClassExit(); - /* free all remaining memory blocks - this is not absolutely necessary, but helps - * us keep memory debugger logs clean and this is in aid in developing. It doesn't - * cost much time, so we do it always. -- rgerhards, 2008-03-20 - */ - freeAllDynMemForTermination(); - /* NO CODE HERE - feeelAllDynMemForTermination() must be the last thing before exit()! */ - + /* NO CODE HERE - dbgClassExit() must be the last thing before exit()! */ remove_pid(PidFile); - exit(0); /* "good" exit, this is the terminator function for rsyslog [die()] */ } -- cgit v1.2.3 From c23ddc0aef3493cd7de31a6c43ee985f751a06cf Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 Jun 2012 12:55:54 +0200 Subject: cleanup & fix of mini-leak --- runtime/rsconf.c | 2 -- tools/pidfile.c | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/runtime/rsconf.c b/runtime/rsconf.c index affa2dd5..9ee13dd4 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -175,13 +175,11 @@ freeCnf(rsconf_t *pThis) /* destructor for the rsconf object */ BEGINobjDestruct(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */ CODESTARTobjDestruct(rsconf) -dbgprintf("AAA: rsconfObjDesctruct called\n"); freeCnf(pThis); tplDeleteAll(pThis); free(pThis->globals.mainQ.pszMainMsgQFName); free(pThis->globals.pszConfDAGFile); llDestroy(&(pThis->rulesets.llRulesets)); -dbgprintf("AAA: rsconfObjDesctruct exit\n"); ENDobjDestruct(rsconf) diff --git a/tools/pidfile.c b/tools/pidfile.c index e7744513..e9601232 100644 --- a/tools/pidfile.c +++ b/tools/pidfile.c @@ -125,7 +125,7 @@ int write_pid (char *pidfile) char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); printf("Can't write pid , %s.\n", errStr); - close(fd); + fclose(f); return 0; } fflush(f); @@ -135,11 +135,11 @@ int write_pid (char *pidfile) char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); printf("Can't unlock pidfile %s, %s.\n", pidfile, errStr); - close(fd); + fclose(f); return 0; } #endif - close(fd); + fclose(f); return pid; } -- cgit v1.2.3 From 4d0fcca412ed9491d1e10bb2ce0b4c7256219118 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 Jun 2012 17:06:40 +0200 Subject: a bit more cleanup --- tools/omfile.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/omfile.c b/tools/omfile.c index 446e1b32..0fbc9207 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -791,12 +791,10 @@ ENDsetModCnf BEGINendCnfLoad CODESTARTendCnfLoad - /* persist module-specific settings from legacy config system */ - //... - loadModConf = NULL; /* done loading */ /* free legacy config vars */ - //... + free(pszFileDfltTplName); + pszFileDfltTplName = NULL; ENDendCnfLoad BEGINcheckCnf @@ -1111,7 +1109,6 @@ BEGINmodExit CODESTARTmodExit objRelease(errmsg, CORE_COMPONENT); objRelease(strm, CORE_COMPONENT); - free(pszFileDfltTplName); DESTROY_ATOMIC_HELPER_MUT(mutClock); ENDmodExit -- cgit v1.2.3 From e9ad3cafd1b745a060e04372162722870ee6cf08 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 Jun 2012 17:21:17 +0200 Subject: ompipe: support for module() global config parameters added --- doc/v6compatibility.html | 10 +++++ tools/ompipe.c | 102 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 107 insertions(+), 5 deletions(-) diff --git a/doc/v6compatibility.html b/doc/v6compatibility.html index 058ab4f1..eec0784b 100644 --- a/doc/v6compatibility.html +++ b/doc/v6compatibility.html @@ -136,6 +136,16 @@ Note that this syntax is available starting with rsyslog v4. It is important to mind that future versions of rsyslog will require different syntax and/or drop outchannel support completely. So if at all possible, avoid using this feature. If you must use it, be prepared for future changes and watch announcements very carefully. +

ompipe default template

+

Starting with 6.5.0, ompipe does no longer use the omfile default template. +Instead, the default template must be set via the module load statement. +An example is +

+module(load="builtin:ompipe" template="myDefaultTemplate") +
+

For obvious reasons, the default template must be defined somewhere in +the config file, otherwise errors will happen during the config load +phase.

omusrmsg

The omusrmsg module is used to send messages to users. In legacy-legacy config format (that is the very old sysklogd style), it was suffucient to use diff --git a/tools/ompipe.c b/tools/ompipe.c index 30cb9bfc..b774b60f 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -65,10 +65,6 @@ DEF_OMOD_STATIC_DATA DEFobjCurrIf(errmsg) -/* globals for default values */ -/* end globals for default values */ - - typedef struct _instanceData { uchar *pipe; /* pipe or template name (display only) */ uchar *tplName; /* format template to use */ @@ -82,6 +78,16 @@ typedef struct configSettings_s { static configSettings_t __attribute__((unused)) cs; /* tables for interfacing with the v6 config system */ +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "template", eCmdHdlrGetWord, 0 }, +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + /* action (instance) parameters */ static struct cnfparamdescr actpdescr[] = { { "pipe", eCmdHdlrString, CNFPARAM_REQUIRED }, @@ -93,6 +99,25 @@ static struct cnfparamblk actpblk = actpdescr }; +struct modConfData_s { + rsconf_t *pConf; /* our overall config object */ + uchar *tplName; /* default template */ +}; + +static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ +static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current exec process */ + +/* this function gets the default template */ +static inline uchar* +getDfltTpl(void) +{ + if(loadModConf != NULL && loadModConf->tplName != NULL) + return loadModConf->tplName; + else + return (uchar*)"RSYSLOG_FileFormat"; +} + + BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars ENDinitConfVars @@ -181,6 +206,71 @@ finalize_it: } +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + pModConf->tplName = NULL; +ENDbeginCnfLoad + +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for omfile:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "template")) { + loadModConf->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + if(pszFileDfltTplName != NULL) { + errmsg.LogError(0, RS_RET_DUP_PARAM, "omfile: warning: default template " + "was already set via legacy directive - may lead to inconsistent " + "results."); + } + } else { + dbgprintf("omfile: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + +BEGINendCnfLoad +CODESTARTendCnfLoad + loadModConf = NULL; /* done loading */ + /* free legacy config vars */ + free(pszFileDfltTplName); + pszFileDfltTplName = NULL; +ENDendCnfLoad + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + +BEGINactivateCnf +CODESTARTactivateCnf + runModConf = pModConf; +ENDactivateCnf + +BEGINfreeCnf +CODESTARTfreeCnf + free(pModConf->tplName); +ENDfreeCnf + BEGINcreateInstance CODESTARTcreateInstance pData->pipe = NULL; @@ -273,7 +363,7 @@ CODESTARTparseSelectorAct CHKmalloc(pData->pipe = malloc(512)); ++p; CHKiRet(cflineParseFileName(p, (uchar*) pData->pipe, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, - (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); + getDfltTpl())); CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct @@ -297,7 +387,9 @@ BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES CODEqueryEtryPt_doHUP +CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From 87002e246d9f9978787acb96e0ede97819985fb6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 Jun 2012 17:41:12 +0200 Subject: omfwd: support for module() global config parameters added --- tools/omfwd.c | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 127 insertions(+), 8 deletions(-) diff --git a/tools/omfwd.c b/tools/omfwd.c index 96458941..7d05cb86 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -115,6 +115,16 @@ typedef struct configSettings_s { static configSettings_t cs; /* tables for interfacing with the v6 config system */ +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "template", eCmdHdlrGetWord, 0 }, +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + /* action (instance) parameters */ static struct cnfparamdescr actpdescr[] = { { "target", eCmdHdlrGetWord, 0 }, @@ -135,6 +145,14 @@ static struct cnfparamblk actpblk = actpdescr }; +struct modConfData_s { + rsconf_t *pConf; /* our overall config object */ + uchar *tplName; /* default template */ +}; + +static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ +static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current exec process */ + BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -151,6 +169,44 @@ ENDinitConfVars static rsRetVal doTryResume(instanceData *pData); +/* this function gets the default template. It coordinates action between + * old-style and new-style configuration parts. + */ +static inline uchar* +getDfltTpl(void) +{ + if(loadModConf != NULL && loadModConf->tplName != NULL) + return loadModConf->tplName; + else if(cs.pszTplName == NULL) + return (uchar*)"RSYSLOG_TraditionalForwardFormat"; + else + return cs.pszTplName; +} + + +/* set the default template to be used + * This is a module-global parameter, and as such needs special handling. It needs to + * be coordinated with values set via the v2 config system (rsyslog v6+). What we do + * is we do not permit this directive after the v2 config system has been used to set + * the parameter. + */ +static rsRetVal +setLegacyDfltTpl(void __attribute__((unused)) *pVal, uchar* newVal) +{ + DEFiRet; + + if(loadModConf != NULL && loadModConf->tplName != NULL) { + free(newVal); + errmsg.LogError(0, RS_RET_ERR, "omfwd default template already set via module " + "global parameter - can no longer be changed"); + ABORT_FINALIZE(RS_RET_ERR); + } + free(cs.pszTplName); + cs.pszTplName = newVal; +finalize_it: + RETiRet; +} + /* Close the UDP sockets. * rgerhards, 2009-05-29 */ @@ -189,6 +245,72 @@ DestructTCPInstanceData(instanceData *pData) netstrms.Destruct(&pData->pNS); } + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + pModConf->tplName = NULL; +ENDbeginCnfLoad + +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for omfwd:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "template")) { + loadModConf->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + if(cs.pszTplName != NULL) { + errmsg.LogError(0, RS_RET_DUP_PARAM, "omfwd: warning: default template " + "was already set via legacy directive - may lead to inconsistent " + "results."); + } + } else { + dbgprintf("omfwd: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + +BEGINendCnfLoad +CODESTARTendCnfLoad + loadModConf = NULL; /* done loading */ + /* free legacy config vars */ + free(cs.pszTplName); + cs.pszTplName = NULL; +ENDendCnfLoad + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + +BEGINactivateCnf +CODESTARTactivateCnf + runModConf = pModConf; +ENDactivateCnf + +BEGINfreeCnf +CODESTARTfreeCnf + free(pModConf->tplName); +ENDfreeCnf + BEGINcreateInstance CODESTARTcreateInstance pData->offsSndBuf = 0; @@ -750,9 +872,7 @@ CODESTARTnewActInst } CODE_STD_STRING_REQUESTnewActInst(1) - CHKiRet(OMSRsetEntry(*ppOMSR, 0, ustrdup((pData->tplName == NULL) ? - (uchar*)"RSYSLOG_TraditionalForwardFormat" : (uchar*)pData->tplName), - OMSR_NO_RQD_TPL_OPTS)); + CHKiRet(OMSRsetEntry(*ppOMSR, 0, ustrdup(getDfltTpl()), OMSR_NO_RQD_TPL_OPTS)); CHKiRet(initTCP(pData)); CODE_STD_FINALIZERnewActInst @@ -908,8 +1028,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) cs.iTCPRebindInterval : cs.iUDPRebindInterval; /* process template */ - CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, - (cs.pszTplName == NULL) ? (uchar*)"RSYSLOG_TraditionalForwardFormat" : cs.pszTplName)); + CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, getDfltTpl())); if(pData->protocol == FORW_TCP) { pData->bResendLastOnRecon = cs.bResendLastOnRecon; @@ -935,8 +1054,6 @@ ENDparseSelectorAct static void freeConfigVars(void) { - free(cs.pszTplName); - cs.pszTplName = NULL; free(cs.pszStrmDrvr); cs.pszStrmDrvr = NULL; free(cs.pszStrmDrvrAuthMode); @@ -962,6 +1079,8 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */ ENDqueryEtryPt @@ -993,7 +1112,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(net,LM_NET_FILENAME)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionforwarddefaulttemplate", 0, eCmdHdlrGetWord, NULL, &cs.pszTplName, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionforwarddefaulttemplate", 0, eCmdHdlrGetWord, setLegacyDfltTpl, NULL, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionsendtcprebindinterval", 0, eCmdHdlrInt, NULL, &cs.iTCPRebindInterval, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionsendudprebindinterval", 0, eCmdHdlrInt, NULL, &cs.iUDPRebindInterval, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionsendstreamdriver", 0, eCmdHdlrGetWord, NULL, &cs.pszStrmDrvr, NULL)); -- cgit v1.2.3 From 5de5166e44da181d042129585a2919550236a5a0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 Jun 2012 17:42:41 +0200 Subject: ompipe: fix copy&paste name errors --- tools/ompipe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/ompipe.c b/tools/ompipe.c index b774b60f..d293114f 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -225,7 +225,7 @@ CODESTARTsetModCnf } if(Debug) { - dbgprintf("module (global) param blk for omfile:\n"); + dbgprintf("module (global) param blk for ompipe:\n"); cnfparamsPrint(&modpblk, pvals); } @@ -235,12 +235,12 @@ CODESTARTsetModCnf if(!strcmp(modpblk.descr[i].name, "template")) { loadModConf->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); if(pszFileDfltTplName != NULL) { - errmsg.LogError(0, RS_RET_DUP_PARAM, "omfile: warning: default template " + errmsg.LogError(0, RS_RET_DUP_PARAM, "ompipe: warning: default template " "was already set via legacy directive - may lead to inconsistent " "results."); } } else { - dbgprintf("omfile: program error, non-handled " + dbgprintf("ompipe: program error, non-handled " "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); } } -- cgit v1.2.3 From 9f3dfc0efe5e63af2b6b6cc44be4afd583603bd2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 Jun 2012 17:52:56 +0200 Subject: doc: typo fix --- doc/omuxsock.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/omuxsock.html b/doc/omuxsock.html index 5fa569eb..a1c09228 100644 --- a/doc/omuxsock.html +++ b/doc/omuxsock.html @@ -29,7 +29,7 @@ actions and each of them should use the same template.

Sample:

The following sample writes all messages to the "/tmp/socksample" socket.

- -- cgit v1.2.3 From 4ed4e8c287a482c8dec1783555f70408e9673e3f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 Jun 2012 18:00:45 +0200 Subject: omuxsock: support for module() global config parameters added --- plugins/omuxsock/omuxsock.c | 132 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 128 insertions(+), 4 deletions(-) diff --git a/plugins/omuxsock/omuxsock.c b/plugins/omuxsock/omuxsock.c index cf27c93c..583b9f94 100644 --- a/plugins/omuxsock/omuxsock.c +++ b/plugins/omuxsock/omuxsock.c @@ -71,6 +71,26 @@ typedef struct configSettings_s { } configSettings_t; static configSettings_t cs; +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "template", eCmdHdlrGetWord, 0 }, +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + +struct modConfData_s { + rsconf_t *pConf; /* our overall config object */ + uchar *tplName; /* default template */ +}; + +static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ +static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current exec process */ + + + BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars cs.tplName = NULL; @@ -80,8 +100,45 @@ ENDinitConfVars static rsRetVal doTryResume(instanceData *pData); -/* Close socket. + +/* this function gets the default template. It coordinates action between + * old-style and new-style configuration parts. + */ +static inline uchar* +getDfltTpl(void) +{ + if(loadModConf != NULL && loadModConf->tplName != NULL) + return loadModConf->tplName; + else if(cs.tplName == NULL) + return (uchar*)"RSYSLOG_TraditionalForwardFormat"; + else + return cs.tplName; +} + +/* set the default template to be used + * This is a module-global parameter, and as such needs special handling. It needs to + * be coordinated with values set via the v2 config system (rsyslog v6+). What we do + * is we do not permit this directive after the v2 config system has been used to set + * the parameter. */ +rsRetVal +setLegacyDfltTpl(void __attribute__((unused)) *pVal, uchar* newVal) +{ + DEFiRet; + + if(loadModConf != NULL && loadModConf->tplName != NULL) { + free(newVal); + errmsg.LogError(0, RS_RET_ERR, "omuxsock default template already set via module " + "global parameter - can no longer be changed"); + ABORT_FINALIZE(RS_RET_ERR); + } + free(cs.tplName); + cs.tplName = newVal; +finalize_it: + RETiRet; +} + + static inline rsRetVal closeSocket(instanceData *pData) { @@ -96,6 +153,72 @@ pData->bIsConnected = 0; // TODO: remove this variable altogether + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + pModConf->tplName = NULL; +ENDbeginCnfLoad + +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for omuxsock:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "template")) { + loadModConf->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + if(cs.tplName != NULL) { + errmsg.LogError(0, RS_RET_DUP_PARAM, "omuxsock: warning: default template " + "was already set via legacy directive - may lead to inconsistent " + "results."); + } + } else { + dbgprintf("omuxsock: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + +BEGINendCnfLoad +CODESTARTendCnfLoad + loadModConf = NULL; /* done loading */ + /* free legacy config vars */ + free(cs.tplName); + cs.tplName = NULL; +ENDendCnfLoad + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + +BEGINactivateCnf +CODESTARTactivateCnf + runModConf = pModConf; +ENDactivateCnf + +BEGINfreeCnf +CODESTARTfreeCnf + free(pModConf->tplName); +ENDfreeCnf + BEGINcreateInstance CODESTARTcreateInstance pData->sock = INVLD_SOCK; @@ -250,8 +373,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) /* check if a non-standard template is to be applied */ if(*(p-1) == ';') --p; - CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0, cs.tplName == NULL ? UCHAR_CONSTANT("RSYSLOG_TraditionalForwardFormat") - : cs.tplName )); + CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0, getDfltTpl())); if(cs.sockName == NULL) { errmsg.LogError(0, RS_RET_NO_SOCK_CONFIGURED, "No output socket configured for omuxsock\n"); @@ -291,6 +413,8 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES ENDqueryEtryPt @@ -312,7 +436,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(glbl, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); - CHKiRet(regCfSysLineHdlr((uchar *)"omuxsockdefaulttemplate", 0, eCmdHdlrGetWord, NULL, &cs.tplName, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"omuxsockdefaulttemplate", 0, eCmdHdlrGetWord, setLegacyDfltTpl, NULL, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"omuxsocksocket", 0, eCmdHdlrGetWord, NULL, &cs.sockName, NULL)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit -- cgit v1.2.3 From ef12fd6b1d1adc8cb5f2ad7c85833993c11772dc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 Jun 2012 18:03:01 +0200 Subject: omudpspoof: remove actually not existing compresion level param This seems to be a copy&paste problem from the initial implementation. The parameter was never documented (how could it have been? ;)), so this causes no problems. In fact, it also did nothing except setting a few never-used variables ;) --- plugins/omudpspoof/omudpspoof.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c index 43b36551..ce5d1f9b 100644 --- a/plugins/omudpspoof/omudpspoof.c +++ b/plugins/omudpspoof/omudpspoof.c @@ -111,7 +111,6 @@ typedef struct configSettings_s { uchar *pszSourceNameTemplate; /* name of the template containing the spoofing address */ uchar *pszTargetHost; uchar *pszTargetPort; - int iCompressionLevel; /* zlib compressionlevel, the usual values */ int iSourcePortStart; int iSourcePortEnd; } configSettings_t; @@ -123,7 +122,6 @@ CODESTARTinitConfVars cs.pszSourceNameTemplate = NULL; cs.pszTargetHost = NULL; cs.pszTargetPort = NULL; - cs.iCompressionLevel = 0; cs.iSourcePortStart = DFLT_SOURCE_PORT_START; cs.iSourcePortEnd = DFLT_SOURCE_PORT_END; ENDinitConfVars @@ -421,7 +419,6 @@ CODE_STD_STRING_REQUESTparseSelectorAct(2) else CHKmalloc(pData->port = ustrdup(cs.pszTargetPort)); CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(sourceTpl), OMSR_NO_RQD_TPL_OPTS)); - pData->compressionLevel = cs.iCompressionLevel; pData->sourcePort = pData->sourcePortStart = cs.iSourcePortStart; pData->sourcePortEnd = cs.iSourcePortEnd; @@ -474,7 +471,6 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a { freeConfigVars(); /* we now must reset all non-string values */ - cs.iCompressionLevel = 0; cs.iSourcePortStart = DFLT_SOURCE_PORT_START; cs.iSourcePortEnd = DFLT_SOURCE_PORT_END; return RS_RET_OK; @@ -510,7 +506,6 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspooftargetport", 0, eCmdHdlrGetWord, NULL, &cs.pszTargetPort, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofsourceportstart", 0, eCmdHdlrInt, NULL, &cs.iSourcePortStart, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofsourceportend", 0, eCmdHdlrInt, NULL, &cs.iSourcePortEnd, NULL)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpcompressionlevel", 0, eCmdHdlrInt, NULL, &cs.iCompressionLevel, NULL)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit -- cgit v1.2.3 From b950b862289ce668b98e2a6bbb6e2c48445b2e47 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 Jun 2012 18:09:39 +0200 Subject: omudpspoof: support for module() global config parameters added --- plugins/omudpspoof/omudpspoof.c | 138 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 132 insertions(+), 6 deletions(-) diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c index ce5d1f9b..4ada8eb0 100644 --- a/plugins/omudpspoof/omudpspoof.c +++ b/plugins/omudpspoof/omudpspoof.c @@ -107,7 +107,7 @@ typedef struct _instanceData { #define DFLT_SOURCE_PORT_END 42000 typedef struct configSettings_s { - uchar *pszTplName; /* name of the default template to use */ + uchar *tplName; /* name of the default template to use */ uchar *pszSourceNameTemplate; /* name of the template containing the spoofing address */ uchar *pszTargetHost; uchar *pszTargetPort; @@ -116,9 +116,29 @@ typedef struct configSettings_s { } configSettings_t; static configSettings_t cs; +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "template", eCmdHdlrGetWord, 0 }, +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + +struct modConfData_s { + rsconf_t *pConf; /* our overall config object */ + uchar *tplName; /* default template */ +}; + +static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ +static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current exec process */ + + + BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars - cs.pszTplName = NULL; + cs.tplName = NULL; cs.pszSourceNameTemplate = NULL; cs.pszTargetHost = NULL; cs.pszTargetPort = NULL; @@ -136,6 +156,44 @@ pthread_mutex_t mutLibnet; static rsRetVal doTryResume(instanceData *pData); +/* this function gets the default template. It coordinates action between + * old-style and new-style configuration parts. + */ +static inline uchar* +getDfltTpl(void) +{ + if(loadModConf != NULL && loadModConf->tplName != NULL) + return loadModConf->tplName; + else if(cs.tplName == NULL) + return (uchar*)"RSYSLOG_FileFormat"; + else + return cs.tplName; +} + + +/* set the default template to be used + * This is a module-global parameter, and as such needs special handling. It needs to + * be coordinated with values set via the v2 config system (rsyslog v6+). What we do + * is we do not permit this directive after the v2 config system has been used to set + * the parameter. + */ +rsRetVal +setLegacyDfltTpl(void __attribute__((unused)) *pVal, uchar* newVal) +{ + DEFiRet; + + if(loadModConf != NULL && loadModConf->tplName != NULL) { + free(newVal); + errmsg.LogError(0, RS_RET_ERR, "omudpspoof default template already set via module " + "global parameter - can no longer be changed"); + ABORT_FINALIZE(RS_RET_ERR); + } + free(cs.tplName); + cs.tplName = newVal; +finalize_it: + RETiRet; +} + /* Close the UDP sockets. * rgerhards, 2009-05-29 */ @@ -165,6 +223,72 @@ static inline uchar *getFwdPt(instanceData *pData) } +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + pModConf->tplName = NULL; +ENDbeginCnfLoad + +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for omudpspoof:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "template")) { + loadModConf->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + if(cs.tplName != NULL) { + errmsg.LogError(0, RS_RET_DUP_PARAM, "omudpspoof: warning: default template " + "was already set via legacy directive - may lead to inconsistent " + "results."); + } + } else { + dbgprintf("omudpspoof: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + +BEGINendCnfLoad +CODESTARTendCnfLoad + loadModConf = NULL; /* done loading */ + /* free legacy config vars */ + free(cs.tplName); + cs.tplName = NULL; +ENDendCnfLoad + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + +BEGINactivateCnf +CODESTARTactivateCnf + runModConf = pModConf; +ENDactivateCnf + +BEGINfreeCnf +CODESTARTfreeCnf + free(pModConf->tplName); +ENDfreeCnf + + BEGINcreateInstance CODESTARTcreateInstance ENDcreateInstance @@ -424,7 +548,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(2) /* process template */ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, - (cs.pszTplName == NULL) ? (uchar*)"RSYSLOG_TraditionalForwardFormat" : cs.pszTplName)); + (cs.tplName == NULL) ? (uchar*)"RSYSLOG_TraditionalForwardFormat" : cs.tplName)); CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct @@ -436,8 +560,8 @@ ENDparseSelectorAct static void freeConfigVars(void) { - free(cs.pszTplName); - cs.pszTplName = NULL; + free(cs.tplName); + cs.tplName = NULL; free(cs.pszTargetHost); cs.pszTargetHost = NULL; free(cs.pszTargetPort); @@ -461,6 +585,8 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES ENDqueryEtryPt @@ -500,7 +626,7 @@ CODEmodInit_QueryRegCFSLineHdlr } pthread_mutex_init(&mutLibnet, NULL); - CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofdefaulttemplate", 0, eCmdHdlrGetWord, NULL, &cs.pszTplName, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofdefaulttemplate", 0, eCmdHdlrGetWord, setLegacyDfltTpl, NULL, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspoofsourcenametemplate", 0, eCmdHdlrGetWord, NULL, &cs.pszSourceNameTemplate, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspooftargethost", 0, eCmdHdlrGetWord, NULL, &cs.pszTargetHost, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionomudpspooftargetport", 0, eCmdHdlrGetWord, NULL, &cs.pszTargetPort, NULL)); -- cgit v1.2.3 From 9b0d03bf8f5eb89d5a1966df16187c5c6757c578 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 26 Jun 2012 17:18:20 +0200 Subject: modules: call new-style entry point only when new-style stmt is used This provides a way for modules to differentiate between old- and new- style config, so that they can react accordingly. --- runtime/modules.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/runtime/modules.c b/runtime/modules.c index 6417cecd..bc8580f1 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -1011,7 +1011,8 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) * because there is no way to set parameters at load * time for obvious reasons... */ - pModInfo->setModCnf(lst); + if(lst != NULL) + pModInfo->setModCnf(lst); pModInfo->bSetModCnfCalled = 1; } } @@ -1128,7 +1129,8 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) if(bConfLoad) { addModToCnfList(pModInfo); if(pModInfo->setModCnf != NULL) { - pModInfo->setModCnf(lst); + if(lst != NULL) + pModInfo->setModCnf(lst); pModInfo->bSetModCnfCalled = 1; } } -- cgit v1.2.3 From dd0572f2a535731828e9c587b036165834166d52 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 26 Jun 2012 17:19:23 +0200 Subject: impstats: support for module() global config parameters added --- plugins/impstats/impstats.c | 128 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 103 insertions(+), 25 deletions(-) diff --git a/plugins/impstats/impstats.c b/plugins/impstats/impstats.c index 0abde84a..84d78178 100644 --- a/plugins/impstats/impstats.c +++ b/plugins/impstats/impstats.c @@ -68,15 +68,39 @@ struct modConfData_s { int iFacility; int iSeverity; statsFmtType_t statsFmt; + sbool configSetViaV2Method; }; static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ - static configSettings_t cs; - static prop_t *pInputName = NULL; +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "interval", eCmdHdlrInt, 0 }, + { "facility", eCmdHdlrInt, 0 }, + { "severity", eCmdHdlrInt, 0 }, + { "format", eCmdHdlrGetWord, 0 }, + { "cee", eCmdHdlrInt, 0 } +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + +BEGINmodExit +CODESTARTmodExit + prop.Destruct(&pInputName); + /* release objects we used */ + objRelease(glbl, CORE_COMPONENT); + objRelease(prop, CORE_COMPONENT); + objRelease(errmsg, CORE_COMPONENT); + objRelease(statsobj, CORE_COMPONENT); +ENDmodExit + + BEGINisCompatibleWithFeature CODESTARTisCompatibleWithFeature if(eFeat == sFEATURENonCancelInputTermination) @@ -148,23 +172,88 @@ BEGINbeginCnfLoad CODESTARTbeginCnfLoad loadModConf = pModConf; pModConf->pConf = pConf; + /* init our settings */ + loadModConf->configSetViaV2Method = 0; + loadModConf->iStatsInterval = DEFAULT_STATS_PERIOD; + loadModConf->iFacility = DEFAULT_FACILITY; + loadModConf->iSeverity = DEFAULT_SEVERITY; + loadModConf->statsFmt = statsFmt_Legacy; /* init legacy config vars */ initConfigSettings(); ENDbeginCnfLoad +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + char *mode; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for impstats:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "interval")) { + loadModConf->iStatsInterval = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "facility")) { + loadModConf->iFacility = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "severity")) { + loadModConf->iSeverity = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "format")) { + mode = es_str2cstr(pvals[i].val.d.estr, NULL); + if(!strcasecmp(mode, "json")) { + loadModConf->statsFmt = statsFmt_JSON; + } else if(!strcasecmp(mode, "cee")) { + loadModConf->statsFmt = statsFmt_CEE; + } else if(!strcasecmp(mode, "legacy")) { + loadModConf->statsFmt = statsFmt_Legacy; + } else { + errmsg.LogError(0, RS_RET_ERR, "impstats: invalid format %s", + mode); + } + } else { + dbgprintf("impstats: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } + + /* remove all of our legacy handlers, as they can not used in addition + * the the new-style config method. + */ + unregCfSysLineHdlrs4Owner(STD_LOADABLE_MODULE_ID); + loadModConf->configSetViaV2Method = 1; + +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + + BEGINendCnfLoad CODESTARTendCnfLoad - /* persist module-specific settings from legacy config system */ - loadModConf->iStatsInterval = cs.iStatsInterval; - loadModConf->iFacility = cs.iFacility; - loadModConf->iSeverity = cs.iSeverity; - if (cs.bCEE == 1) { - loadModConf->statsFmt = statsFmt_CEE; - } else if (cs.bJSON == 1) { - loadModConf->statsFmt = statsFmt_JSON; - } else { - loadModConf->statsFmt = statsFmt_Legacy; +dbgprintf("AAA: impstats, v2 config set: %d\n", loadModConf->configSetViaV2Method); + if(!loadModConf->configSetViaV2Method) { + /* persist module-specific settings from legacy config system */ + loadModConf->iStatsInterval = cs.iStatsInterval; + loadModConf->iFacility = cs.iFacility; + loadModConf->iSeverity = cs.iSeverity; + if (cs.bCEE == 1) { + loadModConf->statsFmt = statsFmt_CEE; + } else if (cs.bJSON == 1) { + loadModConf->statsFmt = statsFmt_JSON; + } else { + loadModConf->statsFmt = statsFmt_Legacy; + } } ENDendCnfLoad @@ -173,7 +262,7 @@ BEGINcheckCnf CODESTARTcheckCnf if(pModConf->iStatsInterval == 0) { errmsg.LogError(0, NO_ERRCODE, "impstats: stats interval zero not permitted, using " - "defaul of %d seconds", DEFAULT_STATS_PERIOD); + "default of %d seconds", DEFAULT_STATS_PERIOD); pModConf->iStatsInterval = DEFAULT_STATS_PERIOD; } ENDcheckCnf @@ -225,22 +314,11 @@ CODESTARTafterRun ENDafterRun -BEGINmodExit -CODESTARTmodExit - prop.Destruct(&pInputName); - /* release objects we used */ - objRelease(glbl, CORE_COMPONENT); - objRelease(prop, CORE_COMPONENT); - objRelease(errmsg, CORE_COMPONENT); - objRelease(statsobj, CORE_COMPONENT); -ENDmodExit - - - BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From 71559ed4d8c1e96c0993751e19fae788457c91cd Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 26 Jun 2012 18:33:41 +0200 Subject: imudp: support for module() global config parameters added --- plugins/impstats/impstats.c | 5 +- plugins/imudp/imudp.c | 130 +++++++++++++++++++++++--------------------- 2 files changed, 71 insertions(+), 64 deletions(-) diff --git a/plugins/impstats/impstats.c b/plugins/impstats/impstats.c index 84d78178..2b1bfd1d 100644 --- a/plugins/impstats/impstats.c +++ b/plugins/impstats/impstats.c @@ -81,8 +81,7 @@ static struct cnfparamdescr modpdescr[] = { { "interval", eCmdHdlrInt, 0 }, { "facility", eCmdHdlrInt, 0 }, { "severity", eCmdHdlrInt, 0 }, - { "format", eCmdHdlrGetWord, 0 }, - { "cee", eCmdHdlrInt, 0 } + { "format", eCmdHdlrGetWord, 0 } }; static struct cnfparamblk modpblk = { CNFPARAMBLK_VERSION, @@ -221,6 +220,7 @@ CODESTARTsetModCnf errmsg.LogError(0, RS_RET_ERR, "impstats: invalid format %s", mode); } + free(mode); } else { dbgprintf("impstats: program error, non-handled " "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); @@ -241,7 +241,6 @@ ENDsetModCnf BEGINendCnfLoad CODESTARTendCnfLoad -dbgprintf("AAA: impstats, v2 config set: %d\n", loadModConf->configSetViaV2Method); if(!loadModConf->configSetViaV2Method) { /* persist module-specific settings from legacy config system */ loadModConf->iStatsInterval = cs.iStatsInterval; diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 165b6680..4f421d8f 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -6,7 +6,7 @@ * * File begun on 2007-12-21 by RGerhards (extracted from syslogd.c) * - * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2012 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -118,10 +118,23 @@ struct modConfData_s { int iSchedPolicy; /* scheduling policy as SCHED_xxx */ int iSchedPrio; /* scheduling priority */ int iTimeRequery; /* how often is time to be queried inside tight recv loop? 0=always */ + sbool configSetViaV2Method; }; static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "schedulingpolicy", eCmdHdlrGetWord, 0 }, + { "schedulingpriority", eCmdHdlrInt, 0 }, + { "timerequery", eCmdHdlrInt, 0 } +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + #include "im-helper.h" /* must be included AFTER the type definitions! */ @@ -185,52 +198,6 @@ addListner(instanceConf_t *inst) /* check which address to bind to. We could do this more compact, but have not * done so in order to make the code more readable. -- rgerhards, 2007-12-27 */ -#if 0 //<<<<<<< HEAD - - DBGPRINTF("imudp: trying to open port at %s:%s.\n", - (inst->pszBindAddr == NULL) ? (uchar*)"*" : inst->pszBindAddr, inst->pszBindPort); - - newSocks = net.create_udp_socket(inst->pszBindAddr, inst->pszBindPort, 1); - if(newSocks != NULL) { - /* we now need to add the new sockets to the existing set */ - if(udpLstnSocks == NULL) { - /* esay, we can just replace it */ - udpLstnSocks = newSocks; - CHKmalloc(udpRulesets = (ruleset_t**) MALLOC(sizeof(ruleset_t*) * (newSocks[0] + 1))); - for(iDst = 1 ; iDst <= newSocks[0] ; ++iDst) - udpRulesets[iDst] = inst->pBindRuleset; - } else { - /* we need to add them */ - tmpSocks = (int*) MALLOC(sizeof(int) * (1 + newSocks[0] + udpLstnSocks[0])); - tmpRulesets = (ruleset_t**) MALLOC(sizeof(ruleset_t*) * (1 + newSocks[0] + udpLstnSocks[0])); - if(tmpSocks == NULL || tmpRulesets == NULL) { - DBGPRINTF("out of memory trying to allocate udp listen socket array\n"); - /* in this case, we discard the new sockets but continue with what we - * already have - */ - free(newSocks); - free(tmpSocks); - free(tmpRulesets); - ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); - } else { - /* ready to copy */ - iDst = 1; - for(iSrc = 1 ; iSrc <= udpLstnSocks[0] ; ++iSrc, ++iDst) { - tmpSocks[iDst] = udpLstnSocks[iSrc]; - tmpRulesets[iDst] = udpRulesets[iSrc]; - } - for(iSrc = 1 ; iSrc <= newSocks[0] ; ++iSrc, ++iDst) { - tmpSocks[iDst] = newSocks[iSrc]; - tmpRulesets[iDst] = inst->pBindRuleset; - } - tmpSocks[0] = udpLstnSocks[0] + newSocks[0]; - free(newSocks); - free(udpLstnSocks); - udpLstnSocks = tmpSocks; - free(udpRulesets); - udpRulesets = tmpRulesets; - } -#else //======= if(inst->pszBindAddr == NULL) bindAddr = NULL; else if(inst->pszBindAddr[0] == '*' && inst->pszBindAddr[1] == '\0') @@ -270,7 +237,6 @@ addListner(instanceConf_t *inst) else { lcnfLast->next = newlcnfinfo; lcnfLast = newlcnfinfo; -#endif //>>>>>>> ef34821a2737799f48c3032b9616418e4f7fa34f } } } @@ -672,6 +638,11 @@ BEGINbeginCnfLoad CODESTARTbeginCnfLoad loadModConf = pModConf; pModConf->pConf = pConf; + /* init our settings */ + loadModConf->configSetViaV2Method = 0; + loadModConf->iTimeRequery = TIME_REQUERY_DFLT; + loadModConf->iSchedPrio = SCHED_PRIO_UNSET; + loadModConf->pszSchedPolicy = NULL; /* init legacy config vars */ cs.pszBindRuleset = NULL; cs.pszSchedPolicy = NULL; @@ -681,21 +652,56 @@ CODESTARTbeginCnfLoad ENDbeginCnfLoad +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for impstats:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "timerequery")) { + loadModConf->iTimeRequery = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "schedulingpriority")) { + loadModConf->iSchedPrio = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "schedulingpolicy")) { + loadModConf->pszSchedPolicy = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + dbgprintf("impstats: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } + + /* remove all of our legacy handlers, as they can not used in addition + * the the new-style config method. + */ + loadModConf->configSetViaV2Method = 1; + +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + BEGINendCnfLoad CODESTARTendCnfLoad - /* persist module-specific settings from legacy config system - * TODO: when we add the new config system, we must decide on priority - * already-set module options should not be overwritable by the legacy - * system (though this is debatable and should at least trigger an error - * message if the equivalent legacy option is selected as well) - * rgerhards, 2011-05-04 - */ - loadModConf->iSchedPrio = cs.iSchedPrio; - loadModConf->iTimeRequery = cs.iTimeRequery; - if((cs.pszSchedPolicy == NULL) || (cs.pszSchedPolicy[0] == '\0')) { - loadModConf->pszSchedPolicy = NULL; - } else { - CHKmalloc(loadModConf->pszSchedPolicy = ustrdup(cs.pszSchedPolicy)); + if(!loadModConf->configSetViaV2Method) { + /* persist module-specific settings from legacy config system */ + loadModConf->iSchedPrio = cs.iSchedPrio; + loadModConf->iTimeRequery = cs.iTimeRequery; + if((cs.pszSchedPolicy != NULL) && (cs.pszSchedPolicy[0] != '\0')) { + CHKmalloc(loadModConf->pszSchedPolicy = ustrdup(cs.pszSchedPolicy)); + } } finalize_it: @@ -746,6 +752,7 @@ CODESTARTactivateCnf /* caching various settings */ iMaxLine = glbl.GetMaxLine(); CHKmalloc(pRcvBuf = MALLOC((iMaxLine + 1) * sizeof(char))); +dbgprintf("AAA: timerequery %d\n", runModConf->iTimeRequery); finalize_it: ENDactivateCnf @@ -828,6 +835,7 @@ BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From ac5a2673ebab72c0c52f59d8e6c175e05268dfc8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 26 Jun 2012 19:08:02 +0200 Subject: provide support to dynamically enable/disable legacy conf command most important to prevent clashes with new style settings --- plugins/impstats/impstats.c | 19 +++++++++---------- plugins/imudp/imudp.c | 19 +++++++++++++------ runtime/cfsysline.c | 38 ++++++++++++++++++++++++++++++-------- runtime/cfsysline.h | 2 ++ runtime/rsyslog.h | 1 + 5 files changed, 55 insertions(+), 24 deletions(-) diff --git a/plugins/impstats/impstats.c b/plugins/impstats/impstats.c index 2b1bfd1d..62599969 100644 --- a/plugins/impstats/impstats.c +++ b/plugins/impstats/impstats.c @@ -74,6 +74,7 @@ static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current l static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ static configSettings_t cs; +static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */ static prop_t *pInputName = NULL; /* module-global parameters */ @@ -177,6 +178,7 @@ CODESTARTbeginCnfLoad loadModConf->iFacility = DEFAULT_FACILITY; loadModConf->iSeverity = DEFAULT_SEVERITY; loadModConf->statsFmt = statsFmt_Legacy; + bLegacyCnfModGlobalsPermitted = 1; /* init legacy config vars */ initConfigSettings(); ENDbeginCnfLoad @@ -227,11 +229,8 @@ CODESTARTsetModCnf } } - /* remove all of our legacy handlers, as they can not used in addition - * the the new-style config method. - */ - unregCfSysLineHdlrs4Owner(STD_LOADABLE_MODULE_ID); loadModConf->configSetViaV2Method = 1; + bLegacyCnfModGlobalsPermitted = 0; finalize_it: if(pvals != NULL) @@ -339,12 +338,12 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(statsobj, CORE_COMPONENT)); /* the pstatsinverval is an alias to support a previous screwed-up syntax... */ - CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatsinterval", 0, eCmdHdlrInt, NULL, &cs.iStatsInterval, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatinterval", 0, eCmdHdlrInt, NULL, &cs.iStatsInterval, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatfacility", 0, eCmdHdlrInt, NULL, &cs.iFacility, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatseverity", 0, eCmdHdlrInt, NULL, &cs.iSeverity, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatjson", 0, eCmdHdlrBinary, NULL, &cs.bJSON, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"pstatcee", 0, eCmdHdlrBinary, NULL, &cs.bCEE, STD_LOADABLE_MODULE_ID)); + CHKiRet(regCfSysLineHdlr2((uchar *)"pstatsinterval", 0, eCmdHdlrInt, NULL, &cs.iStatsInterval, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"pstatinterval", 0, eCmdHdlrInt, NULL, &cs.iStatsInterval, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"pstatfacility", 0, eCmdHdlrInt, NULL, &cs.iFacility, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"pstatseverity", 0, eCmdHdlrInt, NULL, &cs.iSeverity, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"pstatjson", 0, eCmdHdlrBinary, NULL, &cs.bJSON, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"pstatcee", 0, eCmdHdlrBinary, NULL, &cs.bCEE, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(prop.Construct(&pInputName)); diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 4f421d8f..9cb28550 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -80,6 +80,7 @@ static struct lstn_s { STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit) } *lcnfRoot = NULL, *lcnfLast = NULL; +static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */ static int bDoACLCheck; /* are ACL checks neeed? Cached once immediately before listener startup */ static int iMaxLine; /* maximum UDP message size supported */ static time_t ttLastDiscard = 0; /* timestamp when a message from a non-permitted sender was last discarded @@ -643,6 +644,7 @@ CODESTARTbeginCnfLoad loadModConf->iTimeRequery = TIME_REQUERY_DFLT; loadModConf->iSchedPrio = SCHED_PRIO_UNSET; loadModConf->pszSchedPolicy = NULL; + bLegacyCnfModGlobalsPermitted = 1; /* init legacy config vars */ cs.pszBindRuleset = NULL; cs.pszSchedPolicy = NULL; @@ -686,6 +688,7 @@ CODESTARTsetModCnf /* remove all of our legacy handlers, as they can not used in addition * the the new-style config method. */ + bLegacyCnfModGlobalsPermitted = 0; loadModConf->configSetViaV2Method = 1; finalize_it: @@ -884,12 +887,16 @@ CODEmodInit_QueryRegCFSLineHdlr addInstance, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpserveraddress", 0, eCmdHdlrGetWord, NULL, &cs.pszBindAddr, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"imudpschedulingpolicy", 0, eCmdHdlrGetWord, - NULL, &cs.pszSchedPolicy, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"imudpschedulingpriority", 0, eCmdHdlrInt, - NULL, &cs.iSchedPrio, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpservertimerequery", 0, eCmdHdlrInt, - NULL, &cs.iTimeRequery, STD_LOADABLE_MODULE_ID)); + /* module-global config params - will be disabled in configs that are loaded + * via module(...). + */ + CHKiRet(regCfSysLineHdlr2((uchar *)"imudpschedulingpolicy", 0, eCmdHdlrGetWord, + NULL, &cs.pszSchedPolicy, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"imudpschedulingpriority", 0, eCmdHdlrInt, + NULL, &cs.iSchedPrio, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"udpservertimerequery", 0, eCmdHdlrInt, + NULL, &cs.iTimeRequery, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c index d8c33169..6b06d427 100644 --- a/runtime/cfsysline.c +++ b/runtime/cfsysline.c @@ -686,7 +686,7 @@ static int cslchKeyCompare(void *pKey1, void *pKey2) /* set data members for this object */ -rsRetVal cslchSetEntry(cslCmdHdlr_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData) +rsRetVal cslchSetEntry(cslCmdHdlr_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, int *permitted) { assert(pThis != NULL); assert(eType != eCmdHdlrInvalid); @@ -694,6 +694,7 @@ rsRetVal cslchSetEntry(cslCmdHdlr_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pH pThis->eType = eType; pThis->cslCmdHdlr = pHdlr; pThis->pData = pData; + pThis->permitted = permitted; return RS_RET_OK; } @@ -810,7 +811,7 @@ finalize_it: /* add a handler entry to a known command */ -static rsRetVal cslcAddHdlr(cslCmd_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie) +static rsRetVal cslcAddHdlr(cslCmd_t *pThis, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie, int *permitted) { DEFiRet; cslCmdHdlr_t *pCmdHdlr = NULL; @@ -818,7 +819,7 @@ static rsRetVal cslcAddHdlr(cslCmd_t *pThis, ecslCmdHdrlType eType, rsRetVal (*p assert(pThis != NULL); CHKiRet(cslchConstruct(&pCmdHdlr)); - CHKiRet(cslchSetEntry(pCmdHdlr, eType, pHdlr, pData)); + CHKiRet(cslchSetEntry(pCmdHdlr, eType, pHdlr, pData, permitted)); CHKiRet(llAppend(&pThis->llCmdHdlrs, pOwnerCookie, pCmdHdlr)); finalize_it: @@ -836,8 +837,16 @@ finalize_it: * buffer is automatically destroyed when the element is freed, the * caller does not need to take care of that. The caller must, however, * free pCmdName if he allocated it dynamically! -- rgerhards, 2007-08-09 + * Parameter permitted has been added to support the v2 config system. With it, + * we can tell the legacy system (us here!) to check if a config directive is + * still permitted. For example, the v2 system will disable module global + * paramters if the are supplied via the native v2 callbacks. In order not + * to break exisiting modules, we have renamed the rgCfSysLinHdlr routine to + * version 2 and added a new one with the original name. It just calls the + * v2 function and supplies a "don't care (NULL)" pointer as this argument. + * rgerhards, 2012-06-26 */ -rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie) +rsRetVal regCfSysLineHdlr2(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie, int *permitted) { DEFiRet; cslCmd_t *pThis; @@ -847,7 +856,7 @@ rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlTy if(iRet == RS_RET_NOT_FOUND) { /* new command */ CHKiRet(cslcConstruct(&pThis, bChainingPermitted)); - CHKiRet_Hdlr(cslcAddHdlr(pThis, eType, pHdlr, pData, pOwnerCookie)) { + CHKiRet_Hdlr(cslcAddHdlr(pThis, eType, pHdlr, pData, pOwnerCookie, permitted)) { cslcDestruct(pThis); FINALIZE; } @@ -867,7 +876,7 @@ rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlTy if(pThis->bChainingPermitted == 0 || bChainingPermitted == 0) { ABORT_FINALIZE(RS_RET_CHAIN_NOT_PERMITTED); } - CHKiRet_Hdlr(cslcAddHdlr(pThis, eType, pHdlr, pData, pOwnerCookie)) { + CHKiRet_Hdlr(cslcAddHdlr(pThis, eType, pHdlr, pData, pOwnerCookie, permitted)) { cslcDestruct(pThis); FINALIZE; } @@ -877,6 +886,13 @@ finalize_it: RETiRet; } +rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie) +{ + DEFiRet; + iRet = regCfSysLineHdlr2(pCmdName, bChainingPermitted, eType, pHdlr, pData, pOwnerCookie, NULL); + RETiRet; +} + rsRetVal unregCfSysLineHdlrs(void) { @@ -947,7 +963,8 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p) iRet = llFind(&llCmdList, (void *) pCmdName, (void*) &pCmd); if(iRet == RS_RET_NOT_FOUND) { - errmsg.LogError(0, RS_RET_NOT_FOUND, "invalid or yet-unknown config file command - have you forgotten to load a module?"); + errmsg.LogError(0, RS_RET_NOT_FOUND, "invalid or yet-unknown config file command '%s' - " + "have you forgotten to load a module?", pCmdName); } if(iRet != RS_RET_OK) @@ -964,7 +981,12 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p) * necessary). -- rgerhards, 2007-07-31 */ pHdlrP = *p; - if((iRet = cslchCallHdlr(pCmdHdlr, &pHdlrP)) == RS_RET_OK) { + if(pCmdHdlr->permitted != NULL && !*(pCmdHdlr->permitted)) { + errmsg.LogError(0, RS_RET_PARAM_NOT_PERMITTED, "command '%s' is currently not " + "permitted - did you already set it via a RainerScript command (v6+ config)?", + pCmdName); + ABORT_FINALIZE(RS_RET_PARAM_NOT_PERMITTED); + } else if((iRet = cslchCallHdlr(pCmdHdlr, &pHdlrP)) == RS_RET_OK) { bWasOnceOK = 1; pOKp = pHdlrP; } diff --git a/runtime/cfsysline.h b/runtime/cfsysline.h index 2768243f..69389f84 100644 --- a/runtime/cfsysline.h +++ b/runtime/cfsysline.h @@ -33,6 +33,7 @@ struct cslCmdHdlr_s { /* config file sysline parse entry */ ecslCmdHdrlType eType; /* which type of handler is this? */ rsRetVal (*cslCmdHdlr)(); /* function pointer to use with handler (params depending on eType) */ void *pData; /* user-supplied data pointer */ + int *permitted; /* is this parameter currently permitted? (NULL=don't check) */ }; typedef struct cslCmdHdlr_s cslCmdHdlr_t; @@ -49,6 +50,7 @@ typedef struct cslCmd_s cslCmd_t; /* prototypes */ rsRetVal regCfSysLineHdlr(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie); +rsRetVal regCfSysLineHdlr2(uchar *pCmdName, int bChainingPermitted, ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), void *pData, void *pOwnerCookie, int *permitted); rsRetVal unregCfSysLineHdlrs(void); rsRetVal unregCfSysLineHdlrs4Owner(void *pOwnerCookie); rsRetVal processCfSysLineCommand(uchar *pCmd, uchar **p); diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index f75b07ab..778fcf68 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -377,6 +377,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth /* reserved for pre-v6.5 */ RS_RET_DUP_PARAM = -2220, /**< config parameter is given more than once */ RS_RET_MODULE_ALREADY_IN_CONF = -2221, /**< module already in current configuration */ + RS_RET_PARAM_NOT_PERMITTED = -2222, /**< legacy parameter no longer permitted (usally already set by v2) */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ -- cgit v1.2.3 From c36a110d19d789156fa56ced1c25fe97ed50336d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Jun 2012 11:46:38 +0200 Subject: $actionname was not properly set via legacy directive --- action.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/action.c b/action.c index 652c0259..5310a6a7 100644 --- a/action.c +++ b/action.c @@ -327,10 +327,6 @@ rsRetVal actionConstruct(action_t **ppThis) ASSERT(ppThis != NULL); - if(cs.pszActionName != NULL) { - free(cs.pszActionName); - cs.pszActionName = NULL; - } CHKmalloc(pThis = (action_t*) calloc(1, sizeof(action_t))); pThis->iResumeInterval = 30; pThis->iResumeRetryCount = 0; -- cgit v1.2.3 From 18757756ea1036febe6f26db89e42662c20fe35f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Jun 2012 13:01:15 +0200 Subject: imuxsock: support for module() global config parameters added --- plugins/imuxsock/imuxsock.c | 175 ++++++++++++++++++++++++++++++++------------ 1 file changed, 128 insertions(+), 47 deletions(-) diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index eeb18fd2..389a465c 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -6,7 +6,7 @@ * * File begun on 2007-12-20 by RGerhards (extracted from syslogd.c) * - * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2012 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -172,8 +172,10 @@ static struct configSettings_s { int bOmitLocalLogging; uchar *pLogSockName; uchar *pLogHostName; /* host name to use with this socket */ - int bUseFlowCtl; /* use flow control or not (if yes, only LIGHT is used! */ + int bUseFlowCtl; /* use flow control or not (if yes, only LIGHT is used!) */ + int bUseFlowCtlSysSock; int bIgnoreTimestamp; /* ignore timestamps present in the incoming message? */ + int bIgnoreTimestampSysSock; int bUseSysTimeStamp; /* use timestamp from system (rather than from message) */ int bUseSysTimeStampSysSock; /* same, for system log socket */ int bWritePid; /* use credentials from recvmsg() and fixup PID in TAG */ @@ -211,14 +213,36 @@ struct modConfData_s { int ratelimitIntervalSysSock; int ratelimitBurstSysSock; int ratelimitSeveritySysSock; + int bAnnotateSysSock; + sbool bIgnoreTimestamp; /* ignore timestamps present in the incoming message? */ + sbool bUseFlowCtl; /* use flow control or not (if yes, only LIGHT is used! */ sbool bOmitLocalLogging; sbool bWritePidSysSock; - int bAnnotateSysSock; sbool bUseSysTimeStamp; + sbool configSetViaV2Method; }; static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "syssock.use", eCmdHdlrBinary, 0 }, + { "syssock.name", eCmdHdlrGetWord, 0 }, + { "syssock.ignoretimestamp", eCmdHdlrBinary, 0 }, + { "syssock.flowcontrol", eCmdHdlrBinary, 0 }, + { "syssock.usesystimestamp", eCmdHdlrBinary, 0 }, + { "syssock.annotate", eCmdHdlrBinary, 0 }, + { "syssock.usepidfromsystem", eCmdHdlrBinary, 0 }, + { "syssock.ratelimit.interval", eCmdHdlrInt, 0 }, + { "syssock.ratelimit.burst", eCmdHdlrInt, 0 }, + { "syssock.ratelimit.severity", eCmdHdlrInt, 0 } +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + /* we do not use this, because we do not bind to a ruleset so far * enable when this is changed: #include "im-helper.h" */ /* must be included AFTER the type definitions! */ @@ -233,6 +257,8 @@ initRatelimitState(struct rs_ratelimit_state *rs, unsigned short interval, unsig rs->begin = 0; } +static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */ + /* ratelimiting support, modelled after the linux kernel * returns 1 if message is within rate limit and shall be @@ -289,27 +315,6 @@ finalize_it: } -/* set the timestamp ignore / not ignore option for the system - * log socket. This must be done separtely, as it is not added via a command - * but present by default. -- rgerhards, 2008-03-06 - */ -static rsRetVal setSystemLogTimestampIgnore(void __attribute__((unused)) *pVal, int iNewVal) -{ - DEFiRet; - listeners[0].flags = iNewVal ? IGNDATE : NOFLAG; - RETiRet; -} - -/* set flowcontrol for the system log socket - */ -static rsRetVal setSystemLogFlowControl(void __attribute__((unused)) *pVal, int iNewVal) -{ - DEFiRet; - listeners[0].flowCtl = iNewVal ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; - RETiRet; -} - - /* This function is called when a new listen socket instace shall be added to * the current config object via the legacy config system. It just shuffles * all parameters to the listener in-memory instance. @@ -1011,6 +1016,8 @@ activateListeners() listeners[0].bWritePid = runModConf->bWritePidSysSock; listeners[0].bAnnotate = runModConf->bAnnotateSysSock; listeners[0].bUseSysTimeStamp = runModConf->bUseSysTimeStamp; + listeners[0].flags = runModConf->bIgnoreTimestamp ? IGNDATE : NOFLAG; + listeners[0].flowCtl = runModConf->bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; sd_fds = sd_listen_fds(0); if(sd_fds < 0) { @@ -1043,16 +1050,87 @@ BEGINbeginCnfLoad CODESTARTbeginCnfLoad loadModConf = pModConf; pModConf->pConf = pConf; + /* init our settings */ + pModConf->pLogSockName = NULL; + pModConf->bOmitLocalLogging = 0; + pModConf->bIgnoreTimestamp = 1; + pModConf->bUseFlowCtl = 0; + pModConf->bUseSysTimeStamp = 1; + pModConf->bWritePidSysSock = 0; + pModConf->bAnnotateSysSock = 0; + pModConf->ratelimitIntervalSysSock = DFLT_ratelimitInterval; + pModConf->ratelimitBurstSysSock = DFLT_ratelimitBurst; + pModConf->ratelimitSeveritySysSock = DFLT_ratelimitSeverity; + bLegacyCnfModGlobalsPermitted = 1; /* reset legacy config vars */ resetConfigVariables(NULL, NULL); ENDbeginCnfLoad +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for imuxsock:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "syssock.use")) { + loadModConf->bOmitLocalLogging = ((int) pvals[i].val.d.n) ? 0 : 1; + } else if(!strcmp(modpblk.descr[i].name, "syssock.name")) { + loadModConf->pLogSockName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(modpblk.descr[i].name, "syssock.ignoretimestamp")) { + loadModConf->bIgnoreTimestamp = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "syssock.flowcontrol")) { + loadModConf->bUseFlowCtl = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "syssock.usesystimestamp")) { + loadModConf->bUseSysTimeStamp = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "syssock.annotate")) { + loadModConf->bAnnotateSysSock = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "syssock.usepidfromsystem")) { + loadModConf->bWritePidSysSock = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "syssock.ratelimit.interval")) { + loadModConf->ratelimitIntervalSysSock = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "syssock.ratelimit.burst")) { + loadModConf->ratelimitBurstSysSock = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "syssock.ratelimit.severity")) { + loadModConf->ratelimitSeveritySysSock = (int) pvals[i].val.d.n; + } else { + dbgprintf("imuxsock: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } + + /* disable legacy module-global config directives */ + bLegacyCnfModGlobalsPermitted = 0; + loadModConf->configSetViaV2Method = 1; + +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + + BEGINendCnfLoad CODESTARTendCnfLoad - /* persist module-specific settings from legacy config system */ - loadModConf->bOmitLocalLogging = cs.bOmitLocalLogging; - loadModConf->pLogSockName = cs.pLogSockName; + if(!loadModConf->configSetViaV2Method) { + /* persist module-specific settings from legacy config system */ + loadModConf->bOmitLocalLogging = cs.bOmitLocalLogging; + loadModConf->pLogSockName = cs.pLogSockName; + loadModConf->bIgnoreTimestamp = cs.bIgnoreTimestampSysSock; + loadModConf->bUseFlowCtl = cs.bUseFlowCtlSysSock; + } loadModConf = NULL; /* done loading */ /* free legacy config vars */ @@ -1225,6 +1303,7 @@ BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt @@ -1237,7 +1316,9 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a cs.bOmitLocalLogging = 0; cs.pLogHostName = NULL; cs.bIgnoreTimestamp = 1; + cs.bIgnoreTimestampSysSock = 1; cs.bUseFlowCtl = 0; + cs.bUseFlowCtlSysSock = 0; cs.bUseSysTimeStamp = 1; cs.bUseSysTimeStampSysSock = 1; cs.bWritePid = 0; @@ -1311,12 +1392,8 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(prop.ConstructFinalize(pLocalHostIP)); /* register config file handlers */ - CHKiRet(omsdRegCFSLineHdlr((uchar *)"omitlocallogging", 0, eCmdHdlrBinary, - NULL, &cs.bOmitLocalLogging, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketignoremsgtimestamp", 0, eCmdHdlrBinary, NULL, &cs.bIgnoreTimestamp, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketname", 0, eCmdHdlrGetWord, - NULL, &cs.pLogSockName, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensockethostname", 0, eCmdHdlrGetWord, NULL, &cs.pLogHostName, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketflowcontrol", 0, eCmdHdlrBinary, @@ -1345,22 +1422,26 @@ CODEmodInit_QueryRegCFSLineHdlr * for that. We should revisit all of that once we have the new config format... * rgerhards, 2008-03-06 */ - CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketignoremsgtimestamp", 0, eCmdHdlrBinary, - setSystemLogTimestampIgnore, NULL, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketflowcontrol", 0, eCmdHdlrBinary, - setSystemLogFlowControl, NULL, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogusesystimestamp", 0, eCmdHdlrBinary, - NULL, &cs.bUseSysTimeStampSysSock, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketannotate", 0, eCmdHdlrBinary, - NULL, &cs.bAnnotateSysSock, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogusepidfromsystem", 0, eCmdHdlrBinary, - NULL, &cs.bWritePidSysSock, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogratelimitinterval", 0, eCmdHdlrInt, - NULL, &cs.ratelimitIntervalSysSock, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogratelimitburst", 0, eCmdHdlrInt, - NULL, &cs.ratelimitBurstSysSock, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogratelimitseverity", 0, eCmdHdlrInt, - NULL, &cs.ratelimitSeveritySysSock, STD_LOADABLE_MODULE_ID)); + CHKiRet(regCfSysLineHdlr2((uchar *)"omitlocallogging", 0, eCmdHdlrBinary, + NULL, &cs.bOmitLocalLogging, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogsocketname", 0, eCmdHdlrGetWord, + NULL, &cs.pLogSockName, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogsocketignoremsgtimestamp", 0, eCmdHdlrBinary, + NULL, &cs.bIgnoreTimestampSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogsocketflowcontrol", 0, eCmdHdlrBinary, + NULL, &cs.bUseFlowCtlSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogusesystimestamp", 0, eCmdHdlrBinary, + NULL, &cs.bUseSysTimeStampSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogsocketannotate", 0, eCmdHdlrBinary, + NULL, &cs.bAnnotateSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogusepidfromsystem", 0, eCmdHdlrBinary, + NULL, &cs.bWritePidSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogratelimitinterval", 0, eCmdHdlrInt, + NULL, &cs.ratelimitIntervalSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogratelimitburst", 0, eCmdHdlrInt, + NULL, &cs.ratelimitBurstSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogratelimitseverity", 0, eCmdHdlrInt, + NULL, &cs.ratelimitSeveritySysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); /* support statistics gathering */ CHKiRet(statsobj.Construct(&modStats)); -- cgit v1.2.3 From d9fb04c5c5b5c1a789d3776f0441d3c8dca08be2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Jun 2012 16:25:42 +0200 Subject: immark: support for module() global config parameters added --- plugins/immark/immark.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++--- plugins/imudp/imudp.c | 1 - 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/plugins/immark/immark.c b/plugins/immark/immark.c index 273af021..0e946c0b 100644 --- a/plugins/immark/immark.c +++ b/plugins/immark/immark.c @@ -58,9 +58,26 @@ DEFobjCurrIf(errmsg) static int iMarkMessagePeriod = DEFAULT_MARK_PERIOD; struct modConfData_s { + rsconf_t *pConf; /* our overall config object */ int iMarkMessagePeriod; + sbool configSetViaV2Method; }; +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "interval", eCmdHdlrInt, 0 } +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + + +static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ +static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */ + + BEGINisCompatibleWithFeature CODESTARTisCompatibleWithFeature if(eFeat == sFEATURENonCancelInputTermination) @@ -75,12 +92,57 @@ ENDafterRun BEGINbeginCnfLoad CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + /* init our settings */ + pModConf->iMarkMessagePeriod = DEFAULT_MARK_PERIOD; + loadModConf->configSetViaV2Method = 0; + bLegacyCnfModGlobalsPermitted = 1; ENDbeginCnfLoad +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for imuxsock:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "interval")) { + loadModConf->iMarkMessagePeriod = (int) pvals[i].val.d.n; + } else { + dbgprintf("imuxsock: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } + + /* disable legacy module-global config directives */ + bLegacyCnfModGlobalsPermitted = 0; + loadModConf->configSetViaV2Method = 1; + +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + + BEGINendCnfLoad CODESTARTendCnfLoad - pModConf->iMarkMessagePeriod = iMarkMessagePeriod; + if(!loadModConf->configSetViaV2Method) { + pModConf->iMarkMessagePeriod = iMarkMessagePeriod; + } ENDendCnfLoad @@ -97,6 +159,7 @@ ENDcheckCnf BEGINactivateCnf CODESTARTactivateCnf MarkInterval = pModConf->iMarkMessagePeriod; + DBGPRINTF("immark set MarkInterval to %d\n", MarkInterval); ENDactivateCnf @@ -150,6 +213,7 @@ BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt @@ -167,8 +231,8 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); /* legacy config handlers */ - CHKiRet(omsdRegCFSLineHdlr((uchar *)"markmessageperiod", 0, eCmdHdlrInt, NULL, - &iMarkMessagePeriod, STD_LOADABLE_MODULE_ID)); + CHKiRet(regCfSysLineHdlr2((uchar *)"markmessageperiod", 0, eCmdHdlrInt, NULL, + &iMarkMessagePeriod, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 9cb28550..d570e3e5 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -755,7 +755,6 @@ CODESTARTactivateCnf /* caching various settings */ iMaxLine = glbl.GetMaxLine(); CHKmalloc(pRcvBuf = MALLOC((iMaxLine + 1) * sizeof(char))); -dbgprintf("AAA: timerequery %d\n", runModConf->iTimeRequery); finalize_it: ENDactivateCnf -- cgit v1.2.3 From cb2a78b30bf55fd3d356cad7048b9e70968dbb95 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 29 Jun 2012 12:42:08 +0200 Subject: imklog: support for module() global config parameters added --- plugins/imklog/imklog.c | 150 +++++++++++++++++++++++++++++++++++------------- plugins/imklog/imklog.h | 24 ++------ 2 files changed, 116 insertions(+), 58 deletions(-) diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c index 6a607a74..ee0af59d 100644 --- a/plugins/imklog/imklog.c +++ b/plugins/imklog/imklog.c @@ -59,6 +59,7 @@ #include "net.h" #include "glbl.h" #include "prop.h" +#include "errmsg.h" #include "unicode-helper.h" MODULE_TYPE_INPUT @@ -71,23 +72,39 @@ DEFobjCurrIf(datetime) DEFobjCurrIf(glbl) DEFobjCurrIf(prop) DEFobjCurrIf(net) +DEFobjCurrIf(errmsg) /* config settings */ typedef struct configSettings_s { - int dbgPrintSymbols; /* this one is extern so the helpers can access it! */ - int symbols_twice; - int use_syscall; - int symbol_lookup; /* on recent kernels > 2.6, the kernel does this */ + int dbgPrintSymbols; /* DEAD this one is extern so the helpers can access it! */ + int symbols_twice; /* DEAD */ + int use_syscall; /* DEAD */ + int symbol_lookup; /* DEAD on recent kernels > 2.6, the kernel does this */ + char *symfile; /* TODO: actually unsued currently! */ int bPermitNonKernel; /* permit logging of messages not having LOG_KERN facility */ int iFacilIntMsg; /* the facility to use for internal messages (set by driver) */ uchar *pszPath; - int console_log_level; - char *symfile; /* TODO: actually unsued currently! */ + int console_log_level; /* still used for BSD */ } configSettings_t; static configSettings_t cs; static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ +static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */ + +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "logpath", eCmdHdlrGetWord, 0 }, + { "permitnonkernelfacility", eCmdHdlrBinary, 0 }, + { "consoleloglevel", eCmdHdlrInt, 0 }, + { "internalmsgfacility", eCmdHdlrFacility, 0 } +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this module */ @@ -278,41 +295,91 @@ BEGINbeginCnfLoad CODESTARTbeginCnfLoad loadModConf = pModConf; pModConf->pConf = pConf; + /* init our settings */ + pModConf->pszPath = NULL; + pModConf->bPermitNonKernel = 0; + pModConf->console_log_level = -1; + pModConf->iFacilIntMsg = klogFacilIntMsg(); + loadModConf->configSetViaV2Method = 0; + bLegacyCnfModGlobalsPermitted = 1; /* init legacy config vars */ initConfigSettings(); ENDbeginCnfLoad +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for imklog:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "logpath")) { + loadModConf->pszPath = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(modpblk.descr[i].name, "permitnonkernelfacility")) { + loadModConf->bPermitNonKernel = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "consoleloglevel")) { + loadModConf->console_log_level= (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "internalmsgfacility")) { + loadModConf->iFacilIntMsg = (int) pvals[i].val.d.n; + } else { + dbgprintf("imklog: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } + + /* disable legacy module-global config directives */ + bLegacyCnfModGlobalsPermitted = 0; + loadModConf->configSetViaV2Method = 1; + +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + + BEGINendCnfLoad CODESTARTendCnfLoad - /* persist module-specific settings from legacy config system */ - loadModConf->dbgPrintSymbols = cs.dbgPrintSymbols; - loadModConf->symbols_twice = cs.symbols_twice; - loadModConf->use_syscall = cs.use_syscall; - loadModConf->bPermitNonKernel = cs.bPermitNonKernel; - loadModConf->iFacilIntMsg = cs.iFacilIntMsg; - loadModConf->console_log_level = cs.console_log_level; - if((cs.pszPath == NULL) || (cs.pszPath[0] == '\0')) { - loadModConf->pszPath = NULL; - if(cs.pszPath != NULL) - free(cs.pszPath); - } else { - loadModConf->pszPath = cs.pszPath; - } - cs.pszPath = NULL; - if((cs.symfile == NULL) || (cs.symfile[0] == '\0')) { - loadModConf->symfile = NULL; - if(cs.symfile != NULL) - free(cs.symfile); - } else { - loadModConf->symfile = cs.symfile; + if(!loadModConf->configSetViaV2Method) { + /* persist module-specific settings from legacy config system */ + loadModConf->dbgPrintSymbols = cs.dbgPrintSymbols; + loadModConf->symbols_twice = cs.symbols_twice; + loadModConf->use_syscall = cs.use_syscall; + loadModConf->bPermitNonKernel = cs.bPermitNonKernel; + loadModConf->iFacilIntMsg = cs.iFacilIntMsg; + loadModConf->console_log_level = cs.console_log_level; + if((cs.pszPath == NULL) || (cs.pszPath[0] == '\0')) { + loadModConf->pszPath = NULL; + if(cs.pszPath != NULL) + free(cs.pszPath); + } else { + loadModConf->pszPath = cs.pszPath; + } + cs.pszPath = NULL; + if((cs.symfile == NULL) || (cs.symfile[0] == '\0')) { + loadModConf->symfile = NULL; + if(cs.symfile != NULL) + free(cs.symfile); + } else { + loadModConf->symfile = cs.symfile; + } + cs.symfile = NULL; } - cs.symfile = NULL; loadModConf = NULL; /* done loading */ /* free legacy config vars */ - free(cs.pszPath); - cs.pszPath = NULL; free(cs.symfile); cs.symfile = NULL; ENDendCnfLoad @@ -363,6 +430,7 @@ CODESTARTmodExit objRelease(net, CORE_COMPONENT); objRelease(datetime, CORE_COMPONENT); objRelease(prop, CORE_COMPONENT); + objRelease(errmsg, CORE_COMPONENT); ENDmodExit @@ -370,6 +438,7 @@ BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES ENDqueryEtryPt @@ -397,6 +466,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(glbl, CORE_COMPONENT)); CHKiRet(objUse(prop, CORE_COMPONENT)); CHKiRet(objUse(net, CORE_COMPONENT)); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); /* we need to create the inputName property (only once during our lifetime) */ CHKiRet(prop.CreateStringProp(&pInputName, UCHAR_CONSTANT("imklog"), sizeof("imklog") - 1)); @@ -405,22 +475,22 @@ CODEmodInit_QueryRegCFSLineHdlr /* init legacy config settings */ initConfigSettings(); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"debugprintkernelsymbols", 0, eCmdHdlrBinary, - NULL, &cs.dbgPrintSymbols, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogpath", 0, eCmdHdlrGetWord, - NULL, &cs.pszPath, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"debugprintkernelsymbols", 0, eCmdHdlrGoneAway, + NULL, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(regCfSysLineHdlr2((uchar *)"klogpath", 0, eCmdHdlrGetWord, + NULL, &cs.pszPath, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbollookup", 0, eCmdHdlrBinary, NULL, &cs.symbol_lookup, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbolstwice", 0, eCmdHdlrBinary, NULL, &cs.symbols_twice, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogusesyscallinterface", 0, eCmdHdlrBinary, NULL, &cs.use_syscall, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogpermitnonkernelfacility", 0, eCmdHdlrBinary, - NULL, &cs.bPermitNonKernel, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogconsoleloglevel", 0, eCmdHdlrInt, - NULL, &cs.console_log_level, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"kloginternalmsgfacility", 0, eCmdHdlrFacility, - NULL, &cs.iFacilIntMsg, STD_LOADABLE_MODULE_ID)); + CHKiRet(regCfSysLineHdlr2((uchar *)"klogpermitnonkernelfacility", 0, eCmdHdlrBinary, + NULL, &cs.bPermitNonKernel, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"klogconsoleloglevel", 0, eCmdHdlrInt, + NULL, &cs.console_log_level, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"kloginternalmsgfacility", 0, eCmdHdlrFacility, + NULL, &cs.iFacilIntMsg, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit diff --git a/plugins/imklog/imklog.h b/plugins/imklog/imklog.h index 7f6c810a..a9b22b4f 100644 --- a/plugins/imklog/imklog.h +++ b/plugins/imklog/imklog.h @@ -31,16 +31,19 @@ /* we need to have the modConf type present in all submodules */ struct modConfData_s { + /* DEAD */ int dbgPrintSymbols; int symbols_twice; int use_syscall; int symbol_lookup; - int bPermitNonKernel; + char *symfile; + /* end DEAD */ + rsconf_t *pConf; int iFacilIntMsg; uchar *pszPath; int console_log_level; - char *symfile; - rsconf_t *pConf; + sbool bPermitNonKernel; + sbool configSetViaV2Method; }; /* interface to "drivers" @@ -54,21 +57,6 @@ rsRetVal klogWillRun(modConfData_t *pModConf); rsRetVal klogAfterRun(modConfData_t *pModConf); int klogFacilIntMsg(); -/* the following data members may be accessed by the "drivers" - * I admit this is not the cleanest way to doing things, but I honestly - * believe it is appropriate for the job that needs to be done. - * rgerhards, 2008-04-09 - */ -#if 0 -extern int symbols_twice; -extern int use_syscall; -extern int symbol_lookup; -extern char *symfile; -extern int console_log_level; -extern int dbgPrintSymbols; -extern uchar *pszPath; -#endif - /* the functions below may be called by the drivers */ rsRetVal imklogLogIntMsg(int priority, char *fmt, ...) __attribute__((format(printf,2, 3))); rsRetVal Syslog(int priority, uchar *msg, struct timeval *tp); -- cgit v1.2.3 From 5a993ad7425bce33380ff10308f2ae93dadf8dae Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 29 Jun 2012 12:59:46 +0200 Subject: imklog: removal of no longer needed config directives --- plugins/imklog/imklog.c | 36 ++++++------------------------------ plugins/imklog/imklog.h | 7 ------- 2 files changed, 6 insertions(+), 37 deletions(-) diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c index 513619c5..93323707 100644 --- a/plugins/imklog/imklog.c +++ b/plugins/imklog/imklog.c @@ -76,11 +76,6 @@ DEFobjCurrIf(errmsg) /* config settings */ typedef struct configSettings_s { - int dbgPrintSymbols; /* DEAD this one is extern so the helpers can access it! */ - int symbols_twice; /* DEAD */ - int use_syscall; /* DEAD */ - int symbol_lookup; /* DEAD on recent kernels > 2.6, the kernel does this */ - char *symfile; /* TODO: actually unsued currently! */ int bPermitNonKernel; /* permit logging of messages not having LOG_KERN facility */ int iFacilIntMsg; /* the facility to use for internal messages (set by driver) */ uchar *pszPath; @@ -114,10 +109,6 @@ static prop_t *pLocalHostIP = NULL; /* a pseudo-constant propterty for 127.0.0.1 static inline void initConfigSettings(void) { - cs.dbgPrintSymbols = 0; - cs.symbols_twice = 0; - cs.use_syscall = 0; - cs.symbol_lookup = 0; cs.bPermitNonKernel = 0; cs.console_log_level = -1; cs.pszPath = NULL; @@ -353,9 +344,6 @@ BEGINendCnfLoad CODESTARTendCnfLoad if(!loadModConf->configSetViaV2Method) { /* persist module-specific settings from legacy config system */ - loadModConf->dbgPrintSymbols = cs.dbgPrintSymbols; - loadModConf->symbols_twice = cs.symbols_twice; - loadModConf->use_syscall = cs.use_syscall; loadModConf->bPermitNonKernel = cs.bPermitNonKernel; loadModConf->iFacilIntMsg = cs.iFacilIntMsg; loadModConf->console_log_level = cs.console_log_level; @@ -367,14 +355,6 @@ CODESTARTendCnfLoad loadModConf->pszPath = cs.pszPath; } cs.pszPath = NULL; - if((cs.symfile == NULL) || (cs.symfile[0] == '\0')) { - loadModConf->symfile = NULL; - if(cs.symfile != NULL) - free(cs.symfile); - } else { - loadModConf->symfile = cs.symfile; - } - cs.symfile = NULL; } loadModConf = NULL; /* done loading */ @@ -440,10 +420,6 @@ ENDqueryEtryPt static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { - cs.dbgPrintSymbols = 0; - cs.symbols_twice = 0; - cs.use_syscall = 0; - cs.symbol_lookup = 0; cs.bPermitNonKernel = 0; if(cs.pszPath != NULL) { free(cs.pszPath); @@ -474,12 +450,12 @@ CODEmodInit_QueryRegCFSLineHdlr NULL, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(regCfSysLineHdlr2((uchar *)"klogpath", 0, eCmdHdlrGetWord, NULL, &cs.pszPath, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbollookup", 0, eCmdHdlrBinary, - NULL, &cs.symbol_lookup, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbolstwice", 0, eCmdHdlrBinary, - NULL, &cs.symbols_twice, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogusesyscallinterface", 0, eCmdHdlrBinary, - NULL, &cs.use_syscall, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbollookup", 0, eCmdHdlrGoneAway, + NULL, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbolstwice", 0, eCmdHdlrGoneAway, + NULL, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogusesyscallinterface", 0, eCmdHdlrGoneAway, + NULL, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(regCfSysLineHdlr2((uchar *)"klogpermitnonkernelfacility", 0, eCmdHdlrBinary, NULL, &cs.bPermitNonKernel, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); CHKiRet(regCfSysLineHdlr2((uchar *)"klogconsoleloglevel", 0, eCmdHdlrInt, diff --git a/plugins/imklog/imklog.h b/plugins/imklog/imklog.h index a9b22b4f..acfb50ab 100644 --- a/plugins/imklog/imklog.h +++ b/plugins/imklog/imklog.h @@ -31,13 +31,6 @@ /* we need to have the modConf type present in all submodules */ struct modConfData_s { - /* DEAD */ - int dbgPrintSymbols; - int symbols_twice; - int use_syscall; - int symbol_lookup; - char *symfile; - /* end DEAD */ rsconf_t *pConf; int iFacilIntMsg; uchar *pszPath; -- cgit v1.2.3 From 06db028d606874a8e2848dd9b17733dfef8d4587 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 11 Jul 2012 15:26:23 +0200 Subject: bugfix: omhdfs did no longer compile --- ChangeLog | 1 + plugins/omhdfs/omhdfs.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 04cbb1f0..be156d38 100644 --- a/ChangeLog +++ b/ChangeLog @@ -13,6 +13,7 @@ Version 6.5.0 [devel] 2012-0?-?? in some speedup (but serious loss of debugging capabilities) - added new 0mq plugins (via czmq lib) Thanks to David Kelly for contributing these modules +- bugfix: omhdfs did no longer compile --------------------------------------------------------------------------- Version 6.3.13 [BETA] 2012-06-?? - support for elasticsearch via omelasticsearch added diff --git a/plugins/omhdfs/omhdfs.c b/plugins/omhdfs/omhdfs.c index cd14d03c..f8a7e739 100644 --- a/plugins/omhdfs/omhdfs.c +++ b/plugins/omhdfs/omhdfs.c @@ -67,8 +67,8 @@ typedef struct configSettings_s { uchar *dfltTplName; /* default template name to use */ int hdfsPort; } configSettings_t; +static configSettings_t cs; -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars -- cgit v1.2.3 From 9900fbe2e85f39b999f50d2ba4463d507f731f4c Mon Sep 17 00:00:00 2001 From: Florian Riedl Date: Tue, 24 Jul 2012 12:54:56 +0200 Subject: doc: improved doc for built-in modules --- doc/Makefile.am | 4 + doc/omfile.html | 167 ++++++++++++++++++++++++++++++++++++++++++ doc/omfwd.html | 118 +++++++++++++++++++++++++++++ doc/ompipe.html | 62 ++++++++++++++++ doc/omusrmsg.html | 64 ++++++++++++++++ doc/rsyslog_conf_global.html | 48 ++++++------ doc/rsyslog_conf_modules.html | 4 + 7 files changed, 443 insertions(+), 24 deletions(-) create mode 100644 doc/omfile.html create mode 100644 doc/omfwd.html create mode 100644 doc/ompipe.html create mode 100644 doc/omusrmsg.html diff --git a/doc/Makefile.am b/doc/Makefile.am index 04fda6b3..cc1a3209 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -31,6 +31,10 @@ html_files = \ version_naming.html \ contributors.html \ dev_queue.html \ + ompipe.html \ + omfwd.html \ + omfile.html \ + omusrmsg.html \ omstdout.html \ omudpspoof.html \ omruleset.html \ diff --git a/doc/omfile.html b/doc/omfile.html new file mode 100644 index 00000000..bdd1ebc6 --- /dev/null +++ b/doc/omfile.html @@ -0,0 +1,167 @@ + + + +File Output Module + + +back + +

File Output Module

+

Module Name:    omfile

+

Author: Rainer Gerhards <rgergards@adiscon.com>

+

Description:

+

The omfile plug-in provides the core functionality of writing messages to files residing inside the local file system (which may actually be remote if methods like NFS are used). Both files named with static names as well files with names based on message content are supported by this module. It is a built-in module that does not need to be loaded.

+

 

+ +

Global Configuration Directives:

+
    +
  • Template [templateName]
    + sets a new default template for file actions.
  • + +
+

 

+

Action specific Configuration Directives:

+
    +
  • DynaFileCacheSize (not mandatory, default will be used)
    + Defines a template to be used for the output.

  • + +
  • ZipLevel 0..9 [default 0]
    + if greater 0, turns on gzip compression of the output file. The higher the number, the better the compression, but also the more CPU is required for zipping.

  • + +
  • FlushInterval (not mandatory, default will be used)
    + Defines a template to be used for the output.

  • + +
  • ASyncWriting on/off [default off]
    + if turned on, the files will be written in asynchronous mode via a separate thread. In that case, double buffers will be used so that one buffer can be filled while the other buffer is being written. Note that in order to enable FlushInterval, AsyncWriting must be set to "on". Otherwise, the flush interval will be ignored. Also note that when FlushOnTXEnd is "on" but AsyncWriting is off, output will only be written when the buffer is full. This may take several hours, or even require a rsyslog shutdown. However, a buffer flush can be forced in that case by sending rsyslogd a HUP signal.

  • + +
  • FlushOnTXEnd on/off [default on]
    + Omfile has the capability to write output using a buffered writer. Disk writes are only done when the buffer is full. So if an error happens during that write, data is potentially lost. In cases where this is unacceptable, set FlushOnTXEnd to on. Then, data is written at the end of each transaction (for pre-v5 this means after each log message) and the usual error recovery thus can handle write errors without data loss. Note that this option severely reduces the effect of zip compression and should be switched to off for that use case. Note that the default -on- is primarily an aid to preserve the traditional syslogd behaviour.

  • + +
  • IOBufferSize <size_nbr>, default 4k
    + size of the buffer used to writing output data. The larger the buffer, the potentially better performance is. The default of 4k is quite conservative, it is useful to go up to 64k, and 128K if you used gzip compression (then, even higher sizes may make sense)

  • + +
  • DirOwner
    + Set the file owner for directories newly created. Please note that this setting does not affect the owner of directories already existing. The parameter is a user name, for which the userid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.

  • + +
  • DirGroup
    + Set the group for directories newly created. Please note that this setting does not affect the group of directories already existing. The parameter is a group name, for which the groupid is obtained by rsyslogd on during startup processing. Interim changes to the user mapping are not detected.

  • + +
  • FileOwner
    + Set the file owner for dynaFiles newly created. Please note that this setting does not affect the owner of files already existing. The parameter is a user name, for which the userid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.

  • + +
  • FileGroup
    + Set the group for dynaFiles newly created. Please note that this setting does not affect the group of files already existing. The parameter is a group name, for which the groupid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.

  • + +
  • DirCreateMode [defaul 0700]
    + This is the same as $FileCreateMode, but for directories automatically generated.

  • + +
  • FileCreateMode [default 0644]
    + The FileCreateMode directive allows to specify the creation mode with which rsyslogd creates new files. If not specified, the value 0644 is used (which retains backward-compatibility with earlier releases). The value given must always be a 4-digit octal number, with the initial digit being zero.
    Please note that the actual permission depend on rsyslogd's process umask. If in doubt, use "$umask 0000" right at the beginning of the configuration file to remove any restrictions.
    FileCreateMode may be specified multiple times. If so, it specifies the creation mode for all selector lines that follow until the next $FileCreateMode directive. Order of lines is vitally important.

  • + +
  • FailOnCHOwnFailure on/off [default on]
    + This option modifies behaviour of dynaFile creation. If different owners or groups are specified for new files or directories and rsyslogd fails to set these new owners or groups, it will log an error and NOT write to the file in question if that option is set to "on". If it is set to "off", the error will be ignored and processing continues. Keep in mind, that the files in this case may be (in)accessible by people who should not have permission. The default is "on".

  • + +
  • CreateDirs on/off [default on]
    + create directories on an as-needed basis

  • + +
  • Sync on/off [default off]
    + enables file syncing capability of omfile.

  • + +
  • File
    + If the file already exists, new data is appended to it. Existing data is not truncated. If the file does not already exist, it is created. Files are kept open as long as rsyslogd is active. This conflicts with external log file rotation. In order to close a file after rotation, send rsyslogd a HUP signal after the file has been rotated away.

  • + +
  • DynaFile
    + For each message, the file name is generated based on the given template. Then, this file is opened. As with the ``file'' property, data is appended if the file already exists. If the file does not exist, a new file is created. A cache of recent files is kept. Note that this cache can consume quite some memory (especially if large buffer sizes are used). Files are kept open as long as they stay inside the cache. Currently, files are only evicted from the cache when there is need to do so (due to insufficient cache size). To force-close (and evict) a dynafile from cache, send a HUP signal to rsyslogd.

  • + +
  • Template [templateName]
    + sets a new default template for file actions.

  • + +
+

Caveats/Known Bugs:

  • None.
+

Sample:

+

The following command writes all syslog messages into a file.

+ + +

+ +

Legacy Configuration Directives:

+
    +
  • $DynaFileCacheSize (not mandatory, default will be used)
    + Defines a template to be used for the output.

  • + +
  • $OMFileZipLevel 0..9 [default 0]
    + if greater 0, turns on gzip compression of the output file. The higher the number, the better the compression, but also the more CPU is required for zipping.

  • + +
  • $OMFileFlushInterval (not mandatory, default will be used)
    + Defines a template to be used for the output.

  • + +
  • $OMFileASyncWriting on/off [default off]
    + if turned on, the files will be written in asynchronous mode via a separate thread. In that case, double buffers will be used so that one buffer can be filled while the other buffer is being written. Note that in order to enable FlushInterval, AsyncWriting must be set to "on". Otherwise, the flush interval will be ignored. Also note that when FlushOnTXEnd is "on" but AsyncWriting is off, output will only be written when the buffer is full. This may take several hours, or even require a rsyslog shutdown. However, a buffer flush can be forced in that case by sending rsyslogd a HUP signal.

  • + +
  • $OMFileFlushOnTXEnd on/off [default on]
    + Omfile has the capability to write output using a buffered writer. Disk writes are only done when the buffer is full. So if an error happens during that write, data is potentially lost. In cases where this is unacceptable, set FlushOnTXEnd to on. Then, data is written at the end of each transaction (for pre-v5 this means after each log message) and the usual error recovery thus can handle write errors without data loss. Note that this option severely reduces the effect of zip compression and should be switched to off for that use case. Note that the default -on- is primarily an aid to preserve the traditional syslogd behaviour.

  • + +
  • $OMFileIOBufferSize <size_nbr>, default 4k
    + size of the buffer used to writing output data. The larger the buffer, the potentially better performance is. The default of 4k is quite conservative, it is useful to go up to 64k, and 128K if you used gzip compression (then, even higher sizes may make sense)

  • + +
  • $DirOwner
    + Set the file owner for directories newly created. Please note that this setting does not affect the owner of directories already existing. The parameter is a user name, for which the userid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.

  • + +
  • $DirGroup
    + Set the group for directories newly created. Please note that this setting does not affect the group of directories already existing. The parameter is a group name, for which the groupid is obtained by rsyslogd on during startup processing. Interim changes to the user mapping are not detected.

  • + +
  • $FileOwner
    + Set the file owner for dynaFiles newly created. Please note that this setting does not affect the owner of files already existing. The parameter is a user name, for which the userid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.

  • + +
  • $FileGroup
    + Set the group for dynaFiles newly created. Please note that this setting does not affect the group of files already existing. The parameter is a group name, for which the groupid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.

  • + +
  • $DirCreateMode [defaul 0700]
    + This is the same as $FileCreateMode, but for directories automatically generated.

  • + +
  • $FileCreateMode [default 0644]
    + The FileCreateMode directive allows to specify the creation mode with which rsyslogd creates new files. If not specified, the value 0644 is used (which retains backward-compatibility with earlier releases). The value given must always be a 4-digit octal number, with the initial digit being zero.
    Please note that the actual permission depend on rsyslogd's process umask. If in doubt, use "$umask 0000" right at the beginning of the configuration file to remove any restrictions.
    FileCreateMode may be specified multiple times. If so, it specifies the creation mode for all selector lines that follow until the next $FileCreateMode directive. Order of lines is vitally important.

  • + +
  • $FailOnCHOwnFailure on/off [default on]
    + This option modifies behaviour of dynaFile creation. If different owners or groups are specified for new files or directories and rsyslogd fails to set these new owners or groups, it will log an error and NOT write to the file in question if that option is set to "on". If it is set to "off", the error will be ignored and processing continues. Keep in mind, that the files in this case may be (in)accessible by people who should not have permission. The default is "on".

  • + +
  • $F$OMFileForceCHOwn
    + force ownership change for all files

  • + +
  • $CreateDirs on/off [default on]
    + create directories on an as-needed basis

  • + +
  • $ActionFileEnableSync on/off [default off]
    + enables file syncing capability of omfile.

  • + +
  • $ActionFileDefaultTemplate [templateName]
    + sets a new default template for file actions.

  • + +
  • $ResetConfigVariables
    + Resets all configuration variables to their default value. Any settings made will not be applied to configuration lines following the $ResetConfigVariables. This is a good method to make sure no side-effects exists from previous directives. This directive has no parameters.

  • + +
+ +

Legacy Sample:

+

The following command writes all syslog messages into a file.

+ + + +

[rsyslog.conf overview] [manual +index] [rsyslog site]

+

This documentation is part of the +rsyslog project.
+Copyright © 2008 by Rainer Gerhards and +Adiscon. Released under the GNU GPL +version 3 or higher.

+ + diff --git a/doc/omfwd.html b/doc/omfwd.html new file mode 100644 index 00000000..5599ae39 --- /dev/null +++ b/doc/omfwd.html @@ -0,0 +1,118 @@ + + + +Forwarding Output Module + + +back + +

Forwarding Output Module

+

Module Name:    omfwd

+

Author: Rainer Gerhards <rgergards@adiscon.com>

+

Description:

+

The omfwd plug-in provides the core functionality of traditional message forwarding via UDP and plain TCP. It is a built-in module that does not need to be loaded.

+

 

+ +

Global Configuration Directives:

+
    +
  • Template [templateName]
    + sets a new default template for file actions.
  • + +
+

 

+

Action specific Configuration Directives:

+
    +
  • Target string
    + Name or IP-Address of the system that shall receive messages. Any resolvable name is fine.

  • + +
  • Port [Default 514]
    + Name or numerical value of port to use when connecting to target.

  • + +
  • Protocol udp/tcp [default udp]
    + Type of protocol to use for forwarding. Note that ``tcp'' means both legacy plain tcp syslog as well as RFC5425-based TCL-encrypted syslog. Which one is selected depends on the protocol drivers set before the action commend. Note that as of 6.3.6, there is no way to specify this within the action itself.

  • + +
  • TCP_Framing ``traditional'' or ``octet-counted'' [default traditional]
    + Framing-Mode to be for forwarding. This affects only TCP-based protocols. It is ignored for UDP. In protocol engineering, ``framing'' means how multiple messages over the same connection are separated. Usually, this is transparent to users. Unfortunately, the early syslog protocol evolved, and so there are cases where users need to specify the framing. The traditional framing is nontransparent. With it, messages are end when a LF (aka ``line break'', ``return'') is encountered, and the next message starts immediately after the LF. If multi-line messages are received, these are essentially broken up into multiple message, usually with all but the first message segment being incorrectly formatted. The octet-counting framing solves this issue. With it, each message is prefixed with the actual message length, so that a receivers knows exactly where the message ends. Multi-line messages cause no problem here. This mode is very close to the method described in RFC5425 for TLS-enabled syslog. Unfortunately, only few syslogd implementations support octet-counted framing. As such, the traditional framing is set as default, even though it has defects. If it is known that the receiver supports octet-counted framing, it is suggested to use that framing mode.

  • + +
  • ZipLevel 0..9 [default 0]
    + Compression level for messages. Rsyslog implements a proprietary capability to zip transmitted messages. Note that compression happens on a message-per-message basis. As such, there is a performance gain only for larger messages. Before compressing a message, rsyslog checks if there is some gain by compression. If so, the message is sent compressed. If not, it is sent uncompressed. As such, it is totally valid that compressed and uncompressed messages are intermixed within a conversation.
    The compression level is specified via the usual factor of 0 to 9, with 9 being the strongest compression (taking up most processing time) and 0 being no compression at all (taking up no extra processing time).

  • + +
  • RebindInterval integer
    + Permits to specify an interval at which the current connection is broken and re-established. This setting is primarily an aid to load balancers. After the configured number of messages has been transmitted, the current connection is terminated and a new one started. Note that this setting applies to both TCP and UDP traffic. For UDP, the new ``connection'' uses a different source port (ports are cycled and not reused too frequently). This usually is perceived as a ``new connection'' by load balancers, which in turn forward messages to another physical target system.

  • + +
  • StreamDriver string
    + Set the file owner for directories newly created. Please note that this setting does not affect the owner of directories already existing. The parameter is a user name, for which the userid is obtained by rsyslogd during startup processing. Interim changes to the user mapping are not detected.

  • + +
  • StreamDriverMode integer [default 0]
    + mode to use with the stream driver (driver-specific)

  • + +
  • StreamDriverAuthMode string
    + authentication mode to use with the stream driver. Note that this directive requires TLS netstream drivers. For all others, it will be ignored. (driver-specific).

  • + +
  • StreamDriverPermittedPeers string
    + accepted fingerprint (SHA1) or name of remote peer. Note that this directive requires TLS netstream drivers. For all others, it will be ignored. (driver-specific)

  • + +
  • ResendLastMSGOnReconnect on/off
    + Permits to resend the last message when a connection is reconnected. This setting affects TCP-based syslog, only. It is most useful for traditional, plain TCP syslog. Using this protocol, it is not always possible to know which messages were successfully transmitted to the receiver when a connection breaks. In many cases, the last message sent is lost. By switching this setting to "yes", rsyslog will always retransmit the last message when a connection is reestablished. This reduces potential message loss, but comes at the price that some messages may be duplicated (what usually is more acceptable).

  • + +
+

Caveats/Known Bugs:

  • None.
+

Sample:

+

The following command sends all syslog messages to a remote server via TCP port 10514.

+ + +

+ +

Legacy Configuration Directives:

+
    +
  • $ActionForwardDefaultTemplateName string [templatename]
    + sets a new default template for UDP and plain TCP forwarding action

  • + +
  • $ActionSendTCPRebindInterval integer
    + instructs the TCP send action to close and re-open the connection to the remote host every nbr of messages sent. Zero, the default, means that no such processing is done. This directive is useful for use with load-balancers. Note that there is some performance overhead associated with it, so it is advisable to not too often "rebind" the connection (what "too often" actually means depends on your configuration, a rule of thumb is that it should be not be much more often than once per second).

  • + +
  • $ActionSendUDPRebindInterval integer
    + instructs the UDP send action to rebind the send socket every nbr of messages sent. Zero, the default, means that no rebind is done. This directive is useful for use with load-balancers.

  • + +
  • $ActionSendStreamDriver <driver basename>
    + just like $DefaultNetstreamDriver, but for the specific action

  • + +
  • $ActionSendStreamDriverMode <mode> [default 0]
    + mode to use with the stream driver (driver-specific)

  • + +
  • $ActionSendStreamDriverAuthMode <mode>
    + authentication mode to use with the stream driver. Note that this directive requires TLS netstream drivers. For all others, it will be ignored. (driver-specific))

  • + +
  • $ActionSendStreamDriverPermittedPeers <ID>
    + accepted fingerprint (SHA1) or name of remote peer. Note that this directive requires TLS netstream drivers. For all others, it will be ignored. (driver-specific)

  • + +
  • $ActionSendResendLastMsgOnReconnect on/off [default off]
    + specifies if the last message is to be resend when a connecition breaks and has been reconnected. May increase reliability, but comes at the risk of message duplication.

  • + +
  • $ResetConfigVariables
    + Resets all configuration variables to their default value. Any settings made will not be applied to configuration lines following the $ResetConfigVariables. This is a good method to make sure no side-effects exists from previous directives. This directive has no parameters.

  • + +
+ +

Legacy Sample:

+

The following command sends all syslog messages to a remote server via TCP port 10514.

+ + + +

[rsyslog.conf overview] [manual +index] [rsyslog site]

+

This documentation is part of the +rsyslog project.
+Copyright © 2008 by Rainer Gerhards and +Adiscon. Released under the GNU GPL +version 3 or higher.

+ + diff --git a/doc/ompipe.html b/doc/ompipe.html new file mode 100644 index 00000000..49915b78 --- /dev/null +++ b/doc/ompipe.html @@ -0,0 +1,62 @@ + + + +Pipe Output Module + + +back + +

Pipe Output Module

+

Module Name:    omfwd

+

Author: Rainer Gerhards <rgergards@adiscon.com>

+

Description:

+

The ompipe plug-in provides the core functionality for logging output to named pipes (fifos). It is a built-in module that does not need to be loaded.

+

 

+ +

Global Configuration Directives:

+
    +
  • Template [templateName]
    + sets a new default template for file actions.
  • + +
+

 

+

Action specific Configuration Directives:

+
    +
  • Pipe string
    + A fifo or named pipe can be used as a destination for log messages.

  • + + + +
+

Caveats/Known Bugs:

  • None.
+

Sample:

+

The following command sends all syslog messages to a remote server via TCP port 10514.

+ + +

+ +

Legacy Configuration Directives:

+

rsyslog has support for logging output to named pipes (fifos). A fifo or named pipe can be used as a destination for log messages by prepending a pipe symbol ("|'') to the name of the file. This is handy for debugging. Note that the fifo must be created with the mkfifo(1) command before rsyslogd is started. + +

+ +

Legacy Sample:

+

The following command sends all syslog messages to a remote server via TCP port 10514.

+ + + +

[rsyslog.conf overview] [manual +index] [rsyslog site]

+

This documentation is part of the +rsyslog project.
+Copyright © 2008 by Rainer Gerhards and +Adiscon. Released under the GNU GPL +version 3 or higher.

+ + diff --git a/doc/omusrmsg.html b/doc/omusrmsg.html new file mode 100644 index 00000000..eccfef2d --- /dev/null +++ b/doc/omusrmsg.html @@ -0,0 +1,64 @@ + + + +User Message Output Module + + +back + +

User Message Output Module

+

Module Name:    omusrmsg

+

Author: Rainer Gerhards <rgergards@adiscon.com>

+

Description:

+

The omusrmsg plug-in provides the core functionality for logging output to a logged on user. It is a built-in module that does not need to be loaded.

+

 

+ +

Global Configuration Directives:

+
    +
  • Template [templateName]
    + sets a new default template for file actions.
  • + +
+

 

+

Action specific Configuration Directives:

+
    +
  • Users string
    + Must be a valid user name or root.

  • + + + +
+

Caveats/Known Bugs:

  • None.
+

Sample:

+

The following command sends all critical syslog messages to a user and to root.

+ + +

+ +

Legacy Configuration Directives:

+

+ No specific configuration directives available. See configuration sample below for details on using the plugin. +

+ +

Legacy Sample:

+

The following command sends all critical syslog messages to a user and to root.

+ + + +

[rsyslog.conf overview] [manual +index] [rsyslog site]

+

This documentation is part of the +rsyslog project.
+Copyright © 2008 by Rainer Gerhards and +Adiscon. Released under the GNU GPL +version 3 or higher.

+ + diff --git a/doc/rsyslog_conf_global.html b/doc/rsyslog_conf_global.html index 6c20f4c2..a4d760eb 100644 --- a/doc/rsyslog_conf_global.html +++ b/doc/rsyslog_conf_global.html @@ -52,10 +52,10 @@ This directive will timeout previous messages seen if they are older than 20 minutes. In the example above, the count would now be always 1 and consequently no rule would ever be triggered. -
  • $ActionFileDefaultTemplate [templateName] - sets a new default template for file actions
  • -
  • $ActionFileEnableSync [on/off] - enables file +
  • $ActionFileDefaultTemplate [templateName] - sets a new default template for file actions
  • +
  • $ActionFileEnableSync [on/off] - enables file syncing capability of omfile
  • -
  • $ActionForwardDefaultTemplate [templateName] - sets a new +
  • $ActionForwardDefaultTemplate [templateName] - sets a new default template for UDP and plain TCP forwarding action
  • $ActionGSSForwardDefaultTemplate [templateName] - sets a new default template for GSS-API forwarding action
  • @@ -93,23 +93,23 @@ default 60000 (1 minute)]
  • $ActionQueueWorkerThreadMinumumMessages <number>, default 100
  • $ActionResumeInterval
  • $ActionResumeRetryCount <number> [default 0, -1 means eternal]
  • -
  • $ActionSendResendLastMsgOnReconnect <[on/off]> specifies if the last message is to be resend when a connecition breaks and has been reconnected. May increase reliability, but comes at the risk of message duplication. -
  • $ActionSendStreamDriver <driver basename> just like $DefaultNetstreamDriver, but for the specific action
  • -
  • $ActionSendStreamDriverMode <mode>, default 0, mode to use with the stream driver (driver-specific)
  • -
  • $ActionSendStreamDriverAuthMode <mode>,  authentication mode to use with the stream driver. Note that this directive requires TLS +
  • $ActionSendResendLastMsgOnReconnect <[on/off]> specifies if the last message is to be resend when a connecition breaks and has been reconnected. May increase reliability, but comes at the risk of message duplication. +
  • $ActionSendStreamDriver <driver basename> just like $DefaultNetstreamDriver, but for the specific action
  • +
  • $ActionSendStreamDriverMode <mode>, default 0, mode to use with the stream driver (driver-specific)
  • +
  • $ActionSendStreamDriverAuthMode <mode>,  authentication mode to use with the stream driver. Note that this directive requires TLS netstream drivers. For all others, it will be ignored. (driver-specific)
  • -
  • $ActionSendStreamDriverPermittedPeer <ID>,  accepted fingerprint (SHA1) or name of remote peer. Note that this directive requires TLS +
  • $ActionSendStreamDriverPermittedPeer <ID>,  accepted fingerprint (SHA1) or name of remote peer. Note that this directive requires TLS netstream drivers. For all others, it will be ignored. (driver-specific) - directive may go away!
  • -
  • $ActionSendTCPRebindInterval nbr- [available since 4.5.1] - instructs the TCP send +
  • $ActionSendTCPRebindInterval nbr- [available since 4.5.1] - instructs the TCP send action to close and re-open the connection to the remote host every nbr of messages sent. Zero, the default, means that no such processing is done. This directive is useful for use with load-balancers. Note that there is some performance overhead associated with it, so it is advisable to not too often "rebind" the connection (what "too often" actually means depends on your configuration, a rule of thumb is that it should be not be much more often than once per second).
  • -
  • $ActionSendUDPRebindInterval nbr- [available since 4.3.2] - instructs the UDP send +
  • $ActionSendUDPRebindInterval nbr- [available since 4.3.2] - instructs the UDP send action to rebind the send socket every nbr of messages sent. Zero, the default, means that no rebind is done. This directive is useful for use with load-balancers.
  • $ActionWriteAllMarkMessages [on/off]- [available since 5.1.5] - normally, mark messages @@ -133,22 +133,22 @@ functionality. the provided name (the default default ruleset is named "RSYSLOG_DefaultRuleset"). It is advised to also read our paper on using multiple rule sets in rsyslog.
  • -
  • $CreateDirs [on/off] - create directories on an as-needed basis
  • -
  • $DirCreateMode
  • -
  • $DirGroup
  • -
  • $DirOwner
  • +
  • $CreateDirs [on/off] - create directories on an as-needed basis
  • +
  • $DirCreateMode
  • +
  • $DirGroup
  • +
  • $DirOwner
  • $DropMsgsWithMaliciousDnsPTRRecords
  • $DropTrailingLFOnReception
  • -
  • $DynaFileCacheSize
  • +
  • $DynaFileCacheSize
  • $Escape8BitCharactersOnReceive
  • $EscapeControlCharactersOnReceive
  • $EscapeControlCharactersOnReceive [on|off] - escape USASCII HT character
  • $SpaceLFOnReceive [on/off] - instructs rsyslogd to replace LF with spaces during message reception (sysklogd compatibility aid)
  • $ErrorMessagesToStderr [on|off] - direct rsyslogd error message to stderr (in addition to other targets)
  • -
  • $FailOnChownFailure
  • -
  • $FileCreateMode
  • -
  • $FileGroup
  • -
  • $FileOwner
  • +
  • $FailOnChownFailure
  • +
  • $FileCreateMode
  • +
  • $FileGroup
  • +
  • $FileOwner
  • $GenerateConfigGraph
  • $GssForwardServiceName
  • $GssListenServiceName
  • @@ -224,7 +224,7 @@ supported in order to be compliant to the upcoming new syslog RFC series.
  • $MaxOpenFiles
  • $ModDir
  • $ModLoad
  • -
  • $OMFileAsyncWriting [on/off], if turned on, the files will be written +
  • $OMFileAsyncWriting [on/off], if turned on, the files will be written in asynchronous mode via a separate thread. In that case, double buffers will be used so that one buffer can be filled while the other buffer is being written. Note that in order to enable $OMFileFlushInterval, $OMFileAsyncWriting must be set to "on". Otherwise, the flush @@ -232,11 +232,11 @@ interval will be ignored. Also note that when $OMFileFlushOnTXEnd is "on" but $OMFileAsyncWriting is off, output will only be written when the buffer is full. This may take several hours, or even require a rsyslog shutdown. However, a buffer flush can be forced in that case by sending rsyslogd a HUP signal. -
  • $OMFileZipLevel 0..9 [default 0] - if greater 0, turns on gzip compression +
  • $OMFileZipLevel 0..9 [default 0] - if greater 0, turns on gzip compression of the output file. The higher the number, the better the compression, but also the more CPU is required for zipping.
  • -
  • $OMFileIOBufferSize <size_nbr>, default 4k, size of the buffer used to writing output data. The larger the buffer, the potentially better performance is. The default of 4k is quite conservative, it is useful to go up to 64k, and 128K if you used gzip compression (then, even higher sizes may make sense)
  • -
  • $OMFileFlushOnTXEnd <[on/off]>, default on. Omfile has the +
  • $OMFileIOBufferSize <size_nbr>, default 4k, size of the buffer used to writing output data. The larger the buffer, the potentially better performance is. The default of 4k is quite conservative, it is useful to go up to 64k, and 128K if you used gzip compression (then, even higher sizes may make sense)
  • +
  • $OMFileFlushOnTXEnd <[on/off]>, default on. Omfile has the capability to write output using a buffered writer. Disk writes are only done when the buffer is full. So if an error happens during that write, data is potentially lost. In cases where @@ -246,7 +246,7 @@ error recovery thus can handle write errors without data loss. Note that this op severely reduces the effect of zip compression and should be switched to off for that use case. Note that the default -on- is primarily an aid to preserve the traditional syslogd behaviour.
  • -
  • $omfileForceChown - force ownership change for all files
  • +
  • $omfileForceChown - force ownership change for all files
  • $RepeatedMsgContainsOriginalMsg [on/off] - "last message repeated n times" messages, if generated, have a different format that contains the message that is being repeated. Note that only the first "n" characters are included, with n to be at least 80 characters, most diff --git a/doc/rsyslog_conf_modules.html b/doc/rsyslog_conf_modules.html index 650e20ad..cbd60faf 100644 --- a/doc/rsyslog_conf_modules.html +++ b/doc/rsyslog_conf_modules.html @@ -51,6 +51,10 @@ to message generators.

    Output modules process messages. With them, message formats can be transformed and messages be transmitted to various different targets.

      +
    • omfile - file output module
    • +
    • omfwd - syslog forwarding output module
    • +
    • ompipe - named pipe output module
    • +
    • omusrmsg - user message output module
    • omsnmp - SNMP trap output module
    • omtdout - stdout output module (mainly a test tool)
    • omrelp - RELP output module
    • -- cgit v1.2.3 From 91b7e5e34a27c6047fb871e9db77581181bd6f4a Mon Sep 17 00:00:00 2001 From: David Kelly Date: Fri, 6 Jul 2012 11:45:22 -0700 Subject: BAT-40 Found leak in imzmq3 plugin For some reason I forgot to free() the buffer that comes back from zstr_recv(). Doh! --- plugins/imzmq3/imzmq3.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/imzmq3/imzmq3.c b/plugins/imzmq3/imzmq3.c index 78eee887..8107a1fc 100644 --- a/plugins/imzmq3/imzmq3.c +++ b/plugins/imzmq3/imzmq3.c @@ -491,7 +491,10 @@ static int handlePoll(zloop_t __attribute__((unused)) * loop, zmq_pollitem_t *po logmsg->msgFlags = NEEDS_PARSING; submitMsg(logmsg); } - + + /* gotta free the string returned from zstr_recv() */ + free(buf); + if( pollerData->thread->bShallStop == TRUE) { /* a handler that returns -1 will terminate the czmq reactor loop -- cgit v1.2.3 From 6e1774a3515893038914ab91eb2024dbb1ad3112 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Mon, 9 Jul 2012 16:54:41 -0700 Subject: imzmq3: Added the return call to runInput Just to be sure that nothing unfortunate would happen, possible that housekeeping would not get done without this. --- plugins/imzmq3/imzmq3.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/imzmq3/imzmq3.c b/plugins/imzmq3/imzmq3.c index 8107a1fc..dc1d64d3 100644 --- a/plugins/imzmq3/imzmq3.c +++ b/plugins/imzmq3/imzmq3.c @@ -563,6 +563,7 @@ static rsRetVal rcv_loop(thrdInfo_t* pThrd){ BEGINrunInput CODESTARTrunInput iRet = rcv_loop(pThrd); + RETiRet; ENDrunInput -- cgit v1.2.3 From 127e2cf09596c86d106d521c9977434bc128a763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 23 Jul 2012 13:51:59 +0200 Subject: Fix $SystemLogSocketAnnotate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Copy bAnnotateSysSock value from old config data into the new structure * Set bUseCreds on the system log socket if bAnnotateSysSock is set * Process all CMSG records, not only the first one Signed-off-by: Miloslav Trmač --- plugins/imuxsock/imuxsock.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 389a465c..b4289345 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -946,14 +946,12 @@ static rsRetVal readSocket(lstn_t *pLstn) if( pLstn->bUseCreds && cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_CREDENTIALS) { cred = (struct ucred*) CMSG_DATA(cm); - break; } # endif /* HAVE_SCM_CREDENTIALS */ # if HAVE_SO_TIMESTAMP if( pLstn->bUseSysTimeStamp && cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SO_TIMESTAMP) { ts = (struct timeval *)CMSG_DATA(cm); - break; } # endif /* HAVE_SO_TIMESTAMP */ } @@ -1012,7 +1010,7 @@ activateListeners() listeners[0].ratelimitInterval = runModConf->ratelimitIntervalSysSock; listeners[0].ratelimitBurst = runModConf->ratelimitBurstSysSock; listeners[0].ratelimitSev = runModConf->ratelimitSeveritySysSock; - listeners[0].bUseCreds = (runModConf->bWritePidSysSock || runModConf->ratelimitIntervalSysSock) ? 1 : 0; + listeners[0].bUseCreds = (runModConf->bWritePidSysSock || runModConf->ratelimitIntervalSysSock || runModConf->bAnnotateSysSock) ? 1 : 0; listeners[0].bWritePid = runModConf->bWritePidSysSock; listeners[0].bAnnotate = runModConf->bAnnotateSysSock; listeners[0].bUseSysTimeStamp = runModConf->bUseSysTimeStamp; @@ -1130,6 +1128,7 @@ CODESTARTendCnfLoad loadModConf->pLogSockName = cs.pLogSockName; loadModConf->bIgnoreTimestamp = cs.bIgnoreTimestampSysSock; loadModConf->bUseFlowCtl = cs.bUseFlowCtlSysSock; + loadModConf->bAnnotateSysSock = cs.bAnnotateSysSock; } loadModConf = NULL; /* done loading */ -- cgit v1.2.3 From a607651cde36e35fa8c398d907b073e64176ff4e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 31 Jul 2012 08:54:13 +0200 Subject: doc: added last patch to ChangeLog --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 0ad873b4..2e76e5b6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,6 +14,8 @@ Version 6.5.0 [devel] 2012-0?-?? - added new 0mq plugins (via czmq lib) Thanks to David Kelly for contributing these modules - bugfix: omhdfs did no longer compile +- bugfix: SystemLogSocketAnnotate did not work correctly + Thanks to Miloslav Trmač for the patch --------------------------------------------------------------------------- Version 6.3.13 [BETA] 2012-07-?? - omelasticsearch: support for parameters parent & dynparent added -- cgit v1.2.3 From 7e21d789a81eeb03b2703101eab366c53ccc4ca6 Mon Sep 17 00:00:00 2001 From: Milan Bartos Date: Mon, 6 Aug 2012 12:47:25 +0200 Subject: Add support for parsing trusted properties * add support for parsing trusted properties into libee event structure * add $SystemLogParseTrusted config file option to enable it (default off) --- plugins/imuxsock/imuxsock.c | 151 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 121 insertions(+), 30 deletions(-) diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 061cd736..a560def4 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -149,6 +149,7 @@ typedef struct lstn_s { sbool bCreatePath; /* auto-creation of socket directory? */ sbool bUseCreds; /* pull original creator credentials from socket */ sbool bAnnotate; /* annotate events with trusted properties */ + sbool bParseTrusted; /* parse trusted properties */ sbool bWritePid; /* write original PID into tag */ sbool bUseSysTimeStamp; /* use timestamp from system (instead of from message) */ } lstn_t; @@ -163,6 +164,8 @@ static int startIndexUxLocalSockets; /* process fd from that index on (used to static int nfd = 1; /* number of Unix sockets open / read-only after startup */ static int sd_fds = 0; /* number of systemd activated sockets */ +static ee_ctx ctxee = NULL; /* library context */ + /* config vars for legacy config system */ #define DFLT_bCreatePath 0 #define DFLT_ratelimitInterval 0 @@ -189,6 +192,7 @@ static struct configSettings_s { int ratelimitSeveritySysSock; int bAnnotate; /* annotate trusted properties */ int bAnnotateSysSock; /* same, for system log socket */ + int bParseTrusted; /* parse trusted properties */ } cs; struct instanceConf_s { @@ -203,6 +207,7 @@ struct instanceConf_s { int ratelimitBurst; /* max nbr of messages in interval */ int ratelimitSeverity; int bAnnotate; /* annotate trusted properties */ + int bParseTrusted; /* parse trusted properties */ struct instanceConf_s *next; }; @@ -214,6 +219,7 @@ struct modConfData_s { int ratelimitBurstSysSock; int ratelimitSeveritySysSock; int bAnnotateSysSock; + int bParseTrusted; sbool bIgnoreTimestamp; /* ignore timestamps present in the incoming message? */ sbool bUseFlowCtl; /* use flow control or not (if yes, only LIGHT is used! */ sbool bOmitLocalLogging; @@ -345,6 +351,7 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) inst->bUseSysTimeStamp = cs.bUseSysTimeStamp; inst->bWritePid = cs.bWritePid; inst->bAnnotate = cs.bAnnotate; + inst->bParseTrusted = cs.bParseTrusted; inst->next = NULL; /* node created, let's add to config */ @@ -407,6 +414,7 @@ addListner(instanceConf_t *inst) listeners[nfd].sockName = ustrdup(inst->sockName); listeners[nfd].bUseCreds = (inst->bWritePid || inst->ratelimitInterval || inst->bAnnotate) ? 1 : 0; listeners[nfd].bAnnotate = inst->bAnnotate; + listeners[nfd].bParseTrusted = inst->bParseTrusted; listeners[nfd].bWritePid = inst->bWritePid; listeners[nfd].bUseSysTimeStamp = inst->bUseSysTimeStamp; nfd++; @@ -712,6 +720,26 @@ copyescaped(uchar *dstbuf, uchar *inbuf, int inlen) } +/* Creates new field to be added to event + * used for SystemLogParseTrusted parsing + */ +struct ee_field * +createNewField(char *fieldname, char *value, int lenValue) { + es_str_t *newStr; + struct ee_value *newVal; + struct ee_field *newField; + + newStr = es_newStrFromBuf(value, (es_size_t) lenValue); + + newVal = ee_newValue(ctxee); + ee_setStrValue(newVal, newStr); + + newField = ee_newFieldFromNV(ctxee, fieldname, newVal); + + return newField; +} + + /* submit received message to the queue engine * We now parse the message according to expected format so that we * can also mangle it if necessary. @@ -737,6 +765,7 @@ SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred, struct tim uchar *pmsgbuf; int toffs; /* offset for trusted properties */ struct syslogTime dummyTS; + struct ee_event *event = NULL; DEFiRet; /* TODO: handle format errors?? */ @@ -781,37 +810,82 @@ SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred, struct tim } else { CHKmalloc(pmsgbuf = malloc(lenRcv+4096)); } - memcpy(pmsgbuf, pRcv, lenRcv); - memcpy(pmsgbuf+lenRcv, " @[", 3); - toffs = lenRcv + 3; /* next free location */ - lenProp = snprintf((char*)propBuf, sizeof(propBuf), "_PID=%lu _UID=%lu _GID=%lu", - (long unsigned) cred->pid, (long unsigned) cred->uid, - (long unsigned) cred->gid); - memcpy(pmsgbuf+toffs, propBuf, lenProp); - toffs = toffs + lenProp; - getTrustedProp(cred, "comm", propBuf, sizeof(propBuf), &lenProp); - if(lenProp) { - memcpy(pmsgbuf+toffs, " _COMM=", 7); - memcpy(pmsgbuf+toffs+7, propBuf, lenProp); - toffs = toffs + 7 + lenProp; - } - getTrustedExe(cred, propBuf, sizeof(propBuf), &lenProp); - if(lenProp) { - memcpy(pmsgbuf+toffs, " _EXE=", 6); - memcpy(pmsgbuf+toffs+6, propBuf, lenProp); - toffs = toffs + 6 + lenProp; - } - getTrustedProp(cred, "cmdline", propBuf, sizeof(propBuf), &lenProp); - if(lenProp) { - memcpy(pmsgbuf+toffs, " _CMDLINE=", 10); - toffs = toffs + 10 + - copyescaped(pmsgbuf+toffs+10, propBuf, lenProp); + + if (pLstn->bParseTrusted) { + struct ee_field *newField; + + if(ctxee == NULL) { + if((ctxee = ee_initCtx()) == NULL) { + errmsg.LogError(0, RS_RET_NO_RULESET, "error: could not initialize libee ctx, cannot " + "activate action"); + ABORT_FINALIZE(RS_RET_ERR_LIBEE_INIT); + } + } + + event = ee_newEvent(ctxee); + + /* create value string, create field, and add it to event */ + lenProp = snprintf((char *)propBuf, sizeof(propBuf), "%lu", (long unsigned) cred->pid); + newField = createNewField("pid", (char *)propBuf, lenProp); + ee_addFieldToEvent(event, newField); + + lenProp = snprintf((char *)propBuf, sizeof(propBuf), "%lu", (long unsigned) cred->uid); + newField = createNewField("uid", (char *)propBuf, lenProp); + ee_addFieldToEvent(event, newField); + + lenProp = snprintf((char *)propBuf, sizeof(propBuf), "%lu", (long unsigned) cred->gid); + newField = createNewField("gid", (char *)propBuf, lenProp); + ee_addFieldToEvent(event, newField); + + getTrustedProp(cred, "comm", propBuf, sizeof(propBuf), &lenProp); + newField = createNewField("appname", (char *)propBuf, lenProp); + ee_addFieldToEvent(event, newField); + + getTrustedExe(cred, propBuf, sizeof(propBuf), &lenProp); + newField = createNewField("exe", (char *)propBuf, lenProp); + ee_addFieldToEvent(event, newField); + + getTrustedProp(cred, "cmdline", propBuf, sizeof(propBuf), &lenProp); + newField = createNewField("cmd", (char *)propBuf, lenProp); + ee_addFieldToEvent(event, newField); + + } else { + + memcpy(pmsgbuf, pRcv, lenRcv); + memcpy(pmsgbuf+lenRcv, " @[", 3); + toffs = lenRcv + 3; /* next free location */ + lenProp = snprintf((char*)propBuf, sizeof(propBuf), "_PID=%lu _UID=%lu _GID=%lu", + (long unsigned) cred->pid, (long unsigned) cred->uid, + (long unsigned) cred->gid); + memcpy(pmsgbuf+toffs, propBuf, lenProp); + toffs = toffs + lenProp; + + getTrustedProp(cred, "comm", propBuf, sizeof(propBuf), &lenProp); + if(lenProp) { + memcpy(pmsgbuf+toffs, " _COMM=", 7); + memcpy(pmsgbuf+toffs+7, propBuf, lenProp); + toffs = toffs + 7 + lenProp; + } + getTrustedExe(cred, propBuf, sizeof(propBuf), &lenProp); + if(lenProp) { + memcpy(pmsgbuf+toffs, " _EXE=", 6); + memcpy(pmsgbuf+toffs+6, propBuf, lenProp); + toffs = toffs + 6 + lenProp; + } + getTrustedProp(cred, "cmdline", propBuf, sizeof(propBuf), &lenProp); + if(lenProp) { + memcpy(pmsgbuf+toffs, " _CMDLINE=", 9); + toffs = toffs + 9 + + copyescaped(pmsgbuf+toffs+9, propBuf, lenProp); + } + + /* finalize string */ + pmsgbuf[toffs] = ']'; + pmsgbuf[toffs+1] = '\0'; + + pRcv = pmsgbuf; + lenRcv = toffs + 1; } - /* finalize string */ - pmsgbuf[toffs] = ']'; - pmsgbuf[toffs+1] = '\0'; - pRcv = pmsgbuf; - lenRcv = toffs + 1; } /* we now create our own message object and submit it to the queue */ @@ -828,6 +902,14 @@ SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred, struct tim parse++; lenMsg--; /* '>' */ + /* event is saved to pMsg */ + if(pMsg->event != NULL) { + ee_deleteEvent(pMsg->event); + } + if (event != NULL) { + pMsg->event = event; + } + if(ts == NULL) { if((pLstn->flags & IGNDATE)) { /* in this case, we still need to find out if we have a valid @@ -1017,6 +1099,7 @@ activateListeners() listeners[0].bUseCreds = (runModConf->bWritePidSysSock || runModConf->ratelimitIntervalSysSock || runModConf->bAnnotateSysSock) ? 1 : 0; listeners[0].bWritePid = runModConf->bWritePidSysSock; listeners[0].bAnnotate = runModConf->bAnnotateSysSock; + listeners[0].bParseTrusted = runModConf->bParseTrusted; listeners[0].bUseSysTimeStamp = runModConf->bUseSysTimeStamp; listeners[0].flags = runModConf->bIgnoreTimestamp ? IGNDATE : NOFLAG; listeners[0].flowCtl = runModConf->bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; @@ -1060,6 +1143,7 @@ CODESTARTbeginCnfLoad pModConf->bUseSysTimeStamp = 1; pModConf->bWritePidSysSock = 0; pModConf->bAnnotateSysSock = 0; + pModConf->bParseTrusted = 0; pModConf->ratelimitIntervalSysSock = DFLT_ratelimitInterval; pModConf->ratelimitBurstSysSock = DFLT_ratelimitBurst; pModConf->ratelimitSeveritySysSock = DFLT_ratelimitSeverity; @@ -1133,6 +1217,7 @@ CODESTARTendCnfLoad loadModConf->bIgnoreTimestamp = cs.bIgnoreTimestampSysSock; loadModConf->bUseFlowCtl = cs.bUseFlowCtlSysSock; loadModConf->bAnnotateSysSock = cs.bAnnotateSysSock; + loadModConf->bParseTrusted = cs.bParseTrusted; } loadModConf = NULL; /* done loading */ @@ -1276,6 +1361,8 @@ CODESTARTafterRun discardLogSockets(); nfd = 1; + ee_exitCtx(ctxee); + ctxee = NULL; ENDafterRun @@ -1328,6 +1415,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a cs.bWritePidSysSock = 0; cs.bAnnotate = 0; cs.bAnnotateSysSock = 0; + cs.bParseTrusted = 0; cs.bCreatePath = DFLT_bCreatePath; cs.ratelimitInterval = DFLT_ratelimitInterval; cs.ratelimitIntervalSysSock = DFLT_ratelimitInterval; @@ -1380,6 +1468,7 @@ CODEmodInit_QueryRegCFSLineHdlr listeners[0].bParseHost = 0; listeners[0].bUseCreds = 0; listeners[0].bAnnotate = 0; + listeners[0].bParseTrusted = 0; listeners[0].bCreatePath = 0; listeners[0].bUseSysTimeStamp = 1; @@ -1437,6 +1526,8 @@ CODEmodInit_QueryRegCFSLineHdlr NULL, &cs.bUseSysTimeStampSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogsocketannotate", 0, eCmdHdlrBinary, NULL, &cs.bAnnotateSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogparsetrusted", 0, eCmdHdlrBinary, + NULL, &cs.bParseTrusted, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogusepidfromsystem", 0, eCmdHdlrBinary, NULL, &cs.bWritePidSysSock, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); CHKiRet(regCfSysLineHdlr2((uchar *)"systemlogratelimitinterval", 0, eCmdHdlrInt, -- cgit v1.2.3 From fa8a1f57bf92f62daa988973a09a71ecf3e58f07 Mon Sep 17 00:00:00 2001 From: Milan Bartos Date: Mon, 6 Aug 2012 12:48:35 +0200 Subject: update documentation for parsing trusted properties --- doc/imuxsock.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/imuxsock.html b/doc/imuxsock.html index 34a696d9..19f9cf51 100644 --- a/doc/imuxsock.html +++ b/doc/imuxsock.html @@ -104,6 +104,8 @@ to the system log socket. be obtained from the log socket itself. If so, the TAG part of the message is rewritten. It is recommended to turn this option on, but the default is "off" to keep compatible with earlier versions of rsyslog. This option was introduced in 5.7.0. +
    • $SystemLogParseTrusted [on/off] - specifies if Trusted Properties shall be parsed +and saved into libee event structure. This option needs $SystemLogSocketAnnotate to be on.
    • $SystemLogRateLimitInterval [number] - specifies the rate-limiting interval in seconds. Default value is 5 seconds. Set it to 0 to turn rate limiting off.
    • -- cgit v1.2.3 From c718cf1ac37b7959e715b04cccfa11370ab1bbb6 Mon Sep 17 00:00:00 2001 From: Milan Bartos Date: Fri, 17 Aug 2012 09:17:36 +0200 Subject: Fix undefined ctxee problem modified: plugins/imuxsock/imuxsock.c --- plugins/imuxsock/imuxsock.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index a560def4..57b2a70a 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -1361,8 +1361,10 @@ CODESTARTafterRun discardLogSockets(); nfd = 1; - ee_exitCtx(ctxee); - ctxee = NULL; + if(ctxee != NULL) { + ee_exitCtx(ctxee); + ctxee = NULL; + } ENDafterRun -- cgit v1.2.3 From c78f1ef53835f38efa013a91dd89e36c60bc0891 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 21 Aug 2012 14:37:43 +0200 Subject: doc: add imported patch to ChangeLog --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 487d2438..492c27d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -16,6 +16,8 @@ Version 6.5.0 [devel] 2012-0?-?? - bugfix: omhdfs did no longer compile - bugfix: SystemLogSocketAnnotate did not work correctly Thanks to Miloslav Trmač for the patch +- $SystemLogParseTrusted config file option + Thanks to Milan Bartos for the patch --------------------------------------------------------------------------- Version 6.3.13 [BETA] 2012-07-?? - omelasticsearch: support for parameters parent & dynparent added -- cgit v1.2.3 From 2f4292a81c2bf89b349f0e276c69616ac6e51164 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Sat, 11 Aug 2012 09:48:10 +0200 Subject: Fix printing of some template options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- template.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/template.c b/template.c index 994a9029..32b8d561 100644 --- a/template.c +++ b/template.c @@ -1355,7 +1355,10 @@ void tplPrintList(rsconf_t *conf) dbgprintf("[format as CSV (RFC4180)]"); } if(pTpe->data.field.options.bJSON) { - dbgprintf("[format as JSON"); + dbgprintf("[format as JSON] "); + } + if(pTpe->data.field.options.bJSONf) { + dbgprintf("[format as JSON field] "); } if(pTpe->data.field.options.bDropLastLF) { dbgprintf("[drop last LF in msg] "); -- cgit v1.2.3 From ab7b1b381a467d6a61760a5cb84ef804a74598f1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 24 Aug 2012 15:08:12 +0200 Subject: add base plumbing for template() config object to grammar --- grammar/grammar.y | 14 +++++++++++++- grammar/lexer.l | 8 +++++++- grammar/rainerscript.h | 3 +++ runtime/rsconf.c | 10 ++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/grammar/grammar.y b/grammar/grammar.y index 402b1a57..35afae30 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -63,6 +63,9 @@ extern int yyerror(char*); %token ENDOBJ %token CFSYSLINE %token BEGIN_ACTION +%token BEGIN_PROPERTY +%token BEGIN_CONSTANT +%token BEGIN_TPL %token STOP %token LEGACY_ACTION %token PRIFILT @@ -89,7 +92,7 @@ extern int yyerror(char*); %token CMP_STARTSWITHI %type nv nvlst -%type obj +%type obj propconst %type actlst %type act %type cfsysline @@ -128,6 +131,15 @@ conf: /* empty (to end recursion) */ | conf BSD_HOST_SELECTOR { cnfDoBSDHost($2); } obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } + | BEGIN_TPL nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_TPL, $2); dbgprintf("processing template() without {}\n"); } + | BEGIN_TPL nvlst ENDOBJ '{' propconst '}' + { $$ = cnfobjNew(CNFOBJ_TPL, $2); dbgprintf("processing template() WITH {}\n"); } +/* TODO: NOTE: + propconst is the NEXT step. It is just included as an experiment and needs + to be replaced. +*/ +propconst: BEGIN_PROPERTY nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_PROPERTY, $2); + dbgprintf("processed property()\n"); } cfsysline: CFSYSLINE { $$ = $1; } nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } diff --git a/grammar/lexer.l b/grammar/lexer.l index e688ffce..c5e7bf7d 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -9,7 +9,7 @@ * cases. So while we hope that cfsysline support can be dropped some time in * the future, we will probably keep these useful constructs. * - * Copyright 2011 Rainer Gerhards and Adiscon GmbH. + * Copyright 2011-2012 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -151,6 +151,12 @@ int fileno(FILE *stream); BEGIN INITIAL; } "global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; BEGIN INOBJ; return BEGINOBJ; } +"template"[ \n\t]*"(" { yylval.objType = CNFOBJ_TPL; + BEGIN INOBJ; return BEGIN_TPL; } +"property"[ \n\t]*"(" { yylval.objType = CNFOBJ_PROPERTY; + BEGIN INOBJ; return BEGIN_PROPERTY; } +"constant"[ \n\t]*"(" { yylval.objType = CNFOBJ_CONSTANT; + BEGIN INOBJ; return BEGIN_CONSTANT; } "input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; BEGIN INOBJ; return BEGINOBJ; } "module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 5ff71bee..83a253f7 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -16,6 +16,9 @@ enum cnfobjType { CNFOBJ_GLOBAL, CNFOBJ_INPUT, CNFOBJ_MODULE, + CNFOBJ_TPL, + CNFOBJ_PROPERTY, + CNFOBJ_CONSTANT, CNFOBJ_INVALID = 0 }; diff --git a/runtime/rsconf.c b/runtime/rsconf.c index bd002353..f07ab314 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -386,6 +386,7 @@ yyerror(char *s) } void cnfDoObj(struct cnfobj *o) { +int bChkUnuse = 1; // TODO: Delete dbgprintf("cnf:global:obj: "); cnfobjPrint(o); switch(o->objType) { @@ -398,7 +399,16 @@ void cnfDoObj(struct cnfobj *o) case CNFOBJ_ACTION: actionProcessCnf(o); break; + case CNFOBJ_TPL: + //processTemplate(o); +bChkUnuse = 0; + break; + case CNFOBJ_PROPERTY: + //processTemplate(o); +bChkUnuse = 0; + break; } +if(bChkUnuse) nvlstChkUnused(o->nvlst); cnfobjDestruct(o); } -- cgit v1.2.3 From 1eac94e11dab1e7caead5e31a57d2cae31b5ad62 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 25 Aug 2012 11:08:38 +0200 Subject: v6 config/templates: legacy types are now supported via template() --- runtime/rsconf.c | 4 +- template.c | 178 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- template.h | 1 + 3 files changed, 180 insertions(+), 3 deletions(-) diff --git a/runtime/rsconf.c b/runtime/rsconf.c index f07ab314..cbc09c11 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -66,6 +66,7 @@ #include "parserif.h" #include "modules.h" #include "dirty.h" +#include "template.h" /* static data */ DEFobjStaticHelpers @@ -400,8 +401,7 @@ int bChkUnuse = 1; // TODO: Delete actionProcessCnf(o); break; case CNFOBJ_TPL: - //processTemplate(o); -bChkUnuse = 0; + tplProcessCnf(o); break; case CNFOBJ_PROPERTY: //processTemplate(o); diff --git a/template.c b/template.c index 32b8d561..01eab556 100644 --- a/template.c +++ b/template.c @@ -2,7 +2,7 @@ * Please see syslogd.c for license information. * begun 2004-11-17 rgerhards * - * Copyright 2004, 2007 Rainer Gerhards and Adiscon + * Copyright 2004-2012 Rainer Gerhards and Adiscon * * This file is part of rsyslog. * @@ -45,6 +45,22 @@ DEFobjCurrIf(obj) DEFobjCurrIf(errmsg) DEFobjCurrIf(strgen) +/* tables for interfacing with the v6 config system */ +static struct cnfparamdescr cnfparamdescr[] = { + { "name", eCmdHdlrString, 1 }, + { "type", eCmdHdlrString, 0 }, + { "string", eCmdHdlrString, 0 }, + { "plugin", eCmdHdlrString, 0 }, + { "option.stdsql", eCmdHdlrBinary, 0 }, + { "option.sql", eCmdHdlrBinary, 0 }, + { "option.json", eCmdHdlrBinary, 0 } +}; +static struct cnfparamblk pblk = + { CNFPARAMBLK_VERSION, + sizeof(cnfparamdescr)/sizeof(struct cnfparamdescr), + cnfparamdescr + }; + #ifdef FEATURE_REGEXP DEFobjCurrIf(regexp) static int bFirstRegexpErrmsg = 1; /**< did we already do a "can't load regexp" error message? */ @@ -1122,6 +1138,166 @@ struct template *tplAddLine(rsconf_t *conf, char* pName, uchar** ppRestOfConfLin } + +// v6 - ASL 2.0! +/* Add a new template via the v6 config system. + */ +rsRetVal +tplProcessCnf(struct cnfobj *o) +{ + struct template *pTpl = NULL; + struct cnfparamvals *pvals; + int lenName; + char *name = NULL; + uchar *tplStr = NULL; + uchar *p; + uchar *plugin; + enum { T_STRING, T_PLUGIN, T_LIST } tplType; + int i; + int o_sql=0, o_stdsql=0, o_json=0; /* options */ + int numopts; + rsRetVal localRet; + DEFiRet; + + pvals = nvlstGetParams(o->nvlst, &pblk, NULL); + cnfparamsPrint(&pblk, pvals); + + + for(i = 0 ; i < pblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(pblk.descr[i].name, "name")) { + lenName = es_strlen(pvals[i].val.d.estr); + name = es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(pblk.descr[i].name, "type")) { + if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"string", sizeof("string")-1)) { + tplType = T_STRING; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"plugin", sizeof("plugin")-1)) { + tplType = T_PLUGIN; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"list", sizeof("list")-1)) { + tplType = T_LIST; + errmsg.LogError(0, RS_RET_ERR, "template type 'list' is not " + "supported in this rsyslog version"); + ABORT_FINALIZE(RS_RET_ERR); + } else { + uchar *typeStr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_ERR, "invalid template type '%s'", + typeStr); + free(typeStr); + ABORT_FINALIZE(RS_RET_ERR); + } + } else if(!strcmp(pblk.descr[i].name, "string")) { + tplStr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(pblk.descr[i].name, "plugin")) { + plugin = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(pblk.descr[i].name, "option.stdsql")) { + o_stdsql = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "option.sql")) { + o_sql = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "option.json")) { + o_json = pvals[i].val.d.n; + } else { + dbgprintf("template: program error, non-handled " + "param '%s'\n", pblk.descr[i].name); + } + } + + /* do config sanity checks */ + if(tplStr == NULL) { + if(tplType == T_STRING) { + errmsg.LogError(0, RS_RET_ERR, "template '%s' of type string needs " + "string parameter", name); + ABORT_FINALIZE(RS_RET_ERR); + } + } else { + if(tplType != T_STRING) { + errmsg.LogError(0, RS_RET_ERR, "template '%s' is not a string " + "template but has a string specified - ignored", name); + } + } + + if(plugin == NULL) { + if(tplType == T_PLUGIN) { + errmsg.LogError(0, RS_RET_ERR, "template '%s' of type plugin needs " + "plugin parameter - ignored", name); + ABORT_FINALIZE(RS_RET_ERR); + } + } else { + if(tplType != T_PLUGIN) { + errmsg.LogError(0, RS_RET_ERR, "template '%s' is not a plugin " + "template but has a plugin specified - ignored", name); + } + } + + numopts = 0; + if(o_sql) ++numopts; + if(o_stdsql) ++numopts; + if(o_json) ++numopts; + if(numopts > 1) { + errmsg.LogError(0, RS_RET_ERR, "template '%s' has multiple incompatible " + "options of sql, stdsql or json specified", name); + ABORT_FINALIZE(RS_RET_ERR); + } + + /* config ok */ + if((pTpl = tplConstruct(loadConf)) == NULL) { + DBGPRINTF("template.c: tplConstruct failed!\n"); + ABORT_FINALIZE(RS_RET_ERR); + } + pTpl->pszName = name; + pTpl->iLenName = lenName; + + switch(tplType) { + case T_STRING: p = tplStr; + while(*p) { + switch(*p) { + case '%': /* parameter */ + ++p; /* eat '%' */ + do_Parameter(&p, pTpl); + break; + default: /* constant */ + do_Constant(&p, pTpl); + break; + } + } + break; + case T_PLUGIN: p = plugin; + /* TODO: the use of tplAddTplMod() can be improved! */ + localRet = tplAddTplMod(pTpl, &p); + if(localRet != RS_RET_OK) { + errmsg.LogError(0, localRet, "template '%s': error %d " + "defining template via plugin (strgen) module", + pTpl->pszName, localRet); + ABORT_FINALIZE(localRet); + } + } + + pTpl->optFormatEscape = NO_ESCAPE; + if(o_stdsql) + pTpl->optFormatEscape = STDSQL_ESCAPE; + else if(o_sql) + pTpl->optFormatEscape = SQL_ESCAPE; + else if(o_json) + pTpl->optFormatEscape = JSON_ESCAPE; + +finalize_it: + if(iRet != RS_RET_OK) { + if(pTpl != NULL) { + /* we simply make the template defunct in this case by setting + * its name to a zero-string. We do not free it, as this would + * require additional code and causes only a very small memory + * consumption. TODO: maybe in next iteration... + */ + *pTpl->pszName = '\0'; + } + } + + RETiRet; +} + +// END v6 + + /* Find a template object based on name. Search * currently is case-senstive (should we change?). * returns pointer to template object if found and diff --git a/template.h b/template.h index e41823e9..9daf2c6b 100644 --- a/template.h +++ b/template.h @@ -141,6 +141,7 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar** ppSz, size_t *) rsRetVal doEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode); rsRetVal templateInit(); +rsRetVal tplProcessCnf(struct cnfobj *o); #endif /* #ifndef TEMPLATE_H_INCLUDED */ /* vim:set ai: -- cgit v1.2.3 From 6258cb42fd407b9388de63c746634b4df03e78eb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 25 Aug 2012 13:30:53 +0200 Subject: milestone: base plumbing for LIST-type templates mostly in place --- grammar/grammar.y | 22 +++++++++++++++------- grammar/rainerscript.c | 39 +++++++++++++++++++++++++++++++++++++++ grammar/rainerscript.h | 18 ++++++++++++++++++ runtime/rsconf.c | 1 + template.c | 44 +++++++++++++++++++++++++++++++++----------- 5 files changed, 106 insertions(+), 18 deletions(-) diff --git a/grammar/grammar.y b/grammar/grammar.y index 35afae30..d91eb3bb 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -49,6 +49,7 @@ extern int yyerror(char*); enum cnfobjType objType; struct cnfobj *obj; struct nvlst *nvlst; + struct objlst *objlst; struct cnfactlst *actlst; struct cnfexpr *expr; struct cnfrule *rule; @@ -92,7 +93,8 @@ extern int yyerror(char*); %token CMP_STARTSWITHI %type nv nvlst -%type obj propconst +%type obj property constant +%type propconst %type actlst %type act %type cfsysline @@ -133,13 +135,19 @@ obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } | BEGIN_TPL nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_TPL, $2); dbgprintf("processing template() without {}\n"); } | BEGIN_TPL nvlst ENDOBJ '{' propconst '}' - { $$ = cnfobjNew(CNFOBJ_TPL, $2); dbgprintf("processing template() WITH {}\n"); } -/* TODO: NOTE: - propconst is the NEXT step. It is just included as an experiment and needs - to be replaced. -*/ -propconst: BEGIN_PROPERTY nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_PROPERTY, $2); + { $$ = cnfobjNew(CNFOBJ_TPL, $2); + $$->subobjs = $5; + dbgprintf("processing template() WITH {}\n"); } +propconst: { $$ = NULL; } + | propconst property { if($1 == NULL) + $$ = objlstNew($2); + else + $1->next = objlstNew($2); } + | propconst constant { /*$2->next = $1; $$ = $2;*/ } +property: BEGIN_PROPERTY nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_PROPERTY, $2); dbgprintf("processed property()\n"); } +constant: BEGIN_CONSTANT nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_CONSTANT, $2); + dbgprintf("processed constant()\n"); } cfsysline: CFSYSLINE { $$ = $1; } nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 3bfb2e07..1ccac575 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -98,6 +98,44 @@ readConfFile(FILE *fp, es_str_t **str) es_addChar(str, '\0'); } +struct objlst* +objlstNew(struct cnfobj *o) +{ + struct objlst *lst; + + if((lst = malloc(sizeof(struct objlst))) != NULL) { + lst->next = NULL; + lst->obj = o; + } +dbgprintf("AAAA: creating new objlst\n"); +cnfobjPrint(o); + + return lst; +} + +void +objlstDestruct(struct objlst *lst) +{ + struct objlst *toDel; + + while(lst != NULL) { + toDel = lst; + lst = lst->next; + // TODO: delete object + free(toDel); + } +} + +void +objlstPrint(struct objlst *lst) +{ + dbgprintf("objlst %p:\n", lst); + while(lst != NULL) { + cnfobjPrint(lst->obj); + lst = lst->next; + } +} + struct nvlst* nvlstNew(es_str_t *name, es_str_t *value) { @@ -581,6 +619,7 @@ cnfobjNew(enum cnfobjType objType, struct nvlst *lst) nvlstChkDupes(lst); o->objType = objType; o->nvlst = lst; + o->subobjs = NULL; } return o; diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 83a253f7..4c625cd8 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -38,6 +38,15 @@ cnfobjType2str(enum cnfobjType ot) case CNFOBJ_MODULE: return "module"; break; + case CNFOBJ_TPL: + return "template"; + break; + case CNFOBJ_PROPERTY: + return "property"; + break; + case CNFOBJ_CONSTANT: + return "constant"; + break; default:return "error: invalid cnfobjType"; } } @@ -63,6 +72,12 @@ struct var { struct cnfobj { enum cnfobjType objType; struct nvlst *nvlst; + struct objlst *subobjs; +}; + +struct objlst { + struct objlst *next; + struct cnfobj *obj; }; struct nvlst { @@ -221,6 +236,9 @@ struct cnfparamvals { /* the values we obtained for param descr. */ int cnfParseBuffer(char *buf, unsigned lenBuf); void readConfFile(FILE *fp, es_str_t **str); +struct objlst* objlstNew(struct cnfobj *obj); +void objlstDestruct(struct objlst *lst); +void objlstPrint(struct objlst *lst); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); void nvlstDestruct(struct nvlst *lst); void nvlstPrint(struct nvlst *lst); diff --git a/runtime/rsconf.c b/runtime/rsconf.c index cbc09c11..9c6bf00e 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -404,6 +404,7 @@ int bChkUnuse = 1; // TODO: Delete tplProcessCnf(o); break; case CNFOBJ_PROPERTY: + case CNFOBJ_CONSTANT: //processTemplate(o); bChkUnuse = 0; break; diff --git a/template.c b/template.c index 50db86a3..39f95967 100644 --- a/template.c +++ b/template.c @@ -1146,11 +1146,23 @@ struct template *tplAddLine(rsconf_t *conf, char* pName, uchar** ppRestOfConfLin return(pTpl); } +/* create a template in list mode, is build from sub-objects */ +static rsRetVal +createListTpl(struct template *pTpl, struct cnfobj *o) +{ + struct objlst *lst; + DEFiRet; + dbgprintf("AAAA: create template from subobjs\n"); + objlstPrint(o->subobjs); -// v6 - ASL 2.0! -/* Add a new template via the v6 config system. - */ + for(lst = o->subobjs ; lst != NULL ; lst = lst->next) { + dbgprintf("AAAA: subjobject entry %p\n", lst); + } + RETiRet; +} + +/* Add a new template via the v6 config system. */ rsRetVal tplProcessCnf(struct cnfobj *o) { @@ -1159,8 +1171,8 @@ tplProcessCnf(struct cnfobj *o) int lenName; char *name = NULL; uchar *tplStr = NULL; + uchar *plugin = NULL; uchar *p; - uchar *plugin; enum { T_STRING, T_PLUGIN, T_LIST } tplType; int i; int o_sql=0, o_stdsql=0, o_json=0; /* options */ @@ -1170,7 +1182,6 @@ tplProcessCnf(struct cnfobj *o) pvals = nvlstGetParams(o->nvlst, &pblk, NULL); cnfparamsPrint(&pblk, pvals); - for(i = 0 ; i < pblk.nParams ; ++i) { if(!pvals[i].bUsed) @@ -1185,9 +1196,6 @@ tplProcessCnf(struct cnfobj *o) tplType = T_PLUGIN; } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"list", sizeof("list")-1)) { tplType = T_LIST; - errmsg.LogError(0, RS_RET_ERR, "template type 'list' is not " - "supported in this rsyslog version"); - ABORT_FINALIZE(RS_RET_ERR); } else { uchar *typeStr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); errmsg.LogError(0, RS_RET_ERR, "invalid template type '%s'", @@ -1228,7 +1236,7 @@ tplProcessCnf(struct cnfobj *o) if(plugin == NULL) { if(tplType == T_PLUGIN) { errmsg.LogError(0, RS_RET_ERR, "template '%s' of type plugin needs " - "plugin parameter - ignored", name); + "plugin parameter", name); ABORT_FINALIZE(RS_RET_ERR); } } else { @@ -1238,6 +1246,19 @@ tplProcessCnf(struct cnfobj *o) } } + if(o->subobjs == NULL) { + if(tplType == T_LIST) { + errmsg.LogError(0, RS_RET_ERR, "template '%s' of type list has " + "has no parameters specified", name); + ABORT_FINALIZE(RS_RET_ERR); + } + } else { + if(tplType != T_LIST) { + errmsg.LogError(0, RS_RET_ERR, "template '%s' is not a list " + "template but has parameters specified - ignored", name); + } + } + numopts = 0; if(o_sql) ++numopts; if(o_stdsql) ++numopts; @@ -1279,6 +1300,9 @@ tplProcessCnf(struct cnfobj *o) pTpl->pszName, localRet); ABORT_FINALIZE(localRet); } + break; + case T_LIST: createListTpl(pTpl, o); + break; } pTpl->optFormatEscape = NO_ESCAPE; @@ -1304,8 +1328,6 @@ finalize_it: RETiRet; } -// END v6 - /* Find a template object based on name. Search * currently is case-senstive (should we change?). -- cgit v1.2.3 From 76e9968c0890cb4db068c953db6e6574b6c28da0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 25 Aug 2012 17:17:27 +0200 Subject: milestone: LIST-type templates work, but no all options yet present --- grammar/grammar.y | 9 +- grammar/rainerscript.c | 18 ++++ runtime/rsconf.c | 11 +- template.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 291 insertions(+), 13 deletions(-) diff --git a/grammar/grammar.y b/grammar/grammar.y index d91eb3bb..27d0e1d5 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -137,13 +137,10 @@ obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } | BEGIN_TPL nvlst ENDOBJ '{' propconst '}' { $$ = cnfobjNew(CNFOBJ_TPL, $2); $$->subobjs = $5; - dbgprintf("processing template() WITH {}\n"); } + dbgprintf("processing template() WITH {}, subobj=%p\n", $5); } propconst: { $$ = NULL; } - | propconst property { if($1 == NULL) - $$ = objlstNew($2); - else - $1->next = objlstNew($2); } - | propconst constant { /*$2->next = $1; $$ = $2;*/ } + | propconst property { $$ = objlstAdd($1, $2); } + | propconst constant { $$ = objlstAdd($1, $2); } property: BEGIN_PROPERTY nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_PROPERTY, $2); dbgprintf("processed property()\n"); } constant: BEGIN_CONSTANT nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_CONSTANT, $2); diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 1ccac575..33630a76 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -113,6 +113,24 @@ cnfobjPrint(o); return lst; } +/* add object to end of object list, always returns pointer to root object */ +struct objlst* +objlstAdd(struct objlst *root, struct cnfobj *o) +{ + struct objlst *l; + struct objlst *newl; + + newl = objlstNew(o); + if(root == 0) { + root = newl; + } else { /* find last, linear search ok, as only during config phase */ + for(l = root ; l->next != NULL ; l = l->next) + ; + l->next = newl; + } + return root; +} + void objlstDestruct(struct objlst *lst) { diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 9c6bf00e..5d2407ec 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -387,7 +387,8 @@ yyerror(char *s) } void cnfDoObj(struct cnfobj *o) { -int bChkUnuse = 1; // TODO: Delete + int bChkUnuse = 1; + dbgprintf("cnf:global:obj: "); cnfobjPrint(o); switch(o->objType) { @@ -405,12 +406,12 @@ int bChkUnuse = 1; // TODO: Delete break; case CNFOBJ_PROPERTY: case CNFOBJ_CONSTANT: - //processTemplate(o); -bChkUnuse = 0; + /* these types are processed at a later stage */ + bChkUnuse = 0; break; } -if(bChkUnuse) - nvlstChkUnused(o->nvlst); + if(bChkUnuse) + nvlstChkUnused(o->nvlst); cnfobjDestruct(o); } diff --git a/template.c b/template.c index 39f95967..cdcec305 100644 --- a/template.c +++ b/template.c @@ -66,6 +66,35 @@ static struct cnfparamblk pblk = cnfparamdescr }; +static struct cnfparamdescr cnfparamdescrProperty[] = { + { "name", eCmdHdlrString, 1 }, + { "outname", eCmdHdlrString, 0 }, + { "dateformat", eCmdHdlrString, 0 }, + { "caseconversion", eCmdHdlrString, 0 }, + { "controlcharacters", eCmdHdlrString, 0 }, + { "securepath", eCmdHdlrString, 0 }, + { "format", eCmdHdlrString, 0 }, + { "droplastlf", eCmdHdlrBinary, 0 }, + { "spifno1stsp", eCmdHdlrBinary, 0 } +}; +static struct cnfparamblk pblkProperty = + { CNFPARAMBLK_VERSION, + sizeof(cnfparamdescrProperty)/sizeof(struct cnfparamdescr), + cnfparamdescrProperty + }; + +static struct cnfparamdescr cnfparamdescrConstant[] = { + { "value", eCmdHdlrString, 1 }, + { "outname", eCmdHdlrString, 0 }, + { "format", eCmdHdlrString, 0 } +}; +static struct cnfparamblk pblkConstant = + { CNFPARAMBLK_VERSION, + sizeof(cnfparamdescrConstant)/sizeof(struct cnfparamdescr), + cnfparamdescrConstant + }; + + #ifdef FEATURE_REGEXP DEFobjCurrIf(regexp) static int bFirstRegexpErrmsg = 1; /**< did we already do a "can't load regexp" error message? */ @@ -1146,6 +1175,227 @@ struct template *tplAddLine(rsconf_t *conf, char* pName, uchar** ppRestOfConfLin return(pTpl); } +static rsRetVal +createConstantTpe(struct template *pTpl, struct cnfobj *o) +{ + struct templateEntry *pTpe; + es_str_t *value; + int i; + struct cnfparamvals *pvals; + DEFiRet; + + /* pull params */ + pvals = nvlstGetParams(o->nvlst, &pblkConstant, NULL); + cnfparamsPrint(&pblkConstant, pvals); + + for(i = 0 ; i < pblkConstant.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(pblkConstant.descr[i].name, "value")) { + value = pvals[i].val.d.estr; + } else if(!strcmp(pblkConstant.descr[i].name, "format")) { + errmsg.LogError(0, RS_RET_ERR, "paramter 'format' is currently not " + "supported for 'constant' template parts - ignored"); + } else if(!strcmp(pblkConstant.descr[i].name, "outname")) { + errmsg.LogError(0, RS_RET_ERR, "paramter 'outname' is currently not " + "supported for 'constant' template parts - ignored"); + } else { + dbgprintf("template:constantTpe: program error, non-handled " + "param '%s'\n", pblkConstant.descr[i].name); + } + } + + /* sanity check */ + + /* apply */ + CHKmalloc(pTpe = tpeConstruct(pTpl)); + es_unescapeStr(value); + pTpe->eEntryType = CONSTANT; + pTpe->data.constant.iLenConstant = es_strlen(value); + pTpe->data.constant.pConstant = (uchar*)es_str2cstr(value, NULL); + +finalize_it: + RETiRet; +} + +static rsRetVal +createPropertyTpe(struct template *pTpl, struct cnfobj *o) +{ + struct templateEntry *pTpe; + cstr_t *name; + es_str_t *estrname; + es_str_t *outname = NULL; + int i; + int droplastlf = 0; + int spifno1stsp = 0; + struct cnfparamvals *pvals; + enum {F_NONE, F_CSV, F_JSON, F_JSONF} formatType = F_NONE; + enum {CC_NONE, CC_ESCAPE, CC_SPACE, CC_DROP} controlchr = CC_NONE; + enum {SP_NONE, SP_DROP, SP_REPLACE} secpath = SP_NONE; + enum tplFormatCaseConvTypes caseconv = tplCaseConvNo; + enum tplFormatTypes datefmt = tplFmtDefault; + DEFiRet; + + /* pull params */ + pvals = nvlstGetParams(o->nvlst, &pblkProperty, NULL); + cnfparamsPrint(&pblkProperty, pvals); + + for(i = 0 ; i < pblkProperty.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(pblkProperty.descr[i].name, "name")) { + estrname = es_strdup(pvals[i].val.d.estr); + /* TODO: unify strings!!! */ + rsCStrConstructFromszStr(&name, + (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL)); + } else if(!strcmp(pblkProperty.descr[i].name, "droplastlf")) { + droplastlf = pvals[i].val.d.n; + } else if(!strcmp(pblkProperty.descr[i].name, "spifno1stsp")) { + spifno1stsp = pvals[i].val.d.n; + } else if(!strcmp(pblkProperty.descr[i].name, "outname")) { + outname = es_strdup(pvals[i].val.d.estr); + } else if(!strcmp(pblkProperty.descr[i].name, "format")) { + if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"csv", sizeof("csv")-1)) { + formatType = F_CSV; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"json", sizeof("json")-1)) { + formatType = F_JSON; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"jsonf", sizeof("jsonf")-1)) { + formatType = F_JSONF; + } else { + uchar *typeStr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_ERR, "invalid format type '%s' for property", + typeStr); + free(typeStr); + ABORT_FINALIZE(RS_RET_ERR); + } + } else if(!strcmp(pblkProperty.descr[i].name, "controlcharacters")) { + if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"escape", sizeof("escape")-1)) { + controlchr = CC_ESCAPE; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"space", sizeof("space")-1)) { + controlchr = CC_SPACE; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"drop", sizeof("drop")-1)) { + controlchr = CC_DROP; + } else { + uchar *typeStr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_ERR, "invalid controlcharacter mode '%s' for property", + typeStr); + free(typeStr); + ABORT_FINALIZE(RS_RET_ERR); + } + } else if(!strcmp(pblkProperty.descr[i].name, "securepath")) { + if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"drop", sizeof("drop")-1)) { + secpath = SP_DROP; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"replace", sizeof("replace")-1)) { + secpath = SP_REPLACE; + } else { + uchar *typeStr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_ERR, "invalid securepath mode '%s' for property", + typeStr); + free(typeStr); + ABORT_FINALIZE(RS_RET_ERR); + } + } else if(!strcmp(pblkProperty.descr[i].name, "caseconversion")) { + if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"lower", sizeof("lower")-1)) { + caseconv = tplCaseConvLower; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"upper", sizeof("upper")-1)) { + caseconv = tplCaseConvUpper; + } else { + uchar *typeStr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_ERR, "invalid caseconversion type '%s' for property", + typeStr); + free(typeStr); + ABORT_FINALIZE(RS_RET_ERR); + } + } else if(!strcmp(pblkProperty.descr[i].name, "dateformat")) { + if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"mysql", sizeof("mysql")-1)) { + datefmt = tplFmtMySQLDate; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"pgsql", sizeof("pgsql")-1)) { + datefmt = tplFmtPgSQLDate; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"rfc3164", sizeof("rfc3164")-1)) { + datefmt = tplFmtRFC3164Date; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"rfc3164-buggyday", sizeof("rfc3164-buggyday")-1)) { + datefmt = tplFmtRFC3164BuggyDate; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"rfc3339", sizeof("rfc3339")-1)) { + datefmt = tplFmtRFC3339Date; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"unixtimestamp", sizeof("unixtimestamp")-1)) { + datefmt = tplFmtUnixDate; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"subseconds", sizeof("subseconds")-1)) { + datefmt = tplFmtSecFrac; + } else { + uchar *typeStr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_ERR, "invalid date format '%s' for property", + typeStr); + free(typeStr); + ABORT_FINALIZE(RS_RET_ERR); + } + } else { + dbgprintf("template:propertyTpe: program error, non-handled " + "param '%s'\n", pblkProperty.descr[i].name); + } + } + if(outname == NULL) + outname = es_strdup(estrname); + + /* sanity check */ + + /* apply */ + CHKmalloc(pTpe = tpeConstruct(pTpl)); + pTpe->eEntryType = FIELD; + CHKiRet(propNameToID(name, &pTpe->data.field.propid)); + if(pTpe->data.field.propid == PROP_CEE) { + /* in CEE case, we need to preserve the actual property name */ + pTpe->data.field.propName = estrname; + } else { + es_deleteStr(estrname); + } + pTpe->data.field.options.bDropLastLF = droplastlf; + pTpe->data.field.options.bSPIffNo1stSP = spifno1stsp; + pTpe->data.field.eCaseConv = caseconv; + switch(formatType) { + case F_NONE: + /* all set ;) */ + break; + case F_CSV: + pTpe->data.field.options.bCSV = 1; + break; + case F_JSON: + pTpe->data.field.options.bJSON = 1; + break; + case F_JSONF: + pTpe->data.field.options.bJSONf = 1; + break; + } + switch(controlchr) { + case CC_NONE: + /* all set ;) */ + break; + case CC_ESCAPE: + pTpe->data.field.options.bEscapeCC = 1; + break; + case CC_SPACE: + pTpe->data.field.options.bSpaceCC = 1; + break; + case CC_DROP: + pTpe->data.field.options.bDropCC = 1; + break; + } + switch(secpath) { + case SP_NONE: + /* all set ;) */ + break; + case SP_DROP: + pTpe->data.field.options.bSecPathDrop = 1; + break; + case SP_REPLACE: + pTpe->data.field.options.bSecPathReplace = 1; + break; + } + pTpe->data.field.fieldName = outname; + pTpe->data.field.eDateFormat = datefmt; +finalize_it: + RETiRet; +} + /* create a template in list mode, is build from sub-objects */ static rsRetVal createListTpl(struct template *pTpl, struct cnfobj *o) @@ -1153,12 +1403,24 @@ createListTpl(struct template *pTpl, struct cnfobj *o) struct objlst *lst; DEFiRet; - dbgprintf("AAAA: create template from subobjs\n"); + dbgprintf("create template from subobjs\n"); objlstPrint(o->subobjs); for(lst = o->subobjs ; lst != NULL ; lst = lst->next) { - dbgprintf("AAAA: subjobject entry %p\n", lst); + switch(lst->obj->objType) { + case CNFOBJ_PROPERTY: + CHKiRet(createPropertyTpe(pTpl, lst->obj)); + break; + case CNFOBJ_CONSTANT: + CHKiRet(createConstantTpe(pTpl, lst->obj)); + break; + default:dbgprintf("program error: invalid object type %d " + "in createLstTpl\n", lst->obj->objType); + break; + } + nvlstChkUnused(lst->obj->nvlst); } +finalize_it: RETiRet; } -- cgit v1.2.3 From a36b7131ab79204f43c400de7b5663613af62cc6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 25 Aug 2012 17:48:16 +0200 Subject: milestone: LIST-type template now only missing regex support --- template.c | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/template.c b/template.c index cdcec305..7a4c398f 100644 --- a/template.c +++ b/template.c @@ -74,6 +74,17 @@ static struct cnfparamdescr cnfparamdescrProperty[] = { { "controlcharacters", eCmdHdlrString, 0 }, { "securepath", eCmdHdlrString, 0 }, { "format", eCmdHdlrString, 0 }, +// From here + { "position.from", eCmdHdlrInt, 0 }, + { "position.to", eCmdHdlrInt, 0 }, + { "field.number", eCmdHdlrInt, 0 }, + { "field.delimiter", eCmdHdlrInt, 0 }, + { "regex.expression", eCmdHdlrString, 0 }, + { "regex.type", eCmdHdlrString, 0 }, + { "regex.nomatchmode", eCmdHdlrString, 0 }, + { "regex.match", eCmdHdlrInt, 0 }, + { "regex.submatch", eCmdHdlrInt, 0 }, +//-- to here { "droplastlf", eCmdHdlrBinary, 0 }, { "spifno1stsp", eCmdHdlrBinary, 0 } }; @@ -1228,6 +1239,10 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) int i; int droplastlf = 0; int spifno1stsp = 0; + int frompos = -1; + int topos = -1; + int fieldnum = -1; + int fielddelim = 9; /* default is HT (USACSII 9) */ struct cnfparamvals *pvals; enum {F_NONE, F_CSV, F_JSON, F_JSONF} formatType = F_NONE; enum {CC_NONE, CC_ESCAPE, CC_SPACE, CC_DROP} controlchr = CC_NONE; @@ -1254,6 +1269,14 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) spifno1stsp = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "outname")) { outname = es_strdup(pvals[i].val.d.estr); + } else if(!strcmp(pblkProperty.descr[i].name, "position.from")) { + frompos = pvals[i].val.d.n; + } else if(!strcmp(pblkProperty.descr[i].name, "position.to")) { + topos = pvals[i].val.d.n; + } else if(!strcmp(pblkProperty.descr[i].name, "field.number")) { + fieldnum = pvals[i].val.d.n; + } else if(!strcmp(pblkProperty.descr[i].name, "field.delimiter")) { + fielddelim = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "format")) { if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"csv", sizeof("csv")-1)) { formatType = F_CSV; @@ -1337,6 +1360,15 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) outname = es_strdup(estrname); /* sanity check */ + if(topos == -1 && frompos != -1) + topos = 2000000000; /* large enough ;) */ + if(frompos == -1 && topos != -1) + frompos = 0; + if(topos < frompos) { + errmsg.LogError(0, RS_RET_ERR, "position.to=%d is lower than postion.from=%d\n", + topos, frompos); + ABORT_FINALIZE(RS_RET_ERR); + } /* apply */ CHKmalloc(pTpe = tpeConstruct(pTpl)); @@ -1392,6 +1424,15 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) } pTpe->data.field.fieldName = outname; pTpe->data.field.eDateFormat = datefmt; + if(fieldnum != -1) { + pTpe->data.field.has_fields = 1; + pTpe->data.field.iFieldNr = fieldnum; + pTpe->data.field.field_delim = fielddelim; + } + if(frompos != -1) { + pTpe->data.field.iFromPos = frompos; + pTpe->data.field.iToPos = topos; + } finalize_it: RETiRet; } -- cgit v1.2.3 From 00c4f69c559e5ba036e20a095843a1ca6eba57c8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 25 Aug 2012 19:08:07 +0200 Subject: milestone: LIST-type templates support full option set --- template.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ template.h | 10 ++++----- 2 files changed, 77 insertions(+), 5 deletions(-) diff --git a/template.c b/template.c index 7a4c398f..4cad7cb7 100644 --- a/template.c +++ b/template.c @@ -1243,12 +1243,17 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) int topos = -1; int fieldnum = -1; int fielddelim = 9; /* default is HT (USACSII 9) */ + int re_matchToUse = 0; + int re_submatchToUse = 0; + char *re_expr = NULL; struct cnfparamvals *pvals; enum {F_NONE, F_CSV, F_JSON, F_JSONF} formatType = F_NONE; enum {CC_NONE, CC_ESCAPE, CC_SPACE, CC_DROP} controlchr = CC_NONE; enum {SP_NONE, SP_DROP, SP_REPLACE} secpath = SP_NONE; enum tplFormatCaseConvTypes caseconv = tplCaseConvNo; enum tplFormatTypes datefmt = tplFmtDefault; + enum tplRegexType re_type = TPL_REGEX_BRE; + enum tlpRegexNoMatchType re_nomatchType = TPL_REGEX_NOMATCH_USE_DFLTSTR; DEFiRet; /* pull params */ @@ -1277,6 +1282,40 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) fieldnum = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "field.delimiter")) { fielddelim = pvals[i].val.d.n; + } else if(!strcmp(pblkProperty.descr[i].name, "regex.expression")) { + re_expr = es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(pblkProperty.descr[i].name, "regex.type")) { + if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"BRE", sizeof("BRE")-1)) { + re_type = TPL_REGEX_BRE; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"ERE", sizeof("ERE")-1)) { + re_type = TPL_REGEX_ERE; + } else { + uchar *typeStr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_ERR, "invalid regex.type '%s' for property", + typeStr); + free(typeStr); + ABORT_FINALIZE(RS_RET_ERR); + } + } else if(!strcmp(pblkProperty.descr[i].name, "regex.nomatchmode")) { + if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"DFLT", sizeof("DFLT")-1)) { + re_nomatchType = TPL_REGEX_NOMATCH_USE_DFLTSTR; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"BLANK", sizeof("BLANK")-1)) { + re_nomatchType = TPL_REGEX_NOMATCH_USE_BLANK; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"FIELD", sizeof("FIELD")-1)) { + re_nomatchType = TPL_REGEX_NOMATCH_USE_WHOLE_FIELD; + } else if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"ZERO", sizeof("ZERO")-1)) { + re_nomatchType = TPL_REGEX_NOMATCH_USE_ZERO; + } else { + uchar *typeStr = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_ERR, "invalid format type '%s' for property", + typeStr); + free(typeStr); + ABORT_FINALIZE(RS_RET_ERR); + } + } else if(!strcmp(pblkProperty.descr[i].name, "regex.match")) { + re_matchToUse = pvals[i].val.d.n; + } else if(!strcmp(pblkProperty.descr[i].name, "regex.submatch")) { + re_submatchToUse = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "format")) { if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"csv", sizeof("csv")-1)) { formatType = F_CSV; @@ -1369,6 +1408,11 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) topos, frompos); ABORT_FINALIZE(RS_RET_ERR); } + if(fieldnum != -1 && re_expr != NULL) { + errmsg.LogError(0, RS_RET_ERR, "both field extraction and regex extraction " + "specified - this is not possible, remove one"); + ABORT_FINALIZE(RS_RET_ERR); + } /* apply */ CHKmalloc(pTpe = tpeConstruct(pTpl)); @@ -1433,6 +1477,34 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) pTpe->data.field.iFromPos = frompos; pTpe->data.field.iToPos = topos; } + if(re_expr != NULL) { + rsRetVal iRetLocal; + pTpe->data.field.typeRegex = re_type; + pTpe->data.field.nomatchAction = re_nomatchType; + pTpe->data.field.iMatchToUse = re_matchToUse; + pTpe->data.field.iSubMatchToUse = re_submatchToUse; + pTpe->data.field.has_regex = 1; + if((iRetLocal = objUse(regexp, LM_REGEXP_FILENAME)) == RS_RET_OK) { + int iOptions; + iOptions = (pTpe->data.field.typeRegex == TPL_REGEX_ERE) ? REG_EXTENDED : 0; + if(regexp.regcomp(&(pTpe->data.field.re), (char*) re_expr, iOptions) != 0) { + dbgprintf("error: can not compile regex: '%s'\n", re_expr); + errmsg.LogError(0, NO_ERRCODE, "error compiling regex '%s'", re_expr); + pTpe->data.field.has_regex = 2; + ABORT_FINALIZE(RS_RET_ERR); + } + } else { + /* regexp object could not be loaded */ + if(bFirstRegexpErrmsg) { /* prevent flood of messages, maybe even an endless loop! */ + bFirstRegexpErrmsg = 0; + errmsg.LogError(0, NO_ERRCODE, "regexp library could not be loaded (error %d), " + "regexp ignored", iRetLocal); + } + pTpe->data.field.has_regex = 2; + ABORT_FINALIZE(RS_RET_ERR); + } + } + finalize_it: RETiRet; } diff --git a/template.h b/template.h index c58d452c..65435cd8 100644 --- a/template.h +++ b/template.h @@ -58,6 +58,9 @@ enum tplFormatTypes { tplFmtDefault = 0, tplFmtMySQLDate = 1, tplFmtRFC3164Date = 2, tplFmtRFC3339Date = 3, tplFmtPgSQLDate = 4, tplFmtSecFrac = 5, tplFmtRFC3164BuggyDate = 6, tplFmtUnixDate}; enum tplFormatCaseConvTypes { tplCaseConvNo = 0, tplCaseConvUpper = 1, tplCaseConvLower = 2 }; +enum tplRegexType { TPL_REGEX_BRE = 0, /* posix BRE */ + TPL_REGEX_ERE = 1 /* posix ERE */ + }; #include "msg.h" @@ -80,11 +83,8 @@ struct templateEntry { short has_regex; short iMatchToUse;/* which match should be obtained (10 max) */ short iSubMatchToUse;/* which submatch should be obtained (10 max) */ - enum { - TPL_REGEX_BRE = 0, /* posix BRE */ - TPL_REGEX_ERE = 1 /* posix ERE */ - } typeRegex; - enum { + enum tplRegexType typeRegex; + enum tlpRegexNoMatchType { TPL_REGEX_NOMATCH_USE_DFLTSTR = 0, /* use the (old style) default "**NO MATCH**" string */ TPL_REGEX_NOMATCH_USE_BLANK = 1, /* use a blank string */ TPL_REGEX_NOMATCH_USE_WHOLE_FIELD = 2, /* use the full field contents that we were searching in*/ -- cgit v1.2.3 From 3d56820f130e6c1b674560125e677be3b6a2d8f4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 25 Aug 2012 19:21:12 +0200 Subject: add capability to configure outname for constant (inside template) also some cleanup --- grammar/grammar.y | 10 ++++------ runtime/msg.c | 4 ++-- template.c | 21 ++++++++------------- template.h | 2 +- 4 files changed, 15 insertions(+), 22 deletions(-) diff --git a/grammar/grammar.y b/grammar/grammar.y index 27d0e1d5..8371f854 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -133,18 +133,16 @@ conf: /* empty (to end recursion) */ | conf BSD_HOST_SELECTOR { cnfDoBSDHost($2); } obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } - | BEGIN_TPL nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_TPL, $2); dbgprintf("processing template() without {}\n"); } + | BEGIN_TPL nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_TPL, $2); } | BEGIN_TPL nvlst ENDOBJ '{' propconst '}' { $$ = cnfobjNew(CNFOBJ_TPL, $2); $$->subobjs = $5; - dbgprintf("processing template() WITH {}, subobj=%p\n", $5); } + } propconst: { $$ = NULL; } | propconst property { $$ = objlstAdd($1, $2); } | propconst constant { $$ = objlstAdd($1, $2); } -property: BEGIN_PROPERTY nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_PROPERTY, $2); - dbgprintf("processed property()\n"); } -constant: BEGIN_CONSTANT nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_CONSTANT, $2); - dbgprintf("processed constant()\n"); } +property: BEGIN_PROPERTY nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_PROPERTY, $2); } +constant: BEGIN_CONSTANT nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_CONSTANT, $2); } cfsysline: CFSYSLINE { $$ = $1; } nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } diff --git a/runtime/msg.c b/runtime/msg.c index da751dba..891907ec 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -2515,9 +2515,9 @@ jsonField(struct templateEntry *pTpe, uchar **ppRes, unsigned short *pbMustBeFre pSrc = *ppRes; buflen = (*pBufLen == -1) ? ustrlen(pSrc) : *pBufLen; /* we hope we have only few escapes... */ - dst = es_newStr(buflen+es_strlen(pTpe->data.field.fieldName)+15); + dst = es_newStr(buflen+es_strlen(pTpe->fieldName)+15); es_addChar(&dst, '"'); - es_addStr(&dst, pTpe->data.field.fieldName); + es_addStr(&dst, pTpe->fieldName); es_addBufConstcstr(&dst, "\"=\""); CHKiRet(jsonAddVal(pSrc, buflen, &dst)); es_addChar(&dst, '"'); diff --git a/template.c b/template.c index 4cad7cb7..768608f1 100644 --- a/template.c +++ b/template.c @@ -74,7 +74,6 @@ static struct cnfparamdescr cnfparamdescrProperty[] = { { "controlcharacters", eCmdHdlrString, 0 }, { "securepath", eCmdHdlrString, 0 }, { "format", eCmdHdlrString, 0 }, -// From here { "position.from", eCmdHdlrInt, 0 }, { "position.to", eCmdHdlrInt, 0 }, { "field.number", eCmdHdlrInt, 0 }, @@ -84,7 +83,6 @@ static struct cnfparamdescr cnfparamdescrProperty[] = { { "regex.nomatchmode", eCmdHdlrString, 0 }, { "regex.match", eCmdHdlrInt, 0 }, { "regex.submatch", eCmdHdlrInt, 0 }, -//-- to here { "droplastlf", eCmdHdlrBinary, 0 }, { "spifno1stsp", eCmdHdlrBinary, 0 } }; @@ -97,7 +95,6 @@ static struct cnfparamblk pblkProperty = static struct cnfparamdescr cnfparamdescrConstant[] = { { "value", eCmdHdlrString, 1 }, { "outname", eCmdHdlrString, 0 }, - { "format", eCmdHdlrString, 0 } }; static struct cnfparamblk pblkConstant = { CNFPARAMBLK_VERSION, @@ -980,12 +977,12 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) /* save field name - if none was given, use the property name instead */ if(pStrField == NULL) { - if((pTpe->data.field.fieldName = + if((pTpe->fieldName = es_newStrFromCStr((char*)cstrGetSzStrNoNULL(pStrProp), cstrLen(pStrProp))) == NULL) { return 1; } } else { - if((pTpe->data.field.fieldName = + if((pTpe->fieldName = es_newStrFromCStr((char*)cstrGetSzStrNoNULL(pStrField), cstrLen(pStrField))) == NULL) { return 1; } @@ -1193,6 +1190,7 @@ createConstantTpe(struct template *pTpl, struct cnfobj *o) es_str_t *value; int i; struct cnfparamvals *pvals; + es_str_t *outname = NULL; DEFiRet; /* pull params */ @@ -1204,12 +1202,8 @@ createConstantTpe(struct template *pTpl, struct cnfobj *o) continue; if(!strcmp(pblkConstant.descr[i].name, "value")) { value = pvals[i].val.d.estr; - } else if(!strcmp(pblkConstant.descr[i].name, "format")) { - errmsg.LogError(0, RS_RET_ERR, "paramter 'format' is currently not " - "supported for 'constant' template parts - ignored"); } else if(!strcmp(pblkConstant.descr[i].name, "outname")) { - errmsg.LogError(0, RS_RET_ERR, "paramter 'outname' is currently not " - "supported for 'constant' template parts - ignored"); + outname = es_strdup(pvals[i].val.d.estr); } else { dbgprintf("template:constantTpe: program error, non-handled " "param '%s'\n", pblkConstant.descr[i].name); @@ -1222,6 +1216,7 @@ createConstantTpe(struct template *pTpl, struct cnfobj *o) CHKmalloc(pTpe = tpeConstruct(pTpl)); es_unescapeStr(value); pTpe->eEntryType = CONSTANT; + pTpe->fieldName = outname; pTpe->data.constant.iLenConstant = es_strlen(value); pTpe->data.constant.pConstant = (uchar*)es_str2cstr(value, NULL); @@ -1466,7 +1461,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) pTpe->data.field.options.bSecPathReplace = 1; break; } - pTpe->data.field.fieldName = outname; + pTpe->fieldName = outname; pTpe->data.field.eDateFormat = datefmt; if(fieldnum != -1) { pTpe->data.field.has_fields = 1; @@ -1767,8 +1762,8 @@ void tplDeleteAll(rsconf_t *conf) } if(pTpeDel->data.field.propName != NULL) es_deleteStr(pTpeDel->data.field.propName); - if(pTpeDel->data.field.fieldName != NULL) - es_deleteStr(pTpeDel->data.field.fieldName); + if(pTpeDel->fieldName != NULL) + es_deleteStr(pTpeDel->fieldName); #endif break; } diff --git a/template.h b/template.h index 65435cd8..9f6a4c33 100644 --- a/template.h +++ b/template.h @@ -68,6 +68,7 @@ enum tplRegexType { TPL_REGEX_BRE = 0, /* posix BRE */ struct templateEntry { struct templateEntry *pNext; enum EntryTypes eEntryType; + es_str_t *fieldName; /**< field name to be used for structured output */ union { struct { uchar *pConstant; /* pointer to constant value */ @@ -99,7 +100,6 @@ struct templateEntry { #endif es_str_t *propName; /**< property name (currently being used for CEE only) */ - es_str_t *fieldName; /**< field name to be used for structured output */ enum tplFormatTypes eDateFormat; enum tplFormatCaseConvTypes eCaseConv; -- cgit v1.2.3 From 7d58175dbe89502352a044c0d131aa4c5e2b3f37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Fri, 24 Aug 2012 17:50:21 +0200 Subject: Silence compiler warnings about unused parameters. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- plugins/ommongodb/ommongodb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/plugins/ommongodb/ommongodb.c b/plugins/ommongodb/ommongodb.c index 39e2e4f9..d122b6f1 100644 --- a/plugins/ommongodb/ommongodb.c +++ b/plugins/ommongodb/ommongodb.c @@ -120,6 +120,7 @@ ENDfreeInstance BEGINdbgPrintInstInfo CODESTARTdbgPrintInstInfo /* nothing special here */ + (void)pData; ENDdbgPrintInstInfo @@ -139,6 +140,8 @@ reportMongoError(instanceData *pData) errmsg.LogError(0, RS_RET_ERR, "ommongodb: we had an error, but can " "not obtain specifics"); } +#else + (void)pData; #endif } -- cgit v1.2.3 From 14875be702b0c90c098888cba689190cec031646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Thu, 9 Aug 2012 17:07:17 +0200 Subject: Remove a no-effect ", NULL"; MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It does nothing, at is just confusing. Signed-off-by: Miloslav Trmač --- plugins/ommongodb/ommongodb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/ommongodb/ommongodb.c b/plugins/ommongodb/ommongodb.c index d122b6f1..00afcf68 100644 --- a/plugins/ommongodb/ommongodb.c +++ b/plugins/ommongodb/ommongodb.c @@ -343,7 +343,7 @@ CODESTARTnewActInst if(!strcmp(actpblk.descr[i].name, "server")) { pData->server = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); } else if(!strcmp(actpblk.descr[i].name, "serverport")) { - pData->port = (int) pvals[i].val.d.n, NULL; + pData->port = (int) pvals[i].val.d.n; } else if(!strcmp(actpblk.descr[i].name, "db")) { pData->db = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); } else if(!strcmp(actpblk.descr[i].name, "collection")) { -- cgit v1.2.3 From 4f8bbd8b56b35e12d6149b0719241d07f7410c4f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 26 Aug 2012 10:23:03 +0200 Subject: add json-c to build system --- configure.ac | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 80c086f4..499b2de7 100644 --- a/configure.ac +++ b/configure.ac @@ -34,6 +34,9 @@ PKG_PROG_PKG_CONFIG # modules we require PKG_CHECK_MODULES(LIBESTR, libestr >= 0.1.2) PKG_CHECK_MODULES(LIBEE, libee >= 0.4.0) +PKG_CHECK_MODULES([JSON_C], [json]) +AC_SUBST([JSON_CFLAGS]) +AC_SUBST([JSON_LIBS]) case "${host}" in *-*-linux*) @@ -773,8 +776,8 @@ if test "x$enable_rsyslogrt" = "xyes"; then #??CNF_LIBS="\$(top_builddir)/grammar/libgrammar.la" fi AM_CONDITIONAL(ENABLE_RSYSLOGRT, test x$enable_rsyslogrt = xyes) -RSRT_CFLAGS="\$(RSRT_CFLAGS1) \$(LIBESTR_CFLAGS)" -RSRT_LIBS="\$(RSRT_LIBS1) \$(LIBESTR_LIBS)" +RSRT_CFLAGS="\$(RSRT_CFLAGS1) \$(LIBESTR_CFLAGS) \$(JSON_C_FLAGS)" +RSRT_LIBS="\$(RSRT_LIBS1) \$(LIBESTR_LIBS) \$(JSON_C_LIBS)" AC_SUBST(RSRT_CFLAGS1) AC_SUBST(RSRT_LIBS1) AC_SUBST(RSRT_CFLAGS) -- cgit v1.2.3 From 3fd617f1acb7f1a057edb415cec1b144d210da81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Fri, 24 Aug 2012 19:28:59 +0200 Subject: INCOMPATIBLE: use :, not =, as separator for jsonf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit JSON fields are "name":value, not "name"=value. Therefore change the jsonf flag to use a colon. Signed-off-by: Miloslav Trmač --- doc/property_replacer.html | 2 +- runtime/msg.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/property_replacer.html b/doc/property_replacer.html index 4c92bf4c..86a07474 100644 --- a/doc/property_replacer.html +++ b/doc/property_replacer.html @@ -368,7 +368,7 @@ The json option cannot be used together with either jsonf or csv options. This signifies that the property should be expressed as a json field. That means not only the property is written, but rather a complete json field in the format
      -"fieldname"="value" +"fieldname":"value" where "filedname" is the assigend field name (or the property name if none was assigned) and value is the end result of property replacer operation. Note that value supports all property replacer options, like substrings, case converson and the like. diff --git a/runtime/msg.c b/runtime/msg.c index da751dba..61c2f87b 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -2518,7 +2518,7 @@ jsonField(struct templateEntry *pTpe, uchar **ppRes, unsigned short *pbMustBeFre dst = es_newStr(buflen+es_strlen(pTpe->data.field.fieldName)+15); es_addChar(&dst, '"'); es_addStr(&dst, pTpe->data.field.fieldName); - es_addBufConstcstr(&dst, "\"=\""); + es_addBufConstcstr(&dst, "\":\""); CHKiRet(jsonAddVal(pSrc, buflen, &dst)); es_addChar(&dst, '"'); -- cgit v1.2.3 From 744d7c426da4aa3229771358a5da27b79e2edf52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Renard?= Date: Sun, 26 Aug 2012 14:13:26 +0200 Subject: add uuid property to message object --- configure.ac | 15 +++++++++++++ runtime/msg.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- runtime/msg.h | 2 +- runtime/rsyslog.h | 1 + tools/Makefile.am | 2 +- 5 files changed, 79 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index 80c086f4..78315a80 100644 --- a/configure.ac +++ b/configure.ac @@ -674,6 +674,21 @@ AM_CONDITIONAL(ENABLE_OMLIBDBI, test x$enable_libdbi = xyes) AC_SUBST(LIBDBI_CFLAGS) AC_SUBST(LIBDBI_LIBS) +# libuuid support +AC_CHECK_HEADERS( + [uuid/uuid.h],, + [AC_MSG_FAILURE([libuuid is missing])] +) +AC_CHECK_LIB( + [uuid], + [uuid_generate], + [LIBUUID_CFLAGS="" + LIBUUID_LIBS="-luuid" + ], + [AC_MSG_FAILURE([libuuid library is missing])] +) +AC_SUBST(LIBUUID_CFLAGS) +AC_SUBST(LIBUUID_LIBS) # SNMP support AC_ARG_ENABLE(snmp, diff --git a/runtime/msg.c b/runtime/msg.c index 44d36fef..8d24ea66 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -43,6 +43,7 @@ #if HAVE_MALLOC_H # include #endif +#include #include "rsyslog.h" #include "srUtils.h" #include "stringbuf.h" @@ -568,6 +569,8 @@ propNameStrToID(uchar *pName, propid_t *pPropID) *pPropID = PROP_SYS_BOM; } else if(!strcmp((char*) pName, "$uptime")) { *pPropID = PROP_SYS_UPTIME; + } else if(!strcmp((char*) pName, "uuid")) { + *pPropID = PROP_UUID; } else { *pPropID = PROP_INVALID; iRet = RS_RET_VAR_NOT_FOUND; @@ -666,6 +669,8 @@ uchar *propIDToName(propid_t propID) return UCHAR_CONSTANT("$!all-json"); case PROP_SYS_BOM: return UCHAR_CONSTANT("$BOM"); + case PROP_UUID: + return UCHAR_CONSTANT("uuid"); default: return UCHAR_CONSTANT("*invalid property id*"); } @@ -745,6 +750,7 @@ static inline rsRetVal msgBaseConstruct(msg_t **ppThis) pM->pszRcvdAt_SecFrac[0] = '\0'; pM->pszTIMESTAMP_Unix[0] = '\0'; pM->pszRcvdAt_Unix[0] = '\0'; + pM->pszUUID = NULL; /* DEV debugging only! dbgprintf("msgConstruct\t0x%x, ref 1\n", (int)pM);*/ @@ -875,6 +881,8 @@ CODESTARTobjDestruct(msg) rsCStrDestruct(&pThis->pCSMSGID); if(pThis->event != NULL) ee_deleteEvent(pThis->event); + if(pThis->pszUUID != NULL) + free(pThis->pszUUID); # ifndef HAVE_ATOMIC_BUILTINS MsgUnlock(pThis); # endif @@ -1080,6 +1088,8 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm) objSerializePTR(pStrm, pCSPROCID, CSTR); objSerializePTR(pStrm, pCSMSGID, CSTR); + objSerializePTR(pStrm, pszUUID, PSZ); + if(pThis->pRuleset != NULL) { rulesetGetName(pThis->pRuleset); CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszRuleset"), PROPTYPE_PSZ, @@ -1242,6 +1252,54 @@ char *getProtocolVersionString(msg_t *pM) return(pM->iProtocolVersion ? "1" : "0"); } +void msgSetUUID(msg_t *pM) +{ + dbgprintf("[MsgSetUUID] START\n"); + assert(pM != NULL); + + dbgprintf("[MsgSetUUID] pM NOT null \n"); + + size_t lenRes = sizeof(uuid_t) * 2 + 1; + char hex_char [] = "0123456789ABCDEF"; + unsigned int byte_nbr; + uuid_t uuid; + + if((pM->pszUUID = (uchar*) MALLOC(lenRes)) == NULL) { + pM->pszUUID = (uchar *)""; + } else { + uuid_generate(uuid); + for (byte_nbr = 0; byte_nbr < sizeof (uuid_t); byte_nbr++) { + pM->pszUUID[byte_nbr * 2 + 0] = hex_char[uuid [byte_nbr] >> 4]; + pM->pszUUID[byte_nbr * 2 + 1] = hex_char[uuid [byte_nbr] & 15]; + } + + dbgprintf("[MsgSetUUID] UUID : %s LEN: %d \n", pM->pszUUID, (int)lenRes); + pM->pszUUID[lenRes] = '\0'; + } + dbgprintf("[MsgSetUUID] END\n"); +} + +void getUUID(msg_t *pM, uchar **pBuf, int *piLen) +{ + dbgprintf("[getUUID] START\n"); + if(pM == NULL) { + dbgprintf("[getUUID] pM is NULL\n"); + *pBuf= UCHAR_CONSTANT(""); + *piLen = 0; + } else { + if(pM->pszUUID == NULL) { + dbgprintf("[getUUID] pM->pszUUID is NULL\n"); + + msgSetUUID(pM); + } else { + /* UUID already there we reuse it */ + dbgprintf("[getUUID] pM->pszUUID already exists\n"); + } + *pBuf = pM->pszUUID; + *piLen = sizeof(uuid_t) * 2; + } + dbgprintf("[getUUID] END\n"); +} void getRawMsg(msg_t *pM, uchar **pBuf, int *piLen) @@ -1908,7 +1966,6 @@ static inline char *getStructuredData(msg_t *pM) return (char*) pszRet; } - /* check if we have a ProgramName, and, if not, try to aquire/emulate it. * rgerhards, 2009-06-26 */ @@ -2232,7 +2289,6 @@ finalize_it: RETiRet; } - /* set raw message in message object. Size of message is provided. * The function makes sure that the stored rawmsg is properly * terminated by '\0'. @@ -2774,6 +2830,9 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, } # endif break; + case PROP_UUID: + getUUID(pMsg, &pRes, &bufLen); + break; default: /* there is no point in continuing, we may even otherwise render the * error message unreadable. rgerhards, 2007-07-10 diff --git a/runtime/msg.h b/runtime/msg.h index ed2e9d04..f6b54a77 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -123,6 +123,7 @@ struct msg { char pszRcvdAt_SecFrac[7]; /* same as above. Both are fractional seconds for their respective timestamp */ char pszTIMESTAMP_Unix[12]; /* almost as small as a pointer! */ char pszRcvdAt_Unix[12]; + uchar *pszUUID; /* The message's UUID */ }; @@ -184,7 +185,6 @@ void getRawMsg(msg_t *pM, uchar **pBuf, int *piLen); rsRetVal msgGetCEEVar(msg_t *pThis, cstr_t *propName, var_t **ppVar); es_str_t* msgGetCEEVarNew(msg_t *pMsg, char *name); - /* TODO: remove these five (so far used in action.c) */ uchar *getMSG(msg_t *pM); char *getHOSTNAME(msg_t *pM); diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index d802536a..57e8a05c 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -142,6 +142,7 @@ typedef uintTiny propid_t; #define PROP_CEE_ALL_JSON 201 #define PROP_SYS_BOM 159 #define PROP_SYS_UPTIME 160 +#define PROP_UUID 161 /* The error codes below are orginally "borrowed" from diff --git a/tools/Makefile.am b/tools/Makefile.am index 4e457426..60a2dd61 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -40,7 +40,7 @@ rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) $(CNF_LIBS) # note: it looks like librsyslog.la must be explicitely given on LDDADD, # otherwise dependencies are not properly calculated (resulting in a # potentially incomplete build, a problem we had several times...) -rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) $(CNF_LIBS) ../grammar/libgrammar.la ../runtime/librsyslog.la +rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) $(CNF_LIBS) $(LIBUUID_LIBS) ../grammar/libgrammar.la ../runtime/librsyslog.la rsyslogd_LDFLAGS = -export-dynamic if ENABLE_DIAGTOOLS -- cgit v1.2.3 From ec48c41e27ec15618f57b54209eaafe025e29010 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 26 Aug 2012 14:28:13 +0200 Subject: made new uuid property threadsafe --- ChangeLog | 4 ++++ runtime/msg.c | 36 +++++++++++++++++++++--------------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6b96d35b..4ee5beb0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18,6 +18,10 @@ Version 6.5.0 [devel] 2012-0?-?? Thanks to Miloslav Trmač for the patch - $SystemLogParseTrusted config file option Thanks to Milan Bartos for the patch +- added new uuid message property + Thanks to Jérôme Renard for the idea and patches. + Note: patches were released under ASL 2.0, see + http://bugzilla.adiscon.com/show_bug.cgi?id=353 --------------------------------------------------------------------------- Version 6.4.1 [V6-STABLE] 2012-08-?? - bugfix: multiple main queues with same queue file name were not detected diff --git a/runtime/msg.c b/runtime/msg.c index 8d24ea66..7ba46722 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -542,6 +542,8 @@ propNameStrToID(uchar *pName, propid_t *pPropID) *pPropID = PROP_MSGID; } else if(!strcmp((char*) pName, "parsesuccess")) { *pPropID = PROP_PARSESUCCESS; + } else if(!strcmp((char*) pName, "uuid")) { + *pPropID = PROP_UUID; /* here start system properties (those, that do not relate to the message itself */ } else if(!strcmp((char*) pName, "$now")) { *pPropID = PROP_SYS_NOW; @@ -569,8 +571,6 @@ propNameStrToID(uchar *pName, propid_t *pPropID) *pPropID = PROP_SYS_BOM; } else if(!strcmp((char*) pName, "$uptime")) { *pPropID = PROP_SYS_UPTIME; - } else if(!strcmp((char*) pName, "uuid")) { - *pPropID = PROP_UUID; } else { *pPropID = PROP_INVALID; iRet = RS_RET_VAR_NOT_FOUND; @@ -1252,22 +1252,26 @@ char *getProtocolVersionString(msg_t *pM) return(pM->iProtocolVersion ? "1" : "0"); } -void msgSetUUID(msg_t *pM) +/* note: libuuid seems not to be thread-safe, so we need + * to get some safeguards in place. + */ +static void msgSetUUID(msg_t *pM) { - dbgprintf("[MsgSetUUID] START\n"); - assert(pM != NULL); - - dbgprintf("[MsgSetUUID] pM NOT null \n"); - size_t lenRes = sizeof(uuid_t) * 2 + 1; char hex_char [] = "0123456789ABCDEF"; unsigned int byte_nbr; uuid_t uuid; + static pthread_mutex_t mutUUID = PTHREAD_MUTEX_INITIALIZER; + + dbgprintf("[MsgSetUUID] START\n"); + assert(pM != NULL); if((pM->pszUUID = (uchar*) MALLOC(lenRes)) == NULL) { pM->pszUUID = (uchar *)""; } else { + pthread_mutex_lock(&mutUUID); uuid_generate(uuid); + pthread_mutex_unlock(&mutUUID); for (byte_nbr = 0; byte_nbr < sizeof (uuid_t); byte_nbr++) { pM->pszUUID[byte_nbr * 2 + 0] = hex_char[uuid [byte_nbr] >> 4]; pM->pszUUID[byte_nbr * 2 + 1] = hex_char[uuid [byte_nbr] & 15]; @@ -1289,10 +1293,12 @@ void getUUID(msg_t *pM, uchar **pBuf, int *piLen) } else { if(pM->pszUUID == NULL) { dbgprintf("[getUUID] pM->pszUUID is NULL\n"); - - msgSetUUID(pM); - } else { - /* UUID already there we reuse it */ + MsgLock(pM); + /* re-query, things may have changed in the mean time... */ + if(pM->pszUUID == NULL) + msgSetUUID(pM); + MsgUnlock(pM); + } else { /* UUID already there we reuse it */ dbgprintf("[getUUID] pM->pszUUID already exists\n"); } *pBuf = pM->pszUUID; @@ -2732,6 +2738,9 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, case PROP_MSGID: pRes = (uchar*)getMSGID(pMsg); break; + case PROP_UUID: + getUUID(pMsg, &pRes, &bufLen); + break; case PROP_PARSESUCCESS: pRes = (uchar*)getParseSuccess(pMsg); break; @@ -2830,9 +2839,6 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, } # endif break; - case PROP_UUID: - getUUID(pMsg, &pRes, &bufLen); - break; default: /* there is no point in continuing, we may even otherwise render the * error message unreadable. rgerhards, 2007-07-10 -- cgit v1.2.3 From dfd541a1224a2ed407010e9924b6eab66c4643ba Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 28 Aug 2012 09:44:35 +0200 Subject: doc: new template system, some more output modules added base doc for new config language --- doc/omfile.html | 2 +- doc/omsnmp.html | 148 ++++++++++++++++++++++++ doc/property_replacer.html | 246 ++++++++++++++++++++++++++++++++++++++-- doc/rsyslog_conf_templates.html | 59 ++++++++-- 4 files changed, 434 insertions(+), 21 deletions(-) diff --git a/doc/omfile.html b/doc/omfile.html index bdd1ebc6..23ecc034 100644 --- a/doc/omfile.html +++ b/doc/omfile.html @@ -84,7 +84,7 @@ *.* action(type="omfile" DirCreateMode="0700" FileCreateMode="0644" -File= "/var/log/messages") +File="/var/log/messages")

      diff --git a/doc/omsnmp.html b/doc/omsnmp.html index b38a594f..202bb5bb 100644 --- a/doc/omsnmp.html +++ b/doc/omsnmp.html @@ -21,6 +21,153 @@ developer (headers) package installed.

      %omsnmp% without any further parameters.

       

      Configuration Directives:

      +
        +
      • transport (This parameter is optional, the + default value is "udp")
        +
        + Defines the transport type you wish to use. Technically we can support all + transport types which are supported by NET-SNMP.
        + To name a few possible values:
        +
        + udp, tcp, udp6, tcp6, icmp, icmp6 ...
        +
        + Example: transport udp
        +
      • +
      • server
        +
        + This can be a hostname or ip address, and is our snmp target host. This + parameter is required, if the snmptarget is not defined, nothing will be + send.
        +
        + Example: server server.domain.xxx
        +
      • +
      • port (This parameter is optional, the + default value is "162")
        +
        + The port which will be used, common values are port 162 or 161.
        +
        + Example: port 162
        +
      • +
      • version (This parameter is optional, the + default value is "1")
        +
        + There can only be two choices for this parameter for now.
        + 0 means SNMPv1 will be used.
        + 1 means SNMPv2c will be used.
        + Any other value will default to 1.
        +
        + Example: version 1
        +
      • +
      • community (This parameter is optional, the + default value is "public")
        +
        + This sets the used SNMP Community.
        +
        + Example: community public
        +

        +
      • +
      • trapoid (This parameter is + optional, the default value is "1.3.6.1.4.1.19406.1.2.1" which means + "ADISCON-MONITORWARE-MIB::syslogtrap")
        + This configuration parameter is used for SNMPv2 only.
        +
        + This is the OID which defines the trap-type, or notifcation-type rsyslog + uses to send the trap.
        + In order to decode this OID, you will need to have the + ADISCON-MONITORWARE-MIB and ADISCON-MIB mibs installed on the receiver side. Downloads of these mib files + can be found here:
        + + http://www.adiscon.org/download/ADISCON-MIB.txt
        + + http://www.adiscon.org/download/ADISCON-MONITORWARE-MIB.txt
        +
        + Thanks to the net-snmp + mailinglist for the help and the recommendations ;).
        +
        + Example: trapoid 1.3.6.1.4.1.19406.1.2.1
        +
        If you have this MIBS installed, you can also configured with the + OID Name: trapoid ADISCON-MONITORWARE-MIB::syslogtrap
        +
        +
      • +
      • messageoid (This parameter is + optional, the default value is "1.3.6.1.4.1.19406.1.1.2.1" which means + "ADISCON-MONITORWARE-MIB::syslogMsg")
        +
        + This OID will be used as a variable, type "OCTET STRING". This variable will + contain up to 255 characters of the original syslog message including syslog header. It is recommend to + use the default OID.
        + In order to decode this OID, you will need to have the + ADISCON-MONITORWARE-MIB and ADISCON-MIB mibs installed on the receiver side. + To download these custom mibs, see the description of $actionsnmptrapoid. +
        +
        + Example: messageoid 1.3.6.1.4.1.19406.1.1.2.1
        +
        If you have this MIBS installed, you can also configured with the + OID Name: messageoid + ADISCON-MONITORWARE-MIB::syslogMsg
        +

        +
      • +
      • enterpriseoid (This parameter is optional, + the default value is "1.3.6.1.4.1.3.1.1" which means "enterprises.cmu.1.1")
        +
        + Customize this value if needed. I recommend to use the default value unless + you require to use a different OID.
        + This configuration parameter is used for SNMPv1 only. It + has no effect if SNMPv2 is used.
        +
        + Example: enterpriseoid 1.3.6.1.4.1.3.1.1
        +

        +
      • +
      • specifictype (This parameter is optional, + the default value is "0")
        +
        + This is the specific trap number. This configuration parameter is used for + SNMPv1 only. It has no effect if SNMPv2 is + used.
        +
        + Example: specifictype 0
        +

        +
      • +
      • traptype (This parameter is optional, the + default value is "6" which means SNMP_TRAP_ENTERPRISESPECIFIC)
        +
        + There are only 7 Possible trap types defined which can be used here. These + trap types are:
        + 0 = SNMP_TRAP_COLDSTART
        + 1 = SNMP_TRAP_WARMSTART
        + 2 = SNMP_TRAP_LINKDOWN
        + 3 = SNMP_TRAP_LINKUP
        + 4 = SNMP_TRAP_AUTHFAIL
        + 5 = SNMP_TRAP_EGPNEIGHBORLOSS
        + 6 = SNMP_TRAP_ENTERPRISESPECIFIC
        +
        + Any other value will default to 6 automatically. This configuration + parameter is used for SNMPv1 only. It has no effect if + SNMPv2 is used.
        +
        + Example: traptype 6
        +
      • +
      • template [templateName]
        +
        + sets a new default template for file actions. +
      • +
      +

       

      +

      Caveats/Known Bugs:

      • In order to decode the custom OIDs, you + will need to have the adiscon mibs installed.
      +

      Sample:

      +

      The following commands send every message as a snmp trap.

      + + +

      Legacy Configuration Directives:

      • $actionsnmptransport (This parameter is optional, the default value is "udp")
        @@ -164,6 +311,7 @@ $actionsnmpcommunity public *.* :omsnmp: +

        [rsyslog.conf overview] [manual index] [rsyslog site]

        This documentation is part of the diff --git a/doc/property_replacer.html b/doc/property_replacer.html index 86a07474..c6464a3b 100644 --- a/doc/property_replacer.html +++ b/doc/property_replacer.html @@ -236,7 +236,7 @@ or none if no rule with this field did match.

        Properties starting with a $-sign are so-called system properties. These do NOT stem from the message but are rather internally-generated.

        -

        Character Positions

        +

        Legacy Character Positions

        FromChar and toChar are used to build substrings. They specify the offset within the string that should be copied. Offset counting starts at 1, so if you need to @@ -304,15 +304,6 @@ fields in the property is requested. The field number must be placed in the "ToChar" parameter. An example where the 3rd field (delimited by TAB) from the msg property is extracted is as follows: "%msg:F:3%". The same example with semicolon as delimiter is "%msg:F,59:3%".

        -

        The use of fields does not permit to select substrings, what is rather -unfortunate. To solve this issue, starting with 6.3.9, fromPos and toPos -can be specified for strings as well. However, the syntax is quite ugly, but -it was the only way to integrate this functonality into the already-existing -system. To do so, use ",fromPos" and ",toPos" during field extraction. -Let's assume you want to extract the substring from position 5 to 9 in the previous -example. Then, the syntax is as follows: "%msg:F,59,5:3,9%". As you can see, -"F,59" means field-mode, with semicolon delimiter and ",5" means starting -at position 5. Then "3,9" means field 3 and string extraction to position 9.

        Please note that the special characters "F" and "R" are case-sensitive. Only upper case works, lower case will return an error. There are no white spaces permitted inside the sequence (that will lead @@ -342,6 +333,239 @@ It is modeled after perl compatible regular expressions.

        Property Options

        property options are +case-insensitive. They are available as of version 6.5.0. +Currently, the following options are defined: +

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        This feature was introduced in rsyslog 4.6.2 and v4 versions above and +5.5.3 and all versions above. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        NameNew format. Name of the template / property / constant.
        OutnameThis field permits to specify a field name for structured-data emitting property replacer options. +If used for a constant a template with line style, unpredictable behaviour can occur.
        CaseConversionNew format. Additional values below.
        upperconvert property to lowercase only
        lowerconvert property text to uppercase only
        DateFormatNew format, additional parameter is needed. See below.
        mysqlformat as mysql date
        pgsqlformat as pgsql date
        rfc3164format as RFC 3164 date
        rfc3164-buggydaysimilar to date-rfc3164, but emulates a common coding error: RFC 3164 demands +that a space is written for single-digit days. With this option, a zero is +written instead. This format seems to be used by syslog-ng and the +date-rfc3164-buggyday option can be used in migration scenarios where otherwise +lots of scripts would need to be adjusted. It is recommended not to use this +option when forwarding to remote hosts - they may treat the date as invalid +(especially when parsing strictly according to RFC 3164).
        rfc3339format as RFC 3339 date
        unixtimestampformat as unix timestamp (seconds since epoch)
        subsecondsjust the subseconds of a timestamp (always 0 for a low precision timestamp)
        ControlCharactersOption values for how to process control characters
        escapereplace control characters (ASCII value 127 and values +less then 32) with an escape sequence. The sequnce is +"#<charval>" where charval is the 3-digit decimal value +of the control character. For example, a tabulator would be replaced by +"#009".
        +Note: using this option requires that $EscapeControlCharactersOnReceive +is set to off.
        spacereplace control characters by spaces
        +Note: using this option requires that $EscapeControlCharactersOnReceive +is set to off.
        dropdrop control characters - the resulting string will +neither contain control characters, escape sequences nor any other +replacement character like space.
        +Note: using this option requires that $EscapeControlCharactersOnReceive +is set to off.
        SecurePathOption values for securing path templates.
        dropDrops slashes inside the field (e.g. "a/b" becomes "ab"). +Useful for secure pathname generation (with dynafiles). +
        replaceReplace slashes inside the field by an underscore. (e.g. "a/b" becomes "a_b"). +Useful for secure pathname generation (with dynafiles). +
        FormatOption values for the general output format.
        jsonencode the value so that it can be used inside a JSON field. This means +that several characters (according to the JSON spec) are being escaped, for +example US-ASCII LF is replaced by "\n". +The json option cannot be used together with either jsonf or csv options. +
        jsonf(available in 6.3.9+) +This signifies that the property should be expressed as a json field. +That means not only the property is written, but rather a complete json field in +the format
        +"fieldname"="value" +where "filedname" is the assigend field name (or the property name if none was assigned) +and value is the end result of property replacer operation. Note that value supports +all property replacer options, like substrings, case converson and the like. +Values are properly json-escaped. However, field names are (currently) not. It is +expected that proper field names are configured. +The jsonf option cannot be used together with either json or csv options. +
        csvformats the resulting field (after all modifications) in CSV format +as specified in RFC 4180. +Rsyslog will always use double quotes. Note that in order to have full CSV-formatted +text, you need to define a proper template. An example is this one: +
        $template csvline,"%syslogtag:::csv%,%msg:::csv%" +
        Most importantly, you need to provide the commas between the fields +inside the template. +The csv option cannot be used together with either json or jsonf options. +
        This feature was introduced in rsyslog 4.1.6. +
        droplastlfThe last LF in the message (if any), is dropped. +Especially useful for PIX.
        spifno1stspThis option looks scary and should probably not be used by a user. For any field +given, it returns either a single space character or no character at all. Field content +is never returned. A space is returned if (and only if) the first character of the +field's content is NOT a space. This option is kind of a hack to solve a problem rooted +in RFC 3164: 3164 specifies no delimiter between the syslog tag sequence and the actual +message text. Almost all implementation in fact delemit the two by a space. As of +RFC 3164, this space is part of the message text itself. This leads to a problem when +building the message (e.g. when writing to disk or forwarding). Should a delimiting +space be included if the message does not start with one? If not, the tag is immediately +followed by another non-space character, which can lead some log parsers to misinterpret +what is the tag and what the message. The problem finally surfaced when the klog module +was restructured and the tag correctly written. It exists with other message sources, +too. The solution was the introduction of this special property replacer option. Now, +the default template can contain a conditional space, which exists only if the +message does not start with one. While this does not solve all issues, it should +work good enough in the far majority of all cases. If you read this text and have +no idea of what it is talking about - relax: this is a good indication you will never +need this option. Simply forget about it ;) +
        New character positionIn addition to the above mentioned Character Positions in the legacy format, +positions can be determined by specifying the correct options for the properties. +Again, this is mostly for using the list format.
        position.FromCharacter position in the property to start from.
        position.ToCharacter position that determines the end for extraction. If the value is "$" +then the end of the string will be used.
        field.NumberThe number of the field, which should be used for the search operation with Regex.
        field.DelimiterThe Character that should delimit a field. Example: ",". Everything in a +property until this character is considered a field.
        regex.ExpressionValue to be compared to property.
        regex.TypeValues BRE or ERE
        regex.NoMatchModeDFLT, BLANK, ZERO, FIELD
        regex.MatchMatch to use.
        regex.SubmatchSubmatch to use. Values 0-9 whereas 0 = All
        + + + +

        Legacy Property Options

        +property options are case-insensitive. Currently, the following options are defined:

        @@ -368,7 +592,7 @@ The json option cannot be used together with either jsonf or csv options. This signifies that the property should be expressed as a json field. That means not only the property is written, but rather a complete json field in the format
        -"fieldname":"value" +"fieldname"="value" where "filedname" is the assigend field name (or the property name if none was assigned) and value is the end result of property replacer operation. Note that value supports all property replacer options, like substrings, case converson and the like. diff --git a/doc/rsyslog_conf_templates.html b/doc/rsyslog_conf_templates.html index bd0b3253..b97f6609 100644 --- a/doc/rsyslog_conf_templates.html +++ b/doc/rsyslog_conf_templates.html @@ -33,26 +33,31 @@ string generator module, you need to know how to call it. Each such module has a which you need to know (look it up in the module doc or ask the developer). Let's assume that "mystrgen" is the module name. Then you can define a template for that strgen in the following way: + +
        template(name="MyTemplateName" type="plugin" string="mystrgen")
        +

        Legacy example:

        $template MyTemplateName,=mystrgen
        (Of course, you must have first loaded the module via $ModLoad). -

        The important part is the equal sign: it tells the rsyslog config parser that +

        The important part is the equal sign in the legacy format: it tells the rsyslog config parser that no string follows but a strgen module name.

        There are no additional parameters but the module name supported. This is because there is no way to customize anything inside such a "template" other than by modifying the code of the string generator.

        So for most use cases, string-generator module based templates are not -the route to take. Usually, us use string based templates instead. +the route to take. Usually, we use string based templates instead. This is what the rest of the documentation now talks about.

        A template consists of a template directive, a name, the actual template text and optional options. A sample is:

        +
        template(name="MyTemplateName" type="string" string="Example: Text %property% some more text\n" options)
        +

        Legacy example:

        $template MyTemplateName,"\7Text %property% some more text\n",<options>
        -

        The "$template" is the template directive. It tells rsyslog +

        The "template" (legacy: $template) is the template directive. It tells rsyslog that this line contains a template. "MyTemplateName" is the template name. All -other config lines refer to this name. The text within quotes is the +other config lines refer to this name. The text within "string" is the actual template text. The backslash is an escape character, much as it is in C. It does all these "cool" things. For example, \7 rings the bell (this is an ASCII value), \n is a new line. C programmers and perl @@ -69,24 +74,30 @@ on this is below, on some lines of the property replacer.

        The <options> part is optional. It carries options influencing the template as whole. See details below. Be sure NOT to -mistake template options with property options - the later ones are +mistake template options with property options - the latter ones are processed by the property replacer and apply to a SINGLE property, only (and not the whole template).

        Template options are case-insensitive. Currently defined are:

        -

        sql - format the string suitable for a SQL +

        option.sql - format the string suitable for a SQL statement in MySQL format. This will replace single quotes ("'") and the backslash character by their backslash-escaped counterpart ("\'" and "\\") inside each field. Please note that in MySQL configuration, the NO_BACKSLASH_ESCAPES mode must be turned off for this format to work (this is the default).

        -

        stdsql - format the string suitable for a +

        option.stdsql - format the string suitable for a SQL statement that is to be sent to a standards-compliant sql server. This will replace single quotes ("'") by two single quotes ("''") inside each field. You must use stdsql together with MySQL if in MySQL configuration the NO_BACKSLASH_ESCAPES is turned on.

        +

        option.json - format the string suitable for a +json statement. +This will replace single quotes ("'") by two single quotes ("''") +inside each field.

        +

        At no time, multiple template option should be used. This can cause +unpredictable behaviour and is against all logic.

        Either the sql or stdsql  option must be specified when a template is used for writing to a database, otherwise injection might occur. Please note @@ -120,11 +131,41 @@ $template TraditionalFormat,"%timegenerated% %HOSTNAME% %syslogtag%%msg%\n"

        Properties can be accessed by the property replacer (see there for details).

        -

        Please note that templates can also by +

        Templates can be used in the form of a list as well. This has been +introduced with 6.5.0 The list consists of two parts which are either +a constant or a property. The constants +are taking the part of "text" that you usually enter in string-based templates. +The properties stay variable, as they are a substitute for different values of a +certain type. This type of template is extremely useful for complicated cases, +as it helps you to easily keep an overview over the template. Though, it has +the disadvantage of needing more effort to create it.

        +
        Config example: +
        template(name="MyTemplate" type="list" option.json="off") { +
        constant(value="Test: ") +
        property(name="msg" outname="mymessage") +
        constant(value=" --!!!-- ") +
        property(name="timereported" dateFormat="rfc3339" caseConversion="lower") +
        constant(value="\n") +
        } +
        +

        First, the general template option will be defined. The values of the template +itself get defined in the curly brackets. As it can be seen, we have constants +and properties in exchange. Whereas constants will be filled with a value and probably +some options, properties do direct to a property and the options that could be needed +additional format definitions.

        +

        We suggest to use separate lines for all constants and properties. This +helps to keep a good overview over the different parts of the template. +Though, writing it in a single line will work, it is much harder to debug +if anything goes wrong with the template.

        + + +

        Please note that templates can also be used to generate selector lines with dynamic file names. For example, if you would like to split syslog messages from different hosts to different files (one per host), you can define the following template:

        +
        template (name="DynFile" type="string" string="/var/log/system-%HOSTNAME%.log")
        +

        Legacy example:

        $template DynFile,"/var/log/system-%HOSTNAME%.log"

        This template can then be used when defining an output @@ -169,7 +210,7 @@ out, but this may happen. is meant to be written to a log file. Do not use for production or remote forwarding. -

        String-based Template Samples

        +

        Legacy String-based Template Samples

        This section provides some sample of what the default formats would look as a text-based template. Hopefully, their description is self-explanatory. Note that each $Template statement is on a single line, but probably broken -- cgit v1.2.3 From 72e1ccbc69d3b6047a98cfd45c00acab76c1d327 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 28 Aug 2012 09:59:15 +0200 Subject: preparing for 6.5.0 release --- ChangeLog | 3 ++- doc/manual.html | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4ee5beb0..64dfd613 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 6.5.0 [devel] 2012-0?-?? +Version 6.5.0 [devel] 2012-08-28 - imrelp now supports non-cancel thread termination (but now requires at least librelp 1.0.1) - implemented freeCnf() module interface @@ -18,6 +18,7 @@ Version 6.5.0 [devel] 2012-0?-?? Thanks to Miloslav Trmač for the patch - $SystemLogParseTrusted config file option Thanks to Milan Bartos for the patch +- added template config directive - added new uuid message property Thanks to Jérôme Renard for the idea and patches. Note: patches were released under ASL 2.0, see diff --git a/doc/manual.html b/doc/manual.html index de05d7ae..9a8644c9 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -19,7 +19,7 @@ rsyslog support available directly from the source!

        Please visit the rsyslog sponsor's page to honor the project sponsors or become one yourself! We are very grateful for any help towards the project goals.

        -

        This documentation is for version 6.4.0 (stable branch) of rsyslog. +

        This documentation is for version 6.5.0 (devel branch) of rsyslog. Visit the rsyslog status page to obtain current version information and project status.

        If you like rsyslog, you might -- cgit v1.2.3 From 7348da7e02fae85ad24dd496f1cd8f6385cfcfa8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 28 Aug 2012 19:07:58 +0200 Subject: bugfix: imtcp could abort on exit due to invalid free() --- ChangeLog | 3 +++ plugins/imtcp/imtcp.c | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 64dfd613..87beea2c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,7 @@ --------------------------------------------------------------------------- +Version 6.5.1 [devel] 2012-08-?? +- bugfix: imtcp could abort on exit due to invalid free() +--------------------------------------------------------------------------- Version 6.5.0 [devel] 2012-08-28 - imrelp now supports non-cancel thread termination (but now requires at least librelp 1.0.1) diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index a3365d44..f021307b 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -370,7 +370,6 @@ BEGINfreeCnf CODESTARTfreeCnf for(inst = pModConf->root ; inst != NULL ; ) { free(inst->pszBindPort); - free(inst->pBindRuleset); free(inst->pszInputName); del = inst; inst = inst->next; -- cgit v1.2.3 From 901270418eca404a1f05c2b5ace66954b8b690b1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 29 Aug 2012 09:56:49 +0200 Subject: add OMSR_TPL_AS_JSON mode for output modules (interface only) This patch does NOT contain any implementation, this will happen next. Thanks to Miloslav Trmac, who suggested a similar mode, which I based the JSON idea on. --- action.c | 6 ++++++ action.h | 3 ++- doc/dev_oplugins.html | 5 +++++ runtime/objomsr.c | 3 ++- runtime/objomsr.h | 7 ++++--- 5 files changed, 19 insertions(+), 5 deletions(-) diff --git a/action.c b/action.c index 344bdc26..5d9211e2 100644 --- a/action.c +++ b/action.c @@ -823,6 +823,9 @@ static rsRetVal prepareDoActionParams(action_t *pAction, batch_obj_t *pElem) case ACT_MSG_PASSING: pElem->staticActParams[i] = (void*) pMsg; break; + case ACT_JSON_PASSING: + // TODO: implement + break; default:dbgprintf("software bug/error: unknown pAction->eParamPassing %d in prepareDoActionParams\n", (int) pAction->eParamPassing); assert(0); /* software bug if this happens! */ @@ -874,6 +877,7 @@ static rsRetVal releaseBatch(action_t *pAction, batch_t *pBatch) break; case ACT_STRING_PASSING: case ACT_MSG_PASSING: + case ACT_JSON_PASSING: /* nothing to do in that case */ /* TODO ... and yet we do something ;) This is considered not * really needed, but I was not bold enough to remove that while @@ -1933,6 +1937,8 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, pAction->eParamPassing = ACT_ARRAY_PASSING; } else if(iTplOpts & OMSR_TPL_AS_MSG) { pAction->eParamPassing = ACT_MSG_PASSING; + } else if(iTplOpts & OMSR_TPL_AS_JSON) { + pAction->eParamPassing = ACT_JSON_PASSING; } else { pAction->eParamPassing = ACT_STRING_PASSING; } diff --git a/action.h b/action.h index 66ceaae5..0e704ddf 100644 --- a/action.h +++ b/action.h @@ -74,7 +74,8 @@ struct action_s { int f_repeatcount; /* number of "repeated" msgs */ rsRetVal (*submitToActQ)(action_t *, batch_t *);/* function submit message to action queue */ rsRetVal (*qConstruct)(struct queue_s *pThis); - enum { ACT_STRING_PASSING = 0, ACT_ARRAY_PASSING = 1, ACT_MSG_PASSING } + enum { ACT_STRING_PASSING = 0, ACT_ARRAY_PASSING = 1, ACT_MSG_PASSING = 2, + ACT_JSON_PASSING = 3} eParamPassing; /* mode of parameter passing to action */ int iNumTpls; /* number of array entries for template element below */ struct template **ppTpl;/* array of template to use - strings must be passed to doAction diff --git a/doc/dev_oplugins.html b/doc/dev_oplugins.html index 63c186a3..b33b67f9 100644 --- a/doc/dev_oplugins.html +++ b/doc/dev_oplugins.html @@ -143,6 +143,11 @@ omstdout, you can see how a plugin may deal with the situation. array-passing capability not blindly be used. In such cases, we can not guard the plugin from segfaulting and if the plugin (as currently always) is run within rsyslog's process space, that results in a segfault for rsyslog. So do not do this. +

        Another possible mode is OMSR_TPL_AS_JSON, where instead of the template +a json-c memory object tree is passed to the module. The module can extract data +via json-c API calls. It MUST NOT modify the provided structure. This mode is +primarily aimed at plugins that need to process tree-like data, as found +for example in MongoDB or ElasticSearch.

        Batching of Messages

        Starting with rsyslog 4.3.x, batching of output messages is supported. Previously, only a single-message interface was supported. diff --git a/runtime/objomsr.c b/runtime/objomsr.c index 7241fa27..9cf3781b 100644 --- a/runtime/objomsr.c +++ b/runtime/objomsr.c @@ -149,7 +149,8 @@ OMSRgetSupportedTplOpts(unsigned long *pOpts) { DEFiRet; assert(pOpts != NULL); - *pOpts = OMSR_RQD_TPL_OPT_SQL | OMSR_TPL_AS_ARRAY | OMSR_TPL_AS_MSG; + *pOpts = OMSR_RQD_TPL_OPT_SQL | OMSR_TPL_AS_ARRAY | OMSR_TPL_AS_MSG + | OMSR_TPL_AS_JSON; RETiRet; } diff --git a/runtime/objomsr.h b/runtime/objomsr.h index 643e02c5..3baccaa3 100644 --- a/runtime/objomsr.h +++ b/runtime/objomsr.h @@ -25,12 +25,13 @@ /* define flags for required template options */ #define OMSR_NO_RQD_TPL_OPTS 0 #define OMSR_RQD_TPL_OPT_SQL 1 -/* only one of OMSR_TPL_AS_ARRAY or _AS_MSG must be specified, if both are given - * results are unpredictable. +/* only one of OMSR_TPL_AS_ARRAY, _AS_MSG, or _AS_JSON must be specified, + * if all are given results are unpredictable. */ #define OMSR_TPL_AS_ARRAY 2 /* introduced in 4.1.6, 2009-04-03 */ #define OMSR_TPL_AS_MSG 4 /* introduced in 5.3.4, 2009-11-02 */ -/* next option is 8, 16, 32, ... */ +#define OMSR_TPL_AS_JSON 8 /* introduced in 6.5.1, 2012-09-02 */ +/* next option is 16, 32, 64, ... */ struct omodStringRequest_s { /* strings requested by output module for doAction() */ int iNumEntries; /* number of array entries for data elements below */ -- cgit v1.2.3 From df492da1804b14e53a56a3dd6a3b8cc8fb1e2d78 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 29 Aug 2012 12:32:54 +0200 Subject: implement ACT_JSON_PASSING NOTE: this is only compile-tested! For real testing, a module using that mode is required. Will be done as next steps. --- action.c | 23 +++++++++++------------ template.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/action.c b/action.c index 5d9211e2..8f8371f7 100644 --- a/action.c +++ b/action.c @@ -98,6 +98,7 @@ #include #include #include +#include #include "dirty.h" #include "template.h" @@ -803,6 +804,7 @@ static rsRetVal prepareDoActionParams(action_t *pAction, batch_obj_t *pElem) { int i; msg_t *pMsg; + struct json_object *json; DEFiRet; ASSERT(pAction != NULL); @@ -824,7 +826,8 @@ static rsRetVal prepareDoActionParams(action_t *pAction, batch_obj_t *pElem) pElem->staticActParams[i] = (void*) pMsg; break; case ACT_JSON_PASSING: - // TODO: implement + CHKiRet(tplToJSON(pAction->ppTpl[i], pMsg, &json)); + pElem->staticActParams[i] = (void*) json; break; default:dbgprintf("software bug/error: unknown pAction->eParamPassing %d in prepareDoActionParams\n", (int) pAction->eParamPassing); @@ -877,7 +880,6 @@ static rsRetVal releaseBatch(action_t *pAction, batch_t *pBatch) break; case ACT_STRING_PASSING: case ACT_MSG_PASSING: - case ACT_JSON_PASSING: /* nothing to do in that case */ /* TODO ... and yet we do something ;) This is considered not * really needed, but I was not bold enough to remove that while @@ -889,6 +891,13 @@ static rsRetVal releaseBatch(action_t *pAction, batch_t *pBatch) ((uchar**)pElem->staticActParams)[j] = NULL; } break; + case ACT_JSON_PASSING: + for(j = 0 ; j < pAction->iNumTpls ; ++j) { + json_object_put((struct json_object*) + pElem->staticActParams[j]); + pElem->staticActParams[j] = NULL; + } + break; } } } @@ -1098,16 +1107,6 @@ finalize_it: RETiRet; } -/* debug aid */ -static void displayBatchState(batch_t *pBatch) -{ - int i; - for(i = 0 ; i < pBatch->nElem ; ++i) { - dbgprintf("XXXXX: displayBatchState2 %p[%d]: %d\n", pBatch, i, pBatch->pElem[i].state); - } -} - - /* submit a batch for actual action processing. * The first nElem elements are processed. This function calls itself * recursively if it needs to handle errors. diff --git a/template.c b/template.c index 768608f1..a3d2b8d6 100644 --- a/template.c +++ b/template.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "stringbuf.h" #include "syslogd-types.h" #include "template.h" @@ -270,6 +271,50 @@ finalize_it: } +/* This functions converts a template into a json object. + * For further general details, see the very similar funtion + * tpltoString(). + * rgerhards, 2012-08-29 + */ +rsRetVal tplToJSON(struct template *pTpl, msg_t *pMsg, struct json_object **pjson) +{ + struct templateEntry *pTpe; + char *cstr; + size_t propLen; + unsigned short bMustBeFreed; + uchar *pVal; + struct json_object *json, *jsonf; + DEFiRet; + + assert(pTpl != NULL); + assert(pMsg != NULL); + assert(json != NULL); + + json = json_object_new_object(); + for(pTpe = pTpl->pEntryRoot ; pTpe != NULL ; pTpe = pTpe->pNext) { + if(pTpe->eEntryType == CONSTANT) { + if(pTpe->fieldName == NULL) + continue; + jsonf = json_object_new_string((char*) pTpe->data.constant.pConstant); + } else if(pTpe->eEntryType == FIELD) { + pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, + pTpe->data.field.propName, &propLen, &bMustBeFreed); + jsonf = json_object_new_string_len((char*)pVal, propLen); + if(bMustBeFreed) { /* json-c makes its own private copy! */ + free(pVal); + } + } + /* TODO: unify strings, handling currently quite inefficient! */ + cstr = es_str2cstr(pTpe->fieldName, NULL); + json_object_object_add(json, cstr, jsonf); + free(cstr); + } + + *pjson = (iRet == RS_RET_OK) ? json : NULL; + RETiRet; +} + + /* Helper to doEscape. This is called if doEscape * runs out of memory allocating the escaped string. * Then we are in trouble. We can -- cgit v1.2.3 From 1e09e2729e737e4512aa2205d72c537cce6d8cd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Fri, 24 Aug 2012 18:04:44 +0200 Subject: Split MongoDB output into BSON creation and MongoDB interaction MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow us to add template processing more cleanly. Signed-off-by: Miloslav Trmač --- plugins/ommongodb/ommongodb.c | 51 +++++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/plugins/ommongodb/ommongodb.c b/plugins/ommongodb/ommongodb.c index 00afcf68..a3848edb 100644 --- a/plugins/ommongodb/ommongodb.c +++ b/plugins/ommongodb/ommongodb.c @@ -205,13 +205,14 @@ i10pow(int exp) } return r; } -/* write to mongodb in MSG passing mode, that is without a template. +/* Return a BSON document when an user hasn't specified a template. * In this mode, we use the standard document format, which is somewhat * aligned to cee (as described in project lumberjack). Note that this is * a moving target, so we may run out of sync (and stay so to retain * backward compatibility, which we consider pretty important). */ -rsRetVal writeMongoDB_msg(msg_t *pMsg, instanceData *pData) +static bson * +getDefaultBSON(msg_t *pMsg) { bson *doc = NULL; uchar *procid; short unsigned procid_free; size_t procid_len; @@ -222,12 +223,6 @@ rsRetVal writeMongoDB_msg(msg_t *pMsg, instanceData *pData) int severity, facil; gint64 ts_gen, ts_rcv; /* timestamps: generated, received */ int secfrac; - DEFiRet; - - /* see if we are ready to proceed */ - if(pData->conn == NULL) { - CHKiRet(initMongoDB(pData, 0)); - } procid = MsgGetProp(pMsg, NULL, PROP_PROGRAMNAME, NULL, &procid_len, &procid_free); tag = MsgGetProp(pMsg, NULL, PROP_SYSLOGTAG, NULL, &tag_len, &tag_free); @@ -279,22 +274,10 @@ dbgprintf("ommongodb: secfrac is %d, precision %d\n", pMsg->tTIMESTAMP.secfrac, if(sys_free) free(sys); if(msg_free) free(msg); - if(doc == NULL) { - reportMongoError(pData); - dbgprintf("ommongodb: error creating BSON doc\n"); - ABORT_FINALIZE(RS_RET_SUSPENDED); - } + if(doc == NULL) + return doc; bson_finish(doc); - if(!mongo_sync_cmd_insert(pData->conn, (char*)pData->dbNcoll, doc, NULL)) { - reportMongoError(pData); - dbgprintf("ommongodb: insert error\n"); - ABORT_FINALIZE(RS_RET_SUSPENDED); - } - -finalize_it: - if(doc != NULL) - bson_free(doc); - RETiRet; + return doc; } BEGINtryResume @@ -305,10 +288,30 @@ CODESTARTtryResume ENDtryResume BEGINdoAction + bson *doc = NULL; CODESTARTdoAction + /* see if we are ready to proceed */ + if(pData->conn == NULL) { + CHKiRet(initMongoDB(pData, 0)); + } + if(pData->tplName == NULL) { - iRet = writeMongoDB_msg((msg_t*)ppString[0], pData); + doc = getDefaultBSON((msg_t*)ppString[0]); + } + if(doc == NULL) { + dbgprintf("ommongodb: error creating BSON doc\n"); + /* FIXME: is this a correct return code? */ + ABORT_FINALIZE(RS_RET_ERR); + } + if(!mongo_sync_cmd_insert(pData->conn, (char*)pData->dbNcoll, doc, NULL)) { + reportMongoError(pData); + dbgprintf("ommongodb: insert error\n"); + ABORT_FINALIZE(RS_RET_SUSPENDED); } + +finalize_it: + if(doc != NULL) + bson_free(doc); ENDdoAction -- cgit v1.2.3 From 9bd45fcb72e0e3a2abd89fc7fe0d068c0d68e1de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Fri, 24 Aug 2012 19:49:41 +0200 Subject: Add template support: parse text, convert to BSON MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uses a json-c library (http://oss.metaparadigm.com/json-c/). With this, a template > $template MongoTemplate,"{%hostname:::jsonf:sys%, %$!all-json:2:$:%" and action > & action(type="ommongodb" db="ceelog" collection="local" template="MongoTemplate") will store a record created by > logger -d -u p/dev/log -p mail.info -t mymailer '@cee: {"false": false, "null": null, "true": true, "object": {"a":"a", "b":"b"}, "array": [1, 2, 3], "number1": 3, "number2": 3.14, "string": "String"}' as > { "_id" : ObjectId("5037bbfc97dd811374ce5a00"), "sys" : "kulicka", "false" : "false", "null" : "-", "true" : "true", "object.a" : "a", "object.b" : "b", "array.*" : "3", "number1" : "3", "number2" : "3.140000", "string" : "String" } which is not great, but fair enough given the current design of libee (the information loss manifests by the time of template processing, ommongodb can't fix it). Signed-off-by: Miloslav Trmač --- configure.ac | 7 +- plugins/ommongodb/Makefile.am | 4 +- plugins/ommongodb/ommongodb.c | 179 ++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 178 insertions(+), 12 deletions(-) diff --git a/configure.ac b/configure.ac index d0accfeb..0fe664a4 100644 --- a/configure.ac +++ b/configure.ac @@ -1279,14 +1279,13 @@ AC_ARG_ENABLE(ommongodb, esac], [enable_ommongodb=no] ) -# -# you may want to do some library checks here - see snmp, mysql, pgsql modules -# for samples -# if test "x$enable_ommongodb" = "xyes"; then PKG_CHECK_MODULES(LIBMONGO_CLIENT, libmongo-client >= 0.1.4) AC_SUBST(LIBMONGO_CLIENT_CFLAGS) AC_SUBST(LIBMONGO_CLIENT_LIBS) + PKG_CHECK_MODULES([JSON_C], [json]) + AC_SUBST([JSON_CFLAGS]) + AC_SUBST([JSON_LIBS]) fi AM_CONDITIONAL(ENABLE_OMMONGODB, test x$enable_ommongodb = xyes) # end of mongodb code diff --git a/plugins/ommongodb/Makefile.am b/plugins/ommongodb/Makefile.am index 3a05c435..8b13c254 100644 --- a/plugins/ommongodb/Makefile.am +++ b/plugins/ommongodb/Makefile.am @@ -1,7 +1,7 @@ pkglib_LTLIBRARIES = ommongodb.la ommongodb_la_SOURCES = ommongodb.c -ommongodb_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(LIBMONGO_CLIENT_CFLAGS) +ommongodb_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(LIBMONGO_CLIENT_CFLAGS) $(JSON_C_CFLAGS) ommongodb_la_LDFLAGS = -module -avoid-version -ommongodb_la_LIBADD = $(LIBMONGO_CLIENT_LIBS) +ommongodb_la_LIBADD = $(LIBMONGO_CLIENT_LIBS) $(JSON_C_LIBS) EXTRA_DIST = diff --git a/plugins/ommongodb/ommongodb.c b/plugins/ommongodb/ommongodb.c index a3848edb..9a7ca9f7 100644 --- a/plugins/ommongodb/ommongodb.c +++ b/plugins/ommongodb/ommongodb.c @@ -30,8 +30,12 @@ #include #include #include +#include #include #include +#include +/* For struct json_object_iter, should not be necessary in future versions */ +#include #include "rsyslog.h" #include "conf.h" @@ -42,6 +46,7 @@ #include "datetime.h" #include "errmsg.h" #include "cfsysline.h" +#include "unicode-helper.h" MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP @@ -54,6 +59,7 @@ DEFobjCurrIf(datetime) typedef struct _instanceData { mongo_sync_connection *conn; + struct json_tokener *json_tokener; /* only if (tplName != NULL) */ uchar *server; int port; uchar *db; @@ -108,11 +114,14 @@ static void closeMongoDB(instanceData *pData) BEGINfreeInstance CODESTARTfreeInstance closeMongoDB(pData); + if (pData->json_tokener != NULL) + json_tokener_free(pData->json_tokener); free(pData->server); free(pData->db); free(pData->collection); free(pData->uid); free(pData->pwd); + free(pData->dbNcoll); free(pData->tplName); ENDfreeInstance @@ -280,6 +289,165 @@ dbgprintf("ommongodb: secfrac is %d, precision %d\n", pMsg->tTIMESTAMP.secfrac, return doc; } +static bson *BSONFromJSONArray(struct json_object *json); +static bson *BSONFromJSONObject(struct json_object *json); + +/* Append a BSON variant of json to doc using name. Return TRUE on success */ +static gboolean +BSONAppendJSONObject(bson *doc, const gchar *name, struct json_object *json) +{ + switch(json_object_get_type(json)) { + case json_type_boolean: + return bson_append_boolean(doc, name, + json_object_get_boolean(json)); + case json_type_double: + return bson_append_double(doc, name, + json_object_get_double(json)); + case json_type_int: { + int64_t i; + + /* FIXME: the future version will have get_int64 */ + i = json_object_get_int(json); + if (i >= INT32_MIN && i <= INT32_MAX) + return bson_append_int32(doc, name, i); + else + return bson_append_int64(doc, name, i); + } + case json_type_object: { + bson *sub; + gboolean ok; + + sub = BSONFromJSONObject(json); + if (sub == NULL) + return FALSE; + ok = bson_append_document(doc, name, sub); + bson_free(sub); + return ok; + } + case json_type_array: { + bson *sub; + gboolean ok; + + sub = BSONFromJSONArray(json); + if (sub == NULL) + return FALSE; + ok = bson_append_document(doc, name, sub); + bson_free(sub); + return ok; + } + case json_type_string: + return bson_append_string(doc, name, + json_object_get_string(json), -1); + + default: + return FALSE; + } +} + +/* Return a BSON variant of json, which must be a json_type_array */ +static bson * +BSONFromJSONArray(struct json_object *json) +{ + /* Way more than necessary */ + bson *doc = NULL; + size_t i, array_len; + + doc = bson_new(); + if(doc == NULL) + goto error; + + array_len = json_object_array_length(json); + for (i = 0; i < array_len; i++) { + char buf[sizeof(size_t) * CHAR_BIT + 1]; + + if ((size_t)snprintf(buf, sizeof(buf), "%zu", i) >= sizeof(buf)) + goto error; + if (BSONAppendJSONObject(doc, buf, + json_object_array_get_idx(json, i)) + == FALSE) + goto error; + } + + if(bson_finish(doc) == FALSE) + goto error; + + return doc; + +error: + if(doc != NULL) + bson_free(doc); + return NULL; +} + +/* Return a BSON variant of json, which must be a json_type_object */ +static bson * +BSONFromJSONObject(struct json_object *json) +{ + bson *doc = NULL; + struct json_object_iter it; + + doc = bson_new(); + if(doc == NULL) + goto error; + + json_object_object_foreachC(json, it) { + if (BSONAppendJSONObject(doc, it.key, it.val) == FALSE) + goto error; + } + + if(bson_finish(doc) == FALSE) + goto error; + + return doc; + +error: + if(doc != NULL) + bson_free(doc); + return NULL; +} + +/* Return a BSON document based on user's JSON string. */ +static bson * +BSONFromJSONString(instanceData *pData, const char *json_string) +{ + size_t json_string_len; + struct json_object *json; + bson *doc = NULL; + const char *error_message; + + json_tokener_reset(pData->json_tokener); + + json_string_len = strlen(json_string); + json = json_tokener_parse_ex(pData->json_tokener, + json_string, json_string_len); + error_message = NULL; + if(json == NULL) { + enum json_tokener_error err; + + err = pData->json_tokener->err; + if(err != json_tokener_continue) + error_message = json_tokener_errors[err]; + else + error_message = "Unterminated input"; + } else if((size_t)pData->json_tokener->char_offset < json_string_len) + error_message = "Extra characters after JSON object"; + else if(!json_object_is_type(json, json_type_object)) + error_message = "JSON value is not an object"; + if(error_message != NULL) { + /* FIXME: is dbgprintf() the correct way to report the error? */ + dbgprintf("ommongodb: Error parsing JSON '%s': %s\n", + json_string, error_message); + goto done; + } + + doc = BSONFromJSONObject(json); + +done: + if(json != NULL) + json_object_put(json); + return doc; +} + BEGINtryResume CODESTARTtryResume if(pData->conn == NULL) { @@ -297,6 +465,8 @@ CODESTARTdoAction if(pData->tplName == NULL) { doc = getDefaultBSON((msg_t*)ppString[0]); + } else { + doc = BSONFromJSONString(pData, (const char *)ppString[0]); } if(doc == NULL) { dbgprintf("ommongodb: error creating BSON doc\n"); @@ -366,12 +536,9 @@ CODESTARTnewActInst if(pData->tplName == NULL) { CHKiRet(OMSRsetEntry(*ppOMSR, 0, NULL, OMSR_TPL_AS_MSG)); } else { - errmsg.LogError(0, RS_RET_LEGA_ACT_NOT_SUPPORTED, - "ommongodb: templates are not supported in this version"); - ABORT_FINALIZE(RS_RET_ERR); - CHKiRet(OMSRsetEntry(*ppOMSR, 0, - (uchar*) strdup((char*) pData->tplName), - OMSR_TPL_AS_ARRAY)); + CHKiRet(OMSRsetEntry(*ppOMSR, 0, ustrdup(pData->tplName), + OMSR_NO_RQD_TPL_OPTS)); + CHKmalloc(pData->json_tokener = json_tokener_new()); } if(pData->db == NULL) -- cgit v1.2.3 From 081f366c576834554823c017ba950d0b48c687d7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 29 Aug 2012 14:05:06 +0200 Subject: adapted Mirek's changes to new JSON passing mode now the complete code (JSON passing & ommongodb) could be tested and passed the module tests made during development --- configure.ac | 3 -- plugins/ommongodb/Makefile.am | 4 +-- plugins/ommongodb/ommongodb.c | 69 +++++++++++++++---------------------------- runtime/rsyslog.h | 1 + 4 files changed, 27 insertions(+), 50 deletions(-) diff --git a/configure.ac b/configure.ac index 0fe664a4..1d7aec58 100644 --- a/configure.ac +++ b/configure.ac @@ -1283,9 +1283,6 @@ if test "x$enable_ommongodb" = "xyes"; then PKG_CHECK_MODULES(LIBMONGO_CLIENT, libmongo-client >= 0.1.4) AC_SUBST(LIBMONGO_CLIENT_CFLAGS) AC_SUBST(LIBMONGO_CLIENT_LIBS) - PKG_CHECK_MODULES([JSON_C], [json]) - AC_SUBST([JSON_CFLAGS]) - AC_SUBST([JSON_LIBS]) fi AM_CONDITIONAL(ENABLE_OMMONGODB, test x$enable_ommongodb = xyes) # end of mongodb code diff --git a/plugins/ommongodb/Makefile.am b/plugins/ommongodb/Makefile.am index 8b13c254..3a05c435 100644 --- a/plugins/ommongodb/Makefile.am +++ b/plugins/ommongodb/Makefile.am @@ -1,7 +1,7 @@ pkglib_LTLIBRARIES = ommongodb.la ommongodb_la_SOURCES = ommongodb.c -ommongodb_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(LIBMONGO_CLIENT_CFLAGS) $(JSON_C_CFLAGS) +ommongodb_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) $(LIBMONGO_CLIENT_CFLAGS) ommongodb_la_LDFLAGS = -module -avoid-version -ommongodb_la_LIBADD = $(LIBMONGO_CLIENT_LIBS) $(JSON_C_LIBS) +ommongodb_la_LIBADD = $(LIBMONGO_CLIENT_LIBS) EXTRA_DIST = diff --git a/plugins/ommongodb/ommongodb.c b/plugins/ommongodb/ommongodb.c index 9a7ca9f7..f2de33df 100644 --- a/plugins/ommongodb/ommongodb.c +++ b/plugins/ommongodb/ommongodb.c @@ -406,48 +406,6 @@ error: return NULL; } -/* Return a BSON document based on user's JSON string. */ -static bson * -BSONFromJSONString(instanceData *pData, const char *json_string) -{ - size_t json_string_len; - struct json_object *json; - bson *doc = NULL; - const char *error_message; - - json_tokener_reset(pData->json_tokener); - - json_string_len = strlen(json_string); - json = json_tokener_parse_ex(pData->json_tokener, - json_string, json_string_len); - error_message = NULL; - if(json == NULL) { - enum json_tokener_error err; - - err = pData->json_tokener->err; - if(err != json_tokener_continue) - error_message = json_tokener_errors[err]; - else - error_message = "Unterminated input"; - } else if((size_t)pData->json_tokener->char_offset < json_string_len) - error_message = "Extra characters after JSON object"; - else if(!json_object_is_type(json, json_type_object)) - error_message = "JSON value is not an object"; - if(error_message != NULL) { - /* FIXME: is dbgprintf() the correct way to report the error? */ - dbgprintf("ommongodb: Error parsing JSON '%s': %s\n", - json_string, error_message); - goto done; - } - - doc = BSONFromJSONObject(json); - -done: - if(json != NULL) - json_object_put(json); - return doc; -} - BEGINtryResume CODESTARTtryResume if(pData->conn == NULL) { @@ -466,7 +424,7 @@ CODESTARTdoAction if(pData->tplName == NULL) { doc = getDefaultBSON((msg_t*)ppString[0]); } else { - doc = BSONFromJSONString(pData, (const char *)ppString[0]); + doc = BSONFromJSONObject((struct json_object *)ppString[0]); } if(doc == NULL) { dbgprintf("ommongodb: error creating BSON doc\n"); @@ -537,7 +495,7 @@ CODESTARTnewActInst CHKiRet(OMSRsetEntry(*ppOMSR, 0, NULL, OMSR_TPL_AS_MSG)); } else { CHKiRet(OMSRsetEntry(*ppOMSR, 0, ustrdup(pData->tplName), - OMSR_NO_RQD_TPL_OPTS)); + OMSR_TPL_AS_JSON)); CHKmalloc(pData->json_tokener = json_tokener_new()); } @@ -590,6 +548,10 @@ CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES ENDqueryEtryPt BEGINmodInit() + rsRetVal localRet; + rsRetVal (*pomsrGetSupportedTplOpts)(unsigned long *pOpts); + unsigned long opts; + int bJSONPassingSupported; CODESTARTmodInit *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr @@ -597,5 +559,22 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(datetime, CORE_COMPONENT)); INITChkCoreFeature(bCoreSupportsBatching, CORE_FEATURE_BATCHING); DBGPRINTF("ommongodb: module compiled with rsyslog version %s.\n", VERSION); - //DBGPRINTF("ommongodb: %susing transactional output interface.\n", bCoreSupportsBatching ? "" : "not "); + + /* check if the rsyslog core supports parameter passing code */ + bJSONPassingSupported = 0; + localRet = pHostQueryEtryPt((uchar*)"OMSRgetSupportedTplOpts", + &pomsrGetSupportedTplOpts); + if(localRet == RS_RET_OK) { + /* found entry point, so let's see if core supports msg passing */ + CHKiRet((*pomsrGetSupportedTplOpts)(&opts)); + if(opts & OMSR_TPL_AS_JSON) + bJSONPassingSupported = 1; + } else if(localRet != RS_RET_ENTRY_POINT_NOT_FOUND) { + ABORT_FINALIZE(localRet); /* Something else went wrong, not acceptable */ + } + if(!bJSONPassingSupported) { + DBGPRINTF("ommongodb: JSON-passing is not supported by rsyslog core, " + "can not continue.\n"); + ABORT_FINALIZE(RS_RET_NO_JSON_PASSING); + } ENDmodInit diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 57e8a05c..928c3ab9 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -380,6 +380,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_DUP_PARAM = -2220, /**< config parameter is given more than once */ RS_RET_MODULE_ALREADY_IN_CONF = -2221, /**< module already in current configuration */ RS_RET_PARAM_NOT_PERMITTED = -2222, /**< legacy parameter no longer permitted (usally already set by v2) */ + RS_RET_NO_JSON_PASSING = -2223, /**< rsyslog core does not support JSON-passing plugin API */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ -- cgit v1.2.3 From a5e51ced933cb73bd3755bffb81aceceb3f0f953 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 29 Aug 2012 14:10:18 +0200 Subject: milestone: ommongodb supports templates & JSON passing API in place --- ChangeLog | 2 ++ plugins/ommongodb/README | 23 ++++++++--------------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/ChangeLog b/ChangeLog index 87beea2c..f4964760 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ --------------------------------------------------------------------------- Version 6.5.1 [devel] 2012-08-?? +- added pure JSON output plugin parameter passing mode +- ommongodb now supports templates - bugfix: imtcp could abort on exit due to invalid free() --------------------------------------------------------------------------- Version 6.5.0 [devel] 2012-08-28 diff --git a/plugins/ommongodb/README b/plugins/ommongodb/README index 7581131a..ad4a8ea2 100644 --- a/plugins/ommongodb/README +++ b/plugins/ommongodb/README @@ -6,20 +6,13 @@ configuration: in your /etc/rsyslog.conf, together with other modules: $ModLoad ommongodb # provides mongodb support +*.* action(type="ommongodb" db="..." collection="..." template="...") -then in your /etc/rsyslog.d (check your distribution way to organize the configuration..) you create a file 10-mongodb.conf with the following content: +Note: if no template is specified, a default schema will be used. That schema +contains proper data types. However, if a template is specified, only strings +are supported. This is a restriction of the rsyslog v6 core engine. This +changed in v7. -*.* action(type="ommongodb" db="..." collection="...") - -Note: currently templates are not supported. Ommongodb will pick a default -schema and use the message object content for that (templateless). - - -TODO -we must ensure that the collection is a capped collection -refactor my code :-) - -email Victor Pereira -twitter twitter.com/vpereira - -part of this doc by Rainer Gerhards +If templates are used, it is suggested to use list-based templates. Constants +can ONLY be inserted with list-based templates, as only these provide the +capability to specify a field name (outname parameter). -- cgit v1.2.3 From d18a93e943b4552890a0e603b9fc7db5a6fd7761 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 29 Aug 2012 16:00:20 +0200 Subject: default outname for $! is now without $! prefix also some type cleanup and simplification --- doc/property_replacer.html | 6 ++++- runtime/msg.c | 4 ++-- template.c | 60 +++++++++++++++++++++++++--------------------- template.h | 3 ++- 4 files changed, 42 insertions(+), 31 deletions(-) diff --git a/doc/property_replacer.html b/doc/property_replacer.html index c6464a3b..943c4f73 100644 --- a/doc/property_replacer.html +++ b/doc/property_replacer.html @@ -345,7 +345,11 @@ Currently, the following options are defined:

        +It is most useful to set, for example, the name for JSON-based fields (like used in ommngodb). For +text-based modules, it is simply ignored. +If not specified, the original property name is used, with the exception of properties starting with +"$!", where that prefix is removed. Note that unnamaned constants are NOT forwarded to output modules +that expect structure (like ommnogodb). To pass constants, an outname must be set. diff --git a/runtime/msg.c b/runtime/msg.c index 6725203c..187f0c22 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -2577,9 +2577,9 @@ jsonField(struct templateEntry *pTpe, uchar **ppRes, unsigned short *pbMustBeFre pSrc = *ppRes; buflen = (*pBufLen == -1) ? ustrlen(pSrc) : *pBufLen; /* we hope we have only few escapes... */ - dst = es_newStr(buflen+es_strlen(pTpe->fieldName)+15); + dst = es_newStr(buflen+pTpe->lenFieldName+15); es_addChar(&dst, '"'); - es_addStr(&dst, pTpe->fieldName); + es_addBuf(&dst, (char*)pTpe->fieldName, pTpe->lenFieldName); es_addBufConstcstr(&dst, "\":\""); CHKiRet(jsonAddVal(pSrc, buflen, &dst)); es_addChar(&dst, '"'); diff --git a/template.c b/template.c index a3d2b8d6..80427350 100644 --- a/template.c +++ b/template.c @@ -279,7 +279,6 @@ finalize_it: rsRetVal tplToJSON(struct template *pTpl, msg_t *pMsg, struct json_object **pjson) { struct templateEntry *pTpe; - char *cstr; size_t propLen; unsigned short bMustBeFreed; uchar *pVal; @@ -304,10 +303,7 @@ rsRetVal tplToJSON(struct template *pTpl, msg_t *pMsg, struct json_object **pjso free(pVal); } } - /* TODO: unify strings, handling currently quite inefficient! */ - cstr = es_str2cstr(pTpe->fieldName, NULL); - json_object_object_add(json, cstr, jsonf); - free(cstr); + json_object_object_add(json, (char*)pTpe->fieldName, jsonf); } *pjson = (iRet == RS_RET_OK) ? json : NULL; @@ -1022,17 +1018,21 @@ static int do_Parameter(unsigned char **pp, struct template *pTpl) /* save field name - if none was given, use the property name instead */ if(pStrField == NULL) { - if((pTpe->fieldName = - es_newStrFromCStr((char*)cstrGetSzStrNoNULL(pStrProp), cstrLen(pStrProp))) == NULL) { - return 1; + if(pTpe->data.field.propid == PROP_CEE) { + /* in CEE case, we remove "$!" from the fieldname - it's just our indicator */ + pTpe->fieldName = ustrdup(cstrGetSzStrNoNULL(pStrProp)+2); + pTpe->lenFieldName = cstrLen(pStrProp)-2; + } else { + pTpe->fieldName = ustrdup(cstrGetSzStrNoNULL(pStrProp)); + pTpe->lenFieldName = cstrLen(pStrProp); } } else { - if((pTpe->fieldName = - es_newStrFromCStr((char*)cstrGetSzStrNoNULL(pStrField), cstrLen(pStrField))) == NULL) { - return 1; - } + pTpe->fieldName = ustrdup(cstrGetSzStrNoNULL(pStrField)); + pTpe->lenFieldName = cstrLen(pStrProp); cstrDestruct(&pStrField); } + if(pTpe->fieldName == NULL) + return 1; cstrDestruct(&pStrProp); @@ -1235,7 +1235,7 @@ createConstantTpe(struct template *pTpl, struct cnfobj *o) es_str_t *value; int i; struct cnfparamvals *pvals; - es_str_t *outname = NULL; + uchar *outname = NULL; DEFiRet; /* pull params */ @@ -1248,7 +1248,7 @@ createConstantTpe(struct template *pTpl, struct cnfobj *o) if(!strcmp(pblkConstant.descr[i].name, "value")) { value = pvals[i].val.d.estr; } else if(!strcmp(pblkConstant.descr[i].name, "outname")) { - outname = es_strdup(pvals[i].val.d.estr); + outname = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); } else { dbgprintf("template:constantTpe: program error, non-handled " "param '%s'\n", pblkConstant.descr[i].name); @@ -1262,6 +1262,8 @@ createConstantTpe(struct template *pTpl, struct cnfobj *o) es_unescapeStr(value); pTpe->eEntryType = CONSTANT; pTpe->fieldName = outname; + if(outname != NULL) + pTpe->lenFieldName = ustrlen(outname); pTpe->data.constant.iLenConstant = es_strlen(value); pTpe->data.constant.pConstant = (uchar*)es_str2cstr(value, NULL); @@ -1274,8 +1276,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) { struct templateEntry *pTpe; cstr_t *name; - es_str_t *estrname; - es_str_t *outname = NULL; + uchar *outname = NULL; int i; int droplastlf = 0; int spifno1stsp = 0; @@ -1304,16 +1305,15 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) if(!pvals[i].bUsed) continue; if(!strcmp(pblkProperty.descr[i].name, "name")) { - estrname = es_strdup(pvals[i].val.d.estr); - /* TODO: unify strings!!! */ rsCStrConstructFromszStr(&name, (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL)); + cstrFinalize(name); } else if(!strcmp(pblkProperty.descr[i].name, "droplastlf")) { droplastlf = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "spifno1stsp")) { spifno1stsp = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "outname")) { - outname = es_strdup(pvals[i].val.d.estr); + outname = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); } else if(!strcmp(pblkProperty.descr[i].name, "position.from")) { frompos = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "position.to")) { @@ -1435,8 +1435,14 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) "param '%s'\n", pblkProperty.descr[i].name); } } - if(outname == NULL) - outname = es_strdup(estrname); + if(outname == NULL) { + uchar *psz = cstrGetSzStrNoNULL(name); + /* we need to drop "$!" prefix, if present */ + if(!strncmp((char*)psz, "$!", 2)) + outname = ustrdup(psz + 2); + else + outname = ustrdup(psz); + } /* sanity check */ if(topos == -1 && frompos != -1) @@ -1460,9 +1466,8 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) CHKiRet(propNameToID(name, &pTpe->data.field.propid)); if(pTpe->data.field.propid == PROP_CEE) { /* in CEE case, we need to preserve the actual property name */ - pTpe->data.field.propName = estrname; - } else { - es_deleteStr(estrname); + pTpe->data.field.propName = es_newStrFromCStr((char*)cstrGetSzStrNoNULL(name)+2, + cstrLen(name)-2); } pTpe->data.field.options.bDropLastLF = droplastlf; pTpe->data.field.options.bSPIffNo1stSP = spifno1stsp; @@ -1506,7 +1511,9 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) pTpe->data.field.options.bSecPathReplace = 1; break; } - pTpe->fieldName = outname; + pTpe->fieldName = ustrdup(outname); + if(outname != NULL) + pTpe->lenFieldName = ustrlen(outname); pTpe->data.field.eDateFormat = datefmt; if(fieldnum != -1) { pTpe->data.field.has_fields = 1; @@ -1807,11 +1814,10 @@ void tplDeleteAll(rsconf_t *conf) } if(pTpeDel->data.field.propName != NULL) es_deleteStr(pTpeDel->data.field.propName); - if(pTpeDel->fieldName != NULL) - es_deleteStr(pTpeDel->fieldName); #endif break; } + free(pTpeDel->fieldName); /*dbgprintf("\n");*/ free(pTpeDel); } diff --git a/template.h b/template.h index 9f6a4c33..a4b5658e 100644 --- a/template.h +++ b/template.h @@ -68,7 +68,8 @@ enum tplRegexType { TPL_REGEX_BRE = 0, /* posix BRE */ struct templateEntry { struct templateEntry *pNext; enum EntryTypes eEntryType; - es_str_t *fieldName; /**< field name to be used for structured output */ + uchar *fieldName; /**< field name to be used for structured output */ + int lenFieldName; union { struct { uchar *pConstant; /* pointer to constant value */ -- cgit v1.2.3 From a73058031f13f46f79a2697519271a854f04c7d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Wed, 29 Aug 2012 16:07:23 +0200 Subject: Add support for optional fields --- doc/property_replacer.html | 4 ++++ template.c | 5 +++++ template.h | 1 + 3 files changed, 10 insertions(+) diff --git a/doc/property_replacer.html b/doc/property_replacer.html index 943c4f73..217b6dc0 100644 --- a/doc/property_replacer.html +++ b/doc/property_replacer.html @@ -714,6 +714,10 @@ Useful for secure pathname generation (with dynafiles). Useful for secure pathname generation (with dynafiles). + + + +
        Outname This field permits to specify a field name for structured-data emitting property replacer options. -If used for a constant a template with line style, unpredictable behaviour can occur.
        CaseConversion
        optional-fieldIn templates that are used for building field lists (in particular, ommongodb), completely remove this field if the corresponding property is not present. Currently implemented only for the $!<name> properties.

        To use multiple options, simply place them one after each other with a comma delmimiting diff --git a/template.c b/template.c index 80427350..bd622285 100644 --- a/template.c +++ b/template.c @@ -663,6 +663,8 @@ static void doOptions(unsigned char **pp, struct templateEntry *pTpe) } else { pTpe->data.field.options.bJSONf = 1; } + } else if(!strcmp((char*)Buf, "optional-field")) { + pTpe->data.field.options.bOptionalField = 1; } else { dbgprintf("Invalid field option '%s' specified - ignored.\n", Buf); } @@ -1988,6 +1990,9 @@ void tplPrintList(rsconf_t *conf) if(pTpe->data.field.options.bJSONf) { dbgprintf("[format as JSON field] "); } + if(pTpe->data.field.options.bOptionalField) { + dbgprintf("[optional field - skip in field template if not present] "); + } if(pTpe->data.field.options.bDropLastLF) { dbgprintf("[drop last LF in msg] "); } diff --git a/template.h b/template.h index a4b5658e..0d083216 100644 --- a/template.h +++ b/template.h @@ -115,6 +115,7 @@ struct templateEntry { unsigned bCSV: 1; /* format field in CSV (RFC 4180) format */ unsigned bJSON: 1; /* format field JSON escaped */ unsigned bJSONf: 1; /* format field JSON *field* (n/v pair) */ + unsigned bOptionalField: 1; /* optional field - skip in field template if not present */ } options; /* options as bit fields */ } field; } data; -- cgit v1.2.3 From a9f80019dc30b54bf0593367c1cccf46e45a43c7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 29 Aug 2012 16:10:54 +0200 Subject: add capability to specify "optional" attribute for list-type templates, too --- template.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/template.c b/template.c index bd622285..475eae75 100644 --- a/template.c +++ b/template.c @@ -85,6 +85,7 @@ static struct cnfparamdescr cnfparamdescrProperty[] = { { "regex.match", eCmdHdlrInt, 0 }, { "regex.submatch", eCmdHdlrInt, 0 }, { "droplastlf", eCmdHdlrBinary, 0 }, + { "optional", eCmdHdlrBinary, 0 }, { "spifno1stsp", eCmdHdlrBinary, 0 } }; static struct cnfparamblk pblkProperty = @@ -1282,6 +1283,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) int i; int droplastlf = 0; int spifno1stsp = 0; + int optional = 0; int frompos = -1; int topos = -1; int fieldnum = -1; @@ -1312,6 +1314,8 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) cstrFinalize(name); } else if(!strcmp(pblkProperty.descr[i].name, "droplastlf")) { droplastlf = pvals[i].val.d.n; + } else if(!strcmp(pblkProperty.descr[i].name, "optional")) { + optional = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "spifno1stsp")) { spifno1stsp = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "outname")) { @@ -1473,6 +1477,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) } pTpe->data.field.options.bDropLastLF = droplastlf; pTpe->data.field.options.bSPIffNo1stSP = spifno1stsp; + pTpe->data.field.options.bOptionalField = optional; pTpe->data.field.eCaseConv = caseconv; switch(formatType) { case F_NONE: -- cgit v1.2.3 From 0426ad7dd27fda6854f7d306e46331387b20947a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 30 Aug 2012 18:56:23 +0200 Subject: switch field default to "mandatory" and implement that mode --- doc/property_replacer.html | 6 ++++-- template.c | 25 ++++++++++++++----------- template.h | 2 +- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/doc/property_replacer.html b/doc/property_replacer.html index 217b6dc0..dc09d33c 100644 --- a/doc/property_replacer.html +++ b/doc/property_replacer.html @@ -715,8 +715,10 @@ Useful for secure pathname generation (with dynafiles). -optional-field -In templates that are used for building field lists (in particular, ommongodb), completely remove this field if the corresponding property is not present. Currently implemented only for the $!<name> properties. +mandatory-field +In templates that are used for building field lists (in particular, ommongodb), include +this field, even if it is empty (or NULL). If not set, the field will be removed from +the output field set if empty. The latter is the default case. diff --git a/template.c b/template.c index 475eae75..27b508c6 100644 --- a/template.c +++ b/template.c @@ -85,7 +85,7 @@ static struct cnfparamdescr cnfparamdescrProperty[] = { { "regex.match", eCmdHdlrInt, 0 }, { "regex.submatch", eCmdHdlrInt, 0 }, { "droplastlf", eCmdHdlrBinary, 0 }, - { "optional", eCmdHdlrBinary, 0 }, + { "mandatory", eCmdHdlrBinary, 0 }, { "spifno1stsp", eCmdHdlrBinary, 0 } }; static struct cnfparamblk pblkProperty = @@ -296,15 +296,18 @@ rsRetVal tplToJSON(struct template *pTpl, msg_t *pMsg, struct json_object **pjso if(pTpe->fieldName == NULL) continue; jsonf = json_object_new_string((char*) pTpe->data.constant.pConstant); + json_object_object_add(json, (char*)pTpe->fieldName, jsonf); } else if(pTpe->eEntryType == FIELD) { pVal = (uchar*) MsgGetProp(pMsg, pTpe, pTpe->data.field.propid, pTpe->data.field.propName, &propLen, &bMustBeFreed); - jsonf = json_object_new_string_len((char*)pVal, propLen); + if(pTpe->data.field.options.bMandatory || propLen > 0) { + jsonf = json_object_new_string_len((char*)pVal, propLen); + json_object_object_add(json, (char*)pTpe->fieldName, jsonf); + } if(bMustBeFreed) { /* json-c makes its own private copy! */ free(pVal); } } - json_object_object_add(json, (char*)pTpe->fieldName, jsonf); } *pjson = (iRet == RS_RET_OK) ? json : NULL; @@ -664,8 +667,8 @@ static void doOptions(unsigned char **pp, struct templateEntry *pTpe) } else { pTpe->data.field.options.bJSONf = 1; } - } else if(!strcmp((char*)Buf, "optional-field")) { - pTpe->data.field.options.bOptionalField = 1; + } else if(!strcmp((char*)Buf, "mandatory-field")) { + pTpe->data.field.options.bMandatory = 1; } else { dbgprintf("Invalid field option '%s' specified - ignored.\n", Buf); } @@ -1283,7 +1286,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) int i; int droplastlf = 0; int spifno1stsp = 0; - int optional = 0; + int mandatory = 0; int frompos = -1; int topos = -1; int fieldnum = -1; @@ -1314,8 +1317,8 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) cstrFinalize(name); } else if(!strcmp(pblkProperty.descr[i].name, "droplastlf")) { droplastlf = pvals[i].val.d.n; - } else if(!strcmp(pblkProperty.descr[i].name, "optional")) { - optional = pvals[i].val.d.n; + } else if(!strcmp(pblkProperty.descr[i].name, "mandatory")) { + mandatory = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "spifno1stsp")) { spifno1stsp = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "outname")) { @@ -1477,7 +1480,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) } pTpe->data.field.options.bDropLastLF = droplastlf; pTpe->data.field.options.bSPIffNo1stSP = spifno1stsp; - pTpe->data.field.options.bOptionalField = optional; + pTpe->data.field.options.bMandatory = mandatory; pTpe->data.field.eCaseConv = caseconv; switch(formatType) { case F_NONE: @@ -1995,8 +1998,8 @@ void tplPrintList(rsconf_t *conf) if(pTpe->data.field.options.bJSONf) { dbgprintf("[format as JSON field] "); } - if(pTpe->data.field.options.bOptionalField) { - dbgprintf("[optional field - skip in field template if not present] "); + if(pTpe->data.field.options.bMandatory) { + dbgprintf("[mandatory field] "); } if(pTpe->data.field.options.bDropLastLF) { dbgprintf("[drop last LF in msg] "); diff --git a/template.h b/template.h index 0d083216..42e262f8 100644 --- a/template.h +++ b/template.h @@ -115,7 +115,7 @@ struct templateEntry { unsigned bCSV: 1; /* format field in CSV (RFC 4180) format */ unsigned bJSON: 1; /* format field JSON escaped */ unsigned bJSONf: 1; /* format field JSON *field* (n/v pair) */ - unsigned bOptionalField: 1; /* optional field - skip in field template if not present */ + unsigned bMandatory: 1; /* mandatory field - emit even if empty */ } options; /* options as bit fields */ } field; } data; -- cgit v1.2.3 From 4bb35f1e94665fbc6de7348ccd619e3a34ec5f08 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 10 Sep 2012 18:40:42 +0200 Subject: Add missing prototype for tplToJSON() --- template.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/template.h b/template.h index 42e262f8..e30f96b4 100644 --- a/template.h +++ b/template.h @@ -30,6 +30,7 @@ #ifndef TEMPLATE_H_INCLUDED #define TEMPLATE_H_INCLUDED 1 +#include #include #include "regexp.h" #include "stringbuf.h" @@ -147,6 +148,7 @@ rsRetVal ExtendBuf(uchar **pBuf, size_t *pLenBuf, size_t iMinSize); */ rsRetVal tplToArray(struct template *pTpl, msg_t *pMsg, uchar*** ppArr); rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar** ppSz, size_t *); +rsRetVal tplToJSON(struct template *pTpl, msg_t *pMsg, struct json_object **); rsRetVal doEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode); rsRetVal templateInit(); -- cgit v1.2.3 From 35f217ce69b6dbcdc16ff36ef02323ab3257d9df Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 12 Sep 2012 12:11:12 +0200 Subject: forward-compatibility patch for $ruleset processing v7 needs a different handling, it's easer in the long term if we introduce this in v6 as well. Non-intrusive change. --- grammar/grammar.y | 2 ++ grammar/lexer.l | 3 +++ 2 files changed, 5 insertions(+) diff --git a/grammar/grammar.y b/grammar/grammar.y index 8371f854..29ff02fe 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -69,6 +69,7 @@ extern int yyerror(char*); %token BEGIN_TPL %token STOP %token LEGACY_ACTION +%token LEGACY_RULESET %token PRIFILT %token PROPFILT %token BSD_TAG_SELECTOR @@ -129,6 +130,7 @@ conf: /* empty (to end recursion) */ | conf obj { cnfDoObj($2); } | conf rule { cnfDoRule($2); } | conf cfsysline { cnfDoCfsysline($2); } + | conf LEGACY_RULESET { cnfDoCfsysline($2); } | conf BSD_TAG_SELECTOR { cnfDoBSDTag($2); } | conf BSD_HOST_SELECTOR { cnfDoBSDHost($2); } obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } diff --git a/grammar/lexer.l b/grammar/lexer.l index c5e7bf7d..0faacf2e 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -192,6 +192,9 @@ int fileno(FILE *stream); if(!strncasecmp(yytext, "$includeconfig ", 14)) { yyless(14); BEGIN INCL; + } else if(!strncasecmp(yytext, "$ruleset ", 9)) { + yylval.s = strdup(yytext); + return LEGACY_RULESET; } else { yylval.s = strdup(yytext); return CFSYSLINE; -- cgit v1.2.3 From 36b9e37896b2ce89494cc354b3d10cb689ec1ee5 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 13 Sep 2012 12:12:33 +0200 Subject: fix ChangeLog got messed-up during merge :-( --- ChangeLog | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 14c9f317..4d7e4e97 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,22 @@ --------------------------------------------------------------------------- -<<<<<<< HEAD Version 6.5.1 [devel] 2012-08-?? - added pure JSON output plugin parameter passing mode - ommongodb now supports templates - bugfix: imtcp could abort on exit due to invalid free() +- bugfix: remove invalid socket option call from imuxsock + Thanks to Cristian Ionescu-Idbohrn and Jonny Törnbom +- bugfix: missing support for escape sequences in RainerScript + only \' was supported. Now the usual set is supported. Note that v5 + used \x as escape where x was any character (e.g. "\n" meant "n" and NOT + LF). This also means there is some incompatibility to v5 for well-know + sequences. Better break it now than later. +- bugfix: remove invalid socket option call from imuxsock + Thanks to Cristian Ionescu-Idbohrn and Jonny Törnbom +- bugfix: missing support for escape sequences in RainerScript + only \' was supported. Now the usual set is supported. Note that v5 + used \x as escape where x was any character (e.g. "\n" meant "n" and NOT + LF). This also means there is some incompatibility to v5 for well-know + sequences. Better break it now than later. --------------------------------------------------------------------------- Version 6.5.0 [devel] 2012-08-28 - imrelp now supports non-cancel thread termination @@ -29,7 +42,7 @@ Version 6.5.0 [devel] 2012-08-28 Thanks to Jérôme Renard for the idea and patches. Note: patches were released under ASL 2.0, see http://bugzilla.adiscon.com/show_bug.cgi?id=353 -======= +--------------------------------------------------------------------------- Version 6.4.2 [V6-STABLE] 2012-09-?? - bugfix: remove invalid socket option call from imuxsock Thanks to Cristian Ionescu-Idbohrn and Jonny Törnbom @@ -38,7 +51,6 @@ Version 6.4.2 [V6-STABLE] 2012-09-?? used \x as escape where x was any character (e.g. "\n" meant "n" and NOT LF). This also means there is some incompatibility to v5 for well-know sequences. Better break it now than later. ->>>>>>> 11910c59138332a884ed753401afdd84feeb1832 --------------------------------------------------------------------------- Version 6.4.1 [V6-STABLE] 2012-09-06 - bugfix: multiple main queues with same queue file name were not detected -- cgit v1.2.3 From 0569f2e581529d893cd471f6c33bce13a53e0542 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 17 Sep 2012 08:51:26 +0200 Subject: bugfix: small memory leaks in template() statements these were one-time memory leaks during startup, so they did NOT grow during runtime --- ChangeLog | 3 +++ template.c | 12 +++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4d7e4e97..3a1737d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -17,6 +17,9 @@ Version 6.5.1 [devel] 2012-08-?? used \x as escape where x was any character (e.g. "\n" meant "n" and NOT LF). This also means there is some incompatibility to v5 for well-know sequences. Better break it now than later. +- bugfix: small memory leaks in template() statements + these were one-time memory leaks during startup, so they did NOT grow + during runtime --------------------------------------------------------------------------- Version 6.5.0 [devel] 2012-08-28 - imrelp now supports non-cancel thread termination diff --git a/template.c b/template.c index 27b508c6..83dd6e85 100644 --- a/template.c +++ b/template.c @@ -1240,7 +1240,7 @@ createConstantTpe(struct template *pTpl, struct cnfobj *o) struct templateEntry *pTpe; es_str_t *value; int i; - struct cnfparamvals *pvals; + struct cnfparamvals *pvals = NULL; uchar *outname = NULL; DEFiRet; @@ -1274,6 +1274,8 @@ createConstantTpe(struct template *pTpl, struct cnfobj *o) pTpe->data.constant.pConstant = (uchar*)es_str2cstr(value, NULL); finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &pblkConstant); RETiRet; } @@ -1294,7 +1296,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) int re_matchToUse = 0; int re_submatchToUse = 0; char *re_expr = NULL; - struct cnfparamvals *pvals; + struct cnfparamvals *pvals = NULL; enum {F_NONE, F_CSV, F_JSON, F_JSONF} formatType = F_NONE; enum {CC_NONE, CC_ESCAPE, CC_SPACE, CC_DROP} controlchr = CC_NONE; enum {SP_NONE, SP_DROP, SP_REPLACE} secpath = SP_NONE; @@ -1563,6 +1565,8 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) } finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &pblkProperty); RETiRet; } @@ -1599,7 +1603,7 @@ rsRetVal tplProcessCnf(struct cnfobj *o) { struct template *pTpl = NULL; - struct cnfparamvals *pvals; + struct cnfparamvals *pvals = NULL; int lenName; char *name = NULL; uchar *tplStr = NULL; @@ -1746,6 +1750,8 @@ tplProcessCnf(struct cnfobj *o) pTpl->optFormatEscape = JSON_ESCAPE; finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &pblk); if(iRet != RS_RET_OK) { if(pTpl != NULL) { /* we simply make the template defunct in this case by setting -- cgit v1.2.3 From 76300a1342936161d1c82ab39e98193dcc00307d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 17 Sep 2012 08:58:29 +0200 Subject: Fix other small memory leaks in template() processing --- template.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/template.c b/template.c index 83dd6e85..06306115 100644 --- a/template.c +++ b/template.c @@ -1283,7 +1283,7 @@ static rsRetVal createPropertyTpe(struct template *pTpl, struct cnfobj *o) { struct templateEntry *pTpe; - cstr_t *name; + cstr_t *name = NULL; uchar *outname = NULL; int i; int droplastlf = 0; @@ -1314,9 +1314,10 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) if(!pvals[i].bUsed) continue; if(!strcmp(pblkProperty.descr[i].name, "name")) { - rsCStrConstructFromszStr(&name, - (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL)); + uchar *tmpstr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + rsCStrConstructFromszStr(&name, tmpstr); cstrFinalize(name); + free(tmpstr); } else if(!strcmp(pblkProperty.descr[i].name, "droplastlf")) { droplastlf = pvals[i].val.d.n; } else if(!strcmp(pblkProperty.descr[i].name, "mandatory")) { @@ -1523,7 +1524,7 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) pTpe->data.field.options.bSecPathReplace = 1; break; } - pTpe->fieldName = ustrdup(outname); + pTpe->fieldName = outname; if(outname != NULL) pTpe->lenFieldName = ustrlen(outname); pTpe->data.field.eDateFormat = datefmt; @@ -1567,6 +1568,8 @@ createPropertyTpe(struct template *pTpl, struct cnfobj *o) finalize_it: if(pvals != NULL) cnfparamvalsDestruct(pvals, &pblkProperty); + if(name != NULL) + rsCStrDestruct(&name); RETiRet; } -- cgit v1.2.3 From 0a331d59cabba8294bb755597d664b8e2bd780bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= Date: Mon, 3 Sep 2012 19:22:18 +0200 Subject: Free configuration objects after use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Miloslav Trmač --- grammar/rainerscript.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index f4896da8..5e6e492d 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -139,7 +139,7 @@ objlstDestruct(struct objlst *lst) while(lst != NULL) { toDel = lst; lst = lst->next; - // TODO: delete object + cnfobjDestruct(toDel->obj); free(toDel); } } @@ -648,6 +648,7 @@ cnfobjDestruct(struct cnfobj *o) { if(o != NULL) { nvlstDestruct(o->nvlst); + objlstDestruct(o->subobjs); free(o); } } -- cgit v1.2.3 From 911e2ec374d9911804eebf4765911654610384a0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 20 Sep 2012 07:43:04 +0200 Subject: doc: add new functions to RainerScript function list --- doc/rainerscript.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/rainerscript.html b/doc/rainerscript.html index 63a79040..fcc2674d 100644 --- a/doc/rainerscript.html +++ b/doc/rainerscript.html @@ -58,6 +58,9 @@ recommended. variable, if it exists. Returns an empty string if it does not exist.

      • strlen(str) - returns the length of the provided string
      • tolower(str) - converts the provided string into lowercase +
      • cstr(expr) - converts expr to a string value +
      • cnum(expr) - converts expr to a number (integer) +
      • re_match(expr, re) - returns 1, if expr matches re, 0 otherwise

      The following example can be used to build a dynamic filter based on some environment variable: @@ -69,7 +72,7 @@ if $msg contains getenv('TRIGGERVAR') then /path/to/errfile

      This documentation is part of the rsyslog project.
      -Copyright © 2008, 2009 by Rainer Gerhards and +Copyright © 2008-2012 by Rainer Gerhards and Adiscon. Released under the GNU GPL version 3 or higher.

      -- cgit v1.2.3 From 0b7d60132026fea49383eac57fa732f974934371 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 20 Sep 2012 08:02:51 +0200 Subject: bugfix: small memory leak in imdiag This does not have any practical problems associated with it, EXCECPT that it caused almost all valgrind testbench tests to fail. --- plugins/imdiag/imdiag.c | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c index 6ea615a1..09742537 100644 --- a/plugins/imdiag/imdiag.c +++ b/plugins/imdiag/imdiag.c @@ -390,6 +390,7 @@ finalize_it: if(pOurTcpsrv != NULL) tcpsrv.Destruct(&pOurTcpsrv); } + free(pNewVal); RETiRet; } -- cgit v1.2.3 From bbfb5662dae6c863e1022153b765046cd17b088b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 20 Sep 2012 08:17:58 +0200 Subject: testbench: do not run tests requiring root privs if non-root --- tests/sndrcv_omudpspoof.sh | 4 ++++ tests/sndrcv_omudpspoof_nonstdpt.sh | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tests/sndrcv_omudpspoof.sh b/tests/sndrcv_omudpspoof.sh index bb804d93..cb1c2497 100755 --- a/tests/sndrcv_omudpspoof.sh +++ b/tests/sndrcv_omudpspoof.sh @@ -7,4 +7,8 @@ # This file is part of the rsyslog project, released under GPLv3 echo =============================================================================== echo \[sndrcv_omudpspoof.sh\]: testing sending and receiving via omudp +echo This test must be run as root [raw socket access required] +if [ "$EUID" -ne 0 ]; then + exit 77 # Not root, skip this test +fi source $srcdir/sndrcv_drvr.sh sndrcv_omudpspoof 50 diff --git a/tests/sndrcv_omudpspoof_nonstdpt.sh b/tests/sndrcv_omudpspoof_nonstdpt.sh index 6aeb1a5f..ddd3eb7e 100755 --- a/tests/sndrcv_omudpspoof_nonstdpt.sh +++ b/tests/sndrcv_omudpspoof_nonstdpt.sh @@ -7,4 +7,8 @@ # This file is part of the rsyslog project, released under GPLv3 echo =============================================================================== echo \[sndrcv_omudpspoof_nonstdpt.sh\]: testing sending and receiving via omudp +echo This test must be run as root [raw socket access required] +if [ "$EUID" -ne 0 ]; then + exit 77 # Not root, skip this test +fi source $srcdir/sndrcv_drvr.sh sndrcv_omudpspoof_nonstdpt 50 -- cgit v1.2.3 From c0e35e864aebef9de367f736e8b73a3f3753c7f9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 20 Sep 2012 08:31:03 +0200 Subject: bugfix: config validation run did not always return correct return state --- ChangeLog | 1 + tools/syslogd.c | 1 + 2 files changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 3e840726..8504f1a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,7 @@ Version 6.5.1 [devel] 2012-08-?? - bugfix: small memory leaks in template() statements these were one-time memory leaks during startup, so they did NOT grow during runtime +- bugfix: config validation run did not always return correct return state --------------------------------------------------------------------------- Version 6.5.0 [devel] 2012-08-28 - imrelp now supports non-cancel thread termination diff --git a/tools/syslogd.c b/tools/syslogd.c index 219b41ab..152c27ae 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -2108,6 +2108,7 @@ finalize_it: } else if(iRet != RS_RET_OK) { fprintf(stderr, "rsyslogd: run failed with error %d (see rsyslog.h " "or try http://www.rsyslog.com/e/%d to learn what that number means)\n", iRet, iRet*-1); + exit(1); } ENDfunc -- cgit v1.2.3 From 73874b369b68a1596510fca90dcc66201a69ac28 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 25 Sep 2012 18:02:00 +0200 Subject: minor cleanup --- runtime/im-helper.h | 1 - 1 file changed, 1 deletion(-) diff --git a/runtime/im-helper.h b/runtime/im-helper.h index 6bbd6d70..5c58dcd8 100644 --- a/runtime/im-helper.h +++ b/runtime/im-helper.h @@ -47,7 +47,6 @@ std_checkRuleset(modConfData_t *modConf, instanceConf_t *inst) if(inst->pszBindRuleset == NULL) FINALIZE; -dbgprintf("ZZZZZ: inst->pszBindRuleset %s\n", inst->pszBindRuleset); localRet = ruleset.GetRuleset(modConf->pConf, &pRuleset, inst->pszBindRuleset); if(localRet == RS_RET_NOT_FOUND) { -- cgit v1.2.3 From b715e86769b9b6d77e9c57e4d0cc70725962cf1f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 26 Sep 2012 12:24:34 +0200 Subject: cleanup --- grammar/grammar.y | 2 -- 1 file changed, 2 deletions(-) diff --git a/grammar/grammar.y b/grammar/grammar.y index 29ff02fe..cdb19c3d 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -157,8 +157,6 @@ scriptfilt: IF expr THEN actlst { $$ = cnfruleNew(CNFFILT_SCRIPT, $4); $$->filt.expr = $2; } block: actlst { $$ = $1; } | block actlst { $2->next = $1; $$ = $2; } - /* v7: | actlst - v7: | block rule */ /* v7 extensions require new rule engine capabilities! */ actlst: act { $$=$1; } | actlst '&' act { $3->next = $1; $$ = $3; } | actlst cfsysline { $$ = cnfactlstAddSysline($1, $2); } -- cgit v1.2.3 From 7c2183ee323dc062b0dde6bac4cd9c5afa4ab369 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 26 Sep 2012 12:25:10 +0200 Subject: input stmt: add core engine plumbing --- runtime/module-template.h | 28 +++++++++++++++++++++++ runtime/modules.c | 9 +++++++- runtime/modules.h | 1 + runtime/rsconf.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++ runtime/rsyslog.h | 1 + 5 files changed, 96 insertions(+), 1 deletion(-) diff --git a/runtime/module-template.h b/runtime/module-template.h index 5d32b909..9dd759a5 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -353,6 +353,24 @@ finalize_it:\ } +/* newInpInst() + * This is basically the equivalent to newActInst() for creating input + * module (listener) instances. + */ +#define BEGINnewInpInst \ +static rsRetVal newInpInst(struct nvlst *lst)\ +{\ + DEFiRet; + +#define CODESTARTnewInpInst \ + +#define CODE_STD_FINALIZERnewInpInst + +#define ENDnewInpInst \ + RETiRet;\ +} + + /* tryResume() * This entry point is called to check if a module can resume operations. This * happens when a module requested that it be suspended. In suspended state, @@ -521,6 +539,16 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\ CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES +/* the following block is to be added for input modules that support the v2 + * config system. The config name is also provided. + */ +#define CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES \ + else if(!strcmp((char*) name, "newInpInst")) {\ + *pEtryPoint = newInpInst;\ + } \ + CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES + + /* the following block is to be added for modules that require * pre priv drop activation support. */ diff --git a/runtime/modules.c b/runtime/modules.c index d3c51e90..c0dd0ffb 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -607,6 +607,12 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"willRun", &pNew->mod.im.willRun)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"afterRun", &pNew->mod.im.afterRun)); pNew->mod.im.bCanRun = 0; + localRet = (*pNew->modQueryEtryPt)((uchar*)"newInpInst", &pNew->mod.im.newInpInst); + if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { + pNew->mod.om.newActInst = NULL; + } else if(localRet != RS_RET_OK) { + ABORT_FINALIZE(localRet); + } break; case eMOD_OUT: CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeInstance", &pNew->freeInstance)); @@ -625,7 +631,8 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ else if(localRet != RS_RET_OK) ABORT_FINALIZE(localRet); - localRet = (*pNew->modQueryEtryPt)((uchar*)"endTransaction", &pNew->mod.om.endTransaction); + localRet = (*pNew->modQueryEtryPt)((uchar*)"endTransaction", + &pNew->mod.om.endTransaction); if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { pNew->mod.om.endTransaction = dummyEndTransaction; } else if(localRet != RS_RET_OK) { diff --git a/runtime/modules.h b/runtime/modules.h index 6a143ae3..51ce1e51 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -131,6 +131,7 @@ struct modInfo_s { /* TODO: remove? */rsRetVal (*willRun)(void); /* check if the current config will be able to run*/ rsRetVal (*runInput)(thrdInfo_t*); /* function to gather input and submit to queue */ rsRetVal (*afterRun)(thrdInfo_t*); /* function to gather input and submit to queue */ + rsRetVal (*newInpInst)(struct nvlst *lst); int bCanRun; /* cached value of whether willRun() succeeded */ } im; struct {/* data for output modules */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 67a13893..170e0bb1 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -99,6 +99,18 @@ static uchar template_SysklogdFileFormat[] = "\"%TIMESTAMP% %HOSTNAME% %syslogta static uchar template_StdJSONFmt[] = "\"{\\\"message\\\":\\\"%msg:::json%\\\",\\\"fromhost\\\":\\\"%HOSTNAME:::json%\\\",\\\"facility\\\":\\\"%syslogfacility-text%\\\",\\\"priority\\\":\\\"%syslogpriority-text%\\\",\\\"timereported\\\":\\\"%timereported:::date-rfc3339%\\\",\\\"timegenerated\\\":\\\"%timegenerated:::date-rfc3339%\\\"}\""; /* end templates */ +/* tables for interfacing with the v6 config system (as far as we need to) */ +static struct cnfparamdescr inppdescr[] = { + { "name", eCmdHdlrGetWord, 0 }, + { "type", eCmdHdlrString, CNFPARAM_REQUIRED } +}; +static struct cnfparamblk inppblk = + { CNFPARAMBLK_VERSION, + sizeof(inppdescr)/sizeof(struct cnfparamdescr), + inppdescr + }; + +/* forward-definitions */ void cnfDoCfsysline(char *ln); /* Standard-Constructor @@ -373,6 +385,49 @@ finalize_it: return estr; } + +/* Process input() objects */ +rsRetVal +inputProcessCnf(struct cnfobj *o) +{ + struct cnfparamvals *pvals; + modInfo_t *pMod; + uchar *cnfModName = NULL; + void *pModData; + action_t *pAction; + int typeIdx; + DEFiRet; + + pvals = nvlstGetParams(o->nvlst, &inppblk, NULL); + if(pvals == NULL) { + ABORT_FINALIZE(RS_RET_ERR); + } + DBGPRINTF("input param blk after inputProcessCnf:\n"); + cnfparamsPrint(&inppblk, pvals); + typeIdx = cnfparamGetIdx(&inppblk, "type"); + if(pvals[typeIdx].bUsed == 0) { + errmsg.LogError(0, RS_RET_CONF_RQRD_PARAM_MISSING, "input type missing"); + ABORT_FINALIZE(RS_RET_CONF_RQRD_PARAM_MISSING); // TODO: move this into rainerscript handlers + } + cnfModName = (uchar*)es_str2cstr(pvals[typeIdx].val.d.estr, NULL); + if((pMod = module.FindWithCnfName(loadConf, cnfModName, eMOD_IN)) == NULL) { + errmsg.LogError(0, RS_RET_MOD_UNKNOWN, "input module name '%s' is unknown", cnfModName); + ABORT_FINALIZE(RS_RET_MOD_UNKNOWN); + } + if(pMod->mod.im.newInpInst == NULL) { + errmsg.LogError(0, RS_RET_MOD_NO_INPUT_STMT, + "input module '%s' does not support input() statement", cnfModName); + ABORT_FINALIZE(RS_RET_MOD_NO_INPUT_STMT); + } +dbgprintf("DDDD: ready to roll...\n"); + CHKiRet(pMod->mod.im.newInpInst(o->nvlst)); +dbgprintf("DDDD: done calling module entry point\n"); +finalize_it: + free(cnfModName); + cnfparamvalsDestruct(pvals, &inppblk); + RETiRet; +} + /*------------------------------ interface to flex/bison parser ------------------------------*/ extern int yylineno; @@ -416,6 +471,9 @@ void cnfDoObj(struct cnfobj *o) case CNFOBJ_ACTION: actionProcessCnf(o); break; + case CNFOBJ_INPUT: + inputProcessCnf(o); + break; case CNFOBJ_TPL: tplProcessCnf(o); break; diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 928c3ab9..a6e4b100 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -381,6 +381,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_MODULE_ALREADY_IN_CONF = -2221, /**< module already in current configuration */ RS_RET_PARAM_NOT_PERMITTED = -2222, /**< legacy parameter no longer permitted (usally already set by v2) */ RS_RET_NO_JSON_PASSING = -2223, /**< rsyslog core does not support JSON-passing plugin API */ + RS_RET_MOD_NO_INPUT_STMT = -2224, /**< (input) module does not support input() statement */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ -- cgit v1.2.3 From 90849d36eee2928fcbc9971aa7b38cc8f8587178 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 26 Sep 2012 14:51:57 +0200 Subject: Implement input() support in imuxsock --- plugins/imuxsock/imuxsock.c | 129 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 119 insertions(+), 10 deletions(-) diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index eb3011b2..29cc19f5 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -249,10 +249,30 @@ static struct cnfparamblk modpblk = modpdescr }; +/* input instance parameters */ +static struct cnfparamdescr inppdescr[] = { + { "socket", eCmdHdlrString, CNFPARAM_REQUIRED }, /* legacy: addunixlistensocket */ + { "createpath", eCmdHdlrBinary, 0 }, + { "parsetrusted", eCmdHdlrBinary, 0 }, + { "hostname", eCmdHdlrString, 0 }, + { "ignoretimestamp", eCmdHdlrBinary, 0 }, + { "flowcontrol", eCmdHdlrBinary, 0 }, + { "usesystimestamp", eCmdHdlrBinary, 0 }, + { "annotate", eCmdHdlrBinary, 0 }, + { "usepidfromsystem", eCmdHdlrBinary, 0 }, + { "ratelimit.interval", eCmdHdlrInt, 0 }, + { "ratelimit.burst", eCmdHdlrInt, 0 }, + { "ratelimit.severity", eCmdHdlrInt, 0 } +}; +static struct cnfparamblk inppblk = + { CNFPARAMBLK_VERSION, + sizeof(inppdescr)/sizeof(struct cnfparamdescr), + inppdescr + }; + /* we do not use this, because we do not bind to a ruleset so far * enable when this is changed: #include "im-helper.h" */ /* must be included AFTER the type definitions! */ - static void initRatelimitState(struct rs_ratelimit_state *rs, unsigned short interval, unsigned short burst) { @@ -321,6 +341,43 @@ finalize_it: } +/* create input instance, set default paramters, and + * add it to the list of instances. + */ +static rsRetVal +createInstance(instanceConf_t **pinst) +{ + instanceConf_t *inst; + DEFiRet; + CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + inst->sockName = NULL; + inst->pLogHostName = NULL; + inst->ratelimitInterval = DFLT_ratelimitInterval; + inst->ratelimitBurst = DFLT_ratelimitSeverity; + inst->ratelimitSeverity = DFLT_ratelimitSeverity; + inst->bUseFlowCtl = 0; + inst->bIgnoreTimestamp = 1; + inst->bCreatePath = DFLT_bCreatePath; + inst->bUseSysTimeStamp = 1; + inst->bWritePid = 0; + inst->bAnnotate = 0; + inst->bParseTrusted = 0; + inst->next = NULL; + + /* node created, let's add to config */ + if(loadModConf->tail == NULL) { + loadModConf->tail = loadModConf->root = inst; + } else { + loadModConf->tail->next = inst; + loadModConf->tail = inst; + } + + *pinst = inst; +finalize_it: + RETiRet; +} + + /* This function is called when a new listen socket instace shall be added to * the current config object via the legacy config system. It just shuffles * all parameters to the listener in-memory instance. @@ -339,7 +396,7 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) ABORT_FINALIZE(RS_RET_SOCKNAME_MISSING); } - CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + CHKiRet(createInstance(&inst)); inst->sockName = pNewVal; inst->ratelimitInterval = cs.ratelimitInterval; inst->pLogHostName = cs.pLogHostName; @@ -354,14 +411,6 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) inst->bParseTrusted = cs.bParseTrusted; inst->next = NULL; - /* node created, let's add to config */ - if(loadModConf->tail == NULL) { - loadModConf->tail = loadModConf->root = inst; - } else { - loadModConf->tail->next = inst; - loadModConf->tail = inst; - } - /* some legacy conf processing */ free(cs.pLogHostName); /* reset hostname for next socket */ cs.pLogHostName = NULL; @@ -1206,6 +1255,65 @@ finalize_it: ENDsetModCnf +BEGINnewInpInst + struct cnfparamvals *pvals; + instanceConf_t *inst; + int i; +CODESTARTnewInpInst + DBGPRINTF("newInpInst (imuxsock)\n"); + + pvals = nvlstGetParams(lst, &inppblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, + "imuxsock: required parameter are missing\n"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("input param blk in imuxsock:\n"); + cnfparamsPrint(&inppblk, pvals); + } + + CHKiRet(createInstance(&inst)); + + for(i = 0 ; i < inppblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(inppblk.descr[i].name, "socket")) { + inst->sockName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(modpblk.descr[i].name, "createpath")) { + inst->bCreatePath = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "parsetrusted")) { + inst->bParseTrusted = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "hostname")) { + inst->pLogHostName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(modpblk.descr[i].name, "ignoretimestamp")) { + inst->bIgnoreTimestamp = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "flowcontrol")) { + inst->bUseFlowCtl = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "usesystimestamp")) { + inst->bUseSysTimeStamp = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "annotate")) { + inst->bAnnotate = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "usepidfromsystem")) { + inst->bWritePid = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "ratelimit.interval")) { + inst->ratelimitInterval = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "ratelimit.burst")) { + inst->ratelimitBurst = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "ratelimit.severity")) { + inst->ratelimitSeverity = (int) pvals[i].val.d.n; + } else { + dbgprintf("imuxsock: program error, non-handled " + "param '%s'\n", inppblk.descr[i].name); + } + } +finalize_it: +CODE_STD_FINALIZERnewInpInst + cnfparamvalsDestruct(pvals, &inppblk); +ENDnewInpInst + + BEGINendCnfLoad CODESTARTendCnfLoad if(!loadModConf->configSetViaV2Method) { @@ -1395,6 +1503,7 @@ CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES +CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From 62eee485a7b1ec6034e22d2cd60a0c13abb0ad54 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 26 Sep 2012 15:21:53 +0200 Subject: cleanup --- runtime/rsconf.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 170e0bb1..9d5bb135 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -101,7 +101,6 @@ static uchar template_StdJSONFmt[] = "\"{\\\"message\\\":\\\"%msg:::json%\\\",\\ /* tables for interfacing with the v6 config system (as far as we need to) */ static struct cnfparamdescr inppdescr[] = { - { "name", eCmdHdlrGetWord, 0 }, { "type", eCmdHdlrString, CNFPARAM_REQUIRED } }; static struct cnfparamblk inppblk = @@ -393,8 +392,6 @@ inputProcessCnf(struct cnfobj *o) struct cnfparamvals *pvals; modInfo_t *pMod; uchar *cnfModName = NULL; - void *pModData; - action_t *pAction; int typeIdx; DEFiRet; -- cgit v1.2.3 From da01473c60459773170a9405385f5bfde31eca9f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 26 Sep 2012 15:21:59 +0200 Subject: imtcp: implement support for input() --- plugins/imtcp/imtcp.c | 99 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 89 insertions(+), 10 deletions(-) diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index f021307b..5d865945 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -128,6 +128,20 @@ struct modConfData_s { static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ +/* input instance parameters */ +static struct cnfparamdescr inppdescr[] = { + { "port", eCmdHdlrString, CNFPARAM_REQUIRED }, /* legacy: InputTCPServerRun */ + { "name", eCmdHdlrString, 0 }, + { "ruleset", eCmdHdlrString, 0 }, + { "supportOctetCountedFraming", eCmdHdlrBinary, 0 } +}; +static struct cnfparamblk inppblk = + { CNFPARAMBLK_VERSION, + sizeof(inppdescr)/sizeof(struct cnfparamdescr), + inppdescr + }; + + #include "im-helper.h" /* must be included AFTER the type definitions! */ /* callbacks */ @@ -201,6 +215,36 @@ finalize_it: } +/* create input instance, set default paramters, and + * add it to the list of instances. + */ +static rsRetVal +createInstance(instanceConf_t **pinst) +{ + instanceConf_t *inst; + DEFiRet; + CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + inst->next = NULL; + inst->pszBindRuleset = NULL; + inst->pszInputName = NULL; + inst->bSuppOctetFram = 1; + + /* node created, let's add to config */ + if(loadModConf->tail == NULL) { + loadModConf->tail = loadModConf->root = inst; + } else { + loadModConf->tail->next = inst; + loadModConf->tail = inst; + } + + *pinst = inst; +finalize_it: + RETiRet; +} + + + + /* This function is called when a new listener instace shall be added to * the current config object via the legacy config system. It just shuffles * all parameters to the listener in-memory instance. @@ -211,7 +255,7 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) instanceConf_t *inst; DEFiRet; - CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + CHKiRet(createInstance(&inst)); CHKmalloc(inst->pszBindPort = ustrdup((pNewVal == NULL || *pNewVal == '\0') ? (uchar*) "10514" : pNewVal)); @@ -226,15 +270,6 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) CHKmalloc(inst->pszInputName = ustrdup(cs.pszInputName)); } inst->bSuppOctetFram = cs.bSuppOctetFram; - inst->next = NULL; - - /* node created, let's add to config */ - if(loadModConf->tail == NULL) { - loadModConf->tail = loadModConf->root = inst; - } else { - loadModConf->tail->next = inst; - loadModConf->tail = inst; - } finalize_it: free(pNewVal); @@ -288,6 +323,49 @@ finalize_it: } +BEGINnewInpInst + struct cnfparamvals *pvals; + instanceConf_t *inst; + int i; +CODESTARTnewInpInst + DBGPRINTF("newInpInst (imtcp)\n"); + + pvals = nvlstGetParams(lst, &inppblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, + "imtcp: required parameter are missing\n"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("input param blk in imtcp:\n"); + cnfparamsPrint(&inppblk, pvals); + } + + CHKiRet(createInstance(&inst)); + + for(i = 0 ; i < inppblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(inppblk.descr[i].name, "port")) { + inst->pszBindPort = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "name")) { + inst->pszInputName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "ruleset")) { + inst->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "supportOctetCountedFraming")) { + inst->bSuppOctetFram = (int) pvals[i].val.d.n; + } else { + dbgprintf("imtcp: program error, non-handled " + "param '%s'\n", inppblk.descr[i].name); + } + } +finalize_it: +CODE_STD_FINALIZERnewInpInst + cnfparamvalsDestruct(pvals, &inppblk); +ENDnewInpInst + + BEGINbeginCnfLoad CODESTARTbeginCnfLoad loadModConf = pModConf; @@ -451,6 +529,7 @@ CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES +CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From f22cb74085d29bcc8b02ca45b118b60a0c043aca Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 26 Sep 2012 16:08:02 +0200 Subject: cleanup --- runtime/rsconf.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 9d5bb135..e7ff0899 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -416,9 +416,7 @@ inputProcessCnf(struct cnfobj *o) "input module '%s' does not support input() statement", cnfModName); ABORT_FINALIZE(RS_RET_MOD_NO_INPUT_STMT); } -dbgprintf("DDDD: ready to roll...\n"); CHKiRet(pMod->mod.im.newInpInst(o->nvlst)); -dbgprintf("DDDD: done calling module entry point\n"); finalize_it: free(cnfModName); cnfparamvalsDestruct(pvals, &inppblk); -- cgit v1.2.3 From 7366f115aeaca7b7ae4e777f4da86dca42c3dba4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 26 Sep 2012 16:08:19 +0200 Subject: imptcp: implement support for input() --- plugins/imptcp/imptcp.c | 133 +++++++++++++++++++++++++++++++++++++++++++----- plugins/imtcp/imtcp.c | 1 - 2 files changed, 119 insertions(+), 15 deletions(-) diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index aa1ad81e..ec0bc6bd 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -132,6 +132,26 @@ struct modConfData_s { static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ +/* input instance parameters */ +static struct cnfparamdescr inppdescr[] = { + { "port", eCmdHdlrString, CNFPARAM_REQUIRED }, /* legacy: InputTCPServerRun */ + { "address", eCmdHdlrString, 0 }, + { "name", eCmdHdlrString, 0 }, + { "ruleset", eCmdHdlrString, 0 }, + { "supportoctetcountedframing", eCmdHdlrBinary, 0 }, + { "notifyonconnectionclose", eCmdHdlrBinary, 0 }, + { "keepalive", eCmdHdlrBinary, 0 }, + { "keepalive.probes", eCmdHdlrInt, 0 }, + { "keepalive.time", eCmdHdlrInt, 0 }, + { "keepalive.interval", eCmdHdlrInt, 0 }, + { "addtlframedelimiter", eCmdHdlrInt, 0 }, +}; +static struct cnfparamblk inppblk = + { CNFPARAMBLK_VERSION, + sizeof(inppdescr)/sizeof(struct cnfparamdescr), + inppdescr + }; + #include "im-helper.h" /* must be included AFTER the type definitions! */ /* data elements describing our running config */ typedef struct ptcpsrv_s ptcpsrv_t; @@ -379,7 +399,7 @@ startupSrv(ptcpsrv_t *pSrv) #endif ) { /* TODO: check if *we* bound the socket - else we *have* an error! */ - DBGPRINTF("error %d while binding tcp socket", errno); + DBGPRINTF("error %d while binding tcp socket\n", errno); close(sock); sock = -1; continue; @@ -986,7 +1006,45 @@ closeSess(ptcpsess_t *pSess) destructSess(pSess); finalize_it: - DBGPRINTF("imtcp: session on socket %d closed with iRet %d.\n", sock, iRet); + DBGPRINTF("imptcp: session on socket %d closed with iRet %d.\n", sock, iRet); + RETiRet; +} + + +/* create input instance, set default paramters, and + * add it to the list of instances. + */ +static rsRetVal +createInstance(instanceConf_t **pinst) +{ + instanceConf_t *inst; + DEFiRet; + CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + inst->next = NULL; + + inst->pszBindPort = NULL; + inst->pszBindAddr = NULL; + inst->pszBindRuleset = NULL; + inst->pszInputName = NULL; + inst->bSuppOctetFram = 1; + inst->bKeepAlive = 0; + inst->iKeepAliveIntvl = 0; + inst->iKeepAliveProbes = 0; + inst->iKeepAliveTime = 0; + inst->bEmitMsgOnClose = 0; + inst->iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; + inst->pBindRuleset = NULL; + + /* node created, let's add to config */ + if(loadModConf->tail == NULL) { + loadModConf->tail = loadModConf->root = inst; + } else { + loadModConf->tail->next = inst; + loadModConf->tail = inst; + } + + *pinst = inst; +finalize_it: RETiRet; } @@ -1000,7 +1058,7 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) instanceConf_t *inst; DEFiRet; - CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + CHKiRet(createInstance(&inst)); if(pNewVal == NULL || *pNewVal == '\0') { errmsg.LogError(0, NO_ERRCODE, "imptcp: port number must be specified, listener ignored"); } @@ -1032,15 +1090,6 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) inst->iKeepAliveTime = cs.iKeepAliveTime; inst->bEmitMsgOnClose = cs.bEmitMsgOnClose; inst->iAddtlFrameDelim = cs.iAddtlFrameDelim; - inst->next = NULL; - - /* node created, let's add to config */ - if(loadModConf->tail == NULL) { - loadModConf->tail = loadModConf->root = inst; - } else { - loadModConf->tail->next = inst; - loadModConf->tail = inst; - } finalize_it: free(pNewVal); @@ -1213,7 +1262,7 @@ sessActivity(ptcpsess_t *pSess) if(lenRcv > 0) { /* have data, process it */ - DBGPRINTF("imtcp: data(%d) on socket %d: %s\n", lenBuf, pSess->sock, rcvBuf); + DBGPRINTF("imptcp: data(%d) on socket %d: %s\n", lenBuf, pSess->sock, rcvBuf); CHKiRet(DataRcvd(pSess, rcvBuf, lenRcv)); } else if (lenRcv == 0) { /* session was closed, do clean-up */ @@ -1229,7 +1278,7 @@ sessActivity(ptcpsess_t *pSess) } else { if(errno == EAGAIN || errno == EWOULDBLOCK) break; - DBGPRINTF("imtcp: error on session socket %d - closed.\n", pSess->sock); + DBGPRINTF("imptcp: error on session socket %d - closed.\n", pSess->sock); closeSess(pSess); /* try clean-up by dropping session */ break; } @@ -1345,6 +1394,61 @@ wrkr(void *myself) } +BEGINnewInpInst + struct cnfparamvals *pvals; + instanceConf_t *inst; + int i; +CODESTARTnewInpInst + DBGPRINTF("newInpInst (imptcp)\n"); + + pvals = nvlstGetParams(lst, &inppblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, + "imptcp: required parameter are missing\n"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("input param blk in imptcp:\n"); + cnfparamsPrint(&inppblk, pvals); + } + + CHKiRet(createInstance(&inst)); + + for(i = 0 ; i < inppblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(inppblk.descr[i].name, "port")) { + inst->pszBindPort = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "name")) { + inst->pszInputName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "ruleset")) { + inst->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "supportOctetCountedFraming")) { + inst->bSuppOctetFram = (int) pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "keepalive")) { + inst->bKeepAlive = (int) pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "keepalive.probes")) { + inst->iKeepAliveProbes = (int) pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "keepalive.time")) { + inst->iKeepAliveTime = (int) pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "keepalive.interval")) { + inst->iKeepAliveIntvl = (int) pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "addtlframedelimiter")) { + inst->iAddtlFrameDelim = (int) pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "notifyonconnectionclose")) { + inst->bEmitMsgOnClose = (int) pvals[i].val.d.n; + } else { + dbgprintf("imptcp: program error, non-handled " + "param '%s'\n", inppblk.descr[i].name); + } + } +finalize_it: +CODE_STD_FINALIZERnewInpInst + cnfparamvalsDestruct(pvals, &inppblk); +ENDnewInpInst + + BEGINbeginCnfLoad CODESTARTbeginCnfLoad loadModConf = pModConf; @@ -1568,6 +1672,7 @@ CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES +CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index 5d865945..a00d4ebe 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -141,7 +141,6 @@ static struct cnfparamblk inppblk = inppdescr }; - #include "im-helper.h" /* must be included AFTER the type definitions! */ /* callbacks */ -- cgit v1.2.3 From 203ce7a749f6e93eca05c02881402381f21fe6ed Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 26 Sep 2012 16:23:03 +0200 Subject: imudp: implement support for input() --- plugins/imptcp/imptcp.c | 2 ++ plugins/imudp/imudp.c | 91 ++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index ec0bc6bd..9992ee20 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -1420,6 +1420,8 @@ CODESTARTnewInpInst continue; if(!strcmp(inppblk.descr[i].name, "port")) { inst->pszBindPort = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "address")) { + inst->pszBindAddr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); } else if(!strcmp(inppblk.descr[i].name, "name")) { inst->pszInputName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); } else if(!strcmp(inppblk.descr[i].name, "ruleset")) { diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 9c92ddde..2daf9678 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -136,9 +136,48 @@ static struct cnfparamblk modpblk = modpdescr }; +/* input instance parameters */ +static struct cnfparamdescr inppdescr[] = { + { "port", eCmdHdlrString, CNFPARAM_REQUIRED }, /* legacy: InputTCPServerRun */ + { "address", eCmdHdlrString, 0 }, + { "ruleset", eCmdHdlrString, 0 } +}; +static struct cnfparamblk inppblk = + { CNFPARAMBLK_VERSION, + sizeof(inppdescr)/sizeof(struct cnfparamdescr), + inppdescr + }; + #include "im-helper.h" /* must be included AFTER the type definitions! */ +/* create input instance, set default paramters, and + * add it to the list of instances. + */ +static rsRetVal +createInstance(instanceConf_t **pinst) +{ + instanceConf_t *inst; + DEFiRet; + CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + inst->next = NULL; + inst->pBindRuleset = NULL; + + inst->pszBindPort = NULL; + inst->pszBindAddr = NULL; + inst->pszBindRuleset = NULL; + /* node created, let's add to config */ + if(loadModConf->tail == NULL) { + loadModConf->tail = loadModConf->root = inst; + } else { + loadModConf->tail->next = inst; + loadModConf->tail = inst; + } + + *pinst = inst; +finalize_it: + RETiRet; +} /* This function is called when a new listener instace shall be added to * the current config object via the legacy config system. It just shuffles @@ -150,7 +189,7 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) instanceConf_t *inst; DEFiRet; - CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + CHKiRet(createInstance(&inst)); CHKmalloc(inst->pszBindPort = ustrdup((pNewVal == NULL || *pNewVal == '\0') ? (uchar*) "514" : pNewVal)); if((cs.pszBindAddr == NULL) || (cs.pszBindAddr[0] == '\0')) { @@ -166,14 +205,6 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) inst->pBindRuleset = NULL; inst->next = NULL; - /* node created, let's add to config */ - if(loadModConf->tail == NULL) { - loadModConf->tail = loadModConf->root = inst; - } else { - loadModConf->tail->next = inst; - loadModConf->tail = inst; - } - finalize_it: free(pNewVal); RETiRet; @@ -635,6 +666,47 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) #endif /* #if HAVE_EPOLL_CREATE1 */ +BEGINnewInpInst + struct cnfparamvals *pvals; + instanceConf_t *inst; + int i; +CODESTARTnewInpInst + DBGPRINTF("newInpInst (imudp)\n"); + + pvals = nvlstGetParams(lst, &inppblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, + "imudp: required parameter are missing\n"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("input param blk in imudp:\n"); + cnfparamsPrint(&inppblk, pvals); + } + + CHKiRet(createInstance(&inst)); + + for(i = 0 ; i < inppblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(inppblk.descr[i].name, "port")) { + inst->pszBindPort = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "address")) { + inst->pszBindAddr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "ruleset")) { + inst->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + dbgprintf("imudp: program error, non-handled " + "param '%s'\n", inppblk.descr[i].name); + } + } +finalize_it: +CODE_STD_FINALIZERnewInpInst + cnfparamvalsDestruct(pvals, &inppblk); +ENDnewInpInst + + BEGINbeginCnfLoad CODESTARTbeginCnfLoad loadModConf = pModConf; @@ -839,6 +911,7 @@ CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES +CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From e1b9a3a25b4cc330faabe4ec7b4b010ba2fcf697 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 26 Sep 2012 17:02:04 +0200 Subject: imrelp: implement support for input() --- plugins/imrelp/imrelp.c | 86 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 76 insertions(+), 10 deletions(-) diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c index a3209fbe..fe987a50 100644 --- a/plugins/imrelp/imrelp.c +++ b/plugins/imrelp/imrelp.c @@ -88,6 +88,17 @@ struct modConfData_s { static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ +/* input instance parameters */ +static struct cnfparamdescr inppdescr[] = { + { "port", eCmdHdlrString, CNFPARAM_REQUIRED } +}; +static struct cnfparamblk inppblk = + { CNFPARAMBLK_VERSION, + sizeof(inppdescr)/sizeof(struct cnfparamdescr), + inppdescr + }; + + /* ------------------------------ callbacks ------------------------------ */ @@ -114,6 +125,32 @@ onSyslogRcv(uchar *pHostname, uchar *pIP, uchar *pMsg, size_t lenMsg) /* ------------------------------ end callbacks ------------------------------ */ +/* create input instance, set default paramters, and + * add it to the list of instances. + */ +static rsRetVal +createInstance(instanceConf_t **pinst) +{ + instanceConf_t *inst; + DEFiRet; + CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + inst->next = NULL; + + inst->pszBindPort = NULL; + + /* node created, let's add to config */ + if(loadModConf->tail == NULL) { + loadModConf->tail = loadModConf->root = inst; + } else { + loadModConf->tail->next = inst; + loadModConf->tail = inst; + } + + *pinst = inst; +finalize_it: + RETiRet; +} + /* modified to work for module, not instance (as usual) */ static inline void @@ -134,21 +171,12 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) instanceConf_t *inst; DEFiRet; - CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + CHKiRet(createInstance(&inst)); if(pNewVal == NULL || *pNewVal == '\0') { errmsg.LogError(0, NO_ERRCODE, "imrelp: port number must be specified, listener ignored"); } inst->pszBindPort = pNewVal; - inst->next = NULL; - - /* node created, let's add to config */ - if(loadModConf->tail == NULL) { - loadModConf->tail = loadModConf->root = inst; - } else { - loadModConf->tail->next = inst; - loadModConf->tail = inst; - } finalize_it: RETiRet; @@ -176,6 +204,43 @@ finalize_it: } +BEGINnewInpInst + struct cnfparamvals *pvals; + instanceConf_t *inst; + int i; +CODESTARTnewInpInst + DBGPRINTF("newInpInst (imrelp)\n"); + + pvals = nvlstGetParams(lst, &inppblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, + "imrelp: required parameter are missing\n"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("input param blk in imrelp:\n"); + cnfparamsPrint(&inppblk, pvals); + } + + CHKiRet(createInstance(&inst)); + + for(i = 0 ; i < inppblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(inppblk.descr[i].name, "port")) { + inst->pszBindPort = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + dbgprintf("imrelp: program error, non-handled " + "param '%s'\n", inppblk.descr[i].name); + } + } +finalize_it: +CODE_STD_FINALIZERnewInpInst + cnfparamvalsDestruct(pvals, &inppblk); +ENDnewInpInst + + BEGINbeginCnfLoad CODESTARTbeginCnfLoad loadModConf = pModConf; @@ -328,6 +393,7 @@ CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES +CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From 9a1d7044b9d300dd957a046b79629ddd26a76a2c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 26 Sep 2012 19:41:59 +0200 Subject: milestone: port imfile to v6 config system --- plugins/imfile/imfile.c | 408 ++++++++++++++++++++++++++++++++---------------- plugins/imudp/imudp.c | 20 +-- 2 files changed, 279 insertions(+), 149 deletions(-) diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index 440f5991..c2d0db51 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -81,25 +81,48 @@ typedef struct fileInfo_s { multi_submit_t multiSub; } fileInfo_t; +static struct configSettings_s { + uchar *pszFileName; + uchar *pszFileTag; + uchar *pszStateFile; + uchar *pszBindRuleset; + int iPollInterval; /* number of seconds to sleep when there was no file activity */ + int iPersistStateInterval; /* how often if state file to be persisted? (default 0->never) */ + int iFacility; /* local0 */ + int iSeverity; /* notice, as of rfc 3164 */ + int readMode; /* mode to use for ReadMultiLine call */ + int maxLinesAtOnce; /* how many lines to process in a row? */ + ruleset_t *pBindRuleset; /* ruleset to bind listener to (use system default if unspecified) */ +} cs; + +struct instanceConf_s { + uchar *pszFileName; + uchar *pszTag; + uchar *pszStateFile; + uchar *pszBindRuleset; + int nMultiSub; + int iPersistStateInterval; + int iFacility; + int iSeverity; + int readMode; + int maxLinesAtOnce; + ruleset_t *pBindRuleset; /* ruleset to bind listener to (use system default if unspecified) */ + struct instanceConf_s *next; +}; + /* forward definitions */ static rsRetVal persistStrmState(fileInfo_t *pInfo); +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); /* config variables */ struct modConfData_s { - EMPTY_STRUCT; + rsconf_t *pConf; /* our overall config object */ + instanceConf_t *root, *tail; + sbool configSetViaV2Method; }; - -static uchar *pszFileName = NULL; -static uchar *pszFileTag = NULL; -static uchar *pszStateFile = NULL; -static int iPollInterval = 10; /* number of seconds to sleep when there was no file activity */ -static int iPersistStateInterval = 0; /* how often if state file to be persisted? (default 0->never) */ -static int iFacility = 128; /* local0 */ -static int iSeverity = 5; /* notice, as of rfc 3164 */ -static int readMode = 0; /* mode to use for ReadMultiLine call */ -static int maxLinesAtOnce = 10240; /* how many lines to process in a row? */ -static ruleset_t *pBindRuleset = NULL; /* ruleset to bind listener to (use system default if unspecified) */ +static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ +static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ static int iFilPtr = 0; /* number of files to be monitored; pointer to next free spot during config */ #define MAX_INPUT_FILES 100 @@ -107,6 +130,8 @@ static fileInfo_t files[MAX_INPUT_FILES]; static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this input */ +#include "im-helper.h" /* must be included AFTER the type definitions! */ + /* enqueue the read file line as a message. The provided string is * not freed - thuis must be done by the caller. */ @@ -268,6 +293,210 @@ finalize_it: #pragma GCC diagnostic warning "-Wempty-body" +/* create input instance, set default paramters, and + * add it to the list of instances. + */ +static rsRetVal +createInstance(instanceConf_t **pinst) +{ + instanceConf_t *inst; + DEFiRet; + CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + inst->next = NULL; + inst->pBindRuleset = NULL; + + inst->pszBindRuleset = NULL; + inst->pszFileName = NULL; + inst->pszTag = NULL; + inst->pszStateFile = NULL; + inst->nMultiSub = NUM_MULTISUB; + inst->iSeverity = 5; + inst->iFacility = 128; + inst->maxLinesAtOnce = 10240; + inst->iPersistStateInterval = 0; + inst->readMode = 0; + + /* node created, let's add to config */ + if(loadModConf->tail == NULL) { + loadModConf->tail = loadModConf->root = inst; + } else { + loadModConf->tail->next = inst; + loadModConf->tail = inst; + } + + *pinst = inst; +finalize_it: + RETiRet; +} + + +/* add a new monitor */ +static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) +{ + instanceConf_t *inst; + DEFiRet; + + if(cs.pszFileName == NULL) { + errmsg.LogError(0, RS_RET_CONFIG_ERROR, "imfile error: no file name given, file monitor can not be created"); + ABORT_FINALIZE(RS_RET_CONFIG_ERROR); + } + if(cs.pszFileTag == NULL) { + errmsg.LogError(0, RS_RET_CONFIG_ERROR, "imfile error: no tag value given , file monitor can not be created"); + ABORT_FINALIZE(RS_RET_CONFIG_ERROR); + } + if(cs.pszStateFile == NULL) { + errmsg.LogError(0, RS_RET_CONFIG_ERROR, "imfile error: not state file name given, file monitor can not be created"); + ABORT_FINALIZE(RS_RET_CONFIG_ERROR); + } + + CHKiRet(createInstance(&inst)); + if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) { + inst->pszBindRuleset = NULL; + } else { + CHKmalloc(inst->pszBindRuleset = ustrdup(cs.pszBindRuleset)); + } + inst->pszFileName = (uchar*) strdup((char*) cs.pszFileName); + inst->pszTag = (uchar*) strdup((char*) cs.pszFileTag); + inst->pszStateFile = (uchar*) strdup((char*) cs.pszStateFile); + inst->nMultiSub = NUM_MULTISUB; + inst->iSeverity = cs.iSeverity; + inst->iFacility = cs.iFacility; + inst->maxLinesAtOnce = cs.maxLinesAtOnce; + inst->iPersistStateInterval = cs.iPersistStateInterval; + inst->readMode = cs.readMode; + + /* reset legacy system */ + cs.iPersistStateInterval = 0; + resetConfigVariables(NULL, NULL); /* values are both dummies */ + +finalize_it: + free(pNewVal); /* we do not need it, but we must free it! */ + RETiRet; +} + + +/* This function is called when a new listener (monitor) shall be added. */ +static inline rsRetVal +addListner(instanceConf_t *inst) +{ + DEFiRet; + fileInfo_t *pThis; + + if(iFilPtr < MAX_INPUT_FILES) { + pThis = &files[iFilPtr]; + //TODO: optimize, save strdup? + pThis->pszFileName = (uchar*) strdup((char*) inst->pszFileName); + pThis->pszTag = (uchar*) strdup((char*) inst->pszTag); + pThis->lenTag = ustrlen(pThis->pszTag); + pThis->pszStateFile = (uchar*) strdup((char*) inst->pszStateFile); + + CHKmalloc(pThis->multiSub.ppMsgs = MALLOC(inst->nMultiSub * sizeof(msg_t*))); + pThis->multiSub.maxElem = inst->nMultiSub; + pThis->multiSub.nElem = 0; + pThis->iSeverity = inst->iSeverity; + pThis->iFacility = inst->iFacility; + pThis->maxLinesAtOnce = inst->maxLinesAtOnce; + pThis->iPersistStateInterval = inst->iPersistStateInterval; + pThis->readMode = inst->readMode; + pThis->pRuleset = inst->pBindRuleset; + pThis->nRecords = 0; + } else { + errmsg.LogError(0, RS_RET_OUT_OF_DESRIPTORS, + "Too many file monitors configured - ignoring %s", + inst->pszFileName); + ABORT_FINALIZE(RS_RET_OUT_OF_DESRIPTORS); + } + ++iFilPtr; /* we got a new file to monitor */ + + resetConfigVariables(NULL, NULL); /* values are both dummies */ +finalize_it: + RETiRet; +} + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + /* init our settings */ + loadModConf->configSetViaV2Method = 0; + /* init legacy config vars */ + cs.pszFileName = NULL; + cs.pszFileTag = NULL; + cs.pszStateFile = NULL; + cs.iPollInterval = 10; + cs.iPersistStateInterval = 0; + cs.iFacility = 128; + cs.iSeverity = 5; + cs.readMode = 0; + cs.maxLinesAtOnce = 10240; + cs.pBindRuleset = NULL; +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad + if(!loadModConf->configSetViaV2Method) { + /* persist module-specific settings from legacy config system */ + } + +//finalize_it: + loadModConf = NULL; /* done loading */ + /* free legacy config vars */ + free(cs.pszFileName); + free(cs.pszFileTag); + free(cs.pszStateFile); +ENDendCnfLoad + + +BEGINcheckCnf + instanceConf_t *inst; +CODESTARTcheckCnf + for(inst = pModConf->root ; inst != NULL ; inst = inst->next) { + std_checkRuleset(pModConf, inst); + } + if(pModConf->root == NULL) { + errmsg.LogError(0, RS_RET_NO_LISTNERS, + "imfile: no files configured to be monitored - " + "no input will be gathered"); + iRet = RS_RET_NO_LISTNERS; + } +ENDcheckCnf + + +/* note: we do access files AFTER we have dropped privileges. This is + * intentional, user must make sure the files have the right permissions. + */ +BEGINactivateCnf + instanceConf_t *inst; +CODESTARTactivateCnf + runModConf = pModConf; + for(inst = runModConf->root ; inst != NULL ; inst = inst->next) { + addListner(inst); + } + /* if we could not set up any listners, there is no point in running... */ + //if(lcnfRoot == NULL) { + if(iFilPtr == 0) { + errmsg.LogError(0, NO_ERRCODE, "imfile: no file monitors could be started, " + "input not activated.\n"); + ABORT_FINALIZE(RS_RET_NO_RUN); + } +finalize_it: +ENDactivateCnf + + +BEGINfreeCnf + instanceConf_t *inst, *del; +CODESTARTfreeCnf + for(inst = pModConf->root ; inst != NULL ; ) { + // free(inst->pszBindPort); + del = inst; + inst = inst->next; + free(del); + } +ENDfreeCnf + + + /* This function is the cancel cleanup handler. It is called when rsyslog decides the * module must be stopped, what most probably happens during shutdown of rsyslogd. When * this function is called, the runInput() function (below) is already terminated - somewhere @@ -328,7 +557,7 @@ CODESTARTrunInput * other valid scenario. So do not remove. -- rgerhards, 2008-02-14 */ if(glbl.GetGlobalInputTermState() == 0) - srSleep(iPollInterval, 10); + srSleep(cs.iPollInterval, 10); } DBGPRINTF("imfile: terminating upon request of rsyslog core\n"); @@ -350,16 +579,6 @@ ENDrunInput */ BEGINwillRun CODESTARTwillRun - /* free config variables we do no longer needed */ - free(pszFileName); - free(pszFileTag); - free(pszStateFile); - - if(iFilPtr == 0) { - errmsg.LogError(0, RS_RET_NO_RUN, "No files configured to be monitored"); - ABORT_FINALIZE(RS_RET_NO_RUN); - } - /* we need to create the inputName property (only once during our lifetime) */ CHKiRet(prop.Construct(&pInputName)); CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imfile"), sizeof("imfile") - 1)); @@ -458,6 +677,7 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt @@ -468,119 +688,37 @@ ENDqueryEtryPt * but in general this is not necessary. Once runInput() has been called, this * function here is never again called. */ -static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +static rsRetVal +resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { DEFiRet; - if(pszFileName != NULL) { - free(pszFileName); - pszFileName = NULL; - } - - if(pszFileTag != NULL) { - free(pszFileTag); - pszFileTag = NULL; - } - - if(pszStateFile != NULL) { - free(pszFileTag); - pszFileTag = NULL; - } - + free(cs.pszFileName); + cs.pszFileName = NULL; + free(cs.pszFileTag); + cs.pszFileTag = NULL; + free(cs.pszFileTag); + cs.pszFileTag = NULL; /* set defaults... */ - iPollInterval = 10; - iFacility = 128; /* local0 */ - iSeverity = 5; /* notice, as of rfc 3164 */ - readMode = 0; - pBindRuleset = NULL; - maxLinesAtOnce = 10240; + cs.iPollInterval = 10; + cs.iFacility = 128; /* local0 */ + cs.iSeverity = 5; /* notice, as of rfc 3164 */ + cs.readMode = 0; + cs.pBindRuleset = NULL; + cs.maxLinesAtOnce = 10240; RETiRet; } - -/* add a new monitor */ -static rsRetVal addMonitor(void __attribute__((unused)) *pVal, uchar *pNewVal) +static inline void +std_checkRuleset_genErrMsg(__attribute__((unused)) modConfData_t *modConf, instanceConf_t *inst) { - DEFiRet; - fileInfo_t *pThis; - - free(pNewVal); /* we do not need it, but we must free it! */ - - if(iFilPtr < MAX_INPUT_FILES) { - pThis = &files[iFilPtr]; - /* TODO: check for strdup() NULL return */ - if(pszFileName == NULL) { - errmsg.LogError(0, RS_RET_CONFIG_ERROR, "imfile error: no file name given, file monitor can not be created"); - ABORT_FINALIZE(RS_RET_CONFIG_ERROR); - } else { - pThis->pszFileName = (uchar*) strdup((char*) pszFileName); - } - - if(pszFileTag == NULL) { - errmsg.LogError(0, RS_RET_CONFIG_ERROR, "imfile error: no tag value given , file monitor can not be created"); - ABORT_FINALIZE(RS_RET_CONFIG_ERROR); - } else { - pThis->pszTag = (uchar*) strdup((char*) pszFileTag); - pThis->lenTag = ustrlen(pThis->pszTag); - } - - if(pszStateFile == NULL) { - errmsg.LogError(0, RS_RET_CONFIG_ERROR, "imfile error: not state file name given, file monitor can not be created"); - ABORT_FINALIZE(RS_RET_CONFIG_ERROR); - } else { - pThis->pszStateFile = (uchar*) strdup((char*) pszStateFile); - } - - CHKmalloc(pThis->multiSub.ppMsgs = MALLOC(NUM_MULTISUB * sizeof(msg_t*))); - pThis->multiSub.maxElem = NUM_MULTISUB; - pThis->multiSub.nElem = 0; - pThis->iSeverity = iSeverity; - pThis->iFacility = iFacility; - pThis->maxLinesAtOnce = maxLinesAtOnce; - pThis->iPersistStateInterval = iPersistStateInterval; - pThis->nRecords = 0; - pThis->readMode = readMode; - pThis->pRuleset = pBindRuleset; - iPersistStateInterval = 0; - } else { - errmsg.LogError(0, RS_RET_OUT_OF_DESRIPTORS, "Too many file monitors configured - ignoring this one"); - ABORT_FINALIZE(RS_RET_OUT_OF_DESRIPTORS); - } - - CHKiRet(resetConfigVariables((uchar*) "dummy", (void*) pThis)); /* values are both dummies */ - -finalize_it: - if(iRet == RS_RET_OK) - ++iFilPtr; /* we got a new file to monitor */ - - RETiRet; + errmsg.LogError(0, NO_ERRCODE, "imfile: ruleset '%s' for %s not found - " + "using default ruleset instead", inst->pszBindRuleset, + inst->pszFileName); } - -/* accept a new ruleset to bind. Checks if it exists and complains, if not */ -static rsRetVal -setRuleset(void __attribute__((unused)) *pVal, uchar *pszName) -{ - ruleset_t *pRuleset; - rsRetVal localRet; - DEFiRet; - - localRet = ruleset.GetRuleset(ourConf, &pRuleset, pszName); - if(localRet == RS_RET_NOT_FOUND) { - errmsg.LogError(0, NO_ERRCODE, "error: ruleset '%s' not found - ignored", pszName); - } - CHKiRet(localRet); - pBindRuleset = pRuleset; - DBGPRINTF("imfile current bind ruleset %p: '%s'\n", pRuleset, pszName); - -finalize_it: - free(pszName); /* no longer needed */ - RETiRet; -} - - /* modInit() is called once the module is loaded. It must perform all module-wide * initialization tasks. There are also a number of housekeeping tasks that the * framework requires. These are handled by the macros. Please note that the @@ -603,28 +741,28 @@ CODEmodInit_QueryRegCFSLineHdlr DBGPRINTF("imfile: version %s initializing\n", VERSION); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilename", 0, eCmdHdlrGetWord, - NULL, &pszFileName, STD_LOADABLE_MODULE_ID)); + NULL, &cs.pszFileName, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfiletag", 0, eCmdHdlrGetWord, - NULL, &pszFileTag, STD_LOADABLE_MODULE_ID)); + NULL, &cs.pszFileTag, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilestatefile", 0, eCmdHdlrGetWord, - NULL, &pszStateFile, STD_LOADABLE_MODULE_ID)); + NULL, &cs.pszStateFile, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfileseverity", 0, eCmdHdlrSeverity, - NULL, &iSeverity, STD_LOADABLE_MODULE_ID)); + NULL, &cs.iSeverity, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilefacility", 0, eCmdHdlrFacility, - NULL, &iFacility, STD_LOADABLE_MODULE_ID)); + NULL, &cs.iFacility, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilepollinterval", 0, eCmdHdlrInt, - NULL, &iPollInterval, STD_LOADABLE_MODULE_ID)); + NULL, &cs.iPollInterval, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilereadmode", 0, eCmdHdlrInt, - NULL, &readMode, STD_LOADABLE_MODULE_ID)); + NULL, &cs.readMode, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilemaxlinesatonce", 0, eCmdHdlrSize, - NULL, &maxLinesAtOnce, STD_LOADABLE_MODULE_ID)); + NULL, &cs.maxLinesAtOnce, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilepersiststateinterval", 0, eCmdHdlrInt, - NULL, &iPersistStateInterval, STD_LOADABLE_MODULE_ID)); + NULL, &cs.iPersistStateInterval, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilebindruleset", 0, eCmdHdlrGetWord, - setRuleset, NULL, STD_LOADABLE_MODULE_ID)); + NULL, &cs.pszBindRuleset, STD_LOADABLE_MODULE_ID)); /* that command ads a new file! */ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputrunfilemonitor", 0, eCmdHdlrGetWord, - addMonitor, NULL, STD_LOADABLE_MODULE_ID)); + addInstance, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 2daf9678..20425d79 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -202,8 +202,6 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) } else { CHKmalloc(inst->pszBindRuleset = ustrdup(cs.pszBindRuleset)); } - inst->pBindRuleset = NULL; - inst->next = NULL; finalize_it: free(pNewVal); @@ -917,18 +915,12 @@ ENDqueryEtryPt static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { - if(cs.pszBindAddr != NULL) { - free(cs.pszBindAddr); - cs.pszBindAddr = NULL; - } - if(cs.pszSchedPolicy != NULL) { - free(cs.pszSchedPolicy); - cs.pszSchedPolicy = NULL; - } - if(cs.pszBindRuleset != NULL) { - free(cs.pszBindRuleset); - cs.pszBindRuleset = NULL; - } + free(cs.pszBindAddr); + cs.pszBindAddr = NULL; + free(cs.pszSchedPolicy); + cs.pszSchedPolicy = NULL; + free(cs.pszBindRuleset); + cs.pszBindRuleset = NULL; cs.iSchedPrio = SCHED_PRIO_UNSET; cs.iTimeRequery = TIME_REQUERY_DFLT;/* the default is to query only every second time */ return RS_RET_OK; -- cgit v1.2.3 From 24c348bf5cb5fecfcb8e02518cece57d72dbdd58 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 27 Sep 2012 07:51:22 +0200 Subject: imfile: implement support for input() --- plugins/imfile/imfile.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 78 insertions(+), 3 deletions(-) diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index c2d0db51..4edd550d 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -130,6 +130,25 @@ static fileInfo_t files[MAX_INPUT_FILES]; static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this input */ +/* input instance parameters */ +static struct cnfparamdescr inppdescr[] = { + { "file", eCmdHdlrString, CNFPARAM_REQUIRED }, + { "statefile", eCmdHdlrString, CNFPARAM_REQUIRED }, + { "tag", eCmdHdlrString, CNFPARAM_REQUIRED }, + { "severity", eCmdHdlrSeverity, 0 }, + { "facility", eCmdHdlrFacility, 0 }, + { "ruleset", eCmdHdlrString, 0 }, + { "readmode", eCmdHdlrInt, 0 }, + { "maxlinesatonce", eCmdHdlrInt, 0 }, + { "maxsubmitatonce", eCmdHdlrInt, 0 }, + { "persiststateinterval", eCmdHdlrInt, 0 } +}; +static struct cnfparamblk inppblk = + { CNFPARAMBLK_VERSION, + sizeof(inppdescr)/sizeof(struct cnfparamdescr), + inppdescr + }; + #include "im-helper.h" /* must be included AFTER the type definitions! */ /* enqueue the read file line as a message. The provided string is @@ -358,7 +377,6 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) inst->pszFileName = (uchar*) strdup((char*) cs.pszFileName); inst->pszTag = (uchar*) strdup((char*) cs.pszFileTag); inst->pszStateFile = (uchar*) strdup((char*) cs.pszStateFile); - inst->nMultiSub = NUM_MULTISUB; inst->iSeverity = cs.iSeverity; inst->iFacility = cs.iFacility; inst->maxLinesAtOnce = cs.maxLinesAtOnce; @@ -413,6 +431,61 @@ finalize_it: RETiRet; } + +BEGINnewInpInst + struct cnfparamvals *pvals; + instanceConf_t *inst; + int i; +CODESTARTnewInpInst + DBGPRINTF("newInpInst (imfile)\n"); + + pvals = nvlstGetParams(lst, &inppblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, + "imfile: required parameter are missing\n"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("input param blk in imfile:\n"); + cnfparamsPrint(&inppblk, pvals); + } + + CHKiRet(createInstance(&inst)); + + for(i = 0 ; i < inppblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(inppblk.descr[i].name, "file")) { + inst->pszFileName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "statefile")) { + inst->pszStateFile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "tag")) { + inst->pszTag = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "ruleset")) { + inst->pszBindRuleset = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(inppblk.descr[i].name, "severity")) { + inst->iSeverity = pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "facility")) { + inst->iSeverity = pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "readmode")) { + inst->readMode = pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "maxlinesatonce")) { + inst->maxLinesAtOnce = pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "persistStateInterval")) { + inst->iPersistStateInterval = pvals[i].val.d.n; + } else if(!strcmp(inppblk.descr[i].name, "maxsubmitatonce")) { + inst->nMultiSub = pvals[i].val.d.n; + } else { + dbgprintf("imfile: program error, non-handled " + "param '%s'\n", inppblk.descr[i].name); + } + } +finalize_it: +CODE_STD_FINALIZERnewInpInst + cnfparamvalsDestruct(pvals, &inppblk); +ENDnewInpInst + BEGINbeginCnfLoad CODESTARTbeginCnfLoad loadModConf = pModConf; @@ -474,7 +547,6 @@ CODESTARTactivateCnf addListner(inst); } /* if we could not set up any listners, there is no point in running... */ - //if(lcnfRoot == NULL) { if(iFilPtr == 0) { errmsg.LogError(0, NO_ERRCODE, "imfile: no file monitors could be started, " "input not activated.\n"); @@ -488,7 +560,9 @@ BEGINfreeCnf instanceConf_t *inst, *del; CODESTARTfreeCnf for(inst = pModConf->root ; inst != NULL ; ) { - // free(inst->pszBindPort); + free(inst->pszBindRuleset); + free(inst->pszFileName); + free(inst->pszTag); del = inst; inst = inst->next; free(del); @@ -678,6 +752,7 @@ BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From 993630fdcb476adc72cf4f38f3c7e6c7a956228f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 27 Sep 2012 08:09:31 +0200 Subject: nitfix --- plugins/imudp/imudp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 20425d79..0e45aab0 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -730,13 +730,13 @@ BEGINsetModCnf CODESTARTsetModCnf pvals = nvlstGetParams(lst, &modpblk, NULL); if(pvals == NULL) { - errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "error processing module " + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "imudp: error processing module " "config parameters [module(...)]"); ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); } if(Debug) { - dbgprintf("module (global) param blk for impstats:\n"); + dbgprintf("module (global) param blk for imudp:\n"); cnfparamsPrint(&modpblk, pvals); } -- cgit v1.2.3 From 95e73e3cd2c160be769fecd7a13c6e06579a7847 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 27 Sep 2012 08:10:47 +0200 Subject: yet another nitfix... --- plugins/imudp/imudp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 0e45aab0..158d30b8 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -750,7 +750,7 @@ CODESTARTsetModCnf } else if(!strcmp(modpblk.descr[i].name, "schedulingpolicy")) { loadModConf->pszSchedPolicy = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); } else { - dbgprintf("impstats: program error, non-handled " + dbgprintf("imudp: program error, non-handled " "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); } } -- cgit v1.2.3 From 71664616132a47c2b951d72432031283ba040f79 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 27 Sep 2012 08:54:28 +0200 Subject: imfile: implement support for module parameters via module() stmt --- ChangeLog | 3 ++ plugins/imfile/imfile.c | 86 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 80 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9616d3f9..6c6c78e3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ --------------------------------------------------------------------------- Version 6.5.1 [devel] 2012-08-?? +- imfile ported to new v6 config interface +- imfile now supports config parameter for maximum number of submits + which is a fine-tuning parameter in regard to input baching - added pure JSON output plugin parameter passing mode - ommongodb now supports templates - bugfix: imtcp could abort on exit due to invalid free() diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index 4edd550d..83f94296 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -64,7 +64,11 @@ DEFobjCurrIf(strm) DEFobjCurrIf(prop) DEFobjCurrIf(ruleset) -#define NUM_MULTISUB 1024 /* max number of submits -- TODO: make configurable */ +static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */ + +#define NUM_MULTISUB 1024 /* default max number of submits */ +#define DFLT_PollInterval 10 + typedef struct fileInfo_s { uchar *pszFileName; uchar *pszTag; @@ -86,7 +90,7 @@ static struct configSettings_s { uchar *pszFileTag; uchar *pszStateFile; uchar *pszBindRuleset; - int iPollInterval; /* number of seconds to sleep when there was no file activity */ + int iPollInterval; int iPersistStateInterval; /* how often if state file to be persisted? (default 0->never) */ int iFacility; /* local0 */ int iSeverity; /* notice, as of rfc 3164 */ @@ -117,7 +121,8 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a /* config variables */ struct modConfData_s { - rsconf_t *pConf; /* our overall config object */ + rsconf_t *pConf; /* our overall config object */ + int iPollInterval; /* number of seconds to sleep when there was no file activity */ instanceConf_t *root, *tail; sbool configSetViaV2Method; }; @@ -130,6 +135,16 @@ static fileInfo_t files[MAX_INPUT_FILES]; static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this input */ +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "pollinginterval", eCmdHdlrInt, 0 } +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + /* input instance parameters */ static struct cnfparamdescr inppdescr[] = { { "file", eCmdHdlrString, CNFPARAM_REQUIRED }, @@ -491,12 +506,14 @@ CODESTARTbeginCnfLoad loadModConf = pModConf; pModConf->pConf = pConf; /* init our settings */ + loadModConf->iPollInterval = DFLT_PollInterval; loadModConf->configSetViaV2Method = 0; + bLegacyCnfModGlobalsPermitted = 1; /* init legacy config vars */ cs.pszFileName = NULL; cs.pszFileTag = NULL; cs.pszStateFile = NULL; - cs.iPollInterval = 10; + cs.iPollInterval = DFLT_PollInterval; cs.iPersistStateInterval = 0; cs.iFacility = 128; cs.iSeverity = 5; @@ -506,13 +523,59 @@ CODESTARTbeginCnfLoad ENDbeginCnfLoad +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "imfile: error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for imfile:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "pollinginterval")) { + if(pvals[i].val.d.n < 1) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, + "imfile: polling interval cannot be set below 1 - ignored"); + } else { + loadModConf->iPollInterval = (int) pvals[i].val.d.n; + } + } else { + dbgprintf("imfile: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } + + /* remove all of our legacy handlers, as they can not used in addition + * the the new-style config method. + */ + bLegacyCnfModGlobalsPermitted = 0; + loadModConf->configSetViaV2Method = 1; + +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + + + BEGINendCnfLoad CODESTARTendCnfLoad if(!loadModConf->configSetViaV2Method) { /* persist module-specific settings from legacy config system */ + loadModConf->iPollInterval = cs.iPollInterval; } + dbgprintf("imfile: polling interval is %d\n", loadModConf->iPollInterval); -//finalize_it: loadModConf = NULL; /* done loading */ /* free legacy config vars */ free(cs.pszFileName); @@ -563,6 +626,7 @@ CODESTARTfreeCnf free(inst->pszBindRuleset); free(inst->pszFileName); free(inst->pszTag); + free(inst->pszStateFile); del = inst; inst = inst->next; free(del); @@ -631,7 +695,7 @@ CODESTARTrunInput * other valid scenario. So do not remove. -- rgerhards, 2008-02-14 */ if(glbl.GetGlobalInputTermState() == 0) - srSleep(cs.iPollInterval, 10); + srSleep(runModConf->iPollInterval, 10); } DBGPRINTF("imfile: terminating upon request of rsyslog core\n"); @@ -752,6 +816,7 @@ BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt @@ -776,7 +841,7 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus cs.pszFileTag = NULL; /* set defaults... */ - cs.iPollInterval = 10; + cs.iPollInterval = DFLT_PollInterval; cs.iFacility = 128; /* local0 */ cs.iSeverity = 5; /* notice, as of rfc 3164 */ cs.readMode = 0; @@ -825,8 +890,6 @@ CODEmodInit_QueryRegCFSLineHdlr NULL, &cs.iSeverity, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilefacility", 0, eCmdHdlrFacility, NULL, &cs.iFacility, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilepollinterval", 0, eCmdHdlrInt, - NULL, &cs.iPollInterval, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilereadmode", 0, eCmdHdlrInt, NULL, &cs.readMode, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilemaxlinesatonce", 0, eCmdHdlrSize, @@ -838,6 +901,11 @@ CODEmodInit_QueryRegCFSLineHdlr /* that command ads a new file! */ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputrunfilemonitor", 0, eCmdHdlrGetWord, addInstance, NULL, STD_LOADABLE_MODULE_ID)); + /* module-global config params - will be disabled in configs that are loaded + * via module(...). + */ + CHKiRet(regCfSysLineHdlr2((uchar *)"inputfilepollinterval", 0, eCmdHdlrInt, + NULL, &cs.iPollInterval, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit -- cgit v1.2.3 From 2ce900aea233b9f8b0447658f2dc3565c3103e78 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 27 Sep 2012 10:03:12 +0200 Subject: bugfix: config errors did not always cause statement to fail This could lead to startup with invalid parameters. --- ChangeLog | 2 + grammar/rainerscript.c | 129 ++++++++++++++++++++++++++++++++++++++++-------- plugins/imfile/imfile.c | 9 +--- runtime/typedefs.h | 2 + 4 files changed, 114 insertions(+), 28 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6c6c78e3..1c066cb6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24,6 +24,8 @@ Version 6.5.1 [devel] 2012-08-?? these were one-time memory leaks during startup, so they did NOT grow during runtime - bugfix: config validation run did not always return correct return state +- bugfix: config errors did not always cause statement to fail + This could lead to startup with invalid parameters. --------------------------------------------------------------------------- Version 6.5.0 [devel] 2012-08-28 - imrelp now supports non-cancel thread termination diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 5e6e492d..9e0d04c7 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -271,13 +271,14 @@ nvlstChkUnused(struct nvlst *lst) } -static inline void +static inline int doGetSize(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { unsigned char *c; es_size_t i; long long n; + int r; c = es_getBufAddr(valnode->val.d.estr); n = 0; i = 0; @@ -311,17 +312,21 @@ doGetSize(struct nvlst *valnode, struct cnfparamdescr *param, if(i == es_strlen(valnode->val.d.estr)) { val->val.datatype = 'N'; val->val.d.n = n; + r = 1; } else { parser_errmsg("parameter '%s' does not contain a valid size", param->name); + r = 0; } + return r; } -static inline void +static inline int doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { + int r = 1; val->val.datatype = 'N'; if(!es_strbufcmp(valnode->val.d.estr, (unsigned char*) "on", 2)) { val->val.d.n = 1; @@ -331,14 +336,17 @@ doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param, parser_errmsg("parameter '%s' must be \"on\" or \"off\" but " "is neither. Results unpredictable.", param->name); val->val.d.n = 0; + r = 0; } + return r; } -static inline void +static inline int doGetQueueType(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { char *cstr; + int r = 1; if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"fixedarray", 10)) { val->val.d.n = QUEUETYPE_FIXED_ARRAY; } else if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"linkedlist", 10)) { @@ -352,15 +360,17 @@ doGetQueueType(struct nvlst *valnode, struct cnfparamdescr *param, parser_errmsg("param '%s': unknown queue type: '%s'", param->name, cstr); free(cstr); + r = 0; } val->val.datatype = 'N'; + return r; } /* A file create-mode must be a four-digit octal number * starting with '0'. */ -static inline void +static inline int doGetFileCreateMode(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { @@ -389,13 +399,15 @@ doGetFileCreateMode(struct nvlst *valnode, struct cnfparamdescr *param, param->name, cstr); free(cstr); } + return fmtOK; } -static inline void +static inline int doGetGID(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { char *cstr; + int r; struct group *resultBuf; struct group wrkBuf; char stringBuf[2048]; /* 2048 has been proven to be large enough */ @@ -405,20 +417,24 @@ doGetGID(struct nvlst *valnode, struct cnfparamdescr *param, if(resultBuf == NULL) { parser_errmsg("parameter '%s': ID for group %s could not " "be found", param->name, cstr); + r = 0; } else { val->val.datatype = 'N'; val->val.d.n = resultBuf->gr_gid; dbgprintf("param '%s': uid %d obtained for group '%s'\n", param->name, (int) resultBuf->gr_gid, cstr); + r = 1; } free(cstr); + return r; } -static inline void +static inline int doGetUID(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { char *cstr; + int r; struct passwd *resultBuf; struct passwd wrkBuf; char stringBuf[2048]; /* 2048 has been proven to be large enough */ @@ -428,19 +444,22 @@ doGetUID(struct nvlst *valnode, struct cnfparamdescr *param, if(resultBuf == NULL) { parser_errmsg("parameter '%s': ID for user %s could not " "be found", param->name, cstr); + r = 0; } else { val->val.datatype = 'N'; val->val.d.n = resultBuf->pw_uid; dbgprintf("param '%s': uid %d obtained for user '%s'\n", param->name, (int) resultBuf->pw_uid, cstr); + r = 1; } free(cstr); + return r; } /* note: we support all integer formats that es_str2num support, * so hex and octal representations are also valid. */ -static inline void +static inline int doGetInt(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { @@ -454,13 +473,47 @@ doGetInt(struct nvlst *valnode, struct cnfparamdescr *param, } val->val.datatype = 'N'; val->val.d.n = n; + return bSuccess; } -static inline void +static inline int +doGetNonNegInt(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + int bSuccess; + + if((bSuccess = doGetInt(valnode, param, val))) { + if(val->val.d.n < 0) { + parser_errmsg("parameter '%s' cannot be less than zero (was %lld)", + param->name, val->val.d.n); + bSuccess = 0; + } + } + return bSuccess; +} + +static inline int +doGetPositiveInt(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + int bSuccess; + + if((bSuccess = doGetInt(valnode, param, val))) { + if(val->val.d.n < 1) { + parser_errmsg("parameter '%s' cannot be less than one (was %lld)", + param->name, val->val.d.n); + bSuccess = 0; + } + } + return bSuccess; +} + +static inline int doGetWord(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { es_size_t i; + int r = 1; unsigned char *c; val->val.datatype = 'S'; val->val.d.estr = es_newStr(32); @@ -472,30 +525,36 @@ doGetWord(struct nvlst *valnode, struct cnfparamdescr *param, parser_errmsg("parameter '%s' contains whitespace, which is not " "permitted - data after first whitespace ignored", param->name); + r = 0; } + return r; } -static inline void +static inline int doGetChar(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { + int r = 1; if(es_strlen(valnode->val.d.estr) != 1) { parser_errmsg("parameter '%s' must contain exactly one character " "but contains %d - cannot be processed", param->name, es_strlen(valnode->val.d.estr)); + r = 0; } val->val.datatype = 'S'; val->val.d.estr = es_strdup(valnode->val.d.estr); + return r; } /* get a single parameter according to its definition. Helper to - * nvlstGetParams. + * nvlstGetParams. returns 1 if success, 0 otherwise */ -static inline void +static inline int nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { uchar *cstr; + int r; dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d, valnode->bUsed %d\n", param->name, (int) param->type, valnode->bUsed); @@ -503,56 +562,68 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, val->bUsed = 1; switch(param->type) { case eCmdHdlrQueueType: - doGetQueueType(valnode, param, val); + r = doGetQueueType(valnode, param, val); break; case eCmdHdlrUID: - doGetUID(valnode, param, val); + r = doGetUID(valnode, param, val); break; case eCmdHdlrGID: - doGetGID(valnode, param, val); + r = doGetGID(valnode, param, val); break; case eCmdHdlrBinary: - doGetBinary(valnode, param, val); + r = doGetBinary(valnode, param, val); break; case eCmdHdlrFileCreateMode: - doGetFileCreateMode(valnode, param, val); + r = doGetFileCreateMode(valnode, param, val); break; case eCmdHdlrInt: - doGetInt(valnode, param, val); + r = doGetInt(valnode, param, val); + break; + case eCmdHdlrNonNegInt: + r = doGetPositiveInt(valnode, param, val); + break; + case eCmdHdlrPositiveInt: + r = doGetPositiveInt(valnode, param, val); break; case eCmdHdlrSize: - doGetSize(valnode, param, val); + r = doGetSize(valnode, param, val); break; case eCmdHdlrGetChar: - doGetChar(valnode, param, val); + r = doGetChar(valnode, param, val); break; case eCmdHdlrFacility: cstr = (uchar*) es_str2cstr(valnode->val.d.estr, NULL); val->val.datatype = 'N'; val->val.d.n = decodeSyslogName(cstr, syslogFacNames); free(cstr); + r = 1; break; case eCmdHdlrSeverity: cstr = (uchar*) es_str2cstr(valnode->val.d.estr, NULL); val->val.datatype = 'N'; val->val.d.n = decodeSyslogName(cstr, syslogPriNames); free(cstr); + r = 1; break; case eCmdHdlrGetWord: - doGetWord(valnode, param, val); + r = doGetWord(valnode, param, val); break; case eCmdHdlrString: val->val.datatype = 'S'; val->val.d.estr = es_strdup(valnode->val.d.estr); + r = 1; break; case eCmdHdlrGoneAway: parser_errmsg("parameter '%s' is no longer supported", param->name); + r = 1; /* this *is* valid! */ break; default: dbgprintf("error: invalid param type\n"); + r = 0; break; } + return r; } @@ -567,6 +638,8 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, struct cnfparamvals *vals) { int i; + int bValsWasNULL; + int bInError = 0; struct nvlst *valnode; struct cnfparamdescr *param; @@ -578,9 +651,12 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, } if(vals == NULL) { + bValsWasNULL = 1; if((vals = calloc(params->nParams, sizeof(struct cnfparamvals))) == NULL) return NULL; + } else { + bValsWasNULL = 0; } for(i = 0 ; i < params->nParams ; ++i) { @@ -592,8 +668,19 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, "one instance is ignored. Fix config", param->name); continue; } - nvlstGetParam(valnode, param, vals + i); + if(!nvlstGetParam(valnode, param, vals + i)) { + bInError = 1; + } } + + + if(bInError) { + if(bValsWasNULL) + cnfparamvalsDestruct(vals, params); + vals = NULL; + } + +dbgprintf("DDDD: vals %p\n", vals); return vals; } diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index 83f94296..462a5e78 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -137,7 +137,7 @@ static prop_t *pInputName = NULL; /* there is only one global inputName for all /* module-global parameters */ static struct cnfparamdescr modpdescr[] = { - { "pollinginterval", eCmdHdlrInt, 0 } + { "pollinginterval", eCmdHdlrPositiveInt, 0 } }; static struct cnfparamblk modpblk = { CNFPARAMBLK_VERSION, @@ -543,12 +543,7 @@ CODESTARTsetModCnf if(!pvals[i].bUsed) continue; if(!strcmp(modpblk.descr[i].name, "pollinginterval")) { - if(pvals[i].val.d.n < 1) { - errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, - "imfile: polling interval cannot be set below 1 - ignored"); - } else { - loadModConf->iPollInterval = (int) pvals[i].val.d.n; - } + loadModConf->iPollInterval = (int) pvals[i].val.d.n; } else { dbgprintf("imfile: program error, non-handled " "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); diff --git a/runtime/typedefs.h b/runtime/typedefs.h index f994cbc4..4e7f1622 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -154,6 +154,8 @@ typedef enum cslCmdHdlrType { eCmdHdlrBinary, eCmdHdlrFileCreateMode, eCmdHdlrInt, + eCmdHdlrNonNegInt, + eCmdHdlrPositiveInt, eCmdHdlrSize, eCmdHdlrGetChar, eCmdHdlrFacility, -- cgit v1.2.3 From 8020c651a1700eb29a37e6cb8732c3b2c94814ab Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 27 Sep 2012 12:58:27 +0200 Subject: cosmetic: remove irrelevant compiler warning v7 does not even have this code any longer --- action.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.c b/action.c index 4b5c9f30..673d8e13 100644 --- a/action.c +++ b/action.c @@ -2091,7 +2091,7 @@ finalize_it: * rgerhards, 2011-07-19 */ rsRetVal -actionProcessCnf(struct cnfobj *o) +actionProcessCnf(struct cnfobj __attribute__((unused)) *o) { DEFiRet; #if 0 /* we need to check if we actually need this functionality -- later! */ -- cgit v1.2.3 From 77b4efaeecf53678a3de579d73567e61c3b4785b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 27 Sep 2012 14:22:23 +0200 Subject: Do not load module if it had errorneous parameters --- runtime/modules.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++-------- runtime/modules.h | 4 ++-- runtime/rsconf.c | 5 ++++- 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/runtime/modules.c b/runtime/modules.c index c0dd0ffb..5706685f 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -349,11 +349,13 @@ addModToGlblList(modInfo_t *pThis) } -/* Add a module to the config module list for current loadConf and - * provide its config params to it. +/* ready module for config processing. this includes checking if the module + * is already in the config, so this function may return errors. Returns a + * pointer to the last module inthe current config. That pointer needs to + * be passed to addModToCnfLst() when it is called later in the process. */ rsRetVal -addModToCnfList(modInfo_t *pThis) +readyModForCnf(modInfo_t *pThis, cfgmodules_etry_t **ppNew, cfgmodules_etry_t **ppLast) { cfgmodules_etry_t *pNew; cfgmodules_etry_t *pLast; @@ -361,8 +363,7 @@ addModToCnfList(modInfo_t *pThis) assert(pThis != NULL); if(loadConf == NULL) { - /* we are in an early init state */ - FINALIZE; + FINALIZE; /* we are in an early init state */ } /* check for duplicates and, as a side-activity, identify last node */ @@ -398,6 +399,36 @@ addModToCnfList(modInfo_t *pThis) CHKiRet(pThis->beginCnfLoad(&pNew->modCnf, loadConf)); } + *ppLast = pLast; + *ppNew = pNew; +finalize_it: + RETiRet; +} + + +/* abort the creation of a module entry without adding it to the + * module list. Needed to prevent mem leaks. + */ +static inline void +abortCnfUse(cfgmodules_etry_t *pNew) +{ + free(pNew); +} + + +/* Add a module to the config module list for current loadConf. + * Requires last pointer obtained by readyModForCnf(). + */ +rsRetVal +addModToCnfList(cfgmodules_etry_t *pNew, cfgmodules_etry_t *pLast) +{ + DEFiRet; + assert(pNew != NULL); + + if(loadConf == NULL) { + FINALIZE; /* we are in an early init state */ + } + if(pLast == NULL) { loadConf->modules.root = pNew; } else { @@ -971,6 +1002,8 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) int bHasExtension; void *pModHdlr, *pModInit; modInfo_t *pModInfo; + cfgmodules_etry_t *pNew; + cfgmodules_etry_t *pLast; uchar *pModDirCurr, *pModDirNext; int iLoadCnt; struct dlhandle_s *pHandle = NULL; @@ -1005,8 +1038,9 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) if(pModInfo != NULL) { DBGPRINTF("Module '%s' already loaded\n", pModName); if(bConfLoad) { - localRet = addModToCnfList(pModInfo); + localRet = readyModForCnf(pModInfo, &pNew, &pLast); if(pModInfo->setModCnf != NULL && localRet == RS_RET_OK) { + addModToCnfList(pNew, pLast); if(!strncmp((char*)pModName, "builtin:", sizeof("builtin:")-1)) { if(pModInfo->bSetModCnfCalled) { errmsg.LogError(0, RS_RET_DUP_PARAM, @@ -1134,12 +1168,21 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) } if(bConfLoad) { - addModToCnfList(pModInfo); + readyModForCnf(pModInfo, &pNew, &pLast); if(pModInfo->setModCnf != NULL) { - if(lst != NULL) - pModInfo->setModCnf(lst); + if(lst != NULL) { + localRet = pModInfo->setModCnf(lst); + if(localRet != RS_RET_OK) { + errmsg.LogError(0, localRet, + "module '%s', failed processing config parameters", + pPathBuf); + abortCnfUse(pNew); + ABORT_FINALIZE(localRet); + } + } pModInfo->bSetModCnfCalled = 1; } + addModToCnfList(pNew, pLast); } finalize_it: diff --git a/runtime/modules.h b/runtime/modules.h index 51ce1e51..02e4a699 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -192,6 +192,6 @@ PROTOTYPEObj(module); * that are not called from plugins. */ rsRetVal modulesProcessCnf(struct cnfobj *o); - -rsRetVal addModToCnfList(modInfo_t *pThis); +rsRetVal addModToCnfList(cfgmodules_etry_t *pNew, cfgmodules_etry_t *pLast); +rsRetVal readyModForCnf(modInfo_t *pThis, cfgmodules_etry_t **ppNew, cfgmodules_etry_t **ppLast); #endif /* #ifndef MODULES_H_INCLUDED */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index e7ff0899..118e9c11 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -1083,10 +1083,13 @@ setModDir(void __attribute__((unused)) *pVal, uchar* pszNewVal) static rsRetVal regBuildInModule(rsRetVal (*modInit)(), uchar *name, void *pModHdlr) { + cfgmodules_etry_t *pNew; + cfgmodules_etry_t *pLast; modInfo_t *pMod; DEFiRet; CHKiRet(module.doModInit(modInit, name, pModHdlr, &pMod)); - addModToCnfList(pMod); + readyModForCnf(pMod, &pNew, &pLast); + addModToCnfList(pNew, pLast); finalize_it: RETiRet; } -- cgit v1.2.3 From f2f85fcf446dcfb8ca9a21dff6a292bf7f68607f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 27 Sep 2012 18:38:53 +0200 Subject: fix whitespace issue --- plugins/imfile/imfile.c | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index 462a5e78..453b6b05 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -562,7 +562,6 @@ finalize_it: ENDsetModCnf - BEGINendCnfLoad CODESTARTendCnfLoad if(!loadModConf->configSetViaV2Method) { -- cgit v1.2.3 From 5347e87dca36d4c125832b2ef52f16c6d3a9fb83 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 27 Sep 2012 18:47:51 +0200 Subject: imptcp: implement support for module() parameters --- plugins/imptcp/imptcp.c | 77 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 70 insertions(+), 7 deletions(-) diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 9992ee20..a13fd990 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -90,6 +90,8 @@ DEFobjCurrIf(statsobj) /* forward references */ static void * wrkr(void *myself); +#define DFLT_wrkrMax 2 + /* config settings */ typedef struct configSettings_s { int bKeepAlive; /* support keep-alive packets */ @@ -127,11 +129,22 @@ struct modConfData_s { rsconf_t *pConf; /* our overall config object */ instanceConf_t *root, *tail; int wrkrMax; + sbool configSetViaV2Method; }; static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "threads", eCmdHdlrPositiveInt, 0 } +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + /* input instance parameters */ static struct cnfparamdescr inppdescr[] = { { "port", eCmdHdlrString, CNFPARAM_REQUIRED }, /* legacy: InputTCPServerRun */ @@ -153,6 +166,8 @@ static struct cnfparamblk inppblk = }; #include "im-helper.h" /* must be included AFTER the type definitions! */ +static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */ + /* data elements describing our running config */ typedef struct ptcpsrv_s ptcpsrv_t; typedef struct ptcplstn_s ptcplstn_t; @@ -832,7 +847,7 @@ static inline void initConfigSettings(void) { cs.bEmitMsgOnClose = 0; - cs.wrkrMax = 2; + cs.wrkrMax = DFLT_wrkrMax; cs.bSuppOctetFram = 1; cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; cs.pszInputName = NULL; @@ -1152,6 +1167,7 @@ startWorkerPool(void) wrkrRunning = 0; if(runModConf->wrkrMax > 16) runModConf->wrkrMax = 16; /* TODO: make dynamic? */ + DBGPRINTF("imptcp: starting worker pool, %d workers\n", runModConf->wrkrMax); pthread_mutex_init(&wrkrMut, NULL); pthread_cond_init(&wrkrIdle, NULL); for(i = 0 ; i < runModConf->wrkrMax ; ++i) { @@ -1170,6 +1186,7 @@ static inline void stopWorkerPool(void) { int i; + DBGPRINTF("imptcp: stoping worker pool\n"); for(i = 0 ; i < runModConf->wrkrMax ; ++i) { pthread_cond_signal(&wrkrInfo[i].run); /* awake wrkr if not running */ pthread_join(wrkrInfo[i].tid, NULL); @@ -1178,7 +1195,6 @@ stopWorkerPool(void) } pthread_cond_destroy(&wrkrIdle); pthread_mutex_destroy(&wrkrMut); - } @@ -1455,15 +1471,60 @@ BEGINbeginCnfLoad CODESTARTbeginCnfLoad loadModConf = pModConf; pModConf->pConf = pConf; + /* init our settings */ + loadModConf->wrkrMax = DFLT_wrkrMax; + loadModConf->configSetViaV2Method = 0; + bLegacyCnfModGlobalsPermitted = 1; /* init legacy config vars */ initConfigSettings(); ENDbeginCnfLoad +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "imptcp: error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for imptcp:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "threads")) { + loadModConf->wrkrMax = (int) pvals[i].val.d.n; + } else { + dbgprintf("imptcp: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } + + /* remove all of our legacy handlers, as they can not used in addition + * the the new-style config method. + */ + bLegacyCnfModGlobalsPermitted = 0; + loadModConf->configSetViaV2Method = 1; + +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + + BEGINendCnfLoad CODESTARTendCnfLoad - /* persist module-specific settings from legacy config system */ - loadModConf->wrkrMax = cs.wrkrMax; + if(!loadModConf->configSetViaV2Method) { + /* persist module-specific settings from legacy config system */ + loadModConf->wrkrMax = cs.wrkrMax; + } loadModConf = NULL; /* done loading */ /* free legacy config vars */ @@ -1647,7 +1708,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { cs.bEmitMsgOnClose = 0; - cs.wrkrMax = 2; + cs.wrkrMax = DFLT_wrkrMax; cs.bKeepAlive = 0; cs.iKeepAliveProbes = 0; cs.iKeepAliveTime = 0; @@ -1673,6 +1734,7 @@ BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES @@ -1716,14 +1778,15 @@ CODEmodInit_QueryRegCFSLineHdlr eCmdHdlrBinary, NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserveraddtlframedelimiter"), 0, eCmdHdlrInt, NULL, &cs.iAddtlFrameDelim, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverhelperthreads"), 0, eCmdHdlrInt, - NULL, &cs.wrkrMax, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverinputname"), 0, eCmdHdlrGetWord, NULL, &cs.pszInputName, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverlistenip"), 0, eCmdHdlrGetWord, NULL, &cs.lstnIP, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverbindruleset"), 0, eCmdHdlrGetWord, NULL, &cs.pszBindRuleset, STD_LOADABLE_MODULE_ID)); + /* module-global parameters */ + CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputptcpserverhelperthreads"), 0, eCmdHdlrInt, + NULL, &cs.wrkrMax, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("resetconfigvariables"), 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit -- cgit v1.2.3 From 43da91636a5d8f60c21f1795d25fb0755e356d9f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 28 Sep 2012 08:09:47 +0200 Subject: imtcp: implement support for module() parameters --- plugins/imtcp/imtcp.c | 173 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 135 insertions(+), 38 deletions(-) diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index a00d4ebe..3ad03615 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -123,11 +123,31 @@ struct modConfData_s { sbool bKeepAlive; sbool bEmitMsgOnClose; /* emit an informational message on close by remote peer */ uchar *pszStrmDrvrAuthMode; /* authentication mode to use */ + sbool configSetViaV2Method; }; static modConfData_t *loadModConf = NULL;/* modConf ptr to use for the current load process */ static modConfData_t *runModConf = NULL;/* modConf ptr to use for the current load process */ +/* module-global parameters */ +static struct cnfparamdescr modpdescr[] = { + { "flowcontrol", eCmdHdlrBinary, 0 }, + { "disablelfdelimiter", eCmdHdlrBinary, 0 }, + { "octetcountedframing", eCmdHdlrBinary, 0 }, + { "notifyonconnectionclose", eCmdHdlrBinary, 0 }, + { "addtlframedelimiter", eCmdHdlrPositiveInt, 0 }, + { "maxsessions", eCmdHdlrPositiveInt, 0 }, + { "maxlistners", eCmdHdlrPositiveInt, 0 }, + { "streamdriver.mode", eCmdHdlrPositiveInt, 0 }, + { "streamdriver.authmode", eCmdHdlrString, 0 }, + { "keepalive", eCmdHdlrBinary, 0 } +}; +static struct cnfparamblk modpblk = + { CNFPARAMBLK_VERSION, + sizeof(modpdescr)/sizeof(struct cnfparamdescr), + modpdescr + }; + /* input instance parameters */ static struct cnfparamdescr inppdescr[] = { { "port", eCmdHdlrString, CNFPARAM_REQUIRED }, /* legacy: InputTCPServerRun */ @@ -143,6 +163,8 @@ static struct cnfparamblk inppblk = #include "im-helper.h" /* must be included AFTER the type definitions! */ +static int bLegacyCnfModGlobalsPermitted;/* are legacy module-global config parameters permitted? */ + /* callbacks */ /* this shall go into a specific ACL module! */ static int @@ -242,8 +264,6 @@ finalize_it: } - - /* This function is called when a new listener instace shall be added to * the current config object via the legacy config system. It just shuffles * all parameters to the listener in-memory instance. @@ -369,30 +389,103 @@ BEGINbeginCnfLoad CODESTARTbeginCnfLoad loadModConf = pModConf; pModConf->pConf = pConf; + /* init our settings */ + loadModConf->iTCPSessMax = 200; + loadModConf->iTCPLstnMax = 20; + loadModConf->bSuppOctetFram = 1; + loadModConf->iStrmDrvrMode = 0; + loadModConf->bUseFlowControl = 0; + loadModConf->bKeepAlive = 0; + loadModConf->bEmitMsgOnClose = 0; + loadModConf->iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; + loadModConf->bDisableLFDelim = 0; + loadModConf->pszStrmDrvrAuthMode = NULL; + loadModConf->configSetViaV2Method = 0; + bLegacyCnfModGlobalsPermitted = 1; /* init legacy config variables */ cs.pszStrmDrvrAuthMode = NULL; resetConfigVariables(NULL, NULL); /* dummy parameters just to fulfill interface def */ ENDbeginCnfLoad +BEGINsetModCnf + struct cnfparamvals *pvals = NULL; + int i; +CODESTARTsetModCnf + pvals = nvlstGetParams(lst, &modpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "imtcp: error processing module " + "config parameters [module(...)]"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("module (global) param blk for imtcp:\n"); + cnfparamsPrint(&modpblk, pvals); + } + + for(i = 0 ; i < modpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(modpblk.descr[i].name, "flowcontrol")) { + loadModConf->bUseFlowControl = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "disablelfdelimiter")) { + loadModConf->bDisableLFDelim = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "octetcountedframing")) { + loadModConf->bSuppOctetFram = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "notifyonconnectionclose")) { + loadModConf->bEmitMsgOnClose = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "addtlframedelimiter")) { + loadModConf->iAddtlFrameDelim = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "maxsessions")) { + loadModConf->iTCPSessMax = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "maxlistners")) { + loadModConf->iTCPLstnMax = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "keepalive")) { + loadModConf->bKeepAlive = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "streamdriver.mode")) { + loadModConf->iStrmDrvrMode = (int) pvals[i].val.d.n; + } else if(!strcmp(modpblk.descr[i].name, "streamdriver.mode")) { + loadModConf->pszStrmDrvrAuthMode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + dbgprintf("imtcp: program error, non-handled " + "param '%s' in beginCnfLoad\n", modpblk.descr[i].name); + } + } + + /* remove all of our legacy handlers, as they can not used in addition + * the the new-style config method. + */ + bLegacyCnfModGlobalsPermitted = 0; + loadModConf->configSetViaV2Method = 1; + +finalize_it: + if(pvals != NULL) + cnfparamvalsDestruct(pvals, &modpblk); +ENDsetModCnf + + BEGINendCnfLoad CODESTARTendCnfLoad - /* persist module-specific settings from legacy config system */ - pModConf->iTCPSessMax = cs.iTCPSessMax; - pModConf->iTCPLstnMax = cs.iTCPLstnMax; - pModConf->iStrmDrvrMode = cs.iStrmDrvrMode; - pModConf->bEmitMsgOnClose = cs.bEmitMsgOnClose; - pModConf->bSuppOctetFram = cs.bSuppOctetFram; - pModConf->iAddtlFrameDelim = cs.iAddtlFrameDelim; - pModConf->bDisableLFDelim = cs.bDisableLFDelim; - pModConf->bUseFlowControl = cs.bUseFlowControl; - pModConf->bKeepAlive = cs.bKeepAlive; - if((cs.pszStrmDrvrAuthMode == NULL) || (cs.pszStrmDrvrAuthMode[0] == '\0')) { - loadModConf->pszStrmDrvrAuthMode = NULL; - free(cs.pszStrmDrvrAuthMode); - } else { - loadModConf->pszStrmDrvrAuthMode = cs.pszStrmDrvrAuthMode; + if(!loadModConf->configSetViaV2Method) { + /* persist module-specific settings from legacy config system */ + pModConf->iTCPSessMax = cs.iTCPSessMax; + pModConf->iTCPLstnMax = cs.iTCPLstnMax; + pModConf->iStrmDrvrMode = cs.iStrmDrvrMode; + pModConf->bEmitMsgOnClose = cs.bEmitMsgOnClose; + pModConf->bSuppOctetFram = cs.bSuppOctetFram; + pModConf->iAddtlFrameDelim = cs.iAddtlFrameDelim; + pModConf->bDisableLFDelim = cs.bDisableLFDelim; + pModConf->bUseFlowControl = cs.bUseFlowControl; + pModConf->bKeepAlive = cs.bKeepAlive; + if((cs.pszStrmDrvrAuthMode == NULL) || (cs.pszStrmDrvrAuthMode[0] == '\0')) { + loadModConf->pszStrmDrvrAuthMode = NULL; + } else { + loadModConf->pszStrmDrvrAuthMode = cs.pszStrmDrvrAuthMode; + } } + if((cs.pszStrmDrvrAuthMode == NULL) || (cs.pszStrmDrvrAuthMode[0] == '\0')) + free(cs.pszStrmDrvrAuthMode); cs.pszStrmDrvrAuthMode = NULL; loadModConf = NULL; /* done loading */ @@ -527,6 +620,7 @@ BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES @@ -549,36 +643,39 @@ CODEmodInit_QueryRegCFSLineHdlr /* register config file handlers */ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverrun"), 0, eCmdHdlrGetWord, addInstance, NULL, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverkeepalive"), 0, eCmdHdlrBinary, - NULL, &cs.bKeepAlive, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserversupportoctetcountedframing"), 0, eCmdHdlrBinary, - NULL, &cs.bSuppOctetFram, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpmaxsessions"), 0, eCmdHdlrInt, - NULL, &cs.iTCPSessMax, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpmaxlisteners"), 0, eCmdHdlrInt, - NULL, &cs.iTCPLstnMax, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpservernotifyonconnectionclose"), 0, eCmdHdlrBinary, - NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdrivermode"), 0, eCmdHdlrInt, - NULL, &cs.iStrmDrvrMode, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdriverauthmode"), 0, eCmdHdlrGetWord, - NULL, &cs.pszStrmDrvrAuthMode, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdriverpermittedpeer"), 0, eCmdHdlrGetWord, setPermittedPeer, NULL, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserveraddtlframedelimiter"), 0, eCmdHdlrInt, - NULL, &cs.iAddtlFrameDelim, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverdisablelfdelimiter"), 0, eCmdHdlrBinary, - NULL, &cs.bDisableLFDelim, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverinputname"), 0, eCmdHdlrGetWord, NULL, &cs.pszInputName, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverbindruleset"), 0, eCmdHdlrGetWord, NULL, &cs.pszBindRuleset, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpflowcontrol"), 0, eCmdHdlrBinary, - NULL, &cs.bUseFlowControl, STD_LOADABLE_MODULE_ID)); + /* module-global config params - will be disabled in configs that are loaded + * via module(...). + */ + CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpserverstreamdriverauthmode"), 0, eCmdHdlrGetWord, + NULL, &cs.pszStrmDrvrAuthMode, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpserverkeepalive"), 0, eCmdHdlrBinary, + NULL, &cs.bKeepAlive, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpflowcontrol"), 0, eCmdHdlrBinary, + NULL, &cs.bUseFlowControl, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpserverdisablelfdelimiter"), 0, eCmdHdlrBinary, + NULL, &cs.bDisableLFDelim, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpserveraddtlframedelimiter"), 0, eCmdHdlrInt, + NULL, &cs.iAddtlFrameDelim, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpserversupportoctetcountedframing"), 0, eCmdHdlrBinary, + NULL, &cs.bSuppOctetFram, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpmaxsessions"), 0, eCmdHdlrInt, + NULL, &cs.iTCPSessMax, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpmaxlisteners"), 0, eCmdHdlrInt, + NULL, &cs.iTCPLstnMax, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpservernotifyonconnectionclose"), 0, eCmdHdlrBinary, + NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(regCfSysLineHdlr2(UCHAR_CONSTANT("inputtcpserverstreamdrivermode"), 0, eCmdHdlrInt, + NULL, &cs.iStrmDrvrMode, STD_LOADABLE_MODULE_ID, &bLegacyCnfModGlobalsPermitted)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("resetconfigvariables"), 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit - /* vim:set ai: */ -- cgit v1.2.3 From cf0fd87e17db12dd28edd260d02d0e5aa96deb71 Mon Sep 17 00:00:00 2001 From: Florian Riedl Date: Fri, 28 Sep 2012 08:24:13 +0200 Subject: doc: update module doc to new config format --- doc/imfile.html | 137 ++++++++++++++++++++++++++++++--------- doc/imptcp.html | 70 ++++++++++++++++---- doc/imrelp.html | 28 +++++++- doc/imudp.html | 55 ++++++++++++---- doc/imuxsock.html | 190 ++++++++++++++++++++++++++++++++++++++++-------------- 5 files changed, 373 insertions(+), 107 deletions(-) diff --git a/doc/imfile.html b/doc/imfile.html index 7961729b..1594cdce 100644 --- a/doc/imfile.html +++ b/doc/imfile.html @@ -36,17 +36,40 @@ file names in the future.

      Multiple files may be monitored by specifying $InputRunFileMonitor multiple times.

      +

      Configuration Directives:

      +

      Module Directives

        -
      • $InputFileName /path/to/file
        +
      • PollingInterval +seconds
        +This is a global setting. It specifies how often files are to be polled +for new data. The time specified is in seconds. The default value is 10 +seconds. Please note that future +releases of imfile may support per-file polling intervals, but +currently this is not the case. If multiple PollingInterval +statements are present in rsyslog.conf, only the last one is used.
        +A short poll interval provides more rapid message forwarding, but +requires more system ressources. While it is possible, we stongly +recommend not to set the polling interval to 0 seconds. That will make +rsyslogd become a CPU hog, taking up considerable ressources. It is +supported, however, for the few very unusual situations where this +level may be needed. Even if you need quick response, 1 seconds should +be well enough. Please note that imfile keeps reading files as long as +there is any data in them. So a "polling sleep" will only happen when +nothing is left to be processed.
      • +
      + +

      Action Directives

      +
        +
      • File /path/to/file
        The file being monitored. So far, this must be an absolute name (no macros or templates)
      • -
      • $InputFileTag +
      • Tag tag:
        The tag to be used for messages that originate from this file. If you would like to see the colon after the tag, you need to specify it here (as shown above).
      • -
      • $InputFileStateFile +
      • StateFile <name-of-state-file>
        Rsyslog must keep track of which parts of the to be monitored file it already processed. This is done in the state file. This file always is @@ -55,40 +78,19 @@ $WorkDirectory). Be careful to use unique names for different files being monitored. If there are duplicates, all sorts of "interesting" things may happen. Rsyslog currently does not check if a name is specified multiple times.
      • -
      • $InputFileFacility +
      • Facility facility
        The syslog facility to be assigned to lines read. Can be specified in textual form (e.g. "local0", "local1", ...) or as numbers (e.g. 128 for "local0"). Textual form is suggested. Default  is "local0".
      • -
      • $InputFileSeverity
        +
      • Severity
        The syslog severity to be assigned to lines read. Can be specified in textual form (e.g. "info", "warning", ...) or as numbers (e.g. 4 for "info"). Textual form is suggested. Default is "notice".
      • -
      • $InputRunFileMonitor
        -This activates -the current monitor. It has no parameters. If you forget this -directive, no file monitoring will take place.
      • -
      • $InputFilePollInterval -seconds
        -This is a global setting. It specifies how often files are to be polled -for new data. The time specified is in seconds. The default value is 10 -seconds. Please note that future -releases of imfile may support per-file polling intervals, but -currently this is not the case. If multiple $InputFilePollInterval -statements are present in rsyslog.conf, only the last one is used.
        -A short poll interval provides more rapid message forwarding, but -requires more system ressources. While it is possible, we stongly -recommend not to set the polling interval to 0 seconds. That will make -rsyslogd become a CPU hog, taking up considerable ressources. It is -supported, however, for the few very unusual situations where this -level may be needed. Even if you need quick response, 1 seconds should -be well enough. Please note that imfile keeps reading files as long as -there is any data in them. So a "polling sleep" will only happen when -nothing is left to be processed.
      • -
      • $InputFilePersistStateInterval [lines]
        +
      • PersistStateInterval [lines]
        Available in 4.7.3+, 5.6.2+
        Specifies how often the state file shall be written when processing the input file. The default value is 0, which means a new state file is only written when @@ -98,9 +100,9 @@ been processed. This setting can be used to guard against message duplication du to fatal errors (like power fail). Note that this setting affects imfile performance, especially when set to a low value. Frequently writing the state file is very time consuming. -
      • $InputFileReadMode [mode]
        +
      • ReadMode [mode]
        Available in 5.7.5+ -
      • $InputFileMaxLinesAtOnce [number]
        +
      • MaxLinesAtOnce [number]
        Available in 5.9.0+
        This is useful if multiple files need to be monitored. If set to 0, each file @@ -109,8 +111,16 @@ will be fully processed and then processing switches to the next file [number] lines is processed in sequence for each file, and then the file is switched. This provides a kind of mutiplexing the load of multiple files and probably leads to a more natural distribution of events when multiple busy files -are monitored. The default is 10240. -
      • $InputFileBindRuleset <ruleset>
        +are monitored. The default is 1024. +
      • MaxSubmitAtOnce [number]
        +Available in 5.9.0+ +
        +This is an expert option. It can be used to set the maximum input batch size that +imfile can generate. The default is 1024, which is suitable for a wide range of +applications. Be sure to understand rsyslog message batch processing before you +modify this option. If you do not know what this doc here talks about, this is a +good indication that you should NOT modify the default. +
      • Ruleset <ruleset>
        Available in 5.7.5+, 6.1.5+ Binds the listener to a specific ruleset.
      @@ -132,6 +142,71 @@ your distro puts rsyslog's config files). Note that only commands actually needed need to be specified. The second file uses less commands and uses defaults instead.

      + + + +

      Legacy Configuration Directives:

      +
        +
      • $InputFileName /path/to/file
        +equivalent to: File
      • +
      • $InputFileTag +tag:
        +equivalent to: Tag
      • +
      • $InputFileStateFile +<name-of-state-file>
        +equivalent to: StateFile
      • +
      • $InputFileFacility +facility
        +equivalent to: Facility
      • +
      • $InputFileSeverity
        +equivalent to: Severity
      • +
      • $InputRunFileMonitor
        +This activates +the current monitor. It has no parameters. If you forget this +directive, no file monitoring will take place.
      • +
      • $InputFilePollInterval +seconds
        +equivalent to: PollingInterva
      • +
      • $InputFilePersistStateInterval [lines]
        +equivalent to: PersistStateInterval +
      • $InputFileReadMode [mode]
        +equivalent to: ReadMode +
      • $InputFileMaxLinesAtOnce [number]
        +equivalent to: MaxLinesAtOnce +
      • $InputFileBindRuleset <ruleset>
        +equivalent to: Ruleset
      • +
      +Caveats/Known Bugs: +

      So far, only 100 files can be monitored. If more are needed, +the source needs to be patched. See define MAX_INPUT_FILES in imfile.c

      Powertop +users may want to notice that imfile utilizes polling. Thus, it is no +good citizen when it comes to conserving system power consumption. We +are currently evaluating to move to inotify(). However, there are a +number of subtle issues, which needs to be worked out first. We will +make the change as soon as we can. If you can afford it, we recommend +using a long polling interval in the mean time. +

      +

      Sample:

      +

      The following sample monitors two files. If you need just one, +remove the second one. If you need more, add them according to the +sample ;). This code must be placed in /etc/rsyslog.conf (or wherever +your distro puts rsyslog's config files). Note that only commands +actually needed need to be specified. The second file uses less +commands and uses defaults instead.
      +

      + +

      Legacy Configuration Directives:

      +

      This plugin has config directives similar named as imtcp, but they all have PTCP in +their name instead of just TCP. Note that only a subset of the parameters are supported. +

        +
      • $InputPTCPServerAddtlFrameDelimiter <Delimiter>
        +Equivalent to: AddTLFrameDelimiter
      • +
      • $InputPTCPSupportOctetCountedFraming <on|off>
        +Equivalent to: SupportOctetCountedFraming +
      • +
      • $InputPTCPServerNotifyOnConnectionClose [on/off]
        +Equivalent to: ServerNotifyOnConnectionClose.
      • +
      • $InputPTCPServerKeepAlive <on/off>
        +Equivalent to: KeepAlive
      • +
      • $InputPTCPServerKeepAlive_probes <number>
        +Equivalent to: KeepAlive.Probes
      • +
      • $InputPTCPServerKeepAlive_intvl <number>
        +Equivalent to: KeepAlive.Interval
      • +
      • $InputPTCPServerKeepAlive_time <number>
        +Equivalent to: KeepAlive.Time
      • +
      • $InputPTCPServerRun <port>
        +Equivalent to: Port
      • +
      • $InputPTCPServerInputName <name>
        +Equivalent to: Name
      • +
      • $InputPTCPServerBindRuleset <name>
        +Equivalent to: Ruleset
      • $InputPTCPHelperThreads <number>
        Number of helper worker threads to process incoming messages. These threads are utilized to pull data off the network. On a busy system, additional helper threads (but not more than there are CPUs/Cores) can help improving performance. The default value is two.
      • $InputPTCPServerListenIP <name>
        -On multi-homed machines, specifies to which local address the next listerner should -be bound. +Equivalent to: Address
      Caveats/Known Bugs:
        diff --git a/doc/imrelp.html b/doc/imrelp.html index d83b2a15..80ddfd53 100644 --- a/doc/imrelp.html +++ b/doc/imrelp.html @@ -27,11 +27,12 @@ scenarios also exists with plain tcp syslog. RELP, even with the small nits outlined above, is a much more reliable solution than plain tcp syslog and so it is highly suggested to use RELP instead of plain tcp. Clients send messages to the RELP server via omrelp.

        +

        Configuration Directives:

          -
        • InputRELPServerBindRuleset <name> (available in 6.3.6+)
          +
        • Ruleset <name> (available in 6.3.6+)
          Binds the specified ruleset to all RELP listeners. -
        • InputRELPServerRun <port>
          +
        • Port <port>
          Starts a RELP server on selected port
        Caveats/Known Bugs: @@ -46,6 +47,29 @@ not specific ones. This is due to a currently existing limitation in librelp.

        Sample:

        This sets up a RELP server on port 20514.

        + + +

        Legacy Configuration Directives:

        +
          +
        • InputRELPServerBindRuleset <name> (available in 6.3.6+)
          +equivalent to: RuleSet +
        • InputRELPServerRun <port>
          +equivalent to: Port
        • +
        +Caveats/Known Bugs: +
          +
        • see description
        • +
        • To obtain the remote system's IP address, you need to have at least +librelp 1.0.0 installed. Versions below it return the hostname instead +of the IP address.
        • +
        • Contrary to other inputs, the ruleset can only be bound to all listeners, +not specific ones. This is due to a currently existing limitation in librelp. +
        +

        Sample:

        +

        This sets up a RELP server on port 20514.
        +

        diff --git a/doc/imudp.html b/doc/imudp.html index ea985b60..3512d474 100644 --- a/doc/imudp.html +++ b/doc/imudp.html @@ -15,16 +15,13 @@

        Description:

        Provides the ability to receive syslog messages via UDP.

        Multiple receivers may be configured by specifying -$UDPServerRun multiple times. +multiple input actions.

        +

        Configuration Directives:

        +

        Global Directives:

          -
        • $UDPServerAddress <IP>
          -local IP address (or name) the UDP listens should bind to
        • -
        • $UDPServerRun <port>
          -former -r<port> option, default 514, start UDP server on this -port, "*" means all addresses
        • -
        • $UDPServerTimeRequery <nbr-of-times>
          +
        • TimeRequery <nbr-of-times>
          this is a performance optimization. Getting the system time is very costly. With this setting, imudp can be instructed to obtain the precise time only once every n-times. This logic is @@ -33,15 +30,51 @@ time calls should usually be acceptable. The default value is two, because we ha seen that even without optimization the kernel often returns twice the identical time. You can set this value as high as you like, but do so at your own risk. The higher the value, the less precise the timestamp. -
        • $InputUDPServerBindRuleset <ruleset>
          -Binds the listener to a specific ruleset.
        • -
        • $IMUDPSchedulingPolicy <rr/fifo/other>
          +
        • SchedulingPolicy <rr/fifo/other>
          Can be used the set the scheduler priority, if the necessary functionality is provided by the platform. Most useful to select "fifo" for real-time processing under Linux (and thus reduce chance of packet loss). Available since 4.7.4+, 5.7.3+, 6.1.3+. -
        • $IMUDPSchedulingPriority <number>
          +
        • SchedulingPriority <number>
          Scheduling priority to use. Available since 4.7.4+, 5.7.3+, 6.1.3+.
        +

        Action Directives:

        +
          +
        • Address <IP>
          +local IP address (or name) the UDP listens should bind to
        • +
        • Port <port>
          +default 514, start UDP server on this port
        • +
        • Ruleset <ruleset>
          +Binds the listener to a specific ruleset.
        • +
        +Caveats/Known Bugs: +
          +
        • currently none known
        • +
        +

        Sample:

        +

        This sets up an UPD server on port 514:
        +

        + + +

        Legacy Configuration Directives:

        +

        Multiple receivers may be configured by specifying +$UDPServerRun multiple times. +

        +
          +
        • $UDPServerAddress <IP>
          +equivalent to: Address
        • +
        • $UDPServerRun <port>
          +equivalent to: Port
        • +
        • $UDPServerTimeRequery <nbr-of-times>
          +equivalent to: TimeRequery +
        • $InputUDPServerBindRuleset <ruleset>
          +equivalent to: Ruleset
        • +
        • $IMUDPSchedulingPolicy <rr/fifo/other>
          +equivalent to: SchedulingPolicy +
        • $IMUDPSchedulingPriority <number>
          +equivalent to: SchedulingPriority +
        Caveats/Known Bugs:
        • currently none known
        • diff --git a/doc/imuxsock.html b/doc/imuxsock.html index 19f9cf51..bd207a37 100644 --- a/doc/imuxsock.html +++ b/doc/imuxsock.html @@ -24,11 +24,11 @@ information). This seems to be consistent with what sysklogd did for the past four years. Alternate behaviour may be desirable if gateway-like processes send messages via the local log slot - in this case, it can be enabled via the -$InputUnixListenSocketIgnoreMsgTimestamp and $SystemLogSocketIgnoreMsgTimestamp config directives

          +IgnoreTimestamp and SysSock.IgnoreTimestamp config directives

          There is input rate limiting available, (since 5.7.1) to guard you against the problems of a wild running logging process. -If more than $SystemLogRateLimitInterval * $SystemLogRateLimitBurst log messages are emitted -from the same process, those messages with $SystemLogRateLimitSeverity or lower will be +If more than SysSock.RateLimit.Interval * SysSock.RateLimit.Burst log messages are emitted +from the same process, those messages with SysSock.RateLimit.Severity or lower will be dropped. It is not possible to recover anything about these messages, but imuxsock will tell you how many it has dropped one the interval has expired AND the next message is logged. Rate-limiting depends on SCM_CREDENTIALS. If the platform does not support @@ -36,7 +36,7 @@ this socket option, rate limiting is turned off. If multiple sockets are configu rate limiting works independently on each of them (that should be what you usually expect). The same functionality is available for additional log sockets, in which case the config statements just use -the prefix $IMUXSockRateLimit... but otherwise works exactly the same. +the prefix RateLimit... but otherwise works exactly the same. When working with severities, please keep in mind that higher severity numbers mean lower severity and configure things accordingly. To turn off rate limiting, set the interval to zero. @@ -46,8 +46,8 @@ the queues (which may cause exessive disk-io where it actually would not be need flow-controlling a log socket (and especially the system log socket) can lead to a very unresponsive system. As such, flow control is disabled by default. That means any log records are places as quickly as possible into the processing queues. If you would like to have -flow control, you need to enable it via the $SystemLogSocketFlowControl and -$InputUnixListenSocketFlowControl config directives. Just make sure you thought about +flow control, you need to enable it via the SysSock.FlowControl and +FlowControl config directives. Just make sure you thought about the implications. Note that for many systems, turning on flow control does not hurt.

          Starting with rsyslog 5.9.4, trusted syslog properties @@ -57,87 +57,177 @@ privileges are dropped (depending on how they are dropped). Note that trusted pr can be very useful, but also typically cause the message to grow rather large. Also, the format of log messages is obviously changed by adding the trusted properties at the end. For these reasons, the feature is not enabled by default. If you want to use it, -you must turn it on (via $SystemLogSocketAnnotate and $InputUnixListenSocketAnnotate). +you must turn it on (via SysSock.Annotate and Annotate). +

          Configuration Directives:

          +

          Global Parameters

            -
          • $InputUnixListenSocketIgnoreMsgTimestamp [on/off] +
          • SysSock.IgnoreTimestamp [on/off]
            +Ignore timestamps included in the messages, applies to messages received via the system log socket. +
          • +
          • SysSock.Use (imuxsock) [on/off] +do NOT listen for the local log socket. This is most useful if you run multiple +instances of rsyslogd where only one shall handle the system log socket. +
          • +
          • SysSock.Name <name-of-socket> +
          • +
          • SysSock.FlowControl [on/off] - specifies if flow control should be applied +to the system log socket. +
          • +
          • SysSock.UsePIDFromSystem [on/off] - specifies if the pid being logged shall +be obtained from the log socket itself. If so, the TAG part of the message is rewritten. +It is recommended to turn this option on, but the default is "off" to keep compatible +with earlier versions of rsyslog. This option was introduced in 5.7.0. +
          • +
          • SysSock.RateLimit.Interval [number] - specifies the rate-limiting +interval in seconds. Default value is 5 seconds. Set it to 0 to turn rate limiting off. +
          • +
          • SysSock.RateLimit.Burst [number] - specifies the rate-limiting +burst in number of messages. Default is 200. +
          • +
          • SysSock.RateLimit.Severity [numerical severity] - specifies the severity of +messages that shall be rate-limited. +
          • +
          • SysSock.UseSysTimeStamp [on/off] the same as $InputUnixListenSocketUseSysTimeStamp, but for the system log socket. +
          • +
          • SysSock.Annotate <on/off> turn on annotation/trusted +properties for the system log socket.
          • +
          + +

          Input Instance Parameters

          +
            +
          • IgnoreTimestamp [on/off]
            Ignore timestamps included in the message. Applies to the next socket being added.
          • -
          • $InputUnixListenSocketFlowControl [on/off] - specifies if flow control should be applied +
          • FlowControl [on/off] - specifies if flow control should be applied to the next socket.
          • -
          • $IMUXSockRateLimitInterval [number] - specifies the rate-limiting +
          • RateLimit.Interval [number] - specifies the rate-limiting interval in seconds. Default value is 0, which turns off rate limiting. Set it to a number of seconds (5 recommended) to activate rate-limiting. The default of 0 has been choosen in 5.9.6+, as people experienced problems with this feature activated by default. Now it needs an explicit opt-in by setting this parameter.
          • -
          • $IMUXSockRateLimitBurst [number] - specifies the rate-limiting +
          • RateLimit.Burst [number] - specifies the rate-limiting burst in number of messages. Default is 200.
          • -
          • $IMUXSockRateLimitSeverity [numerical severity] - specifies the severity of +
          • RateLimit.Severity [numerical severity] - specifies the severity of messages that shall be rate-limited.
          • -
          • $IMUXSockLocalIPIF [interface name] - (available since 5.9.6) - if provided, the IP of the specified + +
          • UsePIDFromSystem [on/off] - specifies if the pid being logged shall be obtained from the log socket itself. If so, the TAG part of the message is rewritten. It is recommended to turn this option on, but the default is "off" to keep compatible with earlier versions of rsyslog. This option was introduced in 5.7.0.
          • -
          • $InputUnixListenSocketUseSysTimeStamp [on/off] instructs imuxsock +
          • UseSysTimeStamp [on/off] instructs imuxsock to obtain message time from the system (via control messages) insted of using time recorded inside the message. This may be most useful in combination with systemd. Note: this option was introduced with version 5.9.1. Due to the usefulness of it, we decided to enable it by default. As such, 5.9.1 and above behave slightly different than previous versions. However, we do not see how this could negatively affect existing environments.
            -
          • $SystemLogSocketIgnoreMsgTimestamp [on/off]
            -Ignore timestamps included in the messages, applies to messages received via the system log socket.
          • -
          • $OmitLocalLogging (imuxsock) [on/off] -- former -o option; -do NOT listen for the local log socket. This is most useful if you run multiple -instances of rsyslogd where only one shall handle the system log socket.
          • -
          • $SystemLogSocketName <name-of-socket> -- former -p option
          • -
          • $SystemLogFlowControl [on/off] - specifies if flow control should be applied -to the system log socket.
          • -
          • $SystemLogUsePIDFromSystem [on/off] - specifies if the pid being logged shall -be obtained from the log socket itself. If so, the TAG part of the message is rewritten. -It is recommended to turn this option on, but the default is "off" to keep compatible -with earlier versions of rsyslog. This option was introduced in 5.7.0.
          • -
          • $SystemLogParseTrusted [on/off] - specifies if Trusted Properties shall be parsed -and saved into libee event structure. This option needs $SystemLogSocketAnnotate to be on.
          • -
          • $SystemLogRateLimitInterval [number] - specifies the rate-limiting -interval in seconds. Default value is 5 seconds. Set it to 0 to turn rate limiting off. -
          • -
          • $SystemLogRateLimitBurst [number] - specifies the rate-limiting -burst in number of messages. Default is 200. -
          • -
          • $SystemLogRateLimitSeverity [numerical severity] - specifies the severity of -messages that shall be rate-limited. -
          • -
          • $SystemLogUseSysTimeStamp [on/off] the same as $InputUnixListenSocketUseSysTimeStamp, but for the system log socket. -
          • $InputUnixListenSocketCreatePath [on/off] - create directories in the socket path +
          • CreatePath [on/off] - create directories in the socket path if they do not already exist. They are created with 0755 permissions with the owner being the process under which rsyslogd runs. The default is not to create directories. Keep in mind, though, that rsyslogd always creates the socket itself if it does not exist (just not the directories by default).
            Note that this statement affects the -next $AddUnixListenSocket directive that follows in sequence in the configuration file. It never works +next Socket directive that follows in sequence in the configuration file. It never works on the system log socket (where it is deemed unnecessary). Also note that it is automatically -being reset to "off" after the $AddUnixListenSocket directive, so if you would have it active +being reset to "off" after the Socket directive, so if you would have it active for two additional listen sockets, you need to specify it in front of each one. This option is primarily considered useful for defining additional sockets that reside on non-permanent file systems. As rsyslogd probably starts up before the daemons that create these sockets, it is a vehicle to enable rsyslogd to listen to those sockets even though their directories do not yet exist. [available since 4.7.0 and 5.3.0]
          • -
          • $AddUnixListenSocket <name-of-socket> adds additional unix socket, default none -- former -a option
          • -
          • $InputUnixListenSocketHostName <hostname> permits to override the hostname that -shall be used inside messages taken from the next $AddUnixListenSocket socket. Note that +
          • Socket <name-of-socket> adds additional unix socket, default none -- former -a option
          • +
          • HostName <hostname> permits to override the hostname that +shall be used inside messages taken from the next Socket socket. Note that the hostname must be specified before the $AddUnixListenSocket configuration directive, and it will only affect the next one and then automatically be reset. This functionality is provided so that the local hostname can be overridden in cases where that is desired.
          • -
          • $InputUnixListenSocketAnnotate <on/off> turn on annotation/trusted +
          • Annotate <on/off> turn on annotation/trusted properties for the non-system log socket in question.
          • -
          • $SystemLogSocketAnnotate <on/off> turn on annotation/trusted -properties for the system log socket.
          • +
          + +Caveats/Known Bugs:
          +
            +
          • There is a compile-time limit of 50 concurrent sockets. If you need more, you need to +change the array size in imuxsock.c. +
          • This documentation is sparse and incomplete. +
          +

          Sample:

          +

          The following sample is the minimum setup required to accept syslog messages from applications running +on the local system.
          +

          + +

          The following sample is a configuration where rsyslogd pulls logs from two +jails, and assigns different hostnames to each of the jails:

          + +

          The following sample is a configuration where rsyslogd reads the openssh log +messages via a separate socket, but this socket is created on a temporary file +system. As rsyslogd starts up before the sshd, it needs to create the socket +directories, because it otherwise can not open the socket and thus not listen +to openssh messages. Note that it is vital not to place any other socket between +the CreatePath and the Socket.

          + +

          The following sample is used to turn off input rate limiting on the system log +socket. + +

          The following sample is used activate message annotation and thus trusted properties +on the system log socket. + + + +

          Legacy Configuration Directives:

          +
            +
          • $InputUnixListenSocketIgnoreMsgTimestamp [on/off] +
            Please see: IgnoreTimestamp.
          • +
          • $InputUnixListenSocketFlowControl [on/off] - Please see: FlowControl .
          • +
          • $IMUXSockRateLimitInterval [number] - Please see: RateLimit.Interval +
          • +
          • $IMUXSockRateLimitBurst [number] - Please see: RateLimit.Burst +
          • +
          • $IMUXSockRateLimitSeverity [numerical severity] - Please see: RateLimit.Severity +
          • +
          • $IMUXSockLocalIPIF [interface name] - (available since 5.9.6) - if provided, the IP of the specified +interface (e.g. "eth0") shall be used as fromhost-ip for imuxsock-originating messages. +If this directive is not given OR the interface cannot be found (or has no IP address), +the default of "127.0.0.1" is used. +
          • +
          • $InputUnixListenSocketUsePIDFromSystem [on/off] - Please see: UsePIDFromSystem.
          • +
          • $InputUnixListenSocketUseSysTimeStamp [on/off] Please see: UseSysTimeStamp .
            +
          • $SystemLogSocketIgnoreMsgTimestamp [on/off]
            +Please see: SysSock.IgnoreTimestamp.
          • +
          • $OmitLocalLogging (imuxsock) [on/off] Please see: SysSock.Use
          • +
          • $SystemLogSocketName <name-of-socket> Please see: SysSock.Name
          • +
          • $SystemLogFlowControl [on/off] - Please see: SysSock.FlowControl.
          • +
          • $SystemLogUsePIDFromSystem [on/off] - Please see: SysSock.UsePIDFromSystem.
          • +
          • $SystemLogRateLimitInterval [number] - Please see: SysSock.RateLimit.Interval. +
          • +
          • $SystemLogRateLimitBurst [number] - Please see: SysSock.RateLimit.Burst +
          • +
          • $SystemLogRateLimitSeverity [numerical severity] - Please see: SysSock.RateLimit.Severity +
          • +
          • $SystemLogUseSysTimeStamp [on/off] Please see: SysSock.UseSysTimeStamp. +
          • $InputUnixListenSocketCreatePath [on/off] - Please see: CreatePath
          • +
          • $AddUnixListenSocket <name-of-socket> Please see: Socket
          • +
          • $InputUnixListenSocketHostName <hostname> Please see: HostName.
          • +
          • $InputUnixListenSocketAnnotate <on/off> Please see: Annotate.
          • +
          • $SystemLogSocketAnnotate <on/off> Please see: SysSock.Annotate.
          Caveats/Known Bugs:
          @@ -171,7 +261,7 @@ the $InputUnixListenSocketCreatePath and the $InputUnixListenSocketHostName.

          The following sample is used to turn off input rate limiting on the system log socket. -- cgit v1.2.3 From ffab8e595e82e7980955b2ed2ebbb4c7f1fdbe05 Mon Sep 17 00:00:00 2001 From: Ulrike Gerhards Date: Tue, 2 Oct 2012 12:18:25 +0200 Subject: add new tool "logctl" to access lumberjack logs in MongoDB --- tools/logctl.c | 456 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 456 insertions(+) create mode 100644 tools/logctl.c diff --git a/tools/logctl.c b/tools/logctl.c new file mode 100644 index 00000000..324c9840 --- /dev/null +++ b/tools/logctl.c @@ -0,0 +1,456 @@ +/** + * logctl - a tool to access lumberjack logs in MongoDB + * ... and potentially other sources in the future. + * + * Copyright 2012 Ulrike Gerhards and Adiscon GmbH. + * + * long short + + * level l read records with level x + * severity s read records with severity x + * ret r number of records to return + * skip k number of records to skip + * sys y read records of system x + * msg m read records with message containing x + * datef f read records starting on time received x + * dateu u read records until time received x + * + * examples: + * + * logctl -f 15/05/2012-12:00:00 -u 15/05/2012-12:37:00 + * logctl -s 50 --ret 10 + * logctl -m "closed" + * logctl -l "INFO" + * logctl -s 3 + * logctl -y "ubuntu" + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Rsyslog is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#define N 80 + +static struct option long_options[] = +{ + {"level", required_argument, NULL, 'l'}, + {"severity", required_argument, NULL, 's'}, + {"ret", required_argument, NULL, 'r'}, + {"skip", required_argument, NULL, 'k'}, + {"sys", required_argument, NULL, 'y'}, + {"msg", required_argument, NULL, 'm'}, + {"datef", required_argument, NULL, 'f'}, + {"dateu", required_argument, NULL, 'u'}, + {NULL, 0, NULL, 0} +}; + +struct queryopt +{ + gint32 e_sever; + gint32 e_ret; + gint32 e_skip; + char *e_date; + char *e_level; + char *e_msg; + char *e_sys; + char *e_dateu; + int bsever; + int blevel; + int bskip; + int bret; + int bsys; + int bmsg; + int bdate; + int bdatef; + int bdateu; +}; + +struct ofields +{ + const char *msg; + const char *syslog_tag; + const char *prog; + char *date; + gint64 date_r; +}; + +struct query_doc +{ + bson *query; +}; + +struct select_doc +{ + bson *select; +}; + +struct db_connect +{ + mongo_sync_connection *conn; +}; + +struct output +{ + mongo_packet *p; +}; + +struct db_cursor +{ + mongo_sync_cursor *cursor; +}; + +struct results +{ + bson *result; +}; + + + +void formater(struct ofields *fields) +{ + time_t rtime; + rtime = (time_t) (fields->date_r / 1000); + char str[N]; + strftime(str, N, "%b %d %H:%M:%S", gmtime(&rtime)); + printf("%s %s %s %s\n", str, fields->prog, fields->syslog_tag, fields->msg); + +} + +struct ofields* get_data(struct results *res) +{ + struct ofields *fields; + const char *msg; + const char *prog; + const char *level; + const char *syslog_tag; + gint64 date_r; + bson_cursor *c; + + fields = malloc(sizeof(struct ofields)); + + c = bson_find (res->result, "msg"); + if (!bson_cursor_get_string (c, &msg)) + { + perror ("bson_cursor_get_string()"); + exit (1); + } + bson_cursor_free (c); + + c = bson_find (res->result, "sys"); + if (!bson_cursor_get_string (c, &prog)) + { + perror ("bson_cursor_get_string()"); + exit (1); + } + bson_cursor_free (c); + + c = bson_find (res->result, "syslog_tag"); + if (!bson_cursor_get_string (c, &syslog_tag)) + { + perror ("bson_cursor_get_string()"); + exit (1); + } + bson_cursor_free (c); + + c = bson_find (res->result, "time_rcvd"); + if (!bson_cursor_get_utc_datetime (c, &date_r)) + { + perror ("bson_cursor_get_utc_datetime()"); + exit (1); + } + + bson_cursor_free (c); + fields->msg = msg; + fields->prog = prog; + fields->syslog_tag = syslog_tag; + fields->date_r = date_r; + + return fields; + +} + +void getoptions(int argc, char *argv[], struct queryopt *opt) +{ + int iarg; + while ((iarg = getopt_long(argc, argv, "l:s:r:k:y:f:u:m:", long_options, NULL)) != -1) + { + // check to see if a single character or long option came through + switch (iarg) + { + // short option 's' + case 's': + opt->bsever = 1; + opt->e_sever = atoi(optarg); + break; + // short option 'r' + case 'r': + opt->bret = 1; + opt->e_ret = atoi(optarg); + break; + // short option 'f' : date from + case 'f': + opt->bdate = 1; + opt->bdatef = 1; + opt->e_date = optarg; + break; + // short option 'u': date until + case 'u': + opt->bdate = 1; + opt->bdateu = 1; + opt->e_dateu = optarg; + break; + // short option 'k' + case 'k': + opt->bskip = 1; + opt->e_skip = atoi(optarg); + break; + // short option 'l' + case 'l': + opt->blevel = 1; + opt->e_level = optarg; + break; + // short option 'm' + case 'm': + opt->bmsg = 1; + opt->e_msg = optarg; + break; + // short option 'y' + case 'y': + opt->bsys = 1; + opt->e_sys = optarg; + break; + } // end switch iarg + } // end while + +} // end void getoptions + +struct select_doc* create_select() +// BSON object indicating the fields to return +{ + struct select_doc *s_doc; + s_doc = malloc(sizeof(struct select_doc)); + s_doc->select = bson_new (); + bson_append_string (s_doc->select, "syslog_tag", "s", -1); + bson_append_string (s_doc->select, "msg", "ERROR", -1); + bson_append_string (s_doc->select, "sys", "sys", -1); + bson_append_utc_datetime (s_doc->select, "time_rcvd", 1ll); + bson_finish (s_doc->select); + return s_doc; +} + +struct query_doc* create_query(struct queryopt *opt) +{ + struct query_doc *qu_doc; + bson *query_what, *order_what, *order_how, *msg_what, *date_what; + struct tm tm; + time_t t; + gint64 ts; + qu_doc = malloc(sizeof(struct query_doc)); + qu_doc->query = bson_new (); + + query_what = bson_new (); + if (opt->bsever == 1) + { + bson_append_int32 (query_what, "syslog_sever", opt->e_sever); + } + if (opt->blevel == 1) + { + bson_append_string (query_what, "level", opt->e_level, -1); + } + + if (opt->bmsg == 1) + { + msg_what = bson_new (); + bson_append_string (msg_what, "$regex", opt->e_msg, -1); + bson_append_string (msg_what, "$options", "i", -1); + bson_finish (msg_what); + bson_append_document (query_what, "msg", msg_what); + } + + if (opt->bdate == 1) + { + date_what = bson_new (); + if (opt->bdatef == 1) + { + tm.tm_isdst = -1; + strptime(opt->e_date, "%d/%m/%Y-%H:%M:%S", &tm); + tm.tm_hour = tm.tm_hour + 1; + t = mktime(&tm); + ts = 1000 * (gint64) t; + + bson_append_utc_datetime (date_what,"$gt", ts) ; + } + + if (opt->bdateu == 1) + { + tm.tm_isdst = -1; + strptime(opt->e_dateu, "%d/%m/%Y-%H:%M:%S", &tm); + tm.tm_hour = tm.tm_hour +1; + t = mktime(&tm); + ts = 1000 * (gint64) t; + bson_append_utc_datetime (date_what,"$lt", ts); + + } + bson_finish (date_what); + bson_append_document (query_what, "time_rcvd", date_what); + } + + if (opt->bsys == 1) + { + bson_append_string (query_what, "sys", opt->e_sys, -1); + } + + bson_finish (query_what); + + order_what = bson_new (); + bson_append_utc_datetime (order_what, "time_rcvd", 1ll); + bson_finish (order_what); + + bson_append_document (qu_doc->query, "$query", query_what); + bson_append_document (qu_doc->query, "$orderby", order_what); + bson_finish (qu_doc->query); + bson_free (order_what); + return qu_doc; +} + +struct db_connect* create_conn() +{ + struct db_connect *db_conn; + db_conn = malloc(sizeof(struct db_connect)); + db_conn->conn = mongo_sync_connect ("localhost", 27017, TRUE); + + if (!db_conn->conn) + { + perror ("mongo_sync_connect()"); + exit (1); + } + return db_conn; +} + +void close_conn(struct db_connect *db_conn) +{ + mongo_sync_disconnect (db_conn->conn); +} + +void free_cursor(struct db_cursor *db_c) +{ + mongo_sync_cursor_free (db_c->cursor); +} + +struct output* launch_query(struct queryopt *opt, struct select_doc *s_doc, + struct query_doc *qu_doc, + struct db_connect *db_conn) +{ + struct output *out; + out = malloc(sizeof(struct output)); + out->p = mongo_sync_cmd_query (db_conn->conn, "syslog.log", 0, + opt->e_skip, opt->e_ret, qu_doc->query, s_doc->select); + if (!out->p) + { + perror ("mongo_sync_cmd_query()"); + printf("no records found\n"); + exit (1); + } + return out; +} + +struct db_cursor* open_cursor(struct db_connect *db_conn, struct output *out) +{ + struct db_cursor *db_c; + db_c = malloc(sizeof(struct db_cursor)); + + db_c->cursor = mongo_sync_cursor_new (db_conn->conn, "syslog.log", out->p); + if (!db_c->cursor) + { + perror ("mongo_sync_cursor_new()"); + exit (1); + } + return db_c; +} + +struct results* read_data(struct db_cursor *db_c) +{ + struct results *res; + res = malloc(sizeof(struct results)); + res->result = mongo_sync_cursor_get_data (db_c->cursor); + if (!res->result) + { + perror ("mongo_sync_cursor_get_data()"); + exit (1); + } + return res; +} + +gboolean cursor_next (struct db_cursor *db_c) +{ + if (!mongo_sync_cursor_next (db_c->cursor)) + return FALSE; + else + return TRUE; + +} + +int main (int argc, char *argv[]) +{ + + struct queryopt opt; + struct ofields *fields; + struct bson_doc *doc; + struct select_doc *s_doc; + struct query_doc *qu_doc; + struct db_connect *db_conn; + struct output *out; + struct db_cursor *db_c; + struct results *res; + + opt.e_skip = 0; // standard + opt.e_ret = 0; // standard + opt.bsever = 0; + opt.blevel = 0; + opt.bdate = 0; + opt.bdateu = 0; + opt.bdatef = 0; + opt.bmsg = 0; + opt.bskip = 0; + opt.bsys = 0; + + getoptions(argc, argv, &opt); + qu_doc = create_query(&opt); // crate query + s_doc = create_select(); + db_conn = create_conn(); // create connection + out = launch_query(&opt, s_doc, qu_doc, db_conn); // launch the query + db_c = open_cursor(db_conn, out); // open cursor + + while (cursor_next(db_c)) + { + res = read_data(db_c); + fields = get_data(res); + formater(fields); // formate output + free(fields); + } + + free_cursor(db_c); + close_conn(db_conn); + + return (0); +} -- cgit v1.2.3 From 3a7c280e932166fe3dc010d1ad61e5800abeb9ea Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 2 Oct 2012 15:07:41 +0200 Subject: integrate logctl into build process --- ChangeLog | 1 + configure.ac | 13 + tools/Makefile.am | 10 + tools/logctl.c | 914 +++++++++++++++++++++++++++--------------------------- 4 files changed, 482 insertions(+), 456 deletions(-) diff --git a/ChangeLog b/ChangeLog index 93df217c..fa5a861e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ --------------------------------------------------------------------------- Version 6.5.1 [devel] 2012-08-?? +- added tool "logctl" to handle lumberjack logs in MongoDB - imfile ported to new v6 config interface - imfile now supports config parameter for maximum number of submits which is a fine-tuning parameter in regard to input baching diff --git a/configure.ac b/configure.ac index 1d7aec58..c7c74dc4 100644 --- a/configure.ac +++ b/configure.ac @@ -507,6 +507,18 @@ AC_ARG_ENABLE(diagtools, AM_CONDITIONAL(ENABLE_DIAGTOOLS, test x$enable_diagtools = xyes) +# compile end-user tools +AC_ARG_ENABLE(usertools, + [AS_HELP_STRING([--enable-usertools],[Enable end user tools @<:@default=no@:>@])], + [case "${enableval}" in + yes) enable_usertools="yes" ;; + no) enable_usertools="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-usertools) ;; + esac], + [enable_usertools=no] +) +AM_CONDITIONAL(ENABLE_USERTOOLS, test x$enable_usertools = xyes) + # MySQL support AC_ARG_ENABLE(mysql, @@ -1472,6 +1484,7 @@ echo " Debug mode enabled: $enable_debug" echo " Runtime Instrumentation enabled: $enable_rtinst" echo " (total) debugless mode enabled: $enable_debugless" echo " Diagnostic tools enabled: $enable_diagtools" +echo " End-User tools enabled: $enable_usertools" echo " Enhanced memory checking enabled: $enable_memcheck" echo " Valgrind support settings enabled: $enable_valgrind" echo diff --git a/tools/Makefile.am b/tools/Makefile.am index 60a2dd61..7f3ceef8 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,4 +1,5 @@ sbin_PROGRAMS = +bin_PROGRAMS = man_MANS = rsyslogd.8 rsyslog.conf.5 sbin_PROGRAMS += rsyslogd @@ -51,5 +52,14 @@ zpipe_LDADD = -lz msggen_SOURCES = msggen.c endif +if ENABLE_USERTOOLS +if ENABLE_OMMONGODB +bin_PROGRAMS += logctl +logctl_SOURCES = logctl.c +logctl_CPPFLAGS = $(LIBMONGO_CLIENT_CFLAGS) +logctl_LDADD = $(LIBMONGO_CLIENT_LIBS) +endif +endif + EXTRA_DIST = $(man_MANS) \ recover_qi.pl diff --git a/tools/logctl.c b/tools/logctl.c index 324c9840..df332bc2 100644 --- a/tools/logctl.c +++ b/tools/logctl.c @@ -1,456 +1,458 @@ -/** - * logctl - a tool to access lumberjack logs in MongoDB - * ... and potentially other sources in the future. - * - * Copyright 2012 Ulrike Gerhards and Adiscon GmbH. - * - * long short - - * level l read records with level x - * severity s read records with severity x - * ret r number of records to return - * skip k number of records to skip - * sys y read records of system x - * msg m read records with message containing x - * datef f read records starting on time received x - * dateu u read records until time received x - * - * examples: - * - * logctl -f 15/05/2012-12:00:00 -u 15/05/2012-12:37:00 - * logctl -s 50 --ret 10 - * logctl -m "closed" - * logctl -l "INFO" - * logctl -s 3 - * logctl -y "ubuntu" - * This file is part of rsyslog. - * - * Rsyslog is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Rsyslog is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Rsyslog. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define N 80 - -static struct option long_options[] = -{ - {"level", required_argument, NULL, 'l'}, - {"severity", required_argument, NULL, 's'}, - {"ret", required_argument, NULL, 'r'}, - {"skip", required_argument, NULL, 'k'}, - {"sys", required_argument, NULL, 'y'}, - {"msg", required_argument, NULL, 'm'}, - {"datef", required_argument, NULL, 'f'}, - {"dateu", required_argument, NULL, 'u'}, - {NULL, 0, NULL, 0} -}; - -struct queryopt -{ - gint32 e_sever; - gint32 e_ret; - gint32 e_skip; - char *e_date; - char *e_level; - char *e_msg; - char *e_sys; - char *e_dateu; - int bsever; - int blevel; - int bskip; - int bret; - int bsys; - int bmsg; - int bdate; - int bdatef; - int bdateu; -}; - -struct ofields -{ - const char *msg; - const char *syslog_tag; - const char *prog; - char *date; - gint64 date_r; -}; - -struct query_doc -{ - bson *query; -}; - -struct select_doc -{ - bson *select; -}; - -struct db_connect -{ - mongo_sync_connection *conn; -}; - -struct output -{ - mongo_packet *p; -}; - -struct db_cursor -{ - mongo_sync_cursor *cursor; -}; - -struct results -{ - bson *result; -}; - - - -void formater(struct ofields *fields) -{ - time_t rtime; - rtime = (time_t) (fields->date_r / 1000); - char str[N]; - strftime(str, N, "%b %d %H:%M:%S", gmtime(&rtime)); - printf("%s %s %s %s\n", str, fields->prog, fields->syslog_tag, fields->msg); - -} - -struct ofields* get_data(struct results *res) -{ - struct ofields *fields; - const char *msg; - const char *prog; - const char *level; - const char *syslog_tag; - gint64 date_r; - bson_cursor *c; - - fields = malloc(sizeof(struct ofields)); - - c = bson_find (res->result, "msg"); - if (!bson_cursor_get_string (c, &msg)) - { - perror ("bson_cursor_get_string()"); - exit (1); - } - bson_cursor_free (c); - - c = bson_find (res->result, "sys"); - if (!bson_cursor_get_string (c, &prog)) - { - perror ("bson_cursor_get_string()"); - exit (1); - } - bson_cursor_free (c); - - c = bson_find (res->result, "syslog_tag"); - if (!bson_cursor_get_string (c, &syslog_tag)) - { - perror ("bson_cursor_get_string()"); - exit (1); - } - bson_cursor_free (c); - - c = bson_find (res->result, "time_rcvd"); - if (!bson_cursor_get_utc_datetime (c, &date_r)) - { - perror ("bson_cursor_get_utc_datetime()"); - exit (1); - } - - bson_cursor_free (c); - fields->msg = msg; - fields->prog = prog; - fields->syslog_tag = syslog_tag; - fields->date_r = date_r; - - return fields; - -} - -void getoptions(int argc, char *argv[], struct queryopt *opt) -{ - int iarg; - while ((iarg = getopt_long(argc, argv, "l:s:r:k:y:f:u:m:", long_options, NULL)) != -1) - { - // check to see if a single character or long option came through - switch (iarg) - { - // short option 's' - case 's': - opt->bsever = 1; - opt->e_sever = atoi(optarg); - break; - // short option 'r' - case 'r': - opt->bret = 1; - opt->e_ret = atoi(optarg); - break; - // short option 'f' : date from - case 'f': - opt->bdate = 1; - opt->bdatef = 1; - opt->e_date = optarg; - break; - // short option 'u': date until - case 'u': - opt->bdate = 1; - opt->bdateu = 1; - opt->e_dateu = optarg; - break; - // short option 'k' - case 'k': - opt->bskip = 1; - opt->e_skip = atoi(optarg); - break; - // short option 'l' - case 'l': - opt->blevel = 1; - opt->e_level = optarg; - break; - // short option 'm' - case 'm': - opt->bmsg = 1; - opt->e_msg = optarg; - break; - // short option 'y' - case 'y': - opt->bsys = 1; - opt->e_sys = optarg; - break; - } // end switch iarg - } // end while - -} // end void getoptions - -struct select_doc* create_select() -// BSON object indicating the fields to return -{ - struct select_doc *s_doc; - s_doc = malloc(sizeof(struct select_doc)); - s_doc->select = bson_new (); - bson_append_string (s_doc->select, "syslog_tag", "s", -1); - bson_append_string (s_doc->select, "msg", "ERROR", -1); - bson_append_string (s_doc->select, "sys", "sys", -1); - bson_append_utc_datetime (s_doc->select, "time_rcvd", 1ll); - bson_finish (s_doc->select); - return s_doc; -} - -struct query_doc* create_query(struct queryopt *opt) -{ - struct query_doc *qu_doc; - bson *query_what, *order_what, *order_how, *msg_what, *date_what; - struct tm tm; - time_t t; - gint64 ts; - qu_doc = malloc(sizeof(struct query_doc)); - qu_doc->query = bson_new (); - - query_what = bson_new (); - if (opt->bsever == 1) - { - bson_append_int32 (query_what, "syslog_sever", opt->e_sever); - } - if (opt->blevel == 1) - { - bson_append_string (query_what, "level", opt->e_level, -1); - } - - if (opt->bmsg == 1) - { - msg_what = bson_new (); - bson_append_string (msg_what, "$regex", opt->e_msg, -1); - bson_append_string (msg_what, "$options", "i", -1); - bson_finish (msg_what); - bson_append_document (query_what, "msg", msg_what); - } - - if (opt->bdate == 1) - { - date_what = bson_new (); - if (opt->bdatef == 1) - { - tm.tm_isdst = -1; - strptime(opt->e_date, "%d/%m/%Y-%H:%M:%S", &tm); - tm.tm_hour = tm.tm_hour + 1; - t = mktime(&tm); - ts = 1000 * (gint64) t; - - bson_append_utc_datetime (date_what,"$gt", ts) ; - } - - if (opt->bdateu == 1) - { - tm.tm_isdst = -1; - strptime(opt->e_dateu, "%d/%m/%Y-%H:%M:%S", &tm); - tm.tm_hour = tm.tm_hour +1; - t = mktime(&tm); - ts = 1000 * (gint64) t; - bson_append_utc_datetime (date_what,"$lt", ts); - - } - bson_finish (date_what); - bson_append_document (query_what, "time_rcvd", date_what); - } - - if (opt->bsys == 1) - { - bson_append_string (query_what, "sys", opt->e_sys, -1); - } - - bson_finish (query_what); - - order_what = bson_new (); - bson_append_utc_datetime (order_what, "time_rcvd", 1ll); - bson_finish (order_what); - - bson_append_document (qu_doc->query, "$query", query_what); - bson_append_document (qu_doc->query, "$orderby", order_what); - bson_finish (qu_doc->query); - bson_free (order_what); - return qu_doc; -} - -struct db_connect* create_conn() -{ - struct db_connect *db_conn; - db_conn = malloc(sizeof(struct db_connect)); - db_conn->conn = mongo_sync_connect ("localhost", 27017, TRUE); - - if (!db_conn->conn) - { - perror ("mongo_sync_connect()"); - exit (1); - } - return db_conn; -} - -void close_conn(struct db_connect *db_conn) -{ - mongo_sync_disconnect (db_conn->conn); -} - -void free_cursor(struct db_cursor *db_c) -{ - mongo_sync_cursor_free (db_c->cursor); -} - -struct output* launch_query(struct queryopt *opt, struct select_doc *s_doc, - struct query_doc *qu_doc, - struct db_connect *db_conn) -{ - struct output *out; - out = malloc(sizeof(struct output)); - out->p = mongo_sync_cmd_query (db_conn->conn, "syslog.log", 0, - opt->e_skip, opt->e_ret, qu_doc->query, s_doc->select); - if (!out->p) - { - perror ("mongo_sync_cmd_query()"); - printf("no records found\n"); - exit (1); - } - return out; -} - -struct db_cursor* open_cursor(struct db_connect *db_conn, struct output *out) -{ - struct db_cursor *db_c; - db_c = malloc(sizeof(struct db_cursor)); - - db_c->cursor = mongo_sync_cursor_new (db_conn->conn, "syslog.log", out->p); - if (!db_c->cursor) - { - perror ("mongo_sync_cursor_new()"); - exit (1); - } - return db_c; -} - -struct results* read_data(struct db_cursor *db_c) -{ - struct results *res; - res = malloc(sizeof(struct results)); - res->result = mongo_sync_cursor_get_data (db_c->cursor); - if (!res->result) - { - perror ("mongo_sync_cursor_get_data()"); - exit (1); - } - return res; -} - -gboolean cursor_next (struct db_cursor *db_c) -{ - if (!mongo_sync_cursor_next (db_c->cursor)) - return FALSE; - else - return TRUE; - -} - -int main (int argc, char *argv[]) -{ - - struct queryopt opt; - struct ofields *fields; - struct bson_doc *doc; - struct select_doc *s_doc; - struct query_doc *qu_doc; - struct db_connect *db_conn; - struct output *out; - struct db_cursor *db_c; - struct results *res; - - opt.e_skip = 0; // standard - opt.e_ret = 0; // standard - opt.bsever = 0; - opt.blevel = 0; - opt.bdate = 0; - opt.bdateu = 0; - opt.bdatef = 0; - opt.bmsg = 0; - opt.bskip = 0; - opt.bsys = 0; - - getoptions(argc, argv, &opt); - qu_doc = create_query(&opt); // crate query - s_doc = create_select(); - db_conn = create_conn(); // create connection - out = launch_query(&opt, s_doc, qu_doc, db_conn); // launch the query - db_c = open_cursor(db_conn, out); // open cursor - - while (cursor_next(db_c)) - { - res = read_data(db_c); - fields = get_data(res); - formater(fields); // formate output - free(fields); - } - - free_cursor(db_c); - close_conn(db_conn); - - return (0); -} +/** + * logctl - a tool to access lumberjack logs in MongoDB + * ... and potentially other sources in the future. + * + * Copyright 2012 Ulrike Gerhards and Adiscon GmbH. + * + * long short + + * level l read records with level x + * severity s read records with severity x + * ret r number of records to return + * skip k number of records to skip + * sys y read records of system x + * msg m read records with message containing x + * datef f read records starting on time received x + * dateu u read records until time received x + * + * examples: + * + * logctl -f 15/05/2012-12:00:00 -u 15/05/2012-12:37:00 + * logctl -s 50 --ret 10 + * logctl -m "closed" + * logctl -l "INFO" + * logctl -s 3 + * logctl -y "ubuntu" + * + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Rsyslog is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#define N 80 + +static struct option long_options[] = +{ + {"level", required_argument, NULL, 'l'}, + {"severity", required_argument, NULL, 's'}, + {"ret", required_argument, NULL, 'r'}, + {"skip", required_argument, NULL, 'k'}, + {"sys", required_argument, NULL, 'y'}, + {"msg", required_argument, NULL, 'm'}, + {"datef", required_argument, NULL, 'f'}, + {"dateu", required_argument, NULL, 'u'}, + {NULL, 0, NULL, 0} +}; + +struct queryopt +{ + gint32 e_sever; + gint32 e_ret; + gint32 e_skip; + char *e_date; + char *e_level; + char *e_msg; + char *e_sys; + char *e_dateu; + int bsever; + int blevel; + int bskip; + int bret; + int bsys; + int bmsg; + int bdate; + int bdatef; + int bdateu; +}; + +struct ofields +{ + const char *msg; + const char *syslog_tag; + const char *prog; + char *date; + gint64 date_r; +}; + +struct query_doc +{ + bson *query; +}; + +struct select_doc +{ + bson *select; +}; + +struct db_connect +{ + mongo_sync_connection *conn; +}; + +struct output +{ + mongo_packet *p; +}; + +struct db_cursor +{ + mongo_sync_cursor *cursor; +}; + +struct results +{ + bson *result; +}; + + + +void formater(struct ofields *fields) +{ + time_t rtime; + rtime = (time_t) (fields->date_r / 1000); + char str[N]; + strftime(str, N, "%b %d %H:%M:%S", gmtime(&rtime)); + printf("%s %s %s %s\n", str, fields->prog, fields->syslog_tag, fields->msg); + +} + +struct ofields* get_data(struct results *res) +{ + struct ofields *fields; + const char *msg; + const char *prog; + const char *level; + const char *syslog_tag; + gint64 date_r; + bson_cursor *c; + + fields = malloc(sizeof(struct ofields)); + + c = bson_find (res->result, "msg"); + if (!bson_cursor_get_string (c, &msg)) + { + perror ("bson_cursor_get_string()"); + exit (1); + } + bson_cursor_free (c); + + c = bson_find (res->result, "sys"); + if (!bson_cursor_get_string (c, &prog)) + { + perror ("bson_cursor_get_string()"); + exit (1); + } + bson_cursor_free (c); + + c = bson_find (res->result, "syslog_tag"); + if (!bson_cursor_get_string (c, &syslog_tag)) + { + perror ("bson_cursor_get_string()"); + exit (1); + } + bson_cursor_free (c); + + c = bson_find (res->result, "time_rcvd"); + if (!bson_cursor_get_utc_datetime (c, &date_r)) + { + perror ("bson_cursor_get_utc_datetime()"); + exit (1); + } + + bson_cursor_free (c); + fields->msg = msg; + fields->prog = prog; + fields->syslog_tag = syslog_tag; + fields->date_r = date_r; + + return fields; + +} + +void getoptions(int argc, char *argv[], struct queryopt *opt) +{ + int iarg; + while ((iarg = getopt_long(argc, argv, "l:s:r:k:y:f:u:m:", long_options, NULL)) != -1) + { + // check to see if a single character or long option came through + switch (iarg) + { + // short option 's' + case 's': + opt->bsever = 1; + opt->e_sever = atoi(optarg); + break; + // short option 'r' + case 'r': + opt->bret = 1; + opt->e_ret = atoi(optarg); + break; + // short option 'f' : date from + case 'f': + opt->bdate = 1; + opt->bdatef = 1; + opt->e_date = optarg; + break; + // short option 'u': date until + case 'u': + opt->bdate = 1; + opt->bdateu = 1; + opt->e_dateu = optarg; + break; + // short option 'k' + case 'k': + opt->bskip = 1; + opt->e_skip = atoi(optarg); + break; + // short option 'l' + case 'l': + opt->blevel = 1; + opt->e_level = optarg; + break; + // short option 'm' + case 'm': + opt->bmsg = 1; + opt->e_msg = optarg; + break; + // short option 'y' + case 'y': + opt->bsys = 1; + opt->e_sys = optarg; + break; + } // end switch iarg + } // end while + +} // end void getoptions + +struct select_doc* create_select() +// BSON object indicating the fields to return +{ + struct select_doc *s_doc; + s_doc = malloc(sizeof(struct select_doc)); + s_doc->select = bson_new (); + bson_append_string (s_doc->select, "syslog_tag", "s", -1); + bson_append_string (s_doc->select, "msg", "ERROR", -1); + bson_append_string (s_doc->select, "sys", "sys", -1); + bson_append_utc_datetime (s_doc->select, "time_rcvd", 1ll); + bson_finish (s_doc->select); + return s_doc; +} + +struct query_doc* create_query(struct queryopt *opt) +{ + struct query_doc *qu_doc; + bson *query_what, *order_what, *order_how, *msg_what, *date_what; + struct tm tm; + time_t t; + gint64 ts; + qu_doc = malloc(sizeof(struct query_doc)); + qu_doc->query = bson_new (); + + query_what = bson_new (); + if (opt->bsever == 1) + { + bson_append_int32 (query_what, "syslog_sever", opt->e_sever); + } + if (opt->blevel == 1) + { + bson_append_string (query_what, "level", opt->e_level, -1); + } + + if (opt->bmsg == 1) + { + msg_what = bson_new (); + bson_append_string (msg_what, "$regex", opt->e_msg, -1); + bson_append_string (msg_what, "$options", "i", -1); + bson_finish (msg_what); + bson_append_document (query_what, "msg", msg_what); + } + + if (opt->bdate == 1) + { + date_what = bson_new (); + if (opt->bdatef == 1) + { + tm.tm_isdst = -1; + strptime(opt->e_date, "%d/%m/%Y-%H:%M:%S", &tm); + tm.tm_hour = tm.tm_hour + 1; + t = mktime(&tm); + ts = 1000 * (gint64) t; + + bson_append_utc_datetime (date_what,"$gt", ts) ; + } + + if (opt->bdateu == 1) + { + tm.tm_isdst = -1; + strptime(opt->e_dateu, "%d/%m/%Y-%H:%M:%S", &tm); + tm.tm_hour = tm.tm_hour +1; + t = mktime(&tm); + ts = 1000 * (gint64) t; + bson_append_utc_datetime (date_what,"$lt", ts); + + } + bson_finish (date_what); + bson_append_document (query_what, "time_rcvd", date_what); + } + + if (opt->bsys == 1) + { + bson_append_string (query_what, "sys", opt->e_sys, -1); + } + + bson_finish (query_what); + + order_what = bson_new (); + bson_append_utc_datetime (order_what, "time_rcvd", 1ll); + bson_finish (order_what); + + bson_append_document (qu_doc->query, "$query", query_what); + bson_append_document (qu_doc->query, "$orderby", order_what); + bson_finish (qu_doc->query); + bson_free (order_what); + return qu_doc; +} + +struct db_connect* create_conn() +{ + struct db_connect *db_conn; + db_conn = malloc(sizeof(struct db_connect)); + db_conn->conn = mongo_sync_connect ("localhost", 27017, TRUE); + + if (!db_conn->conn) + { + perror ("mongo_sync_connect()"); + exit (1); + } + return db_conn; +} + +void close_conn(struct db_connect *db_conn) +{ + mongo_sync_disconnect (db_conn->conn); +} + +void free_cursor(struct db_cursor *db_c) +{ + mongo_sync_cursor_free (db_c->cursor); +} + +struct output* launch_query(struct queryopt *opt, struct select_doc *s_doc, + struct query_doc *qu_doc, + struct db_connect *db_conn) +{ + struct output *out; + out = malloc(sizeof(struct output)); + out->p = mongo_sync_cmd_query (db_conn->conn, "syslog.log", 0, + opt->e_skip, opt->e_ret, qu_doc->query, s_doc->select); + if (!out->p) + { + perror ("mongo_sync_cmd_query()"); + printf("no records found\n"); + exit (1); + } + return out; +} + +struct db_cursor* open_cursor(struct db_connect *db_conn, struct output *out) +{ + struct db_cursor *db_c; + db_c = malloc(sizeof(struct db_cursor)); + + db_c->cursor = mongo_sync_cursor_new (db_conn->conn, "syslog.log", out->p); + if (!db_c->cursor) + { + perror ("mongo_sync_cursor_new()"); + exit (1); + } + return db_c; +} + +struct results* read_data(struct db_cursor *db_c) +{ + struct results *res; + res = malloc(sizeof(struct results)); + res->result = mongo_sync_cursor_get_data (db_c->cursor); + if (!res->result) + { + perror ("mongo_sync_cursor_get_data()"); + exit (1); + } + return res; +} + +gboolean cursor_next (struct db_cursor *db_c) +{ + if (!mongo_sync_cursor_next (db_c->cursor)) + return FALSE; + else + return TRUE; + +} + +int main (int argc, char *argv[]) +{ + + struct queryopt opt; + struct ofields *fields; + struct bson_doc *doc; + struct select_doc *s_doc; + struct query_doc *qu_doc; + struct db_connect *db_conn; + struct output *out; + struct db_cursor *db_c; + struct results *res; + + opt.e_skip = 0; // standard + opt.e_ret = 0; // standard + opt.bsever = 0; + opt.blevel = 0; + opt.bdate = 0; + opt.bdateu = 0; + opt.bdatef = 0; + opt.bmsg = 0; + opt.bskip = 0; + opt.bsys = 0; + + getoptions(argc, argv, &opt); + qu_doc = create_query(&opt); // crate query + s_doc = create_select(); + db_conn = create_conn(); // create connection + out = launch_query(&opt, s_doc, qu_doc, db_conn); // launch the query + db_c = open_cursor(db_conn, out); // open cursor + + while (cursor_next(db_c)) + { + res = read_data(db_c); + fields = get_data(res); + formater(fields); // formate output + free(fields); + } + + free_cursor(db_c); + close_conn(db_conn); + + return (0); +} -- cgit v1.2.3 From d752786d4f5536828dc6d5cd1665f06d323e8844 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 11 Oct 2012 09:27:30 +0200 Subject: re-enabled commented-out serialization support in debug handler --- runtime/debug.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/runtime/debug.c b/runtime/debug.c index edc4a255..307a8bb8 100644 --- a/runtime/debug.c +++ b/runtime/debug.c @@ -927,12 +927,12 @@ dbgprint(obj_t *pObj, char *pszMsg, size_t lenMsg) pszObjName = obj.GetName(pObj); } -// pthread_mutex_lock(&mutdbgprint); -// pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprint); + pthread_mutex_lock(&mutdbgprint); + pthread_cleanup_push(dbgMutexCancelCleanupHdlr, &mutdbgprint); do_dbgprint(pszObjName, pszMsg, lenMsg); -// pthread_cleanup_pop(1); + pthread_cleanup_pop(1); } #pragma GCC diagnostic warning "-Wempty-body" -- cgit v1.2.3 From a38ccf789944a0ffcba23dff40e318ad6475e451 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 11 Oct 2012 09:33:12 +0200 Subject: fix small memory leak when template is specified in omfile --- tools/omfile.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/omfile.c b/tools/omfile.c index 1a36343f..715b218c 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -820,6 +820,7 @@ ENDcreateInstance BEGINfreeInstance CODESTARTfreeInstance + free(pData->tplName); free(pData->f_fname); if(pData->bDynamicName) { dynaFileFreeCache(pData); -- cgit v1.2.3 From d5b9d43f6abfb8af1433062bb32953cb422ac380 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 11 Oct 2012 09:35:29 +0200 Subject: fix small memory leak with string-type templates --- template.c | 1 + 1 file changed, 1 insertion(+) diff --git a/template.c b/template.c index 06306115..9cf35fd7 100644 --- a/template.c +++ b/template.c @@ -1753,6 +1753,7 @@ tplProcessCnf(struct cnfobj *o) pTpl->optFormatEscape = JSON_ESCAPE; finalize_it: + free(tplStr); if(pvals != NULL) cnfparamvalsDestruct(pvals, &pblk); if(iRet != RS_RET_OK) { -- cgit v1.2.3 From e1037b5b1fa7e31cc9182085899c65dadcba26da Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 11 Oct 2012 09:36:27 +0200 Subject: remove some assert()'s - valgrind does a better job... --- template.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/template.c b/template.c index 9cf35fd7..f62e8453 100644 --- a/template.c +++ b/template.c @@ -286,10 +286,6 @@ rsRetVal tplToJSON(struct template *pTpl, msg_t *pMsg, struct json_object **pjso struct json_object *json, *jsonf; DEFiRet; - assert(pTpl != NULL); - assert(pMsg != NULL); - assert(json != NULL); - json = json_object_new_object(); for(pTpe = pTpl->pEntryRoot ; pTpe != NULL ; pTpe = pTpe->pNext) { if(pTpe->eEntryType == CONSTANT) { -- cgit v1.2.3 From 92c185ccfa0b31b829874e8410bce6e8f3ab58b8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 11 Oct 2012 10:56:01 +0200 Subject: preparing for 6.5.1 release --- ChangeLog | 2 +- configure.ac | 2 +- doc/manual.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index c8cfd79f..0cf1e27d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 6.5.1 [devel] 2012-08-?? +Version 6.5.1 [beta] 2012-10-11 - added tool "logctl" to handle lumberjack logs in MongoDB - imfile ported to new v6 config interface - imfile now supports config parameter for maximum number of submits diff --git a/configure.ac b/configure.ac index 2d5e17cf..2c3bb2ab 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # Process this file with autoconf to produce a configure script. AC_PREREQ(2.61) -AC_INIT([rsyslog],[6.5.0],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[6.5.1],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) diff --git a/doc/manual.html b/doc/manual.html index 9a8644c9..15281921 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -19,7 +19,7 @@ rsyslog support available directly from the source!

          Please visit the rsyslog sponsor's page to honor the project sponsors or become one yourself! We are very grateful for any help towards the project goals.

          -

          This documentation is for version 6.5.0 (devel branch) of rsyslog. +

          This documentation is for version 6.5.1 (beta branch) of rsyslog. Visit the rsyslog status page to obtain current version information and project status.

          If you like rsyslog, you might -- cgit v1.2.3 From b7f1b3265c5578f7f498d98fe9d7cd93bcad2ba4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 19 Oct 2012 08:09:42 +0200 Subject: doc: add imported bugfix to ChangeLog --- ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 718eb70c..e4d3f1d7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,7 @@ --------------------------------------------------------------------------- +Version 6.5.2 [beta] 2012-10-?? +- bugfix: imuxsock did not properly honor $LocalHostIPIF +--------------------------------------------------------------------------- Version 6.5.1 [beta] 2012-10-11 - added tool "logctl" to handle lumberjack logs in MongoDB - imfile ported to new v6 config interface -- cgit v1.2.3