From bb67fd7fbf99ce0ec01b347fad5d1d9d101bfa5d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 18 Mar 2011 14:21:09 +0100 Subject: experimental: support for systemd-induced second PRI in klog if systemd writes a kernel log entry with a non-kernel priority, the priority recorded in the kernel log will be wrong. However, it will be immediately followed by another priority (with the kernel timestamp in between, if enabled). So imklog now tries to see if there is a second PRI and, if so, uses it. Note that we already support non-kernel PRIs in the kernel log, as this was done in BSD for quite some while. HOWEVER the config statement "$klogpermitnonkernelfacility on" must be used to permit this (otherwise non kernel messages are dropped). Sample of a such a message on a kernel without timestamping enabled: $ echo '<14>text' > /dev/kmsg $ dmesg -r <4><14>text NOTE: support for timestamp is NOT YET ENABLED! --- plugins/imklog/imklog.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c index 69c8cd1a..c09fa4d8 100644 --- a/plugins/imklog/imklog.c +++ b/plugins/imklog/imklog.c @@ -186,12 +186,28 @@ rsRetVal imklogLogIntMsg(int priority, char *fmt, ...) rsRetVal Syslog(int priority, uchar *pMsg) { DEFiRet; + int pri = -1; rsRetVal localRet; - /* Output using syslog */ - localRet = parsePRI(&pMsg, &priority); - if(localRet != RS_RET_INVALID_PRI && localRet != RS_RET_OK) - FINALIZE; + /* first check if we have two PRIs. This can happen in case of systemd, + * in which case the second PRI is the rigth one. + * TODO: added kernel timestamp support to this PoC. -- rgerhards, 2011-03-18 + */ + if(pMsg[3] == '<') { /* could be a pri... */ + uchar *pMsgTmp = pMsg + 3; + localRet = parsePRI(&pMsgTmp, &pri); + if(localRet == RS_RET_OK && pri >= 8 && pri <= 192) { + /* *this* is our PRI */ + DBGPRINTF("imklog detected secondary PRI in klog msg\n"); + pMsg = pMsgTmp; + priority = pri; + } + } + if(pri == -1) { + localRet = parsePRI(&pMsg, &priority); + if(localRet != RS_RET_INVALID_PRI && localRet != RS_RET_OK) + FINALIZE; + } /* if we don't get the pri, we use whatever we were supplied */ /* ignore non-kernel messages if not permitted */ -- cgit v1.2.3 From 9faa5048e6140136379c7322c7bd29f3e5629b65 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Apr 2011 07:28:21 +0200 Subject: updates ChangeLog with imported systemd support enhancement --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 3cc13082..dc9c17f9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ --------------------------------------------------------------------------- Version 5.9.0 [V5-DEVEL] (rgerhards), 2011-03-?? - this begins a new devel branch for v5 +- added support for user-level PRI provided via systemd - added new config directive $InputTCPFlowControl to select if tcp received messages shall be flagged as light delayable or not. - enhanced omhdfs to support batching mode. This permits to increase -- cgit v1.2.3 From e1c34e174139ad030ca1108ff9782b294909013c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Apr 2011 07:53:23 +0200 Subject: renamed conf.c to legacyconf.c to make room for new config system --- plugins/mmnormalize/mmnormalize.c | 2 +- plugins/omdbalerting/omdbalerting.c | 2 +- plugins/omgssapi/omgssapi.c | 2 +- plugins/omhdfs/omhdfs.c | 2 +- plugins/ommail/ommail.c | 2 +- plugins/ommongodb/ommongodb.c | 4 +- plugins/ommysql/ommysql.c | 2 +- plugins/ompgsql/ompgsql.c | 2 +- plugins/omprog/omprog.c | 2 +- plugins/omrelp/omrelp.c | 2 +- plugins/omruleset/omruleset.c | 2 +- plugins/omsnmp/omsnmp.c | 2 +- plugins/omstdout/omstdout.c | 2 +- plugins/omtemplate/omtemplate.c | 2 +- plugins/omtesting/omtesting.c | 2 +- plugins/omudpspoof/omudpspoof.c | 2 +- plugins/omuxsock/omuxsock.c | 2 +- plugins/pmaixforwardedfrom/pmaixforwardedfrom.c | 2 +- plugins/pmcisconames/pmcisconames.c | 2 +- plugins/pmlastmsg/pmlastmsg.c | 2 +- plugins/pmrfc3164sd/pmrfc3164sd.c | 2 +- plugins/pmsnare/pmsnare.c | 2 +- plugins/sm_cust_bindcdr/sm_cust_bindcdr.c | 2 +- runtime/Makefile.am | 4 +- runtime/cfsysline.c | 2 +- runtime/conf.c | 1453 ----------------------- runtime/conf.h | 65 - runtime/legacyconf.c | 1453 +++++++++++++++++++++++ runtime/legacyconf.h | 65 + runtime/rsyslog.c | 2 +- runtime/strmsrv.c | 2 +- tcpsrv.c | 2 +- tools/omfile.c | 2 +- tools/omfwd.c | 2 +- tools/ompipe.c | 2 +- tools/omshell.c | 2 +- tools/omusrmsg.c | 2 +- tools/pmrfc3164.c | 2 +- tools/pmrfc5424.c | 2 +- tools/smfile.c | 2 +- tools/smfwd.c | 2 +- tools/smtradfile.c | 2 +- tools/smtradfwd.c | 2 +- tools/syslogd.c | 2 +- 44 files changed, 1560 insertions(+), 1560 deletions(-) delete mode 100644 runtime/conf.c delete mode 100644 runtime/conf.h create mode 100644 runtime/legacyconf.c create mode 100644 runtime/legacyconf.h diff --git a/plugins/mmnormalize/mmnormalize.c b/plugins/mmnormalize/mmnormalize.c index 9c23afde..9517ec09 100644 --- a/plugins/mmnormalize/mmnormalize.c +++ b/plugins/mmnormalize/mmnormalize.c @@ -38,7 +38,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "module-template.h" diff --git a/plugins/omdbalerting/omdbalerting.c b/plugins/omdbalerting/omdbalerting.c index 35de5818..55e8c375 100644 --- a/plugins/omdbalerting/omdbalerting.c +++ b/plugins/omdbalerting/omdbalerting.c @@ -35,7 +35,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/plugins/omgssapi/omgssapi.c b/plugins/omgssapi/omgssapi.c index 6b75540f..1dc96794 100644 --- a/plugins/omgssapi/omgssapi.c +++ b/plugins/omgssapi/omgssapi.c @@ -44,7 +44,7 @@ #include #include #include "dirty.h" -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "net.h" diff --git a/plugins/omhdfs/omhdfs.c b/plugins/omhdfs/omhdfs.c index 48168f28..efd3b672 100644 --- a/plugins/omhdfs/omhdfs.c +++ b/plugins/omhdfs/omhdfs.c @@ -41,7 +41,7 @@ #include "syslogd-types.h" #include "srUtils.h" #include "template.h" -#include "conf.h" +#include "legacyconf.h" #include "cfsysline.h" #include "module-template.h" #include "unicode-helper.h" diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c index 6468dcf2..fbf6bfad 100644 --- a/plugins/ommail/ommail.c +++ b/plugins/ommail/ommail.c @@ -44,7 +44,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "cfsysline.h" diff --git a/plugins/ommongodb/ommongodb.c b/plugins/ommongodb/ommongodb.c index 8e19105f..3b7e9209 100644 --- a/plugins/ommongodb/ommongodb.c +++ b/plugins/ommongodb/ommongodb.c @@ -10,7 +10,7 @@ #include "mongo.h" #include "config.h" #include "rsyslog.h" -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" @@ -277,4 +277,4 @@ CODEmodInit_QueryRegCFSLineHdlr INITChkCoreFeature(bCoreSupportsBatching, CORE_FEATURE_BATCHING); DBGPRINTF("ompgsql: module compiled with rsyslog version %s.\n", VERSION); DBGPRINTF("ompgsql: %susing transactional output interface.\n", bCoreSupportsBatching ? "" : "not "); -ENDmodInit \ No newline at end of file +ENDmodInit diff --git a/plugins/ommysql/ommysql.c b/plugins/ommysql/ommysql.c index 978f3517..90120768 100644 --- a/plugins/ommysql/ommysql.c +++ b/plugins/ommysql/ommysql.c @@ -36,7 +36,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/plugins/ompgsql/ompgsql.c b/plugins/ompgsql/ompgsql.c index df9cc3fe..373bfb6d 100644 --- a/plugins/ompgsql/ompgsql.c +++ b/plugins/ompgsql/ompgsql.c @@ -40,7 +40,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/plugins/omprog/omprog.c b/plugins/omprog/omprog.c index 81098257..05cb0803 100644 --- a/plugins/omprog/omprog.c +++ b/plugins/omprog/omprog.c @@ -36,7 +36,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c index 26e8ccd3..4e8f5419 100644 --- a/plugins/omrelp/omrelp.c +++ b/plugins/omrelp/omrelp.c @@ -36,7 +36,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "cfsysline.h" diff --git a/plugins/omruleset/omruleset.c b/plugins/omruleset/omruleset.c index 365b405d..e41b8445 100644 --- a/plugins/omruleset/omruleset.c +++ b/plugins/omruleset/omruleset.c @@ -39,7 +39,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "module-template.h" diff --git a/plugins/omsnmp/omsnmp.c b/plugins/omsnmp/omsnmp.c index 777a8074..4b928c03 100644 --- a/plugins/omsnmp/omsnmp.c +++ b/plugins/omsnmp/omsnmp.c @@ -36,7 +36,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "cfsysline.h" #include "module-template.h" diff --git a/plugins/omstdout/omstdout.c b/plugins/omstdout/omstdout.c index f57cbe57..55d25fe5 100644 --- a/plugins/omstdout/omstdout.c +++ b/plugins/omstdout/omstdout.c @@ -35,7 +35,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/plugins/omtemplate/omtemplate.c b/plugins/omtemplate/omtemplate.c index 238ec0ae..c6dd9546 100644 --- a/plugins/omtemplate/omtemplate.c +++ b/plugins/omtemplate/omtemplate.c @@ -36,7 +36,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/plugins/omtesting/omtesting.c b/plugins/omtesting/omtesting.c index 414ecfc5..15987077 100644 --- a/plugins/omtesting/omtesting.c +++ b/plugins/omtesting/omtesting.c @@ -53,7 +53,7 @@ #include "dirty.h" #include "syslogd-types.h" #include "module-template.h" -#include "conf.h" +#include "legacyconf.h" #include "cfsysline.h" MODULE_TYPE_OUTPUT diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c index 217de1c8..19e0b70a 100644 --- a/plugins/omudpspoof/omudpspoof.c +++ b/plugins/omudpspoof/omudpspoof.c @@ -60,7 +60,7 @@ #ifdef USE_NETZIP #include #endif -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "net.h" diff --git a/plugins/omuxsock/omuxsock.c b/plugins/omuxsock/omuxsock.c index ea1c8014..8b9ec800 100644 --- a/plugins/omuxsock/omuxsock.c +++ b/plugins/omuxsock/omuxsock.c @@ -41,7 +41,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "srUtils.h" #include "template.h" #include "msg.h" diff --git a/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c b/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c index fa4a9087..12c52ff9 100644 --- a/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c +++ b/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c @@ -29,7 +29,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/plugins/pmcisconames/pmcisconames.c b/plugins/pmcisconames/pmcisconames.c index 61688cbf..bf79e957 100644 --- a/plugins/pmcisconames/pmcisconames.c +++ b/plugins/pmcisconames/pmcisconames.c @@ -29,7 +29,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/plugins/pmlastmsg/pmlastmsg.c b/plugins/pmlastmsg/pmlastmsg.c index 259c5d41..118c4331 100644 --- a/plugins/pmlastmsg/pmlastmsg.c +++ b/plugins/pmlastmsg/pmlastmsg.c @@ -35,7 +35,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/plugins/pmrfc3164sd/pmrfc3164sd.c b/plugins/pmrfc3164sd/pmrfc3164sd.c index 53204ece..4ddd98bc 100644 --- a/plugins/pmrfc3164sd/pmrfc3164sd.c +++ b/plugins/pmrfc3164sd/pmrfc3164sd.c @@ -33,7 +33,7 @@ #include #include #include "syslogd.h" -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/plugins/pmsnare/pmsnare.c b/plugins/pmsnare/pmsnare.c index f3658d11..757e6a8f 100644 --- a/plugins/pmsnare/pmsnare.c +++ b/plugins/pmsnare/pmsnare.c @@ -46,7 +46,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/plugins/sm_cust_bindcdr/sm_cust_bindcdr.c b/plugins/sm_cust_bindcdr/sm_cust_bindcdr.c index 0fa1a4c4..b55cec48 100644 --- a/plugins/sm_cust_bindcdr/sm_cust_bindcdr.c +++ b/plugins/sm_cust_bindcdr/sm_cust_bindcdr.c @@ -41,7 +41,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "cfsysline.h" #include "template.h" diff --git a/runtime/Makefile.am b/runtime/Makefile.am index c8e8ce2a..a963251c 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -18,8 +18,8 @@ librsyslog_la_SOURCES = \ glbl.h \ glbl.c \ unlimited_select.h \ - conf.c \ - conf.h \ + legacyconf.c \ + legacyconf.h \ parser.h \ parser.c \ strgen.h \ diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c index 97b35bb2..44b26022 100644 --- a/runtime/cfsysline.c +++ b/runtime/cfsysline.c @@ -39,7 +39,7 @@ #include "cfsysline.h" #include "obj.h" -#include "conf.h" +#include "legacyconf.h" #include "errmsg.h" #include "srUtils.h" #include "unicode-helper.h" diff --git a/runtime/conf.c b/runtime/conf.c deleted file mode 100644 index 1d28a884..00000000 --- a/runtime/conf.c +++ /dev/null @@ -1,1453 +0,0 @@ -/* The config file handler (not yet a real object) - * - * This file is based on an excerpt from syslogd.c, which dates back - * much later. I began the file on 2008-02-19 as part of the modularization - * effort. Over time, a clean abstration will become even more important - * because the config file handler will by dynamically be loaded and be - * kept in memory only as long as the config file is actually being - * processed. Thereafter, it shall be unloaded. -- rgerhards - * - * TODO: the license MUST be changed to LGPL. However, we can not - * currently do that, because we use some sysklogd code to crunch - * the selector lines (e.g. *.info). That code is scheduled for removal - * as part of RainerScript. After this is done, we can change licenses. - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of rsyslog. - * - * Rsyslog is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Rsyslog is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Rsyslog. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - */ -#define CFGLNSIZ 4096 /* the maximum size of a configuraton file line, after re-combination */ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_LIBGEN_H -# ifndef OS_SOLARIS -# include -# endif -#endif - -#include "rsyslog.h" -#include "dirty.h" -#include "parse.h" -#include "action.h" -#include "template.h" -#include "cfsysline.h" -#include "modules.h" -#include "outchannel.h" -#include "stringbuf.h" -#include "conf.h" -#include "stringbuf.h" -#include "srUtils.h" -#include "errmsg.h" -#include "net.h" -#include "expr.h" -#include "ctok.h" -#include "ctok_token.h" -#include "rule.h" -#include "ruleset.h" -#include "unicode-helper.h" - -#ifdef OS_SOLARIS -# define NAME_MAX MAXNAMELEN -#endif - -/* forward definitions */ -static rsRetVal cfline(uchar *line, rule_t **pfCurr); -static rsRetVal processConfFile(uchar *pConfFile); - - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(expr) -DEFobjCurrIf(ctok) -DEFobjCurrIf(ctok_token) -DEFobjCurrIf(module) -DEFobjCurrIf(errmsg) -DEFobjCurrIf(net) -DEFobjCurrIf(rule) -DEFobjCurrIf(ruleset) - -ecslConfObjType currConfObj = eConfObjGlobal; /* to support scoping - which config object is currently active? */ -int bConfStrictScoping = 0; /* force strict scoping during config processing? */ - - -static int iNbrActions = 0; /* number of currently defined actions */ - -/* The following module-global variables are used for building - * tag and host selector lines during startup and config reload. - * This is stored as a global variable pool because of its ease. It is - * also fairly compatible with multi-threading as the stratup code must - * be run in a single thread anyways. So there can be no race conditions. - * rgerhards 2005-10-18 - */ -static EHostnameCmpMode eDfltHostnameCmpMode = HN_NO_COMP; -static cstr_t *pDfltHostnameCmp = NULL; -static cstr_t *pDfltProgNameCmp = NULL; - - -/* process a directory and include all of its files into - * the current config file. There is no specific order of inclusion, - * files are included in the order they are read from the directory. - * The caller must have make sure that the provided parameter is - * indeed a directory. - * rgerhards, 2007-08-01 - */ -static rsRetVal doIncludeDirectory(uchar *pDirName) -{ - DEFiRet; - int iEntriesDone = 0; - DIR *pDir; - union { - struct dirent d; - char b[offsetof(struct dirent, d_name) + NAME_MAX + 1]; - } u; - struct dirent *res; - size_t iDirNameLen; - size_t iFileNameLen; - uchar szFullFileName[MAXFNAME]; - - ASSERT(pDirName != NULL); - - if((pDir = opendir((char*) pDirName)) == NULL) { - errmsg.LogError(errno, RS_RET_FOPEN_FAILURE, "error opening include directory"); - ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); - } - - /* prepare file name buffer */ - iDirNameLen = strlen((char*) pDirName); - memcpy(szFullFileName, pDirName, iDirNameLen); - - /* now read the directory */ - iEntriesDone = 0; - while(readdir_r(pDir, &u.d, &res) == 0) { - if(res == NULL) - break; /* this also indicates end of directory */ -# ifdef DT_REG - /* TODO: find an alternate way to checking for special files if this is - * not defined. This is currently a known problem on HP UX, but the work- - * around is simple: do not create special files in that directory. So - * fixing this is actually not the most important thing on earth... - * rgerhards, 2008-03-04 - */ - if(res->d_type != DT_REG) - continue; /* we are not interested in special files */ -# endif - if(res->d_name[0] == '.') - continue; /* these files we are also not interested in */ - ++iEntriesDone; - /* construct filename */ - iFileNameLen = strlen(res->d_name); - if (iFileNameLen > NAME_MAX) - iFileNameLen = NAME_MAX; - memcpy(szFullFileName + iDirNameLen, res->d_name, iFileNameLen); - *(szFullFileName + iDirNameLen + iFileNameLen) = '\0'; - dbgprintf("including file '%s'\n", szFullFileName); - processConfFile(szFullFileName); - /* we deliberately ignore the iRet of processConfFile() - this is because - * failure to process one file does not mean all files will fail. By ignoring, - * we retry with the next file, which is the best thing we can do. -- rgerhards, 2007-08-01 - */ - } - - if(iEntriesDone == 0) { - /* I just make it a debug output, because I can think of a lot of cases where it - * makes sense not to have any files. E.g. a system maintainer may place a $Include - * into the config file just in case, when additional modules be installed. When none - * are installed, the directory will be empty, which is fine. -- rgerhards 2007-08-01 - */ - dbgprintf("warning: the include directory contained no files - this may be ok.\n"); - } - -finalize_it: - if(pDir != NULL) - closedir(pDir); - - RETiRet; -} - - -/* process a $include config line. That type of line requires - * inclusion of another file. - * rgerhards, 2007-08-01 - */ -rsRetVal -doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal) -{ - DEFiRet; - char pattern[MAXFNAME]; - uchar *cfgFile; - glob_t cfgFiles; - int result; - size_t i = 0; - struct stat fileInfo; - - ASSERT(pp != NULL); - ASSERT(*pp != NULL); - - if(getSubString(pp, (char*) pattern, sizeof(pattern) / sizeof(char), ' ') != 0) { - errmsg.LogError(0, RS_RET_NOT_FOUND, "could not parse config file name"); - ABORT_FINALIZE(RS_RET_NOT_FOUND); - } - - /* Use GLOB_MARK to append a trailing slash for directories. - * Required by doIncludeDirectory(). - */ - result = glob(pattern, GLOB_MARK, NULL, &cfgFiles); - if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { - char errStr[1024]; - rs_strerror_r(errno, errStr, sizeof(errStr)); - errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s", - pattern, errStr); - ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND); - } - - for(i = 0; i < cfgFiles.gl_pathc; i++) { - cfgFile = (uchar*) cfgFiles.gl_pathv[i]; - - if(stat((char*) cfgFile, &fileInfo) != 0) - continue; /* continue with the next file if we can't stat() the file */ - - if(S_ISREG(fileInfo.st_mode)) { /* config file */ - dbgprintf("requested to include config file '%s'\n", cfgFile); - iRet = processConfFile(cfgFile); - } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */ - dbgprintf("requested to include directory '%s'\n", cfgFile); - iRet = doIncludeDirectory(cfgFile); - } else { /* TODO: shall we handle symlinks or not? */ - dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile); - } - } - - globfree(&cfgFiles); - -finalize_it: - RETiRet; -} - - -/* process a $ModLoad config line. - */ -rsRetVal -doModLoad(uchar **pp, __attribute__((unused)) void* pVal) -{ - DEFiRet; - uchar szName[512]; - uchar *pModName; - - ASSERT(pp != NULL); - ASSERT(*pp != NULL); - - skipWhiteSpace(pp); /* skip over any whitespace */ - if(getSubString(pp, (char*) szName, sizeof(szName) / sizeof(uchar), ' ') != 0) { - errmsg.LogError(0, RS_RET_NOT_FOUND, "could not extract module name"); - ABORT_FINALIZE(RS_RET_NOT_FOUND); - } - 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 - */ - if(!strcmp((char*) szName, "MySQL")) - pModName = (uchar*) "ommysql.so"; - else - pModName = szName; - - CHKiRet(module.Load(pModName)); - -finalize_it: - RETiRet; -} - - -/* parse and interpret a $-config line that starts with - * a name (this is common code). It is parsed to the name - * and then the proper sub-function is called to handle - * the actual directive. - * rgerhards 2004-11-17 - * rgerhards 2005-06-21: previously only for templates, now - * generalized. - */ -rsRetVal -doNameLine(uchar **pp, void* pVal) -{ - DEFiRet; - uchar *p; - enum eDirective eDir; - char szName[128]; - - ASSERT(pp != NULL); - p = *pp; - ASSERT(p != NULL); - - eDir = (enum eDirective) pVal; /* this time, it actually is NOT a pointer! */ - - if(getSubString(&p, szName, sizeof(szName) / sizeof(char), ',') != 0) { - errmsg.LogError(0, RS_RET_NOT_FOUND, "Invalid config line: could not extract name - line ignored"); - ABORT_FINALIZE(RS_RET_NOT_FOUND); - } - if(*p == ',') - ++p; /* comma was eaten */ - - /* we got the name - now we pass name & the rest of the string - * to the subfunction. It makes no sense to do further - * parsing here, as this is in close interaction with the - * respective subsystem. rgerhards 2004-11-17 - */ - - switch(eDir) { - case DIR_TEMPLATE: - tplAddLine(szName, &p); - break; - case DIR_OUTCHANNEL: - ochAddLine(szName, &p); - break; - case DIR_ALLOWEDSENDER: - net.addAllowedSenderLine(szName, &p); - break; - default:/* we do this to avoid compiler warning - not all - * enum values call this function, so an incomplete list - * is quite ok (but then we should not run into this code, - * so at least we log a debug warning). - */ - dbgprintf("INTERNAL ERROR: doNameLine() called with invalid eDir %d.\n", - eDir); - break; - } - - *pp = p; - -finalize_it: - RETiRet; -} - - -/* Parse and interpret a system-directive in the config line - * A system directive is one that starts with a "$" sign. It offers - * extended configuration parameters. - * 2004-11-17 rgerhards - */ -rsRetVal -cfsysline(uchar *p) -{ - DEFiRet; - uchar szCmd[64]; - - ASSERT(p != NULL); - errno = 0; - if(getSubString(&p, (char*) szCmd, sizeof(szCmd) / sizeof(uchar), ' ') != 0) { - errmsg.LogError(0, RS_RET_NOT_FOUND, "Invalid $-configline - could not extract command - line ignored\n"); - ABORT_FINALIZE(RS_RET_NOT_FOUND); - } - - /* we now try and see if we can find the command in the registered - * list of cfsysline handlers. -- rgerhards, 2007-07-31 - */ - CHKiRet(processCfSysLineCommand(szCmd, &p)); - - /* now check if we have some extra characters left on the line - that - * should not be the case. Whitespace is OK, but everything else should - * trigger a warning (that may be an indication of undesired behaviour). - * An exception, of course, are comments (starting with '#'). - * rgerhards, 2007-07-04 - */ - skipWhiteSpace(&p); - - if(*p && *p != '#') { /* we have a non-whitespace, so let's complain */ - errmsg.LogError(0, NO_ERRCODE, - "error: extra characters in config line ignored: '%s'", p); - } - -finalize_it: - RETiRet; -} - - - - -/* process a configuration file - * started with code from init() by rgerhards on 2007-07-31 - */ -static rsRetVal -processConfFile(uchar *pConfFile) -{ - int iLnNbr = 0; - FILE *cf; - rule_t *pCurrRule = NULL; - uchar *p; - uchar cbuf[CFGLNSIZ]; - uchar *cline; - int i; - int bHadAnError = 0; - uchar *pszOrgLine = NULL; - size_t lenLine; - DEFiRet; - ASSERT(pConfFile != NULL); - - if((cf = fopen((char*)pConfFile, "r")) == NULL) { - ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); - } - - /* Now process the file. - */ - cline = cbuf; - while (fgets((char*)cline, sizeof(cbuf) - (cline - cbuf), cf) != NULL) { - ++iLnNbr; - /* drop LF - TODO: make it better, replace fgets(), but its clean as it is */ - lenLine = ustrlen(cline); - if(cline[lenLine-1] == '\n') { - cline[lenLine-1] = '\0'; - } - free(pszOrgLine); - pszOrgLine = ustrdup(cline); /* save if needed for errmsg, NULL ptr is OK */ - /* check for end-of-section, comments, strip off trailing - * spaces and newline character. - */ - p = cline; - skipWhiteSpace(&p); - if (*p == '\0' || *p == '#') - continue; - - /* we now need to copy the characters to the begin of line. As this overlaps, - * we can not use strcpy(). -- rgerhards, 2008-03-20 - * TODO: review the code at whole - this is highly suspect (but will go away - * once we do the rest of RainerScript). - */ - for( i = 0 ; p[i] != '\0' ; ++i) { - cline[i] = p[i]; - } - cline[i] = '\0'; - - for (p = (uchar*) strchr((char*)cline, '\0'); isspace((int) *--p);) - /*EMPTY*/; - if (*p == '\\') { - if ((p - cbuf) > CFGLNSIZ - 30) { - /* Oops the buffer is full - what now? */ - cline = cbuf; - } else { - *p = 0; - cline = p; - continue; - } - } else - cline = cbuf; - *++p = '\0'; /* TODO: check this */ - - /* we now have the complete line, and are positioned at the first non-whitespace - * character. So let's process it - */ - if(cfline(cbuf, &pCurrRule) != RS_RET_OK) { - /* we log a message, but otherwise ignore the error. After all, the next - * line can be correct. -- rgerhards, 2007-08-02 - */ - uchar szErrLoc[MAXFNAME + 64]; - dbgprintf("config line NOT successfully processed\n"); - snprintf((char*)szErrLoc, sizeof(szErrLoc) / sizeof(uchar), - "%s, line %d", pConfFile, iLnNbr); - errmsg.LogError(0, NO_ERRCODE, "the last error occured in %s:\"%s\"", (char*)szErrLoc, (char*)pszOrgLine); - bHadAnError = 1; - } - } - - /* we probably have one selector left to be added - so let's do that now */ - if(pCurrRule != NULL) { - CHKiRet(ruleset.AddRule(rule.GetAssRuleset(pCurrRule), &pCurrRule)); - } - - /* close the configuration file */ - fclose(cf); - -finalize_it: - if(iRet != RS_RET_OK) { - char errStr[1024]; - if(pCurrRule != NULL) - rule.Destruct(&pCurrRule); - - rs_strerror_r(errno, errStr, sizeof(errStr)); - dbgprintf("error %d processing config file '%s'; os error (if any): %s\n", - iRet, pConfFile, errStr); - } - - free(pszOrgLine); - - if(bHadAnError && (iRet == RS_RET_OK)) { /* a bit dirty, enhance in future releases */ - iRet = RS_RET_NONFATAL_CONFIG_ERR; - } - RETiRet; -} - - -/* Helper to cfline() and its helpers. Parses a template name - * from an "action" line. Must be called with the Line pointer - * pointing to the first character after the semicolon. - * rgerhards 2004-11-19 - * changed function to work with OMSR. -- rgerhards, 2007-07-27 - * the default template is to be used when no template is specified. - */ -rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName) -{ - uchar *p; - uchar *tplName = NULL; - cstr_t *pStrB; - DEFiRet; - - ASSERT(pp != NULL); - ASSERT(*pp != NULL); - ASSERT(pOMSR != NULL); - - p =*pp; - /* a template must follow - search it and complain, if not found */ - skipWhiteSpace(&p); - if(*p == ';') - ++p; /* eat it */ - else if(*p != '\0' && *p != '#') { - errmsg.LogError(0, RS_RET_ERR, "invalid character in selector line - ';template' expected"); - ABORT_FINALIZE(RS_RET_ERR); - } - - skipWhiteSpace(&p); /* go to begin of template name */ - - if(*p == '\0' || *p == '#') { - /* no template specified, use the default */ - /* TODO: check NULL ptr */ - tplName = (uchar*) strdup((char*)dfltTplName); - } else { - /* template specified, pick it up */ - CHKiRet(cstrConstruct(&pStrB)); - - /* now copy the string */ - while(*p && *p != '#' && !isspace((int) *p)) { - CHKiRet(cstrAppendChar(pStrB, *p)); - ++p; - } - CHKiRet(cstrFinalize(pStrB)); - CHKiRet(cstrConvSzStrAndDestruct(pStrB, &tplName, 0)); - } - - CHKiRet(OMSRsetEntry(pOMSR, iEntry, tplName, iTplOpts)); - -finalize_it: - if(iRet != RS_RET_OK) - free(tplName); - - *pp = p; - - RETiRet; -} - -/* Helper to cfline(). Parses a file name up until the first - * comma and then looks for the template specifier. Tries - * to find that template. - * rgerhards 2004-11-18 - * parameter pFileName must point to a buffer large enough - * to hold the largest possible filename. - * rgerhards, 2007-07-25 - * updated to include OMSR pointer -- rgerhards, 2007-07-27 - * updated to include template name -- rgerhards, 2008-03-28 - * rgerhards, 2010-01-19: file names end at the first space - */ -rsRetVal -cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *pszTpl) -{ - register uchar *pName; - int i; - DEFiRet; - - ASSERT(pOMSR != NULL); - - pName = pFileName; - i = 1; /* we start at 1 so that we reseve space for the '\0'! */ - while(*p && *p != ';' && *p != ' ' && i < MAXFNAME) { - *pName++ = *p++; - ++i; - } - *pName = '\0'; - - iRet = cflineParseTemplateName(&p, pOMSR, iEntry, iTplOpts, pszTpl); - - RETiRet; -} - - -/* Helper to cfline(). This function takes the filter part of a traditional, PRI - * based line and decodes the PRIs given in the selector line. It processed the - * line up to the beginning of the action part. A pointer to that beginnig is - * passed back to the caller. - * rgerhards 2005-09-15 - */ -/* GPLv3 - stems back to sysklogd */ -static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) -{ - uchar *p; - register uchar *q; - register int i, i2; - uchar *bp; - int pri; - int singlpri = 0; - int ignorepri = 0; - uchar buf[2048]; /* buffer for facility and priority names */ - uchar xbuf[200]; - DEFiRet; - - ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ISOBJ_TYPE_assert(pRule, rule); - - dbgprintf(" - traditional PRI filter\n"); - errno = 0; /* keep strerror_r() stuff out of logerror messages */ - - pRule->f_filter_type = FILTER_PRI; - /* Note: file structure is pre-initialized to zero because it was - * created with calloc()! - */ - for (i = 0; i <= LOG_NFACILITIES; i++) { - pRule->f_filterData.f_pmask[i] = TABLE_NOPRI; - } - - /* scan through the list of selectors */ - for (p = *pline; *p && *p != '\t' && *p != ' ';) { - - /* find the end of this facility name list */ - for (q = p; *q && *q != '\t' && *q++ != '.'; ) - continue; - - /* collect priority name */ - for (bp = buf; *q && !strchr("\t ,;", *q) && bp < buf+sizeof(buf)-1 ; ) - *bp++ = *q++; - *bp = '\0'; - - /* skip cruft */ - while (strchr(",;", *q)) - q++; - - /* decode priority name */ - if ( *buf == '!' ) { - ignorepri = 1; - /* copy below is ok, we can NOT go off the allocated area */ - for (bp=buf; *(bp+1); bp++) - *bp=*(bp+1); - *bp='\0'; - } - else { - ignorepri = 0; - } - if ( *buf == '=' ) - { - singlpri = 1; - pri = decodeSyslogName(&buf[1], syslogPriNames); - } - else { - singlpri = 0; - pri = decodeSyslogName(buf, syslogPriNames); - } - - if (pri < 0) { - snprintf((char*) xbuf, sizeof(xbuf), "unknown priority name \"%s\"", buf); - errmsg.LogError(0, RS_RET_ERR, "%s", xbuf); - return RS_RET_ERR; - } - - /* scan facilities */ - while (*p && !strchr("\t .;", *p)) { - for (bp = buf; *p && !strchr("\t ,;.", *p) && bp < buf+sizeof(buf)-1 ; ) - *bp++ = *p++; - *bp = '\0'; - if (*buf == '*') { - for (i = 0; i <= LOG_NFACILITIES; i++) { - if ( pri == INTERNAL_NOPRI ) { - if ( ignorepri ) - pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI; - else - pRule->f_filterData.f_pmask[i] = TABLE_NOPRI; - } - else if ( singlpri ) { - if ( ignorepri ) - pRule->f_filterData.f_pmask[i] &= ~(1<f_filterData.f_pmask[i] |= (1<f_filterData.f_pmask[i] = TABLE_NOPRI; - else - pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI; - } - else - { - if ( ignorepri ) - for (i2= 0; i2 <= pri; ++i2) - pRule->f_filterData.f_pmask[i] &= ~(1<f_filterData.f_pmask[i] |= (1<f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI; - else - pRule->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI; - } else if ( singlpri ) { - if ( ignorepri ) - pRule->f_filterData.f_pmask[i >> 3] &= ~(1<f_filterData.f_pmask[i >> 3] |= (1<f_filterData.f_pmask[i >> 3] = TABLE_NOPRI; - else - pRule->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI; - } else { - if ( ignorepri ) - for (i2= 0; i2 <= pri; ++i2) - pRule->f_filterData.f_pmask[i >> 3] &= ~(1<f_filterData.f_pmask[i >> 3] |= (1<f_filter_type = FILTER_EXPR; - - /* if we come to over here, pline starts with "if ". We just skip that part. */ - (*pline) += 3; - - /* we first need a tokenizer... */ - CHKiRet(ctok.Construct(&tok)); - CHKiRet(ctok.Setpp(tok, *pline)); - CHKiRet(ctok.ConstructFinalize(tok)); - - /* now construct our expression */ - CHKiRet(expr.Construct(&f->f_filterData.f_expr)); - CHKiRet(expr.ConstructFinalize(f->f_filterData.f_expr)); - - /* ready to go... */ - CHKiRet(expr.Parse(f->f_filterData.f_expr, tok)); - - /* we now need to parse off the "then" - and note an error if it is - * missing... - */ - CHKiRet(ctok.GetToken(tok, &pToken)); - if(pToken->tok != ctok_THEN) { - ctok_token.Destruct(&pToken); - ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); - } - - ctok_token.Destruct(&pToken); /* no longer needed */ - - /* we are done, so we now need to restore things */ - CHKiRet(ctok.Getpp(tok, pline)); - CHKiRet(ctok.Destruct(&tok)); - - /* debug support - print vmprg after construction (uncomment to use) */ - /* vmprgDebugPrint(f->f_filterData.f_expr->pVmprg); */ - - /* we now need to skip whitespace to the action part, else we confuse - * the legacy rsyslog conf parser. -- rgerhards, 2008-02-25 - */ - while(isspace(**pline)) - ++(*pline); - -finalize_it: - if(iRet == RS_RET_SYNTAX_ERROR) { - errmsg.LogError(0, RS_RET_SYNTAX_ERROR, "syntax error in expression"); - } - - RETiRet; -} - - -/* Helper to cfline(). This function takes the filter part of a property - * based filter and decodes it. It processes the line up to the beginning - * of the action part. A pointer to that beginnig is passed back to the caller. - * rgerhards 2005-09-15 - */ -static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) -{ - rsParsObj *pPars; - cstr_t *pCSCompOp; - cstr_t *pCSPropName; - rsRetVal iRet; - int iOffset; /* for compare operations */ - - ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ASSERT(f != NULL); - - dbgprintf(" - property-based filter\n"); - errno = 0; /* keep strerror_r() stuff out of logerror messages */ - - f->f_filter_type = FILTER_PROP; - - /* create parser object starting with line string without leading colon */ - if((iRet = rsParsConstructFromSz(&pPars, (*pline)+1)) != RS_RET_OK) { - errmsg.LogError(0, iRet, "Error %d constructing parser object - ignoring selector", iRet); - return(iRet); - } - - /* read property */ - iRet = parsDelimCStr(pPars, &pCSPropName, ',', 1, 1, 1); - if(iRet != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d parsing filter property - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); - } - iRet = propNameToID(pCSPropName, &f->f_filterData.prop.propID); - if(iRet != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d parsing filter property - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); - } - if(f->f_filterData.prop.propID == PROP_CEE) { - /* in CEE case, we need to preserve the actual property name */ - if((f->f_filterData.prop.propName = - es_newStrFromBuf((char*)cstrGetSzStrNoNULL(pCSPropName)+2, cstrLen(pCSPropName)-2)) == NULL) { - cstrDestruct(&pCSPropName); - return(RS_RET_ERR); - } - } - cstrDestruct(&pCSPropName); - - /* read operation */ - iRet = parsDelimCStr(pPars, &pCSCompOp, ',', 1, 1, 1); - if(iRet != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d compare operation property - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); - } - - /* we now first check if the condition is to be negated. To do so, we first - * must make sure we have at least one char in the param and then check the - * first one. - * rgerhards, 2005-09-26 - */ - if(rsCStrLen(pCSCompOp) > 0) { - if(*rsCStrGetBufBeg(pCSCompOp) == '!') { - f->f_filterData.prop.isNegated = 1; - iOffset = 1; /* ignore '!' */ - } else { - f->f_filterData.prop.isNegated = 0; - iOffset = 0; - } - } else { - f->f_filterData.prop.isNegated = 0; - iOffset = 0; - } - -dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSCompOp)); - if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) { - f->f_filterData.prop.operation = FIOP_CONTAINS; - } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) { - f->f_filterData.prop.operation = FIOP_ISEQUAL; - } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isempty", 7)) { - f->f_filterData.prop.operation = FIOP_ISEMPTY; - } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "startswith", 10)) { - f->f_filterData.prop.operation = FIOP_STARTSWITH; - } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) { - f->f_filterData.prop.operation = FIOP_REGEX; - } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "ereregex", 8)) { - f->f_filterData.prop.operation = FIOP_EREREGEX; - } else { - errmsg.LogError(0, NO_ERRCODE, "error: invalid compare operation '%s' - ignoring selector", - (char*) rsCStrGetSzStrNoNULL(pCSCompOp)); - } - rsCStrDestruct(&pCSCompOp); /* no longer needed */ - -dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); - if(f->f_filterData.prop.operation != FIOP_ISEMPTY) { - /* read compare value */ - iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue); - if(iRet != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); - } - } - - /* skip to action part */ - if((iRet = parsSkipWhitespace(pPars)) != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d skipping to action part - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); - } - - /* cleanup */ - *pline = *pline + rsParsGetParsePointer(pPars) + 1; - /* we are adding one for the skipped initial ":" */ - - return rsParsDestruct(pPars); -} - - -/* - * Helper to cfline(). This function interprets a BSD host selector line - * from the config file ("+/-hostname"). It stores it for further reference. - * rgerhards 2005-10-19 - */ -static rsRetVal cflineProcessHostSelector(uchar **pline) -{ - DEFiRet; - - ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ASSERT(**pline == '-' || **pline == '+'); - - dbgprintf(" - host selector line\n"); - - /* check include/exclude setting */ - if(**pline == '+') { - eDfltHostnameCmpMode = HN_COMP_MATCH; - } else { /* we do not check for '-', it must be, else we wouldn't be here */ - eDfltHostnameCmpMode = HN_COMP_NOMATCH; - } - (*pline)++; /* eat + or - */ - - /* the below is somewhat of a quick hack, but it is efficient (this is - * why it is in here. "+*" resets the tag selector with BSD syslog. We mimic - * this, too. As it is easy to check that condition, we do not fire up a - * parser process, just make sure we do not address beyond our space. - * Order of conditions in the if-statement is vital! rgerhards 2005-10-18 - */ - if(**pline != '\0' && **pline == '*' && *(*pline+1) == '\0') { - dbgprintf("resetting BSD-like hostname filter\n"); - eDfltHostnameCmpMode = HN_NO_COMP; - if(pDfltHostnameCmp != NULL) { - CHKiRet(rsCStrSetSzStr(pDfltHostnameCmp, NULL)); - } - } else { - dbgprintf("setting BSD-like hostname filter to '%s'\n", *pline); - if(pDfltHostnameCmp == NULL) { - /* create string for parser */ - CHKiRet(rsCStrConstructFromszStr(&pDfltHostnameCmp, *pline)); - } else { /* string objects exists, just update... */ - CHKiRet(rsCStrSetSzStr(pDfltHostnameCmp, *pline)); - } - } - -finalize_it: - RETiRet; -} - - -/* - * Helper to cfline(). This function interprets a BSD tag selector line - * from the config file ("!tagname"). It stores it for further reference. - * rgerhards 2005-10-18 - */ -static rsRetVal cflineProcessTagSelector(uchar **pline) -{ - DEFiRet; - - ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ASSERT(**pline == '!'); - - dbgprintf(" - programname selector line\n"); - - (*pline)++; /* eat '!' */ - - /* the below is somewhat of a quick hack, but it is efficient (this is - * why it is in here. "!*" resets the tag selector with BSD syslog. We mimic - * this, too. As it is easy to check that condition, we do not fire up a - * parser process, just make sure we do not address beyond our space. - * Order of conditions in the if-statement is vital! rgerhards 2005-10-18 - */ - if(**pline != '\0' && **pline == '*' && *(*pline+1) == '\0') { - dbgprintf("resetting programname filter\n"); - if(pDfltProgNameCmp != NULL) { - rsCStrDestruct(&pDfltProgNameCmp); - } - } else { - dbgprintf("setting programname filter to '%s'\n", *pline); - if(pDfltProgNameCmp == NULL) { - /* create string for parser */ - CHKiRet(rsCStrConstructFromszStr(&pDfltProgNameCmp, *pline)); - } else { /* string objects exists, just update... */ - CHKiRet(rsCStrSetSzStr(pDfltProgNameCmp, *pline)); - } - } - -finalize_it: - RETiRet; -} - - -/* read the filter part of a configuration line and store the filter - * in the supplied rule_t - * rgerhards, 2007-08-01 - */ -static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) -{ - DEFiRet; - - ASSERT(pp != NULL); - ISOBJ_TYPE_assert(f, rule); - - /* check which filter we need to pull... */ - switch(**pp) { - case ':': - CHKiRet(cflineProcessPropFilter(pp, f)); - break; - case 'i': /* "if" filter? */ - if(*(*pp+1) && (*(*pp+1) == 'f') && isspace(*(*pp+2))) { - CHKiRet(cflineProcessIfFilter(pp, f)); - break; - } - /*FALLTHROUGH*/ - default: - CHKiRet(cflineProcessTradPRIFilter(pp, f)); - break; - } - - /* we now check if there are some global (BSD-style) filter conditions - * and, if so, we copy them over. rgerhards, 2005-10-18 - */ - if(pDfltProgNameCmp != NULL) { - CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp)); - } - - if(eDfltHostnameCmpMode != HN_NO_COMP) { - f->eHostnameCmpMode = eDfltHostnameCmpMode; - CHKiRet(rsCStrConstructFromCStr(&(f->pCSHostnameComp), pDfltHostnameCmp)); - } - -finalize_it: - RETiRet; -} - - -/* process the action part of a selector line - * rgerhards, 2007-08-01 - */ -static rsRetVal cflineDoAction(uchar **p, action_t **ppAction) -{ - DEFiRet; - modInfo_t *pMod; - omodStringRequest_t *pOMSR; - action_t *pAction = NULL; - void *pModData; - - ASSERT(p != NULL); - ASSERT(ppAction != NULL); - - /* loop through all modules and see if one picks up the line */ - pMod = module.GetNxtType(NULL, eMOD_OUT); - /* Note: clang static analyzer reports that pMod mybe == NULL. However, this is - * not possible, because we have the built-in output modules which are always - * present. Anyhow, we guard this by an assert. -- rgerhards, 2010-12-16 - */ - assert(pMod != NULL); - while(pMod != NULL) { - pOMSR = NULL; - iRet = pMod->mod.om.parseSelectorAct(p, &pModData, &pOMSR); - dbgprintf("tried selector action for %s: %d\n", module.GetName(pMod), iRet); - if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) { - /* advance our config parser state: we now only accept an $End as valid, - * no more action statments. - */ - if(currConfObj == eConfObjAction) - currConfObj = eConfObjActionWaitEnd; - if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { - /* now check if the module is compatible with select features */ - if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) - pAction->f_ReduceRepeated = bReduceRepeatMsgs; - else { - dbgprintf("module is incompatible with RepeatedMsgReduction - turned off\n"); - pAction->f_ReduceRepeated = 0; - } - pAction->eState = ACT_STATE_RDY; /* action is enabled */ - iNbrActions++; /* one more active action! */ - } - break; - } - else if(iRet != RS_RET_CONFLINE_UNPROCESSED) { - /* In this case, the module would have handled the config - * line, but some error occured while doing so. This error should - * already by reported by the module. We do not try any other - * modules on this line, because we found the right one. - * rgerhards, 2007-07-24 - */ - dbgprintf("error %d parsing config line\n", (int) iRet); - break; - } - pMod = module.GetNxtType(pMod, eMOD_OUT); - } - - *ppAction = pAction; - RETiRet; -} - - -/* Process a configuration file line in traditional "filter selector" format - * or one that builds upon this format. Note that ppRule may be a NULL pointer, - * which is valid and happens if there is no previous line (right at the start - * of the master config file!). - */ -static rsRetVal -cflineClassic(uchar *p, rule_t **ppRule) -{ - DEFiRet; - action_t *pAction; - - /* lines starting with '&' have no new filters and just add - * new actions to the currently processed selector. - */ - if(*p == '&') { - ++p; /* eat '&' */ - skipWhiteSpace(&p); /* on to command */ - } else { - /* we are finished with the current selector (on previous line). - * So we now need to check - * if it has any actions associated and, if so, link it to the linked - * list. If it has nothing associated with it, we can simply discard - * it. In any case, we create a fresh selector for our new filter. - * We have one special case during initialization: then, the current - * selector is NULL, which means we do not need to care about it at - * all. -- rgerhards, 2007-08-01 - */ - if(*ppRule != NULL) { - CHKiRet(ruleset.AddRule(rule.GetAssRuleset(*ppRule), ppRule)); - } - CHKiRet(rule.Construct(ppRule)); /* create "fresh" selector */ - CHKiRet(rule.SetAssRuleset(*ppRule, ruleset.GetCurrent())); /* create "fresh" selector */ - CHKiRet(rule.ConstructFinalize(*ppRule)); /* create "fresh" selector */ - CHKiRet(cflineDoFilter(&p, *ppRule)); /* pull filters */ - } - - CHKiRet(cflineDoAction(&p, &pAction)); - CHKiRet(llAppend(&(*ppRule)->llActList, NULL, (void*) pAction)); - -finalize_it: - RETiRet; -} - - -/* process a configuration line - * I re-did this functon because it was desperately time to do so - * rgerhards, 2007-08-01 - */ -static rsRetVal -cfline(uchar *line, rule_t **pfCurr) -{ - DEFiRet; - - ASSERT(line != NULL); - - dbgprintf("cfline: '%s'\n", line); - - /* check type of line and call respective processing */ - switch(*line) { - case '!': - iRet = cflineProcessTagSelector(&line); - break; - case '+': - case '-': - iRet = cflineProcessHostSelector(&line); - break; - case '$': - ++line; /* eat '$' */ - iRet = cfsysline(line); - break; - default: - iRet = cflineClassic(line, pfCurr); - break; - } - - RETiRet; -} - - -/* return the current number of active actions - * rgerhards, 2008-07-28 - */ -static rsRetVal -GetNbrActActions(int *piNbrActions) -{ - DEFiRet; - assert(piNbrActions != NULL); - *piNbrActions = iNbrActions; - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-29 - */ -BEGINobjQueryInterface(conf) -CODESTARTobjQueryInterface(conf) - if(pIf->ifVersion != confCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->doNameLine = doNameLine; - pIf->cfsysline = cfsysline; - pIf->doModLoad = doModLoad; - pIf->doIncludeLine = doIncludeLine; - pIf->cfline = cfline; - pIf->processConfFile = processConfFile; - pIf->GetNbrActActions = GetNbrActActions; - -finalize_it: -ENDobjQueryInterface(conf) - - -/* switch to a new action scope. This means that we switch the current - * mode to action, but it also means we need to clear all scope variables, - * so that we have a new environment. - * rgerhards, 2010-07-23 - */ -static inline rsRetVal -setActionScope(void) -{ - DEFiRet; - modInfo_t *pMod; - - currConfObj = eConfObjAction; - DBGPRINTF("entering action scope\n"); - CHKiRet(actionNewScope()); - - /* now tell each action to start the scope */ - pMod = NULL; - while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) { - DBGPRINTF("beginning scope on module %s\n", pMod->pszName); - pMod->mod.om.newScope(); - } - -finalize_it: - RETiRet; -} - - -/* switch back from action scope. - * rgerhards, 2010-07-27 - */ -static inline rsRetVal -unsetActionScope(void) -{ - DEFiRet; - modInfo_t *pMod; - - currConfObj = eConfObjAction; - DBGPRINTF("exiting action scope\n"); - CHKiRet(actionRestoreScope()); - - /* now tell each action to restore the scope */ - pMod = NULL; - while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) { - DBGPRINTF("exiting scope on module %s\n", pMod->pszName); - pMod->mod.om.restoreScope(); - } - -finalize_it: - RETiRet; -} - - -/* This method is called by our own handlers to begin a new config - * object ($Begin statement). This also implies a new scope. - * rgerhards, 2010-07-23 - */ -static rsRetVal -beginConfObj(void __attribute__((unused)) *pVal, uchar *pszName) -{ - DEFiRet; - - if(currConfObj != eConfObjGlobal) { - errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "not in global scope - can not nest $Begin"); - ABORT_FINALIZE(RS_RET_CONF_NOT_GLBL); - } - - if(!strcasecmp((char*)pszName, "action")) { - setActionScope(); - } else { - errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $Begin", pszName); - ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ); - } - -finalize_it: - free(pszName); /* no longer needed */ - RETiRet; -} - - -/* This method is called to end a config scope and switch - * back to global scope. - * rgerhards, 2010-07-23 - */ -static rsRetVal -endConfObj(void __attribute__((unused)) *pVal, uchar *pszName) -{ - DEFiRet; - - if(currConfObj == eConfObjGlobal) { - errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "already in global scope - dangling $End"); - ABORT_FINALIZE(RS_RET_CONF_IN_GLBL); - } - - if(!strcasecmp((char*)pszName, "action")) { - if(currConfObj == eConfObjAction) { - errmsg.LogError(0, RS_RET_CONF_END_NO_ACT, "$End action but not action specified"); - /* this is a warning, we continue processing in that case (unscope) */ - } else if(currConfObj != eConfObjActionWaitEnd) { - errmsg.LogError(0, RS_RET_CONF_INVLD_END, "$End not for active config object - " - "nesting error?"); - ABORT_FINALIZE(RS_RET_CONF_INVLD_END); - } - currConfObj = eConfObjGlobal; - CHKiRet(unsetActionScope()); - } else { - errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $End", pszName); - ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ); - } - -finalize_it: - free(pszName); /* no longer needed */ - RETiRet; -} - - -/* Reset config variables to default values. Note that - * when we are inside an scope, we simply reset this to global. - * However, $ResetConfigVariables is a global directive, and as such - * will not be honored inside a scope! - * rgerhards, 2010-07-23 - */ -static rsRetVal -resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) -{ - currConfObj = eConfObjGlobal; - bConfStrictScoping = 0; - return RS_RET_OK; -} - - -/* exit our class - * rgerhards, 2008-03-11 - */ -BEGINObjClassExit(conf, OBJ_IS_CORE_MODULE) /* CHANGE class also in END MACRO! */ -CODESTARTObjClassExit(conf) - /* free no-longer needed module-global variables */ - if(pDfltHostnameCmp != NULL) { - rsCStrDestruct(&pDfltHostnameCmp); - } - - if(pDfltProgNameCmp != NULL) { - rsCStrDestruct(&pDfltProgNameCmp); - } - - /* release objects we no longer need */ - objRelease(expr, CORE_COMPONENT); - objRelease(ctok, CORE_COMPONENT); - objRelease(ctok_token, CORE_COMPONENT); - objRelease(module, CORE_COMPONENT); - objRelease(errmsg, CORE_COMPONENT); - objRelease(net, LM_NET_FILENAME); - objRelease(rule, CORE_COMPONENT); - objRelease(ruleset, CORE_COMPONENT); -ENDObjClassExit(conf) - - -/* Initialize our class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-29 - */ -BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */ - /* request objects we use */ - CHKiRet(objUse(expr, CORE_COMPONENT)); - CHKiRet(objUse(ctok, CORE_COMPONENT)); - CHKiRet(objUse(ctok_token, CORE_COMPONENT)); - CHKiRet(objUse(module, CORE_COMPONENT)); - CHKiRet(objUse(errmsg, CORE_COMPONENT)); - CHKiRet(objUse(net, LM_NET_FILENAME)); /* TODO: make this dependcy go away! */ - CHKiRet(objUse(rule, CORE_COMPONENT)); - CHKiRet(objUse(ruleset, CORE_COMPONENT)); - - CHKiRet(regCfSysLineHdlr((uchar *)"begin", 0, eCmdHdlrGetWord, beginConfObj, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"end", 0, eCmdHdlrGetWord, endConfObj, NULL, NULL, eConfObjAlways)); - CHKiRet(regCfSysLineHdlr((uchar *)"strictscoping", 0, eCmdHdlrBinary, NULL, &bConfStrictScoping, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjAction)); -ENDObjClassInit(conf) - -/* vi:set ai: - */ diff --git a/runtime/conf.h b/runtime/conf.h deleted file mode 100644 index bc09d502..00000000 --- a/runtime/conf.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Definitions for config file handling (not yet an object). - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of rsyslog. - * - * Rsyslog is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Rsyslog is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Rsyslog. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - */ -#ifndef INCLUDED_CONF_H -#define INCLUDED_CONF_H - -/* definitions used for doNameLine to differentiate between different command types - * (with otherwise identical code). This is a left-over from the previous config - * system. It stays, because it is still useful. So do not wonder why it looks - * somewhat strange (at least its name). -- rgerhards, 2007-08-01 - */ -enum eDirective { DIR_TEMPLATE = 0, DIR_OUTCHANNEL = 1, DIR_ALLOWEDSENDER = 2}; -extern ecslConfObjType currConfObj; -extern int bConfStrictScoping; /* force strict scoping during config processing? */ - -/* interfaces */ -BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ - rsRetVal (*doNameLine)(uchar **pp, void* pVal); - rsRetVal (*cfsysline)(uchar *p); - rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); - rsRetVal (*doIncludeLine)(uchar **pp, __attribute__((unused)) void* pVal); - rsRetVal (*cfline)(uchar *line, rule_t **pfCurr); - rsRetVal (*processConfFile)(uchar *pConfFile); - rsRetVal (*GetNbrActActions)(int *); - /* version 4 -- 2010-07-23 rgerhards */ - /* "just" added global variables - * FYI: we reconsider repacking as a non-object, as only the core currently - * accesses this module. The current object structure complicates things without - * any real benefit. - */ -ENDinterface(conf) -#define confCURR_IF_VERSION 4 /* increment whenever you change the interface structure! */ -/* in Version 3, entry point "ReInitConf()" was removed, as we do not longer need - * to support restart-type HUP -- rgerhards, 2009-07-15 - */ - - -/* prototypes */ -PROTOTYPEObj(conf); - - -/* TODO: the following 2 need to go in conf obj interface... */ -rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName); -rsRetVal cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *pszTpl); - - -#endif /* #ifndef INCLUDED_CONF_H */ diff --git a/runtime/legacyconf.c b/runtime/legacyconf.c new file mode 100644 index 00000000..fd23bdcd --- /dev/null +++ b/runtime/legacyconf.c @@ -0,0 +1,1453 @@ +/* The legacy config file handler (not yet a real object) + * + * This file is based on an excerpt from syslogd.c, which dates back + * much later. I began the file on 2008-02-19 as part of the modularization + * effort. Over time, a clean abstration will become even more important + * because the config file handler will by dynamically be loaded and be + * kept in memory only as long as the config file is actually being + * processed. Thereafter, it shall be unloaded. -- rgerhards + * + * TODO: the license MUST be changed to LGPL. However, we can not + * currently do that, because we use some sysklogd code to crunch + * the selector lines (e.g. *.info). That code is scheduled for removal + * as part of RainerScript. After this is done, we can change licenses. + * + * Copyright 2008 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Rsyslog is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#define CFGLNSIZ 4096 /* the maximum size of a configuraton file line, after re-combination */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LIBGEN_H +# ifndef OS_SOLARIS +# include +# endif +#endif + +#include "rsyslog.h" +#include "dirty.h" +#include "parse.h" +#include "action.h" +#include "template.h" +#include "cfsysline.h" +#include "modules.h" +#include "outchannel.h" +#include "stringbuf.h" +#include "legacyconf.h" +#include "stringbuf.h" +#include "srUtils.h" +#include "errmsg.h" +#include "net.h" +#include "expr.h" +#include "ctok.h" +#include "ctok_token.h" +#include "rule.h" +#include "ruleset.h" +#include "unicode-helper.h" + +#ifdef OS_SOLARIS +# define NAME_MAX MAXNAMELEN +#endif + +/* forward definitions */ +static rsRetVal cfline(uchar *line, rule_t **pfCurr); +static rsRetVal processConfFile(uchar *pConfFile); + + +/* static data */ +DEFobjStaticHelpers +DEFobjCurrIf(expr) +DEFobjCurrIf(ctok) +DEFobjCurrIf(ctok_token) +DEFobjCurrIf(module) +DEFobjCurrIf(errmsg) +DEFobjCurrIf(net) +DEFobjCurrIf(rule) +DEFobjCurrIf(ruleset) + +ecslConfObjType currConfObj = eConfObjGlobal; /* to support scoping - which config object is currently active? */ +int bConfStrictScoping = 0; /* force strict scoping during config processing? */ + + +static int iNbrActions = 0; /* number of currently defined actions */ + +/* The following module-global variables are used for building + * tag and host selector lines during startup and config reload. + * This is stored as a global variable pool because of its ease. It is + * also fairly compatible with multi-threading as the stratup code must + * be run in a single thread anyways. So there can be no race conditions. + * rgerhards 2005-10-18 + */ +static EHostnameCmpMode eDfltHostnameCmpMode = HN_NO_COMP; +static cstr_t *pDfltHostnameCmp = NULL; +static cstr_t *pDfltProgNameCmp = NULL; + + +/* process a directory and include all of its files into + * the current config file. There is no specific order of inclusion, + * files are included in the order they are read from the directory. + * The caller must have make sure that the provided parameter is + * indeed a directory. + * rgerhards, 2007-08-01 + */ +static rsRetVal doIncludeDirectory(uchar *pDirName) +{ + DEFiRet; + int iEntriesDone = 0; + DIR *pDir; + union { + struct dirent d; + char b[offsetof(struct dirent, d_name) + NAME_MAX + 1]; + } u; + struct dirent *res; + size_t iDirNameLen; + size_t iFileNameLen; + uchar szFullFileName[MAXFNAME]; + + ASSERT(pDirName != NULL); + + if((pDir = opendir((char*) pDirName)) == NULL) { + errmsg.LogError(errno, RS_RET_FOPEN_FAILURE, "error opening include directory"); + ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); + } + + /* prepare file name buffer */ + iDirNameLen = strlen((char*) pDirName); + memcpy(szFullFileName, pDirName, iDirNameLen); + + /* now read the directory */ + iEntriesDone = 0; + while(readdir_r(pDir, &u.d, &res) == 0) { + if(res == NULL) + break; /* this also indicates end of directory */ +# ifdef DT_REG + /* TODO: find an alternate way to checking for special files if this is + * not defined. This is currently a known problem on HP UX, but the work- + * around is simple: do not create special files in that directory. So + * fixing this is actually not the most important thing on earth... + * rgerhards, 2008-03-04 + */ + if(res->d_type != DT_REG) + continue; /* we are not interested in special files */ +# endif + if(res->d_name[0] == '.') + continue; /* these files we are also not interested in */ + ++iEntriesDone; + /* construct filename */ + iFileNameLen = strlen(res->d_name); + if (iFileNameLen > NAME_MAX) + iFileNameLen = NAME_MAX; + memcpy(szFullFileName + iDirNameLen, res->d_name, iFileNameLen); + *(szFullFileName + iDirNameLen + iFileNameLen) = '\0'; + dbgprintf("including file '%s'\n", szFullFileName); + processConfFile(szFullFileName); + /* we deliberately ignore the iRet of processConfFile() - this is because + * failure to process one file does not mean all files will fail. By ignoring, + * we retry with the next file, which is the best thing we can do. -- rgerhards, 2007-08-01 + */ + } + + if(iEntriesDone == 0) { + /* I just make it a debug output, because I can think of a lot of cases where it + * makes sense not to have any files. E.g. a system maintainer may place a $Include + * into the config file just in case, when additional modules be installed. When none + * are installed, the directory will be empty, which is fine. -- rgerhards 2007-08-01 + */ + dbgprintf("warning: the include directory contained no files - this may be ok.\n"); + } + +finalize_it: + if(pDir != NULL) + closedir(pDir); + + RETiRet; +} + + +/* process a $include config line. That type of line requires + * inclusion of another file. + * rgerhards, 2007-08-01 + */ +rsRetVal +doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal) +{ + DEFiRet; + char pattern[MAXFNAME]; + uchar *cfgFile; + glob_t cfgFiles; + int result; + size_t i = 0; + struct stat fileInfo; + + ASSERT(pp != NULL); + ASSERT(*pp != NULL); + + if(getSubString(pp, (char*) pattern, sizeof(pattern) / sizeof(char), ' ') != 0) { + errmsg.LogError(0, RS_RET_NOT_FOUND, "could not parse config file name"); + ABORT_FINALIZE(RS_RET_NOT_FOUND); + } + + /* Use GLOB_MARK to append a trailing slash for directories. + * Required by doIncludeDirectory(). + */ + result = glob(pattern, GLOB_MARK, NULL, &cfgFiles); + if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s", + pattern, errStr); + ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND); + } + + for(i = 0; i < cfgFiles.gl_pathc; i++) { + cfgFile = (uchar*) cfgFiles.gl_pathv[i]; + + if(stat((char*) cfgFile, &fileInfo) != 0) + continue; /* continue with the next file if we can't stat() the file */ + + if(S_ISREG(fileInfo.st_mode)) { /* config file */ + dbgprintf("requested to include config file '%s'\n", cfgFile); + iRet = processConfFile(cfgFile); + } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */ + dbgprintf("requested to include directory '%s'\n", cfgFile); + iRet = doIncludeDirectory(cfgFile); + } else { /* TODO: shall we handle symlinks or not? */ + dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile); + } + } + + globfree(&cfgFiles); + +finalize_it: + RETiRet; +} + + +/* process a $ModLoad config line. + */ +rsRetVal +doModLoad(uchar **pp, __attribute__((unused)) void* pVal) +{ + DEFiRet; + uchar szName[512]; + uchar *pModName; + + ASSERT(pp != NULL); + ASSERT(*pp != NULL); + + skipWhiteSpace(pp); /* skip over any whitespace */ + if(getSubString(pp, (char*) szName, sizeof(szName) / sizeof(uchar), ' ') != 0) { + errmsg.LogError(0, RS_RET_NOT_FOUND, "could not extract module name"); + ABORT_FINALIZE(RS_RET_NOT_FOUND); + } + 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 + */ + if(!strcmp((char*) szName, "MySQL")) + pModName = (uchar*) "ommysql.so"; + else + pModName = szName; + + CHKiRet(module.Load(pModName)); + +finalize_it: + RETiRet; +} + + +/* parse and interpret a $-config line that starts with + * a name (this is common code). It is parsed to the name + * and then the proper sub-function is called to handle + * the actual directive. + * rgerhards 2004-11-17 + * rgerhards 2005-06-21: previously only for templates, now + * generalized. + */ +rsRetVal +doNameLine(uchar **pp, void* pVal) +{ + DEFiRet; + uchar *p; + enum eDirective eDir; + char szName[128]; + + ASSERT(pp != NULL); + p = *pp; + ASSERT(p != NULL); + + eDir = (enum eDirective) pVal; /* this time, it actually is NOT a pointer! */ + + if(getSubString(&p, szName, sizeof(szName) / sizeof(char), ',') != 0) { + errmsg.LogError(0, RS_RET_NOT_FOUND, "Invalid config line: could not extract name - line ignored"); + ABORT_FINALIZE(RS_RET_NOT_FOUND); + } + if(*p == ',') + ++p; /* comma was eaten */ + + /* we got the name - now we pass name & the rest of the string + * to the subfunction. It makes no sense to do further + * parsing here, as this is in close interaction with the + * respective subsystem. rgerhards 2004-11-17 + */ + + switch(eDir) { + case DIR_TEMPLATE: + tplAddLine(szName, &p); + break; + case DIR_OUTCHANNEL: + ochAddLine(szName, &p); + break; + case DIR_ALLOWEDSENDER: + net.addAllowedSenderLine(szName, &p); + break; + default:/* we do this to avoid compiler warning - not all + * enum values call this function, so an incomplete list + * is quite ok (but then we should not run into this code, + * so at least we log a debug warning). + */ + dbgprintf("INTERNAL ERROR: doNameLine() called with invalid eDir %d.\n", + eDir); + break; + } + + *pp = p; + +finalize_it: + RETiRet; +} + + +/* Parse and interpret a system-directive in the config line + * A system directive is one that starts with a "$" sign. It offers + * extended configuration parameters. + * 2004-11-17 rgerhards + */ +rsRetVal +cfsysline(uchar *p) +{ + DEFiRet; + uchar szCmd[64]; + + ASSERT(p != NULL); + errno = 0; + if(getSubString(&p, (char*) szCmd, sizeof(szCmd) / sizeof(uchar), ' ') != 0) { + errmsg.LogError(0, RS_RET_NOT_FOUND, "Invalid $-configline - could not extract command - line ignored\n"); + ABORT_FINALIZE(RS_RET_NOT_FOUND); + } + + /* we now try and see if we can find the command in the registered + * list of cfsysline handlers. -- rgerhards, 2007-07-31 + */ + CHKiRet(processCfSysLineCommand(szCmd, &p)); + + /* now check if we have some extra characters left on the line - that + * should not be the case. Whitespace is OK, but everything else should + * trigger a warning (that may be an indication of undesired behaviour). + * An exception, of course, are comments (starting with '#'). + * rgerhards, 2007-07-04 + */ + skipWhiteSpace(&p); + + if(*p && *p != '#') { /* we have a non-whitespace, so let's complain */ + errmsg.LogError(0, NO_ERRCODE, + "error: extra characters in config line ignored: '%s'", p); + } + +finalize_it: + RETiRet; +} + + + + +/* process a configuration file + * started with code from init() by rgerhards on 2007-07-31 + */ +static rsRetVal +processConfFile(uchar *pConfFile) +{ + int iLnNbr = 0; + FILE *cf; + rule_t *pCurrRule = NULL; + uchar *p; + uchar cbuf[CFGLNSIZ]; + uchar *cline; + int i; + int bHadAnError = 0; + uchar *pszOrgLine = NULL; + size_t lenLine; + DEFiRet; + ASSERT(pConfFile != NULL); + + if((cf = fopen((char*)pConfFile, "r")) == NULL) { + ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); + } + + /* Now process the file. + */ + cline = cbuf; + while (fgets((char*)cline, sizeof(cbuf) - (cline - cbuf), cf) != NULL) { + ++iLnNbr; + /* drop LF - TODO: make it better, replace fgets(), but its clean as it is */ + lenLine = ustrlen(cline); + if(cline[lenLine-1] == '\n') { + cline[lenLine-1] = '\0'; + } + free(pszOrgLine); + pszOrgLine = ustrdup(cline); /* save if needed for errmsg, NULL ptr is OK */ + /* check for end-of-section, comments, strip off trailing + * spaces and newline character. + */ + p = cline; + skipWhiteSpace(&p); + if (*p == '\0' || *p == '#') + continue; + + /* we now need to copy the characters to the begin of line. As this overlaps, + * we can not use strcpy(). -- rgerhards, 2008-03-20 + * TODO: review the code at whole - this is highly suspect (but will go away + * once we do the rest of RainerScript). + */ + for( i = 0 ; p[i] != '\0' ; ++i) { + cline[i] = p[i]; + } + cline[i] = '\0'; + + for (p = (uchar*) strchr((char*)cline, '\0'); isspace((int) *--p);) + /*EMPTY*/; + if (*p == '\\') { + if ((p - cbuf) > CFGLNSIZ - 30) { + /* Oops the buffer is full - what now? */ + cline = cbuf; + } else { + *p = 0; + cline = p; + continue; + } + } else + cline = cbuf; + *++p = '\0'; /* TODO: check this */ + + /* we now have the complete line, and are positioned at the first non-whitespace + * character. So let's process it + */ + if(cfline(cbuf, &pCurrRule) != RS_RET_OK) { + /* we log a message, but otherwise ignore the error. After all, the next + * line can be correct. -- rgerhards, 2007-08-02 + */ + uchar szErrLoc[MAXFNAME + 64]; + dbgprintf("config line NOT successfully processed\n"); + snprintf((char*)szErrLoc, sizeof(szErrLoc) / sizeof(uchar), + "%s, line %d", pConfFile, iLnNbr); + errmsg.LogError(0, NO_ERRCODE, "the last error occured in %s:\"%s\"", (char*)szErrLoc, (char*)pszOrgLine); + bHadAnError = 1; + } + } + + /* we probably have one selector left to be added - so let's do that now */ + if(pCurrRule != NULL) { + CHKiRet(ruleset.AddRule(rule.GetAssRuleset(pCurrRule), &pCurrRule)); + } + + /* close the configuration file */ + fclose(cf); + +finalize_it: + if(iRet != RS_RET_OK) { + char errStr[1024]; + if(pCurrRule != NULL) + rule.Destruct(&pCurrRule); + + rs_strerror_r(errno, errStr, sizeof(errStr)); + dbgprintf("error %d processing config file '%s'; os error (if any): %s\n", + iRet, pConfFile, errStr); + } + + free(pszOrgLine); + + if(bHadAnError && (iRet == RS_RET_OK)) { /* a bit dirty, enhance in future releases */ + iRet = RS_RET_NONFATAL_CONFIG_ERR; + } + RETiRet; +} + + +/* Helper to cfline() and its helpers. Parses a template name + * from an "action" line. Must be called with the Line pointer + * pointing to the first character after the semicolon. + * rgerhards 2004-11-19 + * changed function to work with OMSR. -- rgerhards, 2007-07-27 + * the default template is to be used when no template is specified. + */ +rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName) +{ + uchar *p; + uchar *tplName = NULL; + cstr_t *pStrB; + DEFiRet; + + ASSERT(pp != NULL); + ASSERT(*pp != NULL); + ASSERT(pOMSR != NULL); + + p =*pp; + /* a template must follow - search it and complain, if not found */ + skipWhiteSpace(&p); + if(*p == ';') + ++p; /* eat it */ + else if(*p != '\0' && *p != '#') { + errmsg.LogError(0, RS_RET_ERR, "invalid character in selector line - ';template' expected"); + ABORT_FINALIZE(RS_RET_ERR); + } + + skipWhiteSpace(&p); /* go to begin of template name */ + + if(*p == '\0' || *p == '#') { + /* no template specified, use the default */ + /* TODO: check NULL ptr */ + tplName = (uchar*) strdup((char*)dfltTplName); + } else { + /* template specified, pick it up */ + CHKiRet(cstrConstruct(&pStrB)); + + /* now copy the string */ + while(*p && *p != '#' && !isspace((int) *p)) { + CHKiRet(cstrAppendChar(pStrB, *p)); + ++p; + } + CHKiRet(cstrFinalize(pStrB)); + CHKiRet(cstrConvSzStrAndDestruct(pStrB, &tplName, 0)); + } + + CHKiRet(OMSRsetEntry(pOMSR, iEntry, tplName, iTplOpts)); + +finalize_it: + if(iRet != RS_RET_OK) + free(tplName); + + *pp = p; + + RETiRet; +} + +/* Helper to cfline(). Parses a file name up until the first + * comma and then looks for the template specifier. Tries + * to find that template. + * rgerhards 2004-11-18 + * parameter pFileName must point to a buffer large enough + * to hold the largest possible filename. + * rgerhards, 2007-07-25 + * updated to include OMSR pointer -- rgerhards, 2007-07-27 + * updated to include template name -- rgerhards, 2008-03-28 + * rgerhards, 2010-01-19: file names end at the first space + */ +rsRetVal +cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *pszTpl) +{ + register uchar *pName; + int i; + DEFiRet; + + ASSERT(pOMSR != NULL); + + pName = pFileName; + i = 1; /* we start at 1 so that we reseve space for the '\0'! */ + while(*p && *p != ';' && *p != ' ' && i < MAXFNAME) { + *pName++ = *p++; + ++i; + } + *pName = '\0'; + + iRet = cflineParseTemplateName(&p, pOMSR, iEntry, iTplOpts, pszTpl); + + RETiRet; +} + + +/* Helper to cfline(). This function takes the filter part of a traditional, PRI + * based line and decodes the PRIs given in the selector line. It processed the + * line up to the beginning of the action part. A pointer to that beginnig is + * passed back to the caller. + * rgerhards 2005-09-15 + */ +/* GPLv3 - stems back to sysklogd */ +static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) +{ + uchar *p; + register uchar *q; + register int i, i2; + uchar *bp; + int pri; + int singlpri = 0; + int ignorepri = 0; + uchar buf[2048]; /* buffer for facility and priority names */ + uchar xbuf[200]; + DEFiRet; + + ASSERT(pline != NULL); + ASSERT(*pline != NULL); + ISOBJ_TYPE_assert(pRule, rule); + + dbgprintf(" - traditional PRI filter\n"); + errno = 0; /* keep strerror_r() stuff out of logerror messages */ + + pRule->f_filter_type = FILTER_PRI; + /* Note: file structure is pre-initialized to zero because it was + * created with calloc()! + */ + for (i = 0; i <= LOG_NFACILITIES; i++) { + pRule->f_filterData.f_pmask[i] = TABLE_NOPRI; + } + + /* scan through the list of selectors */ + for (p = *pline; *p && *p != '\t' && *p != ' ';) { + + /* find the end of this facility name list */ + for (q = p; *q && *q != '\t' && *q++ != '.'; ) + continue; + + /* collect priority name */ + for (bp = buf; *q && !strchr("\t ,;", *q) && bp < buf+sizeof(buf)-1 ; ) + *bp++ = *q++; + *bp = '\0'; + + /* skip cruft */ + while (strchr(",;", *q)) + q++; + + /* decode priority name */ + if ( *buf == '!' ) { + ignorepri = 1; + /* copy below is ok, we can NOT go off the allocated area */ + for (bp=buf; *(bp+1); bp++) + *bp=*(bp+1); + *bp='\0'; + } + else { + ignorepri = 0; + } + if ( *buf == '=' ) + { + singlpri = 1; + pri = decodeSyslogName(&buf[1], syslogPriNames); + } + else { + singlpri = 0; + pri = decodeSyslogName(buf, syslogPriNames); + } + + if (pri < 0) { + snprintf((char*) xbuf, sizeof(xbuf), "unknown priority name \"%s\"", buf); + errmsg.LogError(0, RS_RET_ERR, "%s", xbuf); + return RS_RET_ERR; + } + + /* scan facilities */ + while (*p && !strchr("\t .;", *p)) { + for (bp = buf; *p && !strchr("\t ,;.", *p) && bp < buf+sizeof(buf)-1 ; ) + *bp++ = *p++; + *bp = '\0'; + if (*buf == '*') { + for (i = 0; i <= LOG_NFACILITIES; i++) { + if ( pri == INTERNAL_NOPRI ) { + if ( ignorepri ) + pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI; + else + pRule->f_filterData.f_pmask[i] = TABLE_NOPRI; + } + else if ( singlpri ) { + if ( ignorepri ) + pRule->f_filterData.f_pmask[i] &= ~(1<f_filterData.f_pmask[i] |= (1<f_filterData.f_pmask[i] = TABLE_NOPRI; + else + pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI; + } + else + { + if ( ignorepri ) + for (i2= 0; i2 <= pri; ++i2) + pRule->f_filterData.f_pmask[i] &= ~(1<f_filterData.f_pmask[i] |= (1<f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI; + else + pRule->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI; + } else if ( singlpri ) { + if ( ignorepri ) + pRule->f_filterData.f_pmask[i >> 3] &= ~(1<f_filterData.f_pmask[i >> 3] |= (1<f_filterData.f_pmask[i >> 3] = TABLE_NOPRI; + else + pRule->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI; + } else { + if ( ignorepri ) + for (i2= 0; i2 <= pri; ++i2) + pRule->f_filterData.f_pmask[i >> 3] &= ~(1<f_filterData.f_pmask[i >> 3] |= (1<f_filter_type = FILTER_EXPR; + + /* if we come to over here, pline starts with "if ". We just skip that part. */ + (*pline) += 3; + + /* we first need a tokenizer... */ + CHKiRet(ctok.Construct(&tok)); + CHKiRet(ctok.Setpp(tok, *pline)); + CHKiRet(ctok.ConstructFinalize(tok)); + + /* now construct our expression */ + CHKiRet(expr.Construct(&f->f_filterData.f_expr)); + CHKiRet(expr.ConstructFinalize(f->f_filterData.f_expr)); + + /* ready to go... */ + CHKiRet(expr.Parse(f->f_filterData.f_expr, tok)); + + /* we now need to parse off the "then" - and note an error if it is + * missing... + */ + CHKiRet(ctok.GetToken(tok, &pToken)); + if(pToken->tok != ctok_THEN) { + ctok_token.Destruct(&pToken); + ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); + } + + ctok_token.Destruct(&pToken); /* no longer needed */ + + /* we are done, so we now need to restore things */ + CHKiRet(ctok.Getpp(tok, pline)); + CHKiRet(ctok.Destruct(&tok)); + + /* debug support - print vmprg after construction (uncomment to use) */ + /* vmprgDebugPrint(f->f_filterData.f_expr->pVmprg); */ + + /* we now need to skip whitespace to the action part, else we confuse + * the legacy rsyslog conf parser. -- rgerhards, 2008-02-25 + */ + while(isspace(**pline)) + ++(*pline); + +finalize_it: + if(iRet == RS_RET_SYNTAX_ERROR) { + errmsg.LogError(0, RS_RET_SYNTAX_ERROR, "syntax error in expression"); + } + + RETiRet; +} + + +/* Helper to cfline(). This function takes the filter part of a property + * based filter and decodes it. It processes the line up to the beginning + * of the action part. A pointer to that beginnig is passed back to the caller. + * rgerhards 2005-09-15 + */ +static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) +{ + rsParsObj *pPars; + cstr_t *pCSCompOp; + cstr_t *pCSPropName; + rsRetVal iRet; + int iOffset; /* for compare operations */ + + ASSERT(pline != NULL); + ASSERT(*pline != NULL); + ASSERT(f != NULL); + + dbgprintf(" - property-based filter\n"); + errno = 0; /* keep strerror_r() stuff out of logerror messages */ + + f->f_filter_type = FILTER_PROP; + + /* create parser object starting with line string without leading colon */ + if((iRet = rsParsConstructFromSz(&pPars, (*pline)+1)) != RS_RET_OK) { + errmsg.LogError(0, iRet, "Error %d constructing parser object - ignoring selector", iRet); + return(iRet); + } + + /* read property */ + iRet = parsDelimCStr(pPars, &pCSPropName, ',', 1, 1, 1); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "error %d parsing filter property - ignoring selector", iRet); + rsParsDestruct(pPars); + return(iRet); + } + iRet = propNameToID(pCSPropName, &f->f_filterData.prop.propID); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "error %d parsing filter property - ignoring selector", iRet); + rsParsDestruct(pPars); + return(iRet); + } + if(f->f_filterData.prop.propID == PROP_CEE) { + /* in CEE case, we need to preserve the actual property name */ + if((f->f_filterData.prop.propName = + es_newStrFromBuf((char*)cstrGetSzStrNoNULL(pCSPropName)+2, cstrLen(pCSPropName)-2)) == NULL) { + cstrDestruct(&pCSPropName); + return(RS_RET_ERR); + } + } + cstrDestruct(&pCSPropName); + + /* read operation */ + iRet = parsDelimCStr(pPars, &pCSCompOp, ',', 1, 1, 1); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "error %d compare operation property - ignoring selector", iRet); + rsParsDestruct(pPars); + return(iRet); + } + + /* we now first check if the condition is to be negated. To do so, we first + * must make sure we have at least one char in the param and then check the + * first one. + * rgerhards, 2005-09-26 + */ + if(rsCStrLen(pCSCompOp) > 0) { + if(*rsCStrGetBufBeg(pCSCompOp) == '!') { + f->f_filterData.prop.isNegated = 1; + iOffset = 1; /* ignore '!' */ + } else { + f->f_filterData.prop.isNegated = 0; + iOffset = 0; + } + } else { + f->f_filterData.prop.isNegated = 0; + iOffset = 0; + } + +dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSCompOp)); + if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) { + f->f_filterData.prop.operation = FIOP_CONTAINS; + } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) { + f->f_filterData.prop.operation = FIOP_ISEQUAL; + } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isempty", 7)) { + f->f_filterData.prop.operation = FIOP_ISEMPTY; + } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "startswith", 10)) { + f->f_filterData.prop.operation = FIOP_STARTSWITH; + } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) { + f->f_filterData.prop.operation = FIOP_REGEX; + } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "ereregex", 8)) { + f->f_filterData.prop.operation = FIOP_EREREGEX; + } else { + errmsg.LogError(0, NO_ERRCODE, "error: invalid compare operation '%s' - ignoring selector", + (char*) rsCStrGetSzStrNoNULL(pCSCompOp)); + } + rsCStrDestruct(&pCSCompOp); /* no longer needed */ + +dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); + if(f->f_filterData.prop.operation != FIOP_ISEMPTY) { + /* read compare value */ + iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet); + rsParsDestruct(pPars); + return(iRet); + } + } + + /* skip to action part */ + if((iRet = parsSkipWhitespace(pPars)) != RS_RET_OK) { + errmsg.LogError(0, iRet, "error %d skipping to action part - ignoring selector", iRet); + rsParsDestruct(pPars); + return(iRet); + } + + /* cleanup */ + *pline = *pline + rsParsGetParsePointer(pPars) + 1; + /* we are adding one for the skipped initial ":" */ + + return rsParsDestruct(pPars); +} + + +/* + * Helper to cfline(). This function interprets a BSD host selector line + * from the config file ("+/-hostname"). It stores it for further reference. + * rgerhards 2005-10-19 + */ +static rsRetVal cflineProcessHostSelector(uchar **pline) +{ + DEFiRet; + + ASSERT(pline != NULL); + ASSERT(*pline != NULL); + ASSERT(**pline == '-' || **pline == '+'); + + dbgprintf(" - host selector line\n"); + + /* check include/exclude setting */ + if(**pline == '+') { + eDfltHostnameCmpMode = HN_COMP_MATCH; + } else { /* we do not check for '-', it must be, else we wouldn't be here */ + eDfltHostnameCmpMode = HN_COMP_NOMATCH; + } + (*pline)++; /* eat + or - */ + + /* the below is somewhat of a quick hack, but it is efficient (this is + * why it is in here. "+*" resets the tag selector with BSD syslog. We mimic + * this, too. As it is easy to check that condition, we do not fire up a + * parser process, just make sure we do not address beyond our space. + * Order of conditions in the if-statement is vital! rgerhards 2005-10-18 + */ + if(**pline != '\0' && **pline == '*' && *(*pline+1) == '\0') { + dbgprintf("resetting BSD-like hostname filter\n"); + eDfltHostnameCmpMode = HN_NO_COMP; + if(pDfltHostnameCmp != NULL) { + CHKiRet(rsCStrSetSzStr(pDfltHostnameCmp, NULL)); + } + } else { + dbgprintf("setting BSD-like hostname filter to '%s'\n", *pline); + if(pDfltHostnameCmp == NULL) { + /* create string for parser */ + CHKiRet(rsCStrConstructFromszStr(&pDfltHostnameCmp, *pline)); + } else { /* string objects exists, just update... */ + CHKiRet(rsCStrSetSzStr(pDfltHostnameCmp, *pline)); + } + } + +finalize_it: + RETiRet; +} + + +/* + * Helper to cfline(). This function interprets a BSD tag selector line + * from the config file ("!tagname"). It stores it for further reference. + * rgerhards 2005-10-18 + */ +static rsRetVal cflineProcessTagSelector(uchar **pline) +{ + DEFiRet; + + ASSERT(pline != NULL); + ASSERT(*pline != NULL); + ASSERT(**pline == '!'); + + dbgprintf(" - programname selector line\n"); + + (*pline)++; /* eat '!' */ + + /* the below is somewhat of a quick hack, but it is efficient (this is + * why it is in here. "!*" resets the tag selector with BSD syslog. We mimic + * this, too. As it is easy to check that condition, we do not fire up a + * parser process, just make sure we do not address beyond our space. + * Order of conditions in the if-statement is vital! rgerhards 2005-10-18 + */ + if(**pline != '\0' && **pline == '*' && *(*pline+1) == '\0') { + dbgprintf("resetting programname filter\n"); + if(pDfltProgNameCmp != NULL) { + rsCStrDestruct(&pDfltProgNameCmp); + } + } else { + dbgprintf("setting programname filter to '%s'\n", *pline); + if(pDfltProgNameCmp == NULL) { + /* create string for parser */ + CHKiRet(rsCStrConstructFromszStr(&pDfltProgNameCmp, *pline)); + } else { /* string objects exists, just update... */ + CHKiRet(rsCStrSetSzStr(pDfltProgNameCmp, *pline)); + } + } + +finalize_it: + RETiRet; +} + + +/* read the filter part of a configuration line and store the filter + * in the supplied rule_t + * rgerhards, 2007-08-01 + */ +static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) +{ + DEFiRet; + + ASSERT(pp != NULL); + ISOBJ_TYPE_assert(f, rule); + + /* check which filter we need to pull... */ + switch(**pp) { + case ':': + CHKiRet(cflineProcessPropFilter(pp, f)); + break; + case 'i': /* "if" filter? */ + if(*(*pp+1) && (*(*pp+1) == 'f') && isspace(*(*pp+2))) { + CHKiRet(cflineProcessIfFilter(pp, f)); + break; + } + /*FALLTHROUGH*/ + default: + CHKiRet(cflineProcessTradPRIFilter(pp, f)); + break; + } + + /* we now check if there are some global (BSD-style) filter conditions + * and, if so, we copy them over. rgerhards, 2005-10-18 + */ + if(pDfltProgNameCmp != NULL) { + CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp)); + } + + if(eDfltHostnameCmpMode != HN_NO_COMP) { + f->eHostnameCmpMode = eDfltHostnameCmpMode; + CHKiRet(rsCStrConstructFromCStr(&(f->pCSHostnameComp), pDfltHostnameCmp)); + } + +finalize_it: + RETiRet; +} + + +/* process the action part of a selector line + * rgerhards, 2007-08-01 + */ +static rsRetVal cflineDoAction(uchar **p, action_t **ppAction) +{ + DEFiRet; + modInfo_t *pMod; + omodStringRequest_t *pOMSR; + action_t *pAction = NULL; + void *pModData; + + ASSERT(p != NULL); + ASSERT(ppAction != NULL); + + /* loop through all modules and see if one picks up the line */ + pMod = module.GetNxtType(NULL, eMOD_OUT); + /* Note: clang static analyzer reports that pMod mybe == NULL. However, this is + * not possible, because we have the built-in output modules which are always + * present. Anyhow, we guard this by an assert. -- rgerhards, 2010-12-16 + */ + assert(pMod != NULL); + while(pMod != NULL) { + pOMSR = NULL; + iRet = pMod->mod.om.parseSelectorAct(p, &pModData, &pOMSR); + dbgprintf("tried selector action for %s: %d\n", module.GetName(pMod), iRet); + if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) { + /* advance our config parser state: we now only accept an $End as valid, + * no more action statments. + */ + if(currConfObj == eConfObjAction) + currConfObj = eConfObjActionWaitEnd; + if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { + /* now check if the module is compatible with select features */ + if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) + pAction->f_ReduceRepeated = bReduceRepeatMsgs; + else { + dbgprintf("module is incompatible with RepeatedMsgReduction - turned off\n"); + pAction->f_ReduceRepeated = 0; + } + pAction->eState = ACT_STATE_RDY; /* action is enabled */ + iNbrActions++; /* one more active action! */ + } + break; + } + else if(iRet != RS_RET_CONFLINE_UNPROCESSED) { + /* In this case, the module would have handled the config + * line, but some error occured while doing so. This error should + * already by reported by the module. We do not try any other + * modules on this line, because we found the right one. + * rgerhards, 2007-07-24 + */ + dbgprintf("error %d parsing config line\n", (int) iRet); + break; + } + pMod = module.GetNxtType(pMod, eMOD_OUT); + } + + *ppAction = pAction; + RETiRet; +} + + +/* Process a configuration file line in traditional "filter selector" format + * or one that builds upon this format. Note that ppRule may be a NULL pointer, + * which is valid and happens if there is no previous line (right at the start + * of the master config file!). + */ +static rsRetVal +cflineClassic(uchar *p, rule_t **ppRule) +{ + DEFiRet; + action_t *pAction; + + /* lines starting with '&' have no new filters and just add + * new actions to the currently processed selector. + */ + if(*p == '&') { + ++p; /* eat '&' */ + skipWhiteSpace(&p); /* on to command */ + } else { + /* we are finished with the current selector (on previous line). + * So we now need to check + * if it has any actions associated and, if so, link it to the linked + * list. If it has nothing associated with it, we can simply discard + * it. In any case, we create a fresh selector for our new filter. + * We have one special case during initialization: then, the current + * selector is NULL, which means we do not need to care about it at + * all. -- rgerhards, 2007-08-01 + */ + if(*ppRule != NULL) { + CHKiRet(ruleset.AddRule(rule.GetAssRuleset(*ppRule), ppRule)); + } + CHKiRet(rule.Construct(ppRule)); /* create "fresh" selector */ + CHKiRet(rule.SetAssRuleset(*ppRule, ruleset.GetCurrent())); /* create "fresh" selector */ + CHKiRet(rule.ConstructFinalize(*ppRule)); /* create "fresh" selector */ + CHKiRet(cflineDoFilter(&p, *ppRule)); /* pull filters */ + } + + CHKiRet(cflineDoAction(&p, &pAction)); + CHKiRet(llAppend(&(*ppRule)->llActList, NULL, (void*) pAction)); + +finalize_it: + RETiRet; +} + + +/* process a configuration line + * I re-did this functon because it was desperately time to do so + * rgerhards, 2007-08-01 + */ +static rsRetVal +cfline(uchar *line, rule_t **pfCurr) +{ + DEFiRet; + + ASSERT(line != NULL); + + dbgprintf("cfline: '%s'\n", line); + + /* check type of line and call respective processing */ + switch(*line) { + case '!': + iRet = cflineProcessTagSelector(&line); + break; + case '+': + case '-': + iRet = cflineProcessHostSelector(&line); + break; + case '$': + ++line; /* eat '$' */ + iRet = cfsysline(line); + break; + default: + iRet = cflineClassic(line, pfCurr); + break; + } + + RETiRet; +} + + +/* return the current number of active actions + * rgerhards, 2008-07-28 + */ +static rsRetVal +GetNbrActActions(int *piNbrActions) +{ + DEFiRet; + assert(piNbrActions != NULL); + *piNbrActions = iNbrActions; + RETiRet; +} + + +/* queryInterface function + * rgerhards, 2008-02-29 + */ +BEGINobjQueryInterface(conf) +CODESTARTobjQueryInterface(conf) + if(pIf->ifVersion != confCURR_IF_VERSION) { /* check for current version, increment on each change */ + ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); + } + + /* ok, we have the right interface, so let's fill it + * Please note that we may also do some backwards-compatibility + * work here (if we can support an older interface version - that, + * of course, also affects the "if" above). + */ + pIf->doNameLine = doNameLine; + pIf->cfsysline = cfsysline; + pIf->doModLoad = doModLoad; + pIf->doIncludeLine = doIncludeLine; + pIf->cfline = cfline; + pIf->processConfFile = processConfFile; + pIf->GetNbrActActions = GetNbrActActions; + +finalize_it: +ENDobjQueryInterface(conf) + + +/* switch to a new action scope. This means that we switch the current + * mode to action, but it also means we need to clear all scope variables, + * so that we have a new environment. + * rgerhards, 2010-07-23 + */ +static inline rsRetVal +setActionScope(void) +{ + DEFiRet; + modInfo_t *pMod; + + currConfObj = eConfObjAction; + DBGPRINTF("entering action scope\n"); + CHKiRet(actionNewScope()); + + /* now tell each action to start the scope */ + pMod = NULL; + while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) { + DBGPRINTF("beginning scope on module %s\n", pMod->pszName); + pMod->mod.om.newScope(); + } + +finalize_it: + RETiRet; +} + + +/* switch back from action scope. + * rgerhards, 2010-07-27 + */ +static inline rsRetVal +unsetActionScope(void) +{ + DEFiRet; + modInfo_t *pMod; + + currConfObj = eConfObjAction; + DBGPRINTF("exiting action scope\n"); + CHKiRet(actionRestoreScope()); + + /* now tell each action to restore the scope */ + pMod = NULL; + while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) { + DBGPRINTF("exiting scope on module %s\n", pMod->pszName); + pMod->mod.om.restoreScope(); + } + +finalize_it: + RETiRet; +} + + +/* This method is called by our own handlers to begin a new config + * object ($Begin statement). This also implies a new scope. + * rgerhards, 2010-07-23 + */ +static rsRetVal +beginConfObj(void __attribute__((unused)) *pVal, uchar *pszName) +{ + DEFiRet; + + if(currConfObj != eConfObjGlobal) { + errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "not in global scope - can not nest $Begin"); + ABORT_FINALIZE(RS_RET_CONF_NOT_GLBL); + } + + if(!strcasecmp((char*)pszName, "action")) { + setActionScope(); + } else { + errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $Begin", pszName); + ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ); + } + +finalize_it: + free(pszName); /* no longer needed */ + RETiRet; +} + + +/* This method is called to end a config scope and switch + * back to global scope. + * rgerhards, 2010-07-23 + */ +static rsRetVal +endConfObj(void __attribute__((unused)) *pVal, uchar *pszName) +{ + DEFiRet; + + if(currConfObj == eConfObjGlobal) { + errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "already in global scope - dangling $End"); + ABORT_FINALIZE(RS_RET_CONF_IN_GLBL); + } + + if(!strcasecmp((char*)pszName, "action")) { + if(currConfObj == eConfObjAction) { + errmsg.LogError(0, RS_RET_CONF_END_NO_ACT, "$End action but not action specified"); + /* this is a warning, we continue processing in that case (unscope) */ + } else if(currConfObj != eConfObjActionWaitEnd) { + errmsg.LogError(0, RS_RET_CONF_INVLD_END, "$End not for active config object - " + "nesting error?"); + ABORT_FINALIZE(RS_RET_CONF_INVLD_END); + } + currConfObj = eConfObjGlobal; + CHKiRet(unsetActionScope()); + } else { + errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $End", pszName); + ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ); + } + +finalize_it: + free(pszName); /* no longer needed */ + RETiRet; +} + + +/* Reset config variables to default values. Note that + * when we are inside an scope, we simply reset this to global. + * However, $ResetConfigVariables is a global directive, and as such + * will not be honored inside a scope! + * rgerhards, 2010-07-23 + */ +static rsRetVal +resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +{ + currConfObj = eConfObjGlobal; + bConfStrictScoping = 0; + return RS_RET_OK; +} + + +/* exit our class + * rgerhards, 2008-03-11 + */ +BEGINObjClassExit(conf, OBJ_IS_CORE_MODULE) /* CHANGE class also in END MACRO! */ +CODESTARTObjClassExit(conf) + /* free no-longer needed module-global variables */ + if(pDfltHostnameCmp != NULL) { + rsCStrDestruct(&pDfltHostnameCmp); + } + + if(pDfltProgNameCmp != NULL) { + rsCStrDestruct(&pDfltProgNameCmp); + } + + /* release objects we no longer need */ + objRelease(expr, CORE_COMPONENT); + objRelease(ctok, CORE_COMPONENT); + objRelease(ctok_token, CORE_COMPONENT); + objRelease(module, CORE_COMPONENT); + objRelease(errmsg, CORE_COMPONENT); + objRelease(net, LM_NET_FILENAME); + objRelease(rule, CORE_COMPONENT); + objRelease(ruleset, CORE_COMPONENT); +ENDObjClassExit(conf) + + +/* Initialize our class. Must be called as the very first method + * before anything else is called inside this class. + * rgerhards, 2008-02-29 + */ +BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */ + /* request objects we use */ + CHKiRet(objUse(expr, CORE_COMPONENT)); + CHKiRet(objUse(ctok, CORE_COMPONENT)); + CHKiRet(objUse(ctok_token, CORE_COMPONENT)); + CHKiRet(objUse(module, CORE_COMPONENT)); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); + CHKiRet(objUse(net, LM_NET_FILENAME)); /* TODO: make this dependcy go away! */ + CHKiRet(objUse(rule, CORE_COMPONENT)); + CHKiRet(objUse(ruleset, CORE_COMPONENT)); + + CHKiRet(regCfSysLineHdlr((uchar *)"begin", 0, eCmdHdlrGetWord, beginConfObj, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"end", 0, eCmdHdlrGetWord, endConfObj, NULL, NULL, eConfObjAlways)); + CHKiRet(regCfSysLineHdlr((uchar *)"strictscoping", 0, eCmdHdlrBinary, NULL, &bConfStrictScoping, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjAction)); +ENDObjClassInit(conf) + +/* vi:set ai: + */ diff --git a/runtime/legacyconf.h b/runtime/legacyconf.h new file mode 100644 index 00000000..2cfd540f --- /dev/null +++ b/runtime/legacyconf.h @@ -0,0 +1,65 @@ +/* Definitions for the legacy config file handling (not yet an object). + * + * Copyright 2008 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Rsyslog is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#ifndef INCLUDED_CONF_H +#define INCLUDED_CONF_H + +/* definitions used for doNameLine to differentiate between different command types + * (with otherwise identical code). This is a left-over from the previous config + * system. It stays, because it is still useful. So do not wonder why it looks + * somewhat strange (at least its name). -- rgerhards, 2007-08-01 + */ +enum eDirective { DIR_TEMPLATE = 0, DIR_OUTCHANNEL = 1, DIR_ALLOWEDSENDER = 2}; +extern ecslConfObjType currConfObj; +extern int bConfStrictScoping; /* force strict scoping during config processing? */ + +/* interfaces */ +BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ + rsRetVal (*doNameLine)(uchar **pp, void* pVal); + rsRetVal (*cfsysline)(uchar *p); + rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); + rsRetVal (*doIncludeLine)(uchar **pp, __attribute__((unused)) void* pVal); + rsRetVal (*cfline)(uchar *line, rule_t **pfCurr); + rsRetVal (*processConfFile)(uchar *pConfFile); + rsRetVal (*GetNbrActActions)(int *); + /* version 4 -- 2010-07-23 rgerhards */ + /* "just" added global variables + * FYI: we reconsider repacking as a non-object, as only the core currently + * accesses this module. The current object structure complicates things without + * any real benefit. + */ +ENDinterface(conf) +#define confCURR_IF_VERSION 4 /* increment whenever you change the interface structure! */ +/* in Version 3, entry point "ReInitConf()" was removed, as we do not longer need + * to support restart-type HUP -- rgerhards, 2009-07-15 + */ + + +/* prototypes */ +PROTOTYPEObj(conf); + + +/* TODO: the following 2 need to go in conf obj interface... */ +rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName); +rsRetVal cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *pszTpl); + + +#endif /* #ifndef INCLUDED_CONF_H */ diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index bdb1c9ff..9cf32f22 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -74,7 +74,7 @@ #include "vmprg.h" #include "datetime.h" #include "queue.h" -#include "conf.h" +#include "legacyconf.h" #include "glbl.h" #include "errmsg.h" #include "prop.h" diff --git a/runtime/strmsrv.c b/runtime/strmsrv.c index e66ad717..4de58b77 100644 --- a/runtime/strmsrv.c +++ b/runtime/strmsrv.c @@ -64,7 +64,7 @@ #include "module-template.h" #include "net.h" #include "srUtils.h" -#include "conf.h" +#include "legacyconf.h" #include "strmsrv.h" #include "obj.h" #include "glbl.h" diff --git a/tcpsrv.c b/tcpsrv.c index 39cba5d1..a7a5e3fd 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -59,7 +59,7 @@ #include "module-template.h" #include "net.h" #include "srUtils.h" -#include "conf.h" +#include "legacyconf.h" #include "tcpsrv.h" #include "obj.h" #include "glbl.h" diff --git a/tools/omfile.c b/tools/omfile.c index 8526cb74..5fc87330 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -56,7 +56,7 @@ #endif -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/tools/omfwd.c b/tools/omfwd.c index be13bf75..3004b082 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -48,7 +48,7 @@ #endif #include #include "syslogd.h" -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "net.h" diff --git a/tools/ompipe.c b/tools/ompipe.c index 01695369..db4de73b 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -53,7 +53,7 @@ #include "omfile.h" /* for dirty trick: access to $ActionFileDefaultTemplate value */ #include "cfsysline.h" #include "module-template.h" -#include "conf.h" +#include "legacyconf.h" #include "errmsg.h" MODULE_TYPE_OUTPUT diff --git a/tools/omshell.c b/tools/omshell.c index 0e4e0f24..046fb41d 100644 --- a/tools/omshell.c +++ b/tools/omshell.c @@ -38,7 +38,7 @@ #include #include #include -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "srUtils.h" #include "omshell.h" diff --git a/tools/omusrmsg.c b/tools/omusrmsg.c index da510e08..e5477a1c 100644 --- a/tools/omusrmsg.c +++ b/tools/omusrmsg.c @@ -74,7 +74,7 @@ #include "srUtils.h" #include "stringbuf.h" #include "syslogd-types.h" -#include "conf.h" +#include "legacyconf.h" #include "omusrmsg.h" #include "module-template.h" #include "errmsg.h" diff --git a/tools/pmrfc3164.c b/tools/pmrfc3164.c index 635ca985..3876ca0b 100644 --- a/tools/pmrfc3164.c +++ b/tools/pmrfc3164.c @@ -33,7 +33,7 @@ #include #include #include "syslogd.h" -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/tools/pmrfc5424.c b/tools/pmrfc5424.c index b06f1347..d39ec8e5 100644 --- a/tools/pmrfc5424.c +++ b/tools/pmrfc5424.c @@ -32,7 +32,7 @@ #include #include #include "syslogd.h" -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/tools/smfile.c b/tools/smfile.c index 1e0bf091..c8f66120 100644 --- a/tools/smfile.c +++ b/tools/smfile.c @@ -38,7 +38,7 @@ #include #include #include "syslogd.h" -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/tools/smfwd.c b/tools/smfwd.c index 60fe94a7..3f9a3a84 100644 --- a/tools/smfwd.c +++ b/tools/smfwd.c @@ -35,7 +35,7 @@ #include #include #include "syslogd.h" -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/tools/smtradfile.c b/tools/smtradfile.c index 5484f7be..e57d2937 100644 --- a/tools/smtradfile.c +++ b/tools/smtradfile.c @@ -35,7 +35,7 @@ #include #include #include "syslogd.h" -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/tools/smtradfwd.c b/tools/smtradfwd.c index 37717434..be3982d7 100644 --- a/tools/smtradfwd.c +++ b/tools/smtradfwd.c @@ -35,7 +35,7 @@ #include #include #include "syslogd.h" -#include "conf.h" +#include "legacyconf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/tools/syslogd.c b/tools/syslogd.c index 44c88624..a6127305 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -124,7 +124,7 @@ #include "wti.h" #include "queue.h" #include "stream.h" -#include "conf.h" +#include "legacyconf.h" #include "errmsg.h" #include "datetime.h" #include "parser.h" -- cgit v1.2.3 From bbe1f2688c4bd5cb1b66bb48af1ce5428d69c3b9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Apr 2011 08:24:25 +0200 Subject: renaming conf.* wasn't a good idea -- undoing too many dependencies, things get cluttered (and merging probably gets problematic). Now new config will be "conf2". --- plugins/mmnormalize/mmnormalize.c | 2 +- plugins/omdbalerting/omdbalerting.c | 2 +- plugins/omgssapi/omgssapi.c | 2 +- plugins/omhdfs/omhdfs.c | 2 +- plugins/ommail/ommail.c | 2 +- plugins/ommongodb/ommongodb.c | 4 +- plugins/ommysql/ommysql.c | 2 +- plugins/ompgsql/ompgsql.c | 2 +- plugins/omprog/omprog.c | 2 +- plugins/omrelp/omrelp.c | 2 +- plugins/omruleset/omruleset.c | 2 +- plugins/omsnmp/omsnmp.c | 2 +- plugins/omstdout/omstdout.c | 2 +- plugins/omtemplate/omtemplate.c | 2 +- plugins/omtesting/omtesting.c | 2 +- plugins/omudpspoof/omudpspoof.c | 2 +- plugins/omuxsock/omuxsock.c | 2 +- plugins/pmaixforwardedfrom/pmaixforwardedfrom.c | 2 +- plugins/pmcisconames/pmcisconames.c | 2 +- plugins/pmlastmsg/pmlastmsg.c | 2 +- plugins/pmrfc3164sd/pmrfc3164sd.c | 2 +- plugins/pmsnare/pmsnare.c | 2 +- plugins/sm_cust_bindcdr/sm_cust_bindcdr.c | 2 +- runtime/Makefile.am | 4 +- runtime/cfsysline.c | 2 +- runtime/conf.c | 1453 +++++++++++++++++++++++ runtime/conf.h | 65 + runtime/legacyconf.c | 1453 ----------------------- runtime/legacyconf.h | 65 - runtime/rsyslog.c | 2 +- runtime/strmsrv.c | 2 +- tcpsrv.c | 2 +- tools/omfile.c | 2 +- tools/omfwd.c | 2 +- tools/ompipe.c | 2 +- tools/omshell.c | 2 +- tools/omusrmsg.c | 2 +- tools/pmrfc3164.c | 2 +- tools/pmrfc5424.c | 2 +- tools/smfile.c | 2 +- tools/smfwd.c | 2 +- tools/smtradfile.c | 2 +- tools/smtradfwd.c | 2 +- tools/syslogd.c | 2 +- 44 files changed, 1560 insertions(+), 1560 deletions(-) create mode 100644 runtime/conf.c create mode 100644 runtime/conf.h delete mode 100644 runtime/legacyconf.c delete mode 100644 runtime/legacyconf.h diff --git a/plugins/mmnormalize/mmnormalize.c b/plugins/mmnormalize/mmnormalize.c index 9517ec09..9c23afde 100644 --- a/plugins/mmnormalize/mmnormalize.c +++ b/plugins/mmnormalize/mmnormalize.c @@ -38,7 +38,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "module-template.h" diff --git a/plugins/omdbalerting/omdbalerting.c b/plugins/omdbalerting/omdbalerting.c index 55e8c375..35de5818 100644 --- a/plugins/omdbalerting/omdbalerting.c +++ b/plugins/omdbalerting/omdbalerting.c @@ -35,7 +35,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/plugins/omgssapi/omgssapi.c b/plugins/omgssapi/omgssapi.c index 1dc96794..6b75540f 100644 --- a/plugins/omgssapi/omgssapi.c +++ b/plugins/omgssapi/omgssapi.c @@ -44,7 +44,7 @@ #include #include #include "dirty.h" -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "net.h" diff --git a/plugins/omhdfs/omhdfs.c b/plugins/omhdfs/omhdfs.c index efd3b672..48168f28 100644 --- a/plugins/omhdfs/omhdfs.c +++ b/plugins/omhdfs/omhdfs.c @@ -41,7 +41,7 @@ #include "syslogd-types.h" #include "srUtils.h" #include "template.h" -#include "legacyconf.h" +#include "conf.h" #include "cfsysline.h" #include "module-template.h" #include "unicode-helper.h" diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c index fbf6bfad..6468dcf2 100644 --- a/plugins/ommail/ommail.c +++ b/plugins/ommail/ommail.c @@ -44,7 +44,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "cfsysline.h" diff --git a/plugins/ommongodb/ommongodb.c b/plugins/ommongodb/ommongodb.c index 3b7e9209..8e19105f 100644 --- a/plugins/ommongodb/ommongodb.c +++ b/plugins/ommongodb/ommongodb.c @@ -10,7 +10,7 @@ #include "mongo.h" #include "config.h" #include "rsyslog.h" -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" @@ -277,4 +277,4 @@ CODEmodInit_QueryRegCFSLineHdlr INITChkCoreFeature(bCoreSupportsBatching, CORE_FEATURE_BATCHING); DBGPRINTF("ompgsql: module compiled with rsyslog version %s.\n", VERSION); DBGPRINTF("ompgsql: %susing transactional output interface.\n", bCoreSupportsBatching ? "" : "not "); -ENDmodInit +ENDmodInit \ No newline at end of file diff --git a/plugins/ommysql/ommysql.c b/plugins/ommysql/ommysql.c index 90120768..978f3517 100644 --- a/plugins/ommysql/ommysql.c +++ b/plugins/ommysql/ommysql.c @@ -36,7 +36,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/plugins/ompgsql/ompgsql.c b/plugins/ompgsql/ompgsql.c index 373bfb6d..df9cc3fe 100644 --- a/plugins/ompgsql/ompgsql.c +++ b/plugins/ompgsql/ompgsql.c @@ -40,7 +40,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/plugins/omprog/omprog.c b/plugins/omprog/omprog.c index 05cb0803..81098257 100644 --- a/plugins/omprog/omprog.c +++ b/plugins/omprog/omprog.c @@ -36,7 +36,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c index 4e8f5419..26e8ccd3 100644 --- a/plugins/omrelp/omrelp.c +++ b/plugins/omrelp/omrelp.c @@ -36,7 +36,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "cfsysline.h" diff --git a/plugins/omruleset/omruleset.c b/plugins/omruleset/omruleset.c index e41b8445..365b405d 100644 --- a/plugins/omruleset/omruleset.c +++ b/plugins/omruleset/omruleset.c @@ -39,7 +39,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "module-template.h" diff --git a/plugins/omsnmp/omsnmp.c b/plugins/omsnmp/omsnmp.c index 4b928c03..777a8074 100644 --- a/plugins/omsnmp/omsnmp.c +++ b/plugins/omsnmp/omsnmp.c @@ -36,7 +36,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "cfsysline.h" #include "module-template.h" diff --git a/plugins/omstdout/omstdout.c b/plugins/omstdout/omstdout.c index 55d25fe5..f57cbe57 100644 --- a/plugins/omstdout/omstdout.c +++ b/plugins/omstdout/omstdout.c @@ -35,7 +35,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/plugins/omtemplate/omtemplate.c b/plugins/omtemplate/omtemplate.c index c6dd9546..238ec0ae 100644 --- a/plugins/omtemplate/omtemplate.c +++ b/plugins/omtemplate/omtemplate.c @@ -36,7 +36,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/plugins/omtesting/omtesting.c b/plugins/omtesting/omtesting.c index 15987077..414ecfc5 100644 --- a/plugins/omtesting/omtesting.c +++ b/plugins/omtesting/omtesting.c @@ -53,7 +53,7 @@ #include "dirty.h" #include "syslogd-types.h" #include "module-template.h" -#include "legacyconf.h" +#include "conf.h" #include "cfsysline.h" MODULE_TYPE_OUTPUT diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c index 19e0b70a..217de1c8 100644 --- a/plugins/omudpspoof/omudpspoof.c +++ b/plugins/omudpspoof/omudpspoof.c @@ -60,7 +60,7 @@ #ifdef USE_NETZIP #include #endif -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "net.h" diff --git a/plugins/omuxsock/omuxsock.c b/plugins/omuxsock/omuxsock.c index 8b9ec800..ea1c8014 100644 --- a/plugins/omuxsock/omuxsock.c +++ b/plugins/omuxsock/omuxsock.c @@ -41,7 +41,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "srUtils.h" #include "template.h" #include "msg.h" diff --git a/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c b/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c index 12c52ff9..fa4a9087 100644 --- a/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c +++ b/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c @@ -29,7 +29,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/plugins/pmcisconames/pmcisconames.c b/plugins/pmcisconames/pmcisconames.c index bf79e957..61688cbf 100644 --- a/plugins/pmcisconames/pmcisconames.c +++ b/plugins/pmcisconames/pmcisconames.c @@ -29,7 +29,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/plugins/pmlastmsg/pmlastmsg.c b/plugins/pmlastmsg/pmlastmsg.c index 118c4331..259c5d41 100644 --- a/plugins/pmlastmsg/pmlastmsg.c +++ b/plugins/pmlastmsg/pmlastmsg.c @@ -35,7 +35,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/plugins/pmrfc3164sd/pmrfc3164sd.c b/plugins/pmrfc3164sd/pmrfc3164sd.c index 4ddd98bc..53204ece 100644 --- a/plugins/pmrfc3164sd/pmrfc3164sd.c +++ b/plugins/pmrfc3164sd/pmrfc3164sd.c @@ -33,7 +33,7 @@ #include #include #include "syslogd.h" -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/plugins/pmsnare/pmsnare.c b/plugins/pmsnare/pmsnare.c index 757e6a8f..f3658d11 100644 --- a/plugins/pmsnare/pmsnare.c +++ b/plugins/pmsnare/pmsnare.c @@ -46,7 +46,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/plugins/sm_cust_bindcdr/sm_cust_bindcdr.c b/plugins/sm_cust_bindcdr/sm_cust_bindcdr.c index b55cec48..0fa1a4c4 100644 --- a/plugins/sm_cust_bindcdr/sm_cust_bindcdr.c +++ b/plugins/sm_cust_bindcdr/sm_cust_bindcdr.c @@ -41,7 +41,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "cfsysline.h" #include "template.h" diff --git a/runtime/Makefile.am b/runtime/Makefile.am index a963251c..c8e8ce2a 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -18,8 +18,8 @@ librsyslog_la_SOURCES = \ glbl.h \ glbl.c \ unlimited_select.h \ - legacyconf.c \ - legacyconf.h \ + conf.c \ + conf.h \ parser.h \ parser.c \ strgen.h \ diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c index 44b26022..97b35bb2 100644 --- a/runtime/cfsysline.c +++ b/runtime/cfsysline.c @@ -39,7 +39,7 @@ #include "cfsysline.h" #include "obj.h" -#include "legacyconf.h" +#include "conf.h" #include "errmsg.h" #include "srUtils.h" #include "unicode-helper.h" diff --git a/runtime/conf.c b/runtime/conf.c new file mode 100644 index 00000000..1d28a884 --- /dev/null +++ b/runtime/conf.c @@ -0,0 +1,1453 @@ +/* The config file handler (not yet a real object) + * + * This file is based on an excerpt from syslogd.c, which dates back + * much later. I began the file on 2008-02-19 as part of the modularization + * effort. Over time, a clean abstration will become even more important + * because the config file handler will by dynamically be loaded and be + * kept in memory only as long as the config file is actually being + * processed. Thereafter, it shall be unloaded. -- rgerhards + * + * TODO: the license MUST be changed to LGPL. However, we can not + * currently do that, because we use some sysklogd code to crunch + * the selector lines (e.g. *.info). That code is scheduled for removal + * as part of RainerScript. After this is done, we can change licenses. + * + * Copyright 2008 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Rsyslog is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#define CFGLNSIZ 4096 /* the maximum size of a configuraton file line, after re-combination */ +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_LIBGEN_H +# ifndef OS_SOLARIS +# include +# endif +#endif + +#include "rsyslog.h" +#include "dirty.h" +#include "parse.h" +#include "action.h" +#include "template.h" +#include "cfsysline.h" +#include "modules.h" +#include "outchannel.h" +#include "stringbuf.h" +#include "conf.h" +#include "stringbuf.h" +#include "srUtils.h" +#include "errmsg.h" +#include "net.h" +#include "expr.h" +#include "ctok.h" +#include "ctok_token.h" +#include "rule.h" +#include "ruleset.h" +#include "unicode-helper.h" + +#ifdef OS_SOLARIS +# define NAME_MAX MAXNAMELEN +#endif + +/* forward definitions */ +static rsRetVal cfline(uchar *line, rule_t **pfCurr); +static rsRetVal processConfFile(uchar *pConfFile); + + +/* static data */ +DEFobjStaticHelpers +DEFobjCurrIf(expr) +DEFobjCurrIf(ctok) +DEFobjCurrIf(ctok_token) +DEFobjCurrIf(module) +DEFobjCurrIf(errmsg) +DEFobjCurrIf(net) +DEFobjCurrIf(rule) +DEFobjCurrIf(ruleset) + +ecslConfObjType currConfObj = eConfObjGlobal; /* to support scoping - which config object is currently active? */ +int bConfStrictScoping = 0; /* force strict scoping during config processing? */ + + +static int iNbrActions = 0; /* number of currently defined actions */ + +/* The following module-global variables are used for building + * tag and host selector lines during startup and config reload. + * This is stored as a global variable pool because of its ease. It is + * also fairly compatible with multi-threading as the stratup code must + * be run in a single thread anyways. So there can be no race conditions. + * rgerhards 2005-10-18 + */ +static EHostnameCmpMode eDfltHostnameCmpMode = HN_NO_COMP; +static cstr_t *pDfltHostnameCmp = NULL; +static cstr_t *pDfltProgNameCmp = NULL; + + +/* process a directory and include all of its files into + * the current config file. There is no specific order of inclusion, + * files are included in the order they are read from the directory. + * The caller must have make sure that the provided parameter is + * indeed a directory. + * rgerhards, 2007-08-01 + */ +static rsRetVal doIncludeDirectory(uchar *pDirName) +{ + DEFiRet; + int iEntriesDone = 0; + DIR *pDir; + union { + struct dirent d; + char b[offsetof(struct dirent, d_name) + NAME_MAX + 1]; + } u; + struct dirent *res; + size_t iDirNameLen; + size_t iFileNameLen; + uchar szFullFileName[MAXFNAME]; + + ASSERT(pDirName != NULL); + + if((pDir = opendir((char*) pDirName)) == NULL) { + errmsg.LogError(errno, RS_RET_FOPEN_FAILURE, "error opening include directory"); + ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); + } + + /* prepare file name buffer */ + iDirNameLen = strlen((char*) pDirName); + memcpy(szFullFileName, pDirName, iDirNameLen); + + /* now read the directory */ + iEntriesDone = 0; + while(readdir_r(pDir, &u.d, &res) == 0) { + if(res == NULL) + break; /* this also indicates end of directory */ +# ifdef DT_REG + /* TODO: find an alternate way to checking for special files if this is + * not defined. This is currently a known problem on HP UX, but the work- + * around is simple: do not create special files in that directory. So + * fixing this is actually not the most important thing on earth... + * rgerhards, 2008-03-04 + */ + if(res->d_type != DT_REG) + continue; /* we are not interested in special files */ +# endif + if(res->d_name[0] == '.') + continue; /* these files we are also not interested in */ + ++iEntriesDone; + /* construct filename */ + iFileNameLen = strlen(res->d_name); + if (iFileNameLen > NAME_MAX) + iFileNameLen = NAME_MAX; + memcpy(szFullFileName + iDirNameLen, res->d_name, iFileNameLen); + *(szFullFileName + iDirNameLen + iFileNameLen) = '\0'; + dbgprintf("including file '%s'\n", szFullFileName); + processConfFile(szFullFileName); + /* we deliberately ignore the iRet of processConfFile() - this is because + * failure to process one file does not mean all files will fail. By ignoring, + * we retry with the next file, which is the best thing we can do. -- rgerhards, 2007-08-01 + */ + } + + if(iEntriesDone == 0) { + /* I just make it a debug output, because I can think of a lot of cases where it + * makes sense not to have any files. E.g. a system maintainer may place a $Include + * into the config file just in case, when additional modules be installed. When none + * are installed, the directory will be empty, which is fine. -- rgerhards 2007-08-01 + */ + dbgprintf("warning: the include directory contained no files - this may be ok.\n"); + } + +finalize_it: + if(pDir != NULL) + closedir(pDir); + + RETiRet; +} + + +/* process a $include config line. That type of line requires + * inclusion of another file. + * rgerhards, 2007-08-01 + */ +rsRetVal +doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal) +{ + DEFiRet; + char pattern[MAXFNAME]; + uchar *cfgFile; + glob_t cfgFiles; + int result; + size_t i = 0; + struct stat fileInfo; + + ASSERT(pp != NULL); + ASSERT(*pp != NULL); + + if(getSubString(pp, (char*) pattern, sizeof(pattern) / sizeof(char), ' ') != 0) { + errmsg.LogError(0, RS_RET_NOT_FOUND, "could not parse config file name"); + ABORT_FINALIZE(RS_RET_NOT_FOUND); + } + + /* Use GLOB_MARK to append a trailing slash for directories. + * Required by doIncludeDirectory(). + */ + result = glob(pattern, GLOB_MARK, NULL, &cfgFiles); + if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s", + pattern, errStr); + ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND); + } + + for(i = 0; i < cfgFiles.gl_pathc; i++) { + cfgFile = (uchar*) cfgFiles.gl_pathv[i]; + + if(stat((char*) cfgFile, &fileInfo) != 0) + continue; /* continue with the next file if we can't stat() the file */ + + if(S_ISREG(fileInfo.st_mode)) { /* config file */ + dbgprintf("requested to include config file '%s'\n", cfgFile); + iRet = processConfFile(cfgFile); + } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */ + dbgprintf("requested to include directory '%s'\n", cfgFile); + iRet = doIncludeDirectory(cfgFile); + } else { /* TODO: shall we handle symlinks or not? */ + dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile); + } + } + + globfree(&cfgFiles); + +finalize_it: + RETiRet; +} + + +/* process a $ModLoad config line. + */ +rsRetVal +doModLoad(uchar **pp, __attribute__((unused)) void* pVal) +{ + DEFiRet; + uchar szName[512]; + uchar *pModName; + + ASSERT(pp != NULL); + ASSERT(*pp != NULL); + + skipWhiteSpace(pp); /* skip over any whitespace */ + if(getSubString(pp, (char*) szName, sizeof(szName) / sizeof(uchar), ' ') != 0) { + errmsg.LogError(0, RS_RET_NOT_FOUND, "could not extract module name"); + ABORT_FINALIZE(RS_RET_NOT_FOUND); + } + 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 + */ + if(!strcmp((char*) szName, "MySQL")) + pModName = (uchar*) "ommysql.so"; + else + pModName = szName; + + CHKiRet(module.Load(pModName)); + +finalize_it: + RETiRet; +} + + +/* parse and interpret a $-config line that starts with + * a name (this is common code). It is parsed to the name + * and then the proper sub-function is called to handle + * the actual directive. + * rgerhards 2004-11-17 + * rgerhards 2005-06-21: previously only for templates, now + * generalized. + */ +rsRetVal +doNameLine(uchar **pp, void* pVal) +{ + DEFiRet; + uchar *p; + enum eDirective eDir; + char szName[128]; + + ASSERT(pp != NULL); + p = *pp; + ASSERT(p != NULL); + + eDir = (enum eDirective) pVal; /* this time, it actually is NOT a pointer! */ + + if(getSubString(&p, szName, sizeof(szName) / sizeof(char), ',') != 0) { + errmsg.LogError(0, RS_RET_NOT_FOUND, "Invalid config line: could not extract name - line ignored"); + ABORT_FINALIZE(RS_RET_NOT_FOUND); + } + if(*p == ',') + ++p; /* comma was eaten */ + + /* we got the name - now we pass name & the rest of the string + * to the subfunction. It makes no sense to do further + * parsing here, as this is in close interaction with the + * respective subsystem. rgerhards 2004-11-17 + */ + + switch(eDir) { + case DIR_TEMPLATE: + tplAddLine(szName, &p); + break; + case DIR_OUTCHANNEL: + ochAddLine(szName, &p); + break; + case DIR_ALLOWEDSENDER: + net.addAllowedSenderLine(szName, &p); + break; + default:/* we do this to avoid compiler warning - not all + * enum values call this function, so an incomplete list + * is quite ok (but then we should not run into this code, + * so at least we log a debug warning). + */ + dbgprintf("INTERNAL ERROR: doNameLine() called with invalid eDir %d.\n", + eDir); + break; + } + + *pp = p; + +finalize_it: + RETiRet; +} + + +/* Parse and interpret a system-directive in the config line + * A system directive is one that starts with a "$" sign. It offers + * extended configuration parameters. + * 2004-11-17 rgerhards + */ +rsRetVal +cfsysline(uchar *p) +{ + DEFiRet; + uchar szCmd[64]; + + ASSERT(p != NULL); + errno = 0; + if(getSubString(&p, (char*) szCmd, sizeof(szCmd) / sizeof(uchar), ' ') != 0) { + errmsg.LogError(0, RS_RET_NOT_FOUND, "Invalid $-configline - could not extract command - line ignored\n"); + ABORT_FINALIZE(RS_RET_NOT_FOUND); + } + + /* we now try and see if we can find the command in the registered + * list of cfsysline handlers. -- rgerhards, 2007-07-31 + */ + CHKiRet(processCfSysLineCommand(szCmd, &p)); + + /* now check if we have some extra characters left on the line - that + * should not be the case. Whitespace is OK, but everything else should + * trigger a warning (that may be an indication of undesired behaviour). + * An exception, of course, are comments (starting with '#'). + * rgerhards, 2007-07-04 + */ + skipWhiteSpace(&p); + + if(*p && *p != '#') { /* we have a non-whitespace, so let's complain */ + errmsg.LogError(0, NO_ERRCODE, + "error: extra characters in config line ignored: '%s'", p); + } + +finalize_it: + RETiRet; +} + + + + +/* process a configuration file + * started with code from init() by rgerhards on 2007-07-31 + */ +static rsRetVal +processConfFile(uchar *pConfFile) +{ + int iLnNbr = 0; + FILE *cf; + rule_t *pCurrRule = NULL; + uchar *p; + uchar cbuf[CFGLNSIZ]; + uchar *cline; + int i; + int bHadAnError = 0; + uchar *pszOrgLine = NULL; + size_t lenLine; + DEFiRet; + ASSERT(pConfFile != NULL); + + if((cf = fopen((char*)pConfFile, "r")) == NULL) { + ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); + } + + /* Now process the file. + */ + cline = cbuf; + while (fgets((char*)cline, sizeof(cbuf) - (cline - cbuf), cf) != NULL) { + ++iLnNbr; + /* drop LF - TODO: make it better, replace fgets(), but its clean as it is */ + lenLine = ustrlen(cline); + if(cline[lenLine-1] == '\n') { + cline[lenLine-1] = '\0'; + } + free(pszOrgLine); + pszOrgLine = ustrdup(cline); /* save if needed for errmsg, NULL ptr is OK */ + /* check for end-of-section, comments, strip off trailing + * spaces and newline character. + */ + p = cline; + skipWhiteSpace(&p); + if (*p == '\0' || *p == '#') + continue; + + /* we now need to copy the characters to the begin of line. As this overlaps, + * we can not use strcpy(). -- rgerhards, 2008-03-20 + * TODO: review the code at whole - this is highly suspect (but will go away + * once we do the rest of RainerScript). + */ + for( i = 0 ; p[i] != '\0' ; ++i) { + cline[i] = p[i]; + } + cline[i] = '\0'; + + for (p = (uchar*) strchr((char*)cline, '\0'); isspace((int) *--p);) + /*EMPTY*/; + if (*p == '\\') { + if ((p - cbuf) > CFGLNSIZ - 30) { + /* Oops the buffer is full - what now? */ + cline = cbuf; + } else { + *p = 0; + cline = p; + continue; + } + } else + cline = cbuf; + *++p = '\0'; /* TODO: check this */ + + /* we now have the complete line, and are positioned at the first non-whitespace + * character. So let's process it + */ + if(cfline(cbuf, &pCurrRule) != RS_RET_OK) { + /* we log a message, but otherwise ignore the error. After all, the next + * line can be correct. -- rgerhards, 2007-08-02 + */ + uchar szErrLoc[MAXFNAME + 64]; + dbgprintf("config line NOT successfully processed\n"); + snprintf((char*)szErrLoc, sizeof(szErrLoc) / sizeof(uchar), + "%s, line %d", pConfFile, iLnNbr); + errmsg.LogError(0, NO_ERRCODE, "the last error occured in %s:\"%s\"", (char*)szErrLoc, (char*)pszOrgLine); + bHadAnError = 1; + } + } + + /* we probably have one selector left to be added - so let's do that now */ + if(pCurrRule != NULL) { + CHKiRet(ruleset.AddRule(rule.GetAssRuleset(pCurrRule), &pCurrRule)); + } + + /* close the configuration file */ + fclose(cf); + +finalize_it: + if(iRet != RS_RET_OK) { + char errStr[1024]; + if(pCurrRule != NULL) + rule.Destruct(&pCurrRule); + + rs_strerror_r(errno, errStr, sizeof(errStr)); + dbgprintf("error %d processing config file '%s'; os error (if any): %s\n", + iRet, pConfFile, errStr); + } + + free(pszOrgLine); + + if(bHadAnError && (iRet == RS_RET_OK)) { /* a bit dirty, enhance in future releases */ + iRet = RS_RET_NONFATAL_CONFIG_ERR; + } + RETiRet; +} + + +/* Helper to cfline() and its helpers. Parses a template name + * from an "action" line. Must be called with the Line pointer + * pointing to the first character after the semicolon. + * rgerhards 2004-11-19 + * changed function to work with OMSR. -- rgerhards, 2007-07-27 + * the default template is to be used when no template is specified. + */ +rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName) +{ + uchar *p; + uchar *tplName = NULL; + cstr_t *pStrB; + DEFiRet; + + ASSERT(pp != NULL); + ASSERT(*pp != NULL); + ASSERT(pOMSR != NULL); + + p =*pp; + /* a template must follow - search it and complain, if not found */ + skipWhiteSpace(&p); + if(*p == ';') + ++p; /* eat it */ + else if(*p != '\0' && *p != '#') { + errmsg.LogError(0, RS_RET_ERR, "invalid character in selector line - ';template' expected"); + ABORT_FINALIZE(RS_RET_ERR); + } + + skipWhiteSpace(&p); /* go to begin of template name */ + + if(*p == '\0' || *p == '#') { + /* no template specified, use the default */ + /* TODO: check NULL ptr */ + tplName = (uchar*) strdup((char*)dfltTplName); + } else { + /* template specified, pick it up */ + CHKiRet(cstrConstruct(&pStrB)); + + /* now copy the string */ + while(*p && *p != '#' && !isspace((int) *p)) { + CHKiRet(cstrAppendChar(pStrB, *p)); + ++p; + } + CHKiRet(cstrFinalize(pStrB)); + CHKiRet(cstrConvSzStrAndDestruct(pStrB, &tplName, 0)); + } + + CHKiRet(OMSRsetEntry(pOMSR, iEntry, tplName, iTplOpts)); + +finalize_it: + if(iRet != RS_RET_OK) + free(tplName); + + *pp = p; + + RETiRet; +} + +/* Helper to cfline(). Parses a file name up until the first + * comma and then looks for the template specifier. Tries + * to find that template. + * rgerhards 2004-11-18 + * parameter pFileName must point to a buffer large enough + * to hold the largest possible filename. + * rgerhards, 2007-07-25 + * updated to include OMSR pointer -- rgerhards, 2007-07-27 + * updated to include template name -- rgerhards, 2008-03-28 + * rgerhards, 2010-01-19: file names end at the first space + */ +rsRetVal +cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *pszTpl) +{ + register uchar *pName; + int i; + DEFiRet; + + ASSERT(pOMSR != NULL); + + pName = pFileName; + i = 1; /* we start at 1 so that we reseve space for the '\0'! */ + while(*p && *p != ';' && *p != ' ' && i < MAXFNAME) { + *pName++ = *p++; + ++i; + } + *pName = '\0'; + + iRet = cflineParseTemplateName(&p, pOMSR, iEntry, iTplOpts, pszTpl); + + RETiRet; +} + + +/* Helper to cfline(). This function takes the filter part of a traditional, PRI + * based line and decodes the PRIs given in the selector line. It processed the + * line up to the beginning of the action part. A pointer to that beginnig is + * passed back to the caller. + * rgerhards 2005-09-15 + */ +/* GPLv3 - stems back to sysklogd */ +static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) +{ + uchar *p; + register uchar *q; + register int i, i2; + uchar *bp; + int pri; + int singlpri = 0; + int ignorepri = 0; + uchar buf[2048]; /* buffer for facility and priority names */ + uchar xbuf[200]; + DEFiRet; + + ASSERT(pline != NULL); + ASSERT(*pline != NULL); + ISOBJ_TYPE_assert(pRule, rule); + + dbgprintf(" - traditional PRI filter\n"); + errno = 0; /* keep strerror_r() stuff out of logerror messages */ + + pRule->f_filter_type = FILTER_PRI; + /* Note: file structure is pre-initialized to zero because it was + * created with calloc()! + */ + for (i = 0; i <= LOG_NFACILITIES; i++) { + pRule->f_filterData.f_pmask[i] = TABLE_NOPRI; + } + + /* scan through the list of selectors */ + for (p = *pline; *p && *p != '\t' && *p != ' ';) { + + /* find the end of this facility name list */ + for (q = p; *q && *q != '\t' && *q++ != '.'; ) + continue; + + /* collect priority name */ + for (bp = buf; *q && !strchr("\t ,;", *q) && bp < buf+sizeof(buf)-1 ; ) + *bp++ = *q++; + *bp = '\0'; + + /* skip cruft */ + while (strchr(",;", *q)) + q++; + + /* decode priority name */ + if ( *buf == '!' ) { + ignorepri = 1; + /* copy below is ok, we can NOT go off the allocated area */ + for (bp=buf; *(bp+1); bp++) + *bp=*(bp+1); + *bp='\0'; + } + else { + ignorepri = 0; + } + if ( *buf == '=' ) + { + singlpri = 1; + pri = decodeSyslogName(&buf[1], syslogPriNames); + } + else { + singlpri = 0; + pri = decodeSyslogName(buf, syslogPriNames); + } + + if (pri < 0) { + snprintf((char*) xbuf, sizeof(xbuf), "unknown priority name \"%s\"", buf); + errmsg.LogError(0, RS_RET_ERR, "%s", xbuf); + return RS_RET_ERR; + } + + /* scan facilities */ + while (*p && !strchr("\t .;", *p)) { + for (bp = buf; *p && !strchr("\t ,;.", *p) && bp < buf+sizeof(buf)-1 ; ) + *bp++ = *p++; + *bp = '\0'; + if (*buf == '*') { + for (i = 0; i <= LOG_NFACILITIES; i++) { + if ( pri == INTERNAL_NOPRI ) { + if ( ignorepri ) + pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI; + else + pRule->f_filterData.f_pmask[i] = TABLE_NOPRI; + } + else if ( singlpri ) { + if ( ignorepri ) + pRule->f_filterData.f_pmask[i] &= ~(1<f_filterData.f_pmask[i] |= (1<f_filterData.f_pmask[i] = TABLE_NOPRI; + else + pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI; + } + else + { + if ( ignorepri ) + for (i2= 0; i2 <= pri; ++i2) + pRule->f_filterData.f_pmask[i] &= ~(1<f_filterData.f_pmask[i] |= (1<f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI; + else + pRule->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI; + } else if ( singlpri ) { + if ( ignorepri ) + pRule->f_filterData.f_pmask[i >> 3] &= ~(1<f_filterData.f_pmask[i >> 3] |= (1<f_filterData.f_pmask[i >> 3] = TABLE_NOPRI; + else + pRule->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI; + } else { + if ( ignorepri ) + for (i2= 0; i2 <= pri; ++i2) + pRule->f_filterData.f_pmask[i >> 3] &= ~(1<f_filterData.f_pmask[i >> 3] |= (1<f_filter_type = FILTER_EXPR; + + /* if we come to over here, pline starts with "if ". We just skip that part. */ + (*pline) += 3; + + /* we first need a tokenizer... */ + CHKiRet(ctok.Construct(&tok)); + CHKiRet(ctok.Setpp(tok, *pline)); + CHKiRet(ctok.ConstructFinalize(tok)); + + /* now construct our expression */ + CHKiRet(expr.Construct(&f->f_filterData.f_expr)); + CHKiRet(expr.ConstructFinalize(f->f_filterData.f_expr)); + + /* ready to go... */ + CHKiRet(expr.Parse(f->f_filterData.f_expr, tok)); + + /* we now need to parse off the "then" - and note an error if it is + * missing... + */ + CHKiRet(ctok.GetToken(tok, &pToken)); + if(pToken->tok != ctok_THEN) { + ctok_token.Destruct(&pToken); + ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); + } + + ctok_token.Destruct(&pToken); /* no longer needed */ + + /* we are done, so we now need to restore things */ + CHKiRet(ctok.Getpp(tok, pline)); + CHKiRet(ctok.Destruct(&tok)); + + /* debug support - print vmprg after construction (uncomment to use) */ + /* vmprgDebugPrint(f->f_filterData.f_expr->pVmprg); */ + + /* we now need to skip whitespace to the action part, else we confuse + * the legacy rsyslog conf parser. -- rgerhards, 2008-02-25 + */ + while(isspace(**pline)) + ++(*pline); + +finalize_it: + if(iRet == RS_RET_SYNTAX_ERROR) { + errmsg.LogError(0, RS_RET_SYNTAX_ERROR, "syntax error in expression"); + } + + RETiRet; +} + + +/* Helper to cfline(). This function takes the filter part of a property + * based filter and decodes it. It processes the line up to the beginning + * of the action part. A pointer to that beginnig is passed back to the caller. + * rgerhards 2005-09-15 + */ +static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) +{ + rsParsObj *pPars; + cstr_t *pCSCompOp; + cstr_t *pCSPropName; + rsRetVal iRet; + int iOffset; /* for compare operations */ + + ASSERT(pline != NULL); + ASSERT(*pline != NULL); + ASSERT(f != NULL); + + dbgprintf(" - property-based filter\n"); + errno = 0; /* keep strerror_r() stuff out of logerror messages */ + + f->f_filter_type = FILTER_PROP; + + /* create parser object starting with line string without leading colon */ + if((iRet = rsParsConstructFromSz(&pPars, (*pline)+1)) != RS_RET_OK) { + errmsg.LogError(0, iRet, "Error %d constructing parser object - ignoring selector", iRet); + return(iRet); + } + + /* read property */ + iRet = parsDelimCStr(pPars, &pCSPropName, ',', 1, 1, 1); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "error %d parsing filter property - ignoring selector", iRet); + rsParsDestruct(pPars); + return(iRet); + } + iRet = propNameToID(pCSPropName, &f->f_filterData.prop.propID); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "error %d parsing filter property - ignoring selector", iRet); + rsParsDestruct(pPars); + return(iRet); + } + if(f->f_filterData.prop.propID == PROP_CEE) { + /* in CEE case, we need to preserve the actual property name */ + if((f->f_filterData.prop.propName = + es_newStrFromBuf((char*)cstrGetSzStrNoNULL(pCSPropName)+2, cstrLen(pCSPropName)-2)) == NULL) { + cstrDestruct(&pCSPropName); + return(RS_RET_ERR); + } + } + cstrDestruct(&pCSPropName); + + /* read operation */ + iRet = parsDelimCStr(pPars, &pCSCompOp, ',', 1, 1, 1); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "error %d compare operation property - ignoring selector", iRet); + rsParsDestruct(pPars); + return(iRet); + } + + /* we now first check if the condition is to be negated. To do so, we first + * must make sure we have at least one char in the param and then check the + * first one. + * rgerhards, 2005-09-26 + */ + if(rsCStrLen(pCSCompOp) > 0) { + if(*rsCStrGetBufBeg(pCSCompOp) == '!') { + f->f_filterData.prop.isNegated = 1; + iOffset = 1; /* ignore '!' */ + } else { + f->f_filterData.prop.isNegated = 0; + iOffset = 0; + } + } else { + f->f_filterData.prop.isNegated = 0; + iOffset = 0; + } + +dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSCompOp)); + if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) { + f->f_filterData.prop.operation = FIOP_CONTAINS; + } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) { + f->f_filterData.prop.operation = FIOP_ISEQUAL; + } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isempty", 7)) { + f->f_filterData.prop.operation = FIOP_ISEMPTY; + } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "startswith", 10)) { + f->f_filterData.prop.operation = FIOP_STARTSWITH; + } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) { + f->f_filterData.prop.operation = FIOP_REGEX; + } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "ereregex", 8)) { + f->f_filterData.prop.operation = FIOP_EREREGEX; + } else { + errmsg.LogError(0, NO_ERRCODE, "error: invalid compare operation '%s' - ignoring selector", + (char*) rsCStrGetSzStrNoNULL(pCSCompOp)); + } + rsCStrDestruct(&pCSCompOp); /* no longer needed */ + +dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); + if(f->f_filterData.prop.operation != FIOP_ISEMPTY) { + /* read compare value */ + iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue); + if(iRet != RS_RET_OK) { + errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet); + rsParsDestruct(pPars); + return(iRet); + } + } + + /* skip to action part */ + if((iRet = parsSkipWhitespace(pPars)) != RS_RET_OK) { + errmsg.LogError(0, iRet, "error %d skipping to action part - ignoring selector", iRet); + rsParsDestruct(pPars); + return(iRet); + } + + /* cleanup */ + *pline = *pline + rsParsGetParsePointer(pPars) + 1; + /* we are adding one for the skipped initial ":" */ + + return rsParsDestruct(pPars); +} + + +/* + * Helper to cfline(). This function interprets a BSD host selector line + * from the config file ("+/-hostname"). It stores it for further reference. + * rgerhards 2005-10-19 + */ +static rsRetVal cflineProcessHostSelector(uchar **pline) +{ + DEFiRet; + + ASSERT(pline != NULL); + ASSERT(*pline != NULL); + ASSERT(**pline == '-' || **pline == '+'); + + dbgprintf(" - host selector line\n"); + + /* check include/exclude setting */ + if(**pline == '+') { + eDfltHostnameCmpMode = HN_COMP_MATCH; + } else { /* we do not check for '-', it must be, else we wouldn't be here */ + eDfltHostnameCmpMode = HN_COMP_NOMATCH; + } + (*pline)++; /* eat + or - */ + + /* the below is somewhat of a quick hack, but it is efficient (this is + * why it is in here. "+*" resets the tag selector with BSD syslog. We mimic + * this, too. As it is easy to check that condition, we do not fire up a + * parser process, just make sure we do not address beyond our space. + * Order of conditions in the if-statement is vital! rgerhards 2005-10-18 + */ + if(**pline != '\0' && **pline == '*' && *(*pline+1) == '\0') { + dbgprintf("resetting BSD-like hostname filter\n"); + eDfltHostnameCmpMode = HN_NO_COMP; + if(pDfltHostnameCmp != NULL) { + CHKiRet(rsCStrSetSzStr(pDfltHostnameCmp, NULL)); + } + } else { + dbgprintf("setting BSD-like hostname filter to '%s'\n", *pline); + if(pDfltHostnameCmp == NULL) { + /* create string for parser */ + CHKiRet(rsCStrConstructFromszStr(&pDfltHostnameCmp, *pline)); + } else { /* string objects exists, just update... */ + CHKiRet(rsCStrSetSzStr(pDfltHostnameCmp, *pline)); + } + } + +finalize_it: + RETiRet; +} + + +/* + * Helper to cfline(). This function interprets a BSD tag selector line + * from the config file ("!tagname"). It stores it for further reference. + * rgerhards 2005-10-18 + */ +static rsRetVal cflineProcessTagSelector(uchar **pline) +{ + DEFiRet; + + ASSERT(pline != NULL); + ASSERT(*pline != NULL); + ASSERT(**pline == '!'); + + dbgprintf(" - programname selector line\n"); + + (*pline)++; /* eat '!' */ + + /* the below is somewhat of a quick hack, but it is efficient (this is + * why it is in here. "!*" resets the tag selector with BSD syslog. We mimic + * this, too. As it is easy to check that condition, we do not fire up a + * parser process, just make sure we do not address beyond our space. + * Order of conditions in the if-statement is vital! rgerhards 2005-10-18 + */ + if(**pline != '\0' && **pline == '*' && *(*pline+1) == '\0') { + dbgprintf("resetting programname filter\n"); + if(pDfltProgNameCmp != NULL) { + rsCStrDestruct(&pDfltProgNameCmp); + } + } else { + dbgprintf("setting programname filter to '%s'\n", *pline); + if(pDfltProgNameCmp == NULL) { + /* create string for parser */ + CHKiRet(rsCStrConstructFromszStr(&pDfltProgNameCmp, *pline)); + } else { /* string objects exists, just update... */ + CHKiRet(rsCStrSetSzStr(pDfltProgNameCmp, *pline)); + } + } + +finalize_it: + RETiRet; +} + + +/* read the filter part of a configuration line and store the filter + * in the supplied rule_t + * rgerhards, 2007-08-01 + */ +static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) +{ + DEFiRet; + + ASSERT(pp != NULL); + ISOBJ_TYPE_assert(f, rule); + + /* check which filter we need to pull... */ + switch(**pp) { + case ':': + CHKiRet(cflineProcessPropFilter(pp, f)); + break; + case 'i': /* "if" filter? */ + if(*(*pp+1) && (*(*pp+1) == 'f') && isspace(*(*pp+2))) { + CHKiRet(cflineProcessIfFilter(pp, f)); + break; + } + /*FALLTHROUGH*/ + default: + CHKiRet(cflineProcessTradPRIFilter(pp, f)); + break; + } + + /* we now check if there are some global (BSD-style) filter conditions + * and, if so, we copy them over. rgerhards, 2005-10-18 + */ + if(pDfltProgNameCmp != NULL) { + CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp)); + } + + if(eDfltHostnameCmpMode != HN_NO_COMP) { + f->eHostnameCmpMode = eDfltHostnameCmpMode; + CHKiRet(rsCStrConstructFromCStr(&(f->pCSHostnameComp), pDfltHostnameCmp)); + } + +finalize_it: + RETiRet; +} + + +/* process the action part of a selector line + * rgerhards, 2007-08-01 + */ +static rsRetVal cflineDoAction(uchar **p, action_t **ppAction) +{ + DEFiRet; + modInfo_t *pMod; + omodStringRequest_t *pOMSR; + action_t *pAction = NULL; + void *pModData; + + ASSERT(p != NULL); + ASSERT(ppAction != NULL); + + /* loop through all modules and see if one picks up the line */ + pMod = module.GetNxtType(NULL, eMOD_OUT); + /* Note: clang static analyzer reports that pMod mybe == NULL. However, this is + * not possible, because we have the built-in output modules which are always + * present. Anyhow, we guard this by an assert. -- rgerhards, 2010-12-16 + */ + assert(pMod != NULL); + while(pMod != NULL) { + pOMSR = NULL; + iRet = pMod->mod.om.parseSelectorAct(p, &pModData, &pOMSR); + dbgprintf("tried selector action for %s: %d\n", module.GetName(pMod), iRet); + if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) { + /* advance our config parser state: we now only accept an $End as valid, + * no more action statments. + */ + if(currConfObj == eConfObjAction) + currConfObj = eConfObjActionWaitEnd; + if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { + /* now check if the module is compatible with select features */ + if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) + pAction->f_ReduceRepeated = bReduceRepeatMsgs; + else { + dbgprintf("module is incompatible with RepeatedMsgReduction - turned off\n"); + pAction->f_ReduceRepeated = 0; + } + pAction->eState = ACT_STATE_RDY; /* action is enabled */ + iNbrActions++; /* one more active action! */ + } + break; + } + else if(iRet != RS_RET_CONFLINE_UNPROCESSED) { + /* In this case, the module would have handled the config + * line, but some error occured while doing so. This error should + * already by reported by the module. We do not try any other + * modules on this line, because we found the right one. + * rgerhards, 2007-07-24 + */ + dbgprintf("error %d parsing config line\n", (int) iRet); + break; + } + pMod = module.GetNxtType(pMod, eMOD_OUT); + } + + *ppAction = pAction; + RETiRet; +} + + +/* Process a configuration file line in traditional "filter selector" format + * or one that builds upon this format. Note that ppRule may be a NULL pointer, + * which is valid and happens if there is no previous line (right at the start + * of the master config file!). + */ +static rsRetVal +cflineClassic(uchar *p, rule_t **ppRule) +{ + DEFiRet; + action_t *pAction; + + /* lines starting with '&' have no new filters and just add + * new actions to the currently processed selector. + */ + if(*p == '&') { + ++p; /* eat '&' */ + skipWhiteSpace(&p); /* on to command */ + } else { + /* we are finished with the current selector (on previous line). + * So we now need to check + * if it has any actions associated and, if so, link it to the linked + * list. If it has nothing associated with it, we can simply discard + * it. In any case, we create a fresh selector for our new filter. + * We have one special case during initialization: then, the current + * selector is NULL, which means we do not need to care about it at + * all. -- rgerhards, 2007-08-01 + */ + if(*ppRule != NULL) { + CHKiRet(ruleset.AddRule(rule.GetAssRuleset(*ppRule), ppRule)); + } + CHKiRet(rule.Construct(ppRule)); /* create "fresh" selector */ + CHKiRet(rule.SetAssRuleset(*ppRule, ruleset.GetCurrent())); /* create "fresh" selector */ + CHKiRet(rule.ConstructFinalize(*ppRule)); /* create "fresh" selector */ + CHKiRet(cflineDoFilter(&p, *ppRule)); /* pull filters */ + } + + CHKiRet(cflineDoAction(&p, &pAction)); + CHKiRet(llAppend(&(*ppRule)->llActList, NULL, (void*) pAction)); + +finalize_it: + RETiRet; +} + + +/* process a configuration line + * I re-did this functon because it was desperately time to do so + * rgerhards, 2007-08-01 + */ +static rsRetVal +cfline(uchar *line, rule_t **pfCurr) +{ + DEFiRet; + + ASSERT(line != NULL); + + dbgprintf("cfline: '%s'\n", line); + + /* check type of line and call respective processing */ + switch(*line) { + case '!': + iRet = cflineProcessTagSelector(&line); + break; + case '+': + case '-': + iRet = cflineProcessHostSelector(&line); + break; + case '$': + ++line; /* eat '$' */ + iRet = cfsysline(line); + break; + default: + iRet = cflineClassic(line, pfCurr); + break; + } + + RETiRet; +} + + +/* return the current number of active actions + * rgerhards, 2008-07-28 + */ +static rsRetVal +GetNbrActActions(int *piNbrActions) +{ + DEFiRet; + assert(piNbrActions != NULL); + *piNbrActions = iNbrActions; + RETiRet; +} + + +/* queryInterface function + * rgerhards, 2008-02-29 + */ +BEGINobjQueryInterface(conf) +CODESTARTobjQueryInterface(conf) + if(pIf->ifVersion != confCURR_IF_VERSION) { /* check for current version, increment on each change */ + ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); + } + + /* ok, we have the right interface, so let's fill it + * Please note that we may also do some backwards-compatibility + * work here (if we can support an older interface version - that, + * of course, also affects the "if" above). + */ + pIf->doNameLine = doNameLine; + pIf->cfsysline = cfsysline; + pIf->doModLoad = doModLoad; + pIf->doIncludeLine = doIncludeLine; + pIf->cfline = cfline; + pIf->processConfFile = processConfFile; + pIf->GetNbrActActions = GetNbrActActions; + +finalize_it: +ENDobjQueryInterface(conf) + + +/* switch to a new action scope. This means that we switch the current + * mode to action, but it also means we need to clear all scope variables, + * so that we have a new environment. + * rgerhards, 2010-07-23 + */ +static inline rsRetVal +setActionScope(void) +{ + DEFiRet; + modInfo_t *pMod; + + currConfObj = eConfObjAction; + DBGPRINTF("entering action scope\n"); + CHKiRet(actionNewScope()); + + /* now tell each action to start the scope */ + pMod = NULL; + while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) { + DBGPRINTF("beginning scope on module %s\n", pMod->pszName); + pMod->mod.om.newScope(); + } + +finalize_it: + RETiRet; +} + + +/* switch back from action scope. + * rgerhards, 2010-07-27 + */ +static inline rsRetVal +unsetActionScope(void) +{ + DEFiRet; + modInfo_t *pMod; + + currConfObj = eConfObjAction; + DBGPRINTF("exiting action scope\n"); + CHKiRet(actionRestoreScope()); + + /* now tell each action to restore the scope */ + pMod = NULL; + while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) { + DBGPRINTF("exiting scope on module %s\n", pMod->pszName); + pMod->mod.om.restoreScope(); + } + +finalize_it: + RETiRet; +} + + +/* This method is called by our own handlers to begin a new config + * object ($Begin statement). This also implies a new scope. + * rgerhards, 2010-07-23 + */ +static rsRetVal +beginConfObj(void __attribute__((unused)) *pVal, uchar *pszName) +{ + DEFiRet; + + if(currConfObj != eConfObjGlobal) { + errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "not in global scope - can not nest $Begin"); + ABORT_FINALIZE(RS_RET_CONF_NOT_GLBL); + } + + if(!strcasecmp((char*)pszName, "action")) { + setActionScope(); + } else { + errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $Begin", pszName); + ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ); + } + +finalize_it: + free(pszName); /* no longer needed */ + RETiRet; +} + + +/* This method is called to end a config scope and switch + * back to global scope. + * rgerhards, 2010-07-23 + */ +static rsRetVal +endConfObj(void __attribute__((unused)) *pVal, uchar *pszName) +{ + DEFiRet; + + if(currConfObj == eConfObjGlobal) { + errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "already in global scope - dangling $End"); + ABORT_FINALIZE(RS_RET_CONF_IN_GLBL); + } + + if(!strcasecmp((char*)pszName, "action")) { + if(currConfObj == eConfObjAction) { + errmsg.LogError(0, RS_RET_CONF_END_NO_ACT, "$End action but not action specified"); + /* this is a warning, we continue processing in that case (unscope) */ + } else if(currConfObj != eConfObjActionWaitEnd) { + errmsg.LogError(0, RS_RET_CONF_INVLD_END, "$End not for active config object - " + "nesting error?"); + ABORT_FINALIZE(RS_RET_CONF_INVLD_END); + } + currConfObj = eConfObjGlobal; + CHKiRet(unsetActionScope()); + } else { + errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $End", pszName); + ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ); + } + +finalize_it: + free(pszName); /* no longer needed */ + RETiRet; +} + + +/* Reset config variables to default values. Note that + * when we are inside an scope, we simply reset this to global. + * However, $ResetConfigVariables is a global directive, and as such + * will not be honored inside a scope! + * rgerhards, 2010-07-23 + */ +static rsRetVal +resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +{ + currConfObj = eConfObjGlobal; + bConfStrictScoping = 0; + return RS_RET_OK; +} + + +/* exit our class + * rgerhards, 2008-03-11 + */ +BEGINObjClassExit(conf, OBJ_IS_CORE_MODULE) /* CHANGE class also in END MACRO! */ +CODESTARTObjClassExit(conf) + /* free no-longer needed module-global variables */ + if(pDfltHostnameCmp != NULL) { + rsCStrDestruct(&pDfltHostnameCmp); + } + + if(pDfltProgNameCmp != NULL) { + rsCStrDestruct(&pDfltProgNameCmp); + } + + /* release objects we no longer need */ + objRelease(expr, CORE_COMPONENT); + objRelease(ctok, CORE_COMPONENT); + objRelease(ctok_token, CORE_COMPONENT); + objRelease(module, CORE_COMPONENT); + objRelease(errmsg, CORE_COMPONENT); + objRelease(net, LM_NET_FILENAME); + objRelease(rule, CORE_COMPONENT); + objRelease(ruleset, CORE_COMPONENT); +ENDObjClassExit(conf) + + +/* Initialize our class. Must be called as the very first method + * before anything else is called inside this class. + * rgerhards, 2008-02-29 + */ +BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */ + /* request objects we use */ + CHKiRet(objUse(expr, CORE_COMPONENT)); + CHKiRet(objUse(ctok, CORE_COMPONENT)); + CHKiRet(objUse(ctok_token, CORE_COMPONENT)); + CHKiRet(objUse(module, CORE_COMPONENT)); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); + CHKiRet(objUse(net, LM_NET_FILENAME)); /* TODO: make this dependcy go away! */ + CHKiRet(objUse(rule, CORE_COMPONENT)); + CHKiRet(objUse(ruleset, CORE_COMPONENT)); + + CHKiRet(regCfSysLineHdlr((uchar *)"begin", 0, eCmdHdlrGetWord, beginConfObj, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"end", 0, eCmdHdlrGetWord, endConfObj, NULL, NULL, eConfObjAlways)); + CHKiRet(regCfSysLineHdlr((uchar *)"strictscoping", 0, eCmdHdlrBinary, NULL, &bConfStrictScoping, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjAction)); +ENDObjClassInit(conf) + +/* vi:set ai: + */ diff --git a/runtime/conf.h b/runtime/conf.h new file mode 100644 index 00000000..bc09d502 --- /dev/null +++ b/runtime/conf.h @@ -0,0 +1,65 @@ +/* Definitions for config file handling (not yet an object). + * + * Copyright 2008 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Rsyslog is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#ifndef INCLUDED_CONF_H +#define INCLUDED_CONF_H + +/* definitions used for doNameLine to differentiate between different command types + * (with otherwise identical code). This is a left-over from the previous config + * system. It stays, because it is still useful. So do not wonder why it looks + * somewhat strange (at least its name). -- rgerhards, 2007-08-01 + */ +enum eDirective { DIR_TEMPLATE = 0, DIR_OUTCHANNEL = 1, DIR_ALLOWEDSENDER = 2}; +extern ecslConfObjType currConfObj; +extern int bConfStrictScoping; /* force strict scoping during config processing? */ + +/* interfaces */ +BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ + rsRetVal (*doNameLine)(uchar **pp, void* pVal); + rsRetVal (*cfsysline)(uchar *p); + rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); + rsRetVal (*doIncludeLine)(uchar **pp, __attribute__((unused)) void* pVal); + rsRetVal (*cfline)(uchar *line, rule_t **pfCurr); + rsRetVal (*processConfFile)(uchar *pConfFile); + rsRetVal (*GetNbrActActions)(int *); + /* version 4 -- 2010-07-23 rgerhards */ + /* "just" added global variables + * FYI: we reconsider repacking as a non-object, as only the core currently + * accesses this module. The current object structure complicates things without + * any real benefit. + */ +ENDinterface(conf) +#define confCURR_IF_VERSION 4 /* increment whenever you change the interface structure! */ +/* in Version 3, entry point "ReInitConf()" was removed, as we do not longer need + * to support restart-type HUP -- rgerhards, 2009-07-15 + */ + + +/* prototypes */ +PROTOTYPEObj(conf); + + +/* TODO: the following 2 need to go in conf obj interface... */ +rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName); +rsRetVal cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *pszTpl); + + +#endif /* #ifndef INCLUDED_CONF_H */ diff --git a/runtime/legacyconf.c b/runtime/legacyconf.c deleted file mode 100644 index fd23bdcd..00000000 --- a/runtime/legacyconf.c +++ /dev/null @@ -1,1453 +0,0 @@ -/* The legacy config file handler (not yet a real object) - * - * This file is based on an excerpt from syslogd.c, which dates back - * much later. I began the file on 2008-02-19 as part of the modularization - * effort. Over time, a clean abstration will become even more important - * because the config file handler will by dynamically be loaded and be - * kept in memory only as long as the config file is actually being - * processed. Thereafter, it shall be unloaded. -- rgerhards - * - * TODO: the license MUST be changed to LGPL. However, we can not - * currently do that, because we use some sysklogd code to crunch - * the selector lines (e.g. *.info). That code is scheduled for removal - * as part of RainerScript. After this is done, we can change licenses. - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of rsyslog. - * - * Rsyslog is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Rsyslog is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Rsyslog. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - */ -#define CFGLNSIZ 4096 /* the maximum size of a configuraton file line, after re-combination */ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_LIBGEN_H -# ifndef OS_SOLARIS -# include -# endif -#endif - -#include "rsyslog.h" -#include "dirty.h" -#include "parse.h" -#include "action.h" -#include "template.h" -#include "cfsysline.h" -#include "modules.h" -#include "outchannel.h" -#include "stringbuf.h" -#include "legacyconf.h" -#include "stringbuf.h" -#include "srUtils.h" -#include "errmsg.h" -#include "net.h" -#include "expr.h" -#include "ctok.h" -#include "ctok_token.h" -#include "rule.h" -#include "ruleset.h" -#include "unicode-helper.h" - -#ifdef OS_SOLARIS -# define NAME_MAX MAXNAMELEN -#endif - -/* forward definitions */ -static rsRetVal cfline(uchar *line, rule_t **pfCurr); -static rsRetVal processConfFile(uchar *pConfFile); - - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(expr) -DEFobjCurrIf(ctok) -DEFobjCurrIf(ctok_token) -DEFobjCurrIf(module) -DEFobjCurrIf(errmsg) -DEFobjCurrIf(net) -DEFobjCurrIf(rule) -DEFobjCurrIf(ruleset) - -ecslConfObjType currConfObj = eConfObjGlobal; /* to support scoping - which config object is currently active? */ -int bConfStrictScoping = 0; /* force strict scoping during config processing? */ - - -static int iNbrActions = 0; /* number of currently defined actions */ - -/* The following module-global variables are used for building - * tag and host selector lines during startup and config reload. - * This is stored as a global variable pool because of its ease. It is - * also fairly compatible with multi-threading as the stratup code must - * be run in a single thread anyways. So there can be no race conditions. - * rgerhards 2005-10-18 - */ -static EHostnameCmpMode eDfltHostnameCmpMode = HN_NO_COMP; -static cstr_t *pDfltHostnameCmp = NULL; -static cstr_t *pDfltProgNameCmp = NULL; - - -/* process a directory and include all of its files into - * the current config file. There is no specific order of inclusion, - * files are included in the order they are read from the directory. - * The caller must have make sure that the provided parameter is - * indeed a directory. - * rgerhards, 2007-08-01 - */ -static rsRetVal doIncludeDirectory(uchar *pDirName) -{ - DEFiRet; - int iEntriesDone = 0; - DIR *pDir; - union { - struct dirent d; - char b[offsetof(struct dirent, d_name) + NAME_MAX + 1]; - } u; - struct dirent *res; - size_t iDirNameLen; - size_t iFileNameLen; - uchar szFullFileName[MAXFNAME]; - - ASSERT(pDirName != NULL); - - if((pDir = opendir((char*) pDirName)) == NULL) { - errmsg.LogError(errno, RS_RET_FOPEN_FAILURE, "error opening include directory"); - ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); - } - - /* prepare file name buffer */ - iDirNameLen = strlen((char*) pDirName); - memcpy(szFullFileName, pDirName, iDirNameLen); - - /* now read the directory */ - iEntriesDone = 0; - while(readdir_r(pDir, &u.d, &res) == 0) { - if(res == NULL) - break; /* this also indicates end of directory */ -# ifdef DT_REG - /* TODO: find an alternate way to checking for special files if this is - * not defined. This is currently a known problem on HP UX, but the work- - * around is simple: do not create special files in that directory. So - * fixing this is actually not the most important thing on earth... - * rgerhards, 2008-03-04 - */ - if(res->d_type != DT_REG) - continue; /* we are not interested in special files */ -# endif - if(res->d_name[0] == '.') - continue; /* these files we are also not interested in */ - ++iEntriesDone; - /* construct filename */ - iFileNameLen = strlen(res->d_name); - if (iFileNameLen > NAME_MAX) - iFileNameLen = NAME_MAX; - memcpy(szFullFileName + iDirNameLen, res->d_name, iFileNameLen); - *(szFullFileName + iDirNameLen + iFileNameLen) = '\0'; - dbgprintf("including file '%s'\n", szFullFileName); - processConfFile(szFullFileName); - /* we deliberately ignore the iRet of processConfFile() - this is because - * failure to process one file does not mean all files will fail. By ignoring, - * we retry with the next file, which is the best thing we can do. -- rgerhards, 2007-08-01 - */ - } - - if(iEntriesDone == 0) { - /* I just make it a debug output, because I can think of a lot of cases where it - * makes sense not to have any files. E.g. a system maintainer may place a $Include - * into the config file just in case, when additional modules be installed. When none - * are installed, the directory will be empty, which is fine. -- rgerhards 2007-08-01 - */ - dbgprintf("warning: the include directory contained no files - this may be ok.\n"); - } - -finalize_it: - if(pDir != NULL) - closedir(pDir); - - RETiRet; -} - - -/* process a $include config line. That type of line requires - * inclusion of another file. - * rgerhards, 2007-08-01 - */ -rsRetVal -doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal) -{ - DEFiRet; - char pattern[MAXFNAME]; - uchar *cfgFile; - glob_t cfgFiles; - int result; - size_t i = 0; - struct stat fileInfo; - - ASSERT(pp != NULL); - ASSERT(*pp != NULL); - - if(getSubString(pp, (char*) pattern, sizeof(pattern) / sizeof(char), ' ') != 0) { - errmsg.LogError(0, RS_RET_NOT_FOUND, "could not parse config file name"); - ABORT_FINALIZE(RS_RET_NOT_FOUND); - } - - /* Use GLOB_MARK to append a trailing slash for directories. - * Required by doIncludeDirectory(). - */ - result = glob(pattern, GLOB_MARK, NULL, &cfgFiles); - if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { - char errStr[1024]; - rs_strerror_r(errno, errStr, sizeof(errStr)); - errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s", - pattern, errStr); - ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND); - } - - for(i = 0; i < cfgFiles.gl_pathc; i++) { - cfgFile = (uchar*) cfgFiles.gl_pathv[i]; - - if(stat((char*) cfgFile, &fileInfo) != 0) - continue; /* continue with the next file if we can't stat() the file */ - - if(S_ISREG(fileInfo.st_mode)) { /* config file */ - dbgprintf("requested to include config file '%s'\n", cfgFile); - iRet = processConfFile(cfgFile); - } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */ - dbgprintf("requested to include directory '%s'\n", cfgFile); - iRet = doIncludeDirectory(cfgFile); - } else { /* TODO: shall we handle symlinks or not? */ - dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile); - } - } - - globfree(&cfgFiles); - -finalize_it: - RETiRet; -} - - -/* process a $ModLoad config line. - */ -rsRetVal -doModLoad(uchar **pp, __attribute__((unused)) void* pVal) -{ - DEFiRet; - uchar szName[512]; - uchar *pModName; - - ASSERT(pp != NULL); - ASSERT(*pp != NULL); - - skipWhiteSpace(pp); /* skip over any whitespace */ - if(getSubString(pp, (char*) szName, sizeof(szName) / sizeof(uchar), ' ') != 0) { - errmsg.LogError(0, RS_RET_NOT_FOUND, "could not extract module name"); - ABORT_FINALIZE(RS_RET_NOT_FOUND); - } - 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 - */ - if(!strcmp((char*) szName, "MySQL")) - pModName = (uchar*) "ommysql.so"; - else - pModName = szName; - - CHKiRet(module.Load(pModName)); - -finalize_it: - RETiRet; -} - - -/* parse and interpret a $-config line that starts with - * a name (this is common code). It is parsed to the name - * and then the proper sub-function is called to handle - * the actual directive. - * rgerhards 2004-11-17 - * rgerhards 2005-06-21: previously only for templates, now - * generalized. - */ -rsRetVal -doNameLine(uchar **pp, void* pVal) -{ - DEFiRet; - uchar *p; - enum eDirective eDir; - char szName[128]; - - ASSERT(pp != NULL); - p = *pp; - ASSERT(p != NULL); - - eDir = (enum eDirective) pVal; /* this time, it actually is NOT a pointer! */ - - if(getSubString(&p, szName, sizeof(szName) / sizeof(char), ',') != 0) { - errmsg.LogError(0, RS_RET_NOT_FOUND, "Invalid config line: could not extract name - line ignored"); - ABORT_FINALIZE(RS_RET_NOT_FOUND); - } - if(*p == ',') - ++p; /* comma was eaten */ - - /* we got the name - now we pass name & the rest of the string - * to the subfunction. It makes no sense to do further - * parsing here, as this is in close interaction with the - * respective subsystem. rgerhards 2004-11-17 - */ - - switch(eDir) { - case DIR_TEMPLATE: - tplAddLine(szName, &p); - break; - case DIR_OUTCHANNEL: - ochAddLine(szName, &p); - break; - case DIR_ALLOWEDSENDER: - net.addAllowedSenderLine(szName, &p); - break; - default:/* we do this to avoid compiler warning - not all - * enum values call this function, so an incomplete list - * is quite ok (but then we should not run into this code, - * so at least we log a debug warning). - */ - dbgprintf("INTERNAL ERROR: doNameLine() called with invalid eDir %d.\n", - eDir); - break; - } - - *pp = p; - -finalize_it: - RETiRet; -} - - -/* Parse and interpret a system-directive in the config line - * A system directive is one that starts with a "$" sign. It offers - * extended configuration parameters. - * 2004-11-17 rgerhards - */ -rsRetVal -cfsysline(uchar *p) -{ - DEFiRet; - uchar szCmd[64]; - - ASSERT(p != NULL); - errno = 0; - if(getSubString(&p, (char*) szCmd, sizeof(szCmd) / sizeof(uchar), ' ') != 0) { - errmsg.LogError(0, RS_RET_NOT_FOUND, "Invalid $-configline - could not extract command - line ignored\n"); - ABORT_FINALIZE(RS_RET_NOT_FOUND); - } - - /* we now try and see if we can find the command in the registered - * list of cfsysline handlers. -- rgerhards, 2007-07-31 - */ - CHKiRet(processCfSysLineCommand(szCmd, &p)); - - /* now check if we have some extra characters left on the line - that - * should not be the case. Whitespace is OK, but everything else should - * trigger a warning (that may be an indication of undesired behaviour). - * An exception, of course, are comments (starting with '#'). - * rgerhards, 2007-07-04 - */ - skipWhiteSpace(&p); - - if(*p && *p != '#') { /* we have a non-whitespace, so let's complain */ - errmsg.LogError(0, NO_ERRCODE, - "error: extra characters in config line ignored: '%s'", p); - } - -finalize_it: - RETiRet; -} - - - - -/* process a configuration file - * started with code from init() by rgerhards on 2007-07-31 - */ -static rsRetVal -processConfFile(uchar *pConfFile) -{ - int iLnNbr = 0; - FILE *cf; - rule_t *pCurrRule = NULL; - uchar *p; - uchar cbuf[CFGLNSIZ]; - uchar *cline; - int i; - int bHadAnError = 0; - uchar *pszOrgLine = NULL; - size_t lenLine; - DEFiRet; - ASSERT(pConfFile != NULL); - - if((cf = fopen((char*)pConfFile, "r")) == NULL) { - ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); - } - - /* Now process the file. - */ - cline = cbuf; - while (fgets((char*)cline, sizeof(cbuf) - (cline - cbuf), cf) != NULL) { - ++iLnNbr; - /* drop LF - TODO: make it better, replace fgets(), but its clean as it is */ - lenLine = ustrlen(cline); - if(cline[lenLine-1] == '\n') { - cline[lenLine-1] = '\0'; - } - free(pszOrgLine); - pszOrgLine = ustrdup(cline); /* save if needed for errmsg, NULL ptr is OK */ - /* check for end-of-section, comments, strip off trailing - * spaces and newline character. - */ - p = cline; - skipWhiteSpace(&p); - if (*p == '\0' || *p == '#') - continue; - - /* we now need to copy the characters to the begin of line. As this overlaps, - * we can not use strcpy(). -- rgerhards, 2008-03-20 - * TODO: review the code at whole - this is highly suspect (but will go away - * once we do the rest of RainerScript). - */ - for( i = 0 ; p[i] != '\0' ; ++i) { - cline[i] = p[i]; - } - cline[i] = '\0'; - - for (p = (uchar*) strchr((char*)cline, '\0'); isspace((int) *--p);) - /*EMPTY*/; - if (*p == '\\') { - if ((p - cbuf) > CFGLNSIZ - 30) { - /* Oops the buffer is full - what now? */ - cline = cbuf; - } else { - *p = 0; - cline = p; - continue; - } - } else - cline = cbuf; - *++p = '\0'; /* TODO: check this */ - - /* we now have the complete line, and are positioned at the first non-whitespace - * character. So let's process it - */ - if(cfline(cbuf, &pCurrRule) != RS_RET_OK) { - /* we log a message, but otherwise ignore the error. After all, the next - * line can be correct. -- rgerhards, 2007-08-02 - */ - uchar szErrLoc[MAXFNAME + 64]; - dbgprintf("config line NOT successfully processed\n"); - snprintf((char*)szErrLoc, sizeof(szErrLoc) / sizeof(uchar), - "%s, line %d", pConfFile, iLnNbr); - errmsg.LogError(0, NO_ERRCODE, "the last error occured in %s:\"%s\"", (char*)szErrLoc, (char*)pszOrgLine); - bHadAnError = 1; - } - } - - /* we probably have one selector left to be added - so let's do that now */ - if(pCurrRule != NULL) { - CHKiRet(ruleset.AddRule(rule.GetAssRuleset(pCurrRule), &pCurrRule)); - } - - /* close the configuration file */ - fclose(cf); - -finalize_it: - if(iRet != RS_RET_OK) { - char errStr[1024]; - if(pCurrRule != NULL) - rule.Destruct(&pCurrRule); - - rs_strerror_r(errno, errStr, sizeof(errStr)); - dbgprintf("error %d processing config file '%s'; os error (if any): %s\n", - iRet, pConfFile, errStr); - } - - free(pszOrgLine); - - if(bHadAnError && (iRet == RS_RET_OK)) { /* a bit dirty, enhance in future releases */ - iRet = RS_RET_NONFATAL_CONFIG_ERR; - } - RETiRet; -} - - -/* Helper to cfline() and its helpers. Parses a template name - * from an "action" line. Must be called with the Line pointer - * pointing to the first character after the semicolon. - * rgerhards 2004-11-19 - * changed function to work with OMSR. -- rgerhards, 2007-07-27 - * the default template is to be used when no template is specified. - */ -rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName) -{ - uchar *p; - uchar *tplName = NULL; - cstr_t *pStrB; - DEFiRet; - - ASSERT(pp != NULL); - ASSERT(*pp != NULL); - ASSERT(pOMSR != NULL); - - p =*pp; - /* a template must follow - search it and complain, if not found */ - skipWhiteSpace(&p); - if(*p == ';') - ++p; /* eat it */ - else if(*p != '\0' && *p != '#') { - errmsg.LogError(0, RS_RET_ERR, "invalid character in selector line - ';template' expected"); - ABORT_FINALIZE(RS_RET_ERR); - } - - skipWhiteSpace(&p); /* go to begin of template name */ - - if(*p == '\0' || *p == '#') { - /* no template specified, use the default */ - /* TODO: check NULL ptr */ - tplName = (uchar*) strdup((char*)dfltTplName); - } else { - /* template specified, pick it up */ - CHKiRet(cstrConstruct(&pStrB)); - - /* now copy the string */ - while(*p && *p != '#' && !isspace((int) *p)) { - CHKiRet(cstrAppendChar(pStrB, *p)); - ++p; - } - CHKiRet(cstrFinalize(pStrB)); - CHKiRet(cstrConvSzStrAndDestruct(pStrB, &tplName, 0)); - } - - CHKiRet(OMSRsetEntry(pOMSR, iEntry, tplName, iTplOpts)); - -finalize_it: - if(iRet != RS_RET_OK) - free(tplName); - - *pp = p; - - RETiRet; -} - -/* Helper to cfline(). Parses a file name up until the first - * comma and then looks for the template specifier. Tries - * to find that template. - * rgerhards 2004-11-18 - * parameter pFileName must point to a buffer large enough - * to hold the largest possible filename. - * rgerhards, 2007-07-25 - * updated to include OMSR pointer -- rgerhards, 2007-07-27 - * updated to include template name -- rgerhards, 2008-03-28 - * rgerhards, 2010-01-19: file names end at the first space - */ -rsRetVal -cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *pszTpl) -{ - register uchar *pName; - int i; - DEFiRet; - - ASSERT(pOMSR != NULL); - - pName = pFileName; - i = 1; /* we start at 1 so that we reseve space for the '\0'! */ - while(*p && *p != ';' && *p != ' ' && i < MAXFNAME) { - *pName++ = *p++; - ++i; - } - *pName = '\0'; - - iRet = cflineParseTemplateName(&p, pOMSR, iEntry, iTplOpts, pszTpl); - - RETiRet; -} - - -/* Helper to cfline(). This function takes the filter part of a traditional, PRI - * based line and decodes the PRIs given in the selector line. It processed the - * line up to the beginning of the action part. A pointer to that beginnig is - * passed back to the caller. - * rgerhards 2005-09-15 - */ -/* GPLv3 - stems back to sysklogd */ -static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) -{ - uchar *p; - register uchar *q; - register int i, i2; - uchar *bp; - int pri; - int singlpri = 0; - int ignorepri = 0; - uchar buf[2048]; /* buffer for facility and priority names */ - uchar xbuf[200]; - DEFiRet; - - ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ISOBJ_TYPE_assert(pRule, rule); - - dbgprintf(" - traditional PRI filter\n"); - errno = 0; /* keep strerror_r() stuff out of logerror messages */ - - pRule->f_filter_type = FILTER_PRI; - /* Note: file structure is pre-initialized to zero because it was - * created with calloc()! - */ - for (i = 0; i <= LOG_NFACILITIES; i++) { - pRule->f_filterData.f_pmask[i] = TABLE_NOPRI; - } - - /* scan through the list of selectors */ - for (p = *pline; *p && *p != '\t' && *p != ' ';) { - - /* find the end of this facility name list */ - for (q = p; *q && *q != '\t' && *q++ != '.'; ) - continue; - - /* collect priority name */ - for (bp = buf; *q && !strchr("\t ,;", *q) && bp < buf+sizeof(buf)-1 ; ) - *bp++ = *q++; - *bp = '\0'; - - /* skip cruft */ - while (strchr(",;", *q)) - q++; - - /* decode priority name */ - if ( *buf == '!' ) { - ignorepri = 1; - /* copy below is ok, we can NOT go off the allocated area */ - for (bp=buf; *(bp+1); bp++) - *bp=*(bp+1); - *bp='\0'; - } - else { - ignorepri = 0; - } - if ( *buf == '=' ) - { - singlpri = 1; - pri = decodeSyslogName(&buf[1], syslogPriNames); - } - else { - singlpri = 0; - pri = decodeSyslogName(buf, syslogPriNames); - } - - if (pri < 0) { - snprintf((char*) xbuf, sizeof(xbuf), "unknown priority name \"%s\"", buf); - errmsg.LogError(0, RS_RET_ERR, "%s", xbuf); - return RS_RET_ERR; - } - - /* scan facilities */ - while (*p && !strchr("\t .;", *p)) { - for (bp = buf; *p && !strchr("\t ,;.", *p) && bp < buf+sizeof(buf)-1 ; ) - *bp++ = *p++; - *bp = '\0'; - if (*buf == '*') { - for (i = 0; i <= LOG_NFACILITIES; i++) { - if ( pri == INTERNAL_NOPRI ) { - if ( ignorepri ) - pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI; - else - pRule->f_filterData.f_pmask[i] = TABLE_NOPRI; - } - else if ( singlpri ) { - if ( ignorepri ) - pRule->f_filterData.f_pmask[i] &= ~(1<f_filterData.f_pmask[i] |= (1<f_filterData.f_pmask[i] = TABLE_NOPRI; - else - pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI; - } - else - { - if ( ignorepri ) - for (i2= 0; i2 <= pri; ++i2) - pRule->f_filterData.f_pmask[i] &= ~(1<f_filterData.f_pmask[i] |= (1<f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI; - else - pRule->f_filterData.f_pmask[i >> 3] = TABLE_NOPRI; - } else if ( singlpri ) { - if ( ignorepri ) - pRule->f_filterData.f_pmask[i >> 3] &= ~(1<f_filterData.f_pmask[i >> 3] |= (1<f_filterData.f_pmask[i >> 3] = TABLE_NOPRI; - else - pRule->f_filterData.f_pmask[i >> 3] = TABLE_ALLPRI; - } else { - if ( ignorepri ) - for (i2= 0; i2 <= pri; ++i2) - pRule->f_filterData.f_pmask[i >> 3] &= ~(1<f_filterData.f_pmask[i >> 3] |= (1<f_filter_type = FILTER_EXPR; - - /* if we come to over here, pline starts with "if ". We just skip that part. */ - (*pline) += 3; - - /* we first need a tokenizer... */ - CHKiRet(ctok.Construct(&tok)); - CHKiRet(ctok.Setpp(tok, *pline)); - CHKiRet(ctok.ConstructFinalize(tok)); - - /* now construct our expression */ - CHKiRet(expr.Construct(&f->f_filterData.f_expr)); - CHKiRet(expr.ConstructFinalize(f->f_filterData.f_expr)); - - /* ready to go... */ - CHKiRet(expr.Parse(f->f_filterData.f_expr, tok)); - - /* we now need to parse off the "then" - and note an error if it is - * missing... - */ - CHKiRet(ctok.GetToken(tok, &pToken)); - if(pToken->tok != ctok_THEN) { - ctok_token.Destruct(&pToken); - ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); - } - - ctok_token.Destruct(&pToken); /* no longer needed */ - - /* we are done, so we now need to restore things */ - CHKiRet(ctok.Getpp(tok, pline)); - CHKiRet(ctok.Destruct(&tok)); - - /* debug support - print vmprg after construction (uncomment to use) */ - /* vmprgDebugPrint(f->f_filterData.f_expr->pVmprg); */ - - /* we now need to skip whitespace to the action part, else we confuse - * the legacy rsyslog conf parser. -- rgerhards, 2008-02-25 - */ - while(isspace(**pline)) - ++(*pline); - -finalize_it: - if(iRet == RS_RET_SYNTAX_ERROR) { - errmsg.LogError(0, RS_RET_SYNTAX_ERROR, "syntax error in expression"); - } - - RETiRet; -} - - -/* Helper to cfline(). This function takes the filter part of a property - * based filter and decodes it. It processes the line up to the beginning - * of the action part. A pointer to that beginnig is passed back to the caller. - * rgerhards 2005-09-15 - */ -static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) -{ - rsParsObj *pPars; - cstr_t *pCSCompOp; - cstr_t *pCSPropName; - rsRetVal iRet; - int iOffset; /* for compare operations */ - - ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ASSERT(f != NULL); - - dbgprintf(" - property-based filter\n"); - errno = 0; /* keep strerror_r() stuff out of logerror messages */ - - f->f_filter_type = FILTER_PROP; - - /* create parser object starting with line string without leading colon */ - if((iRet = rsParsConstructFromSz(&pPars, (*pline)+1)) != RS_RET_OK) { - errmsg.LogError(0, iRet, "Error %d constructing parser object - ignoring selector", iRet); - return(iRet); - } - - /* read property */ - iRet = parsDelimCStr(pPars, &pCSPropName, ',', 1, 1, 1); - if(iRet != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d parsing filter property - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); - } - iRet = propNameToID(pCSPropName, &f->f_filterData.prop.propID); - if(iRet != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d parsing filter property - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); - } - if(f->f_filterData.prop.propID == PROP_CEE) { - /* in CEE case, we need to preserve the actual property name */ - if((f->f_filterData.prop.propName = - es_newStrFromBuf((char*)cstrGetSzStrNoNULL(pCSPropName)+2, cstrLen(pCSPropName)-2)) == NULL) { - cstrDestruct(&pCSPropName); - return(RS_RET_ERR); - } - } - cstrDestruct(&pCSPropName); - - /* read operation */ - iRet = parsDelimCStr(pPars, &pCSCompOp, ',', 1, 1, 1); - if(iRet != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d compare operation property - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); - } - - /* we now first check if the condition is to be negated. To do so, we first - * must make sure we have at least one char in the param and then check the - * first one. - * rgerhards, 2005-09-26 - */ - if(rsCStrLen(pCSCompOp) > 0) { - if(*rsCStrGetBufBeg(pCSCompOp) == '!') { - f->f_filterData.prop.isNegated = 1; - iOffset = 1; /* ignore '!' */ - } else { - f->f_filterData.prop.isNegated = 0; - iOffset = 0; - } - } else { - f->f_filterData.prop.isNegated = 0; - iOffset = 0; - } - -dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSCompOp)); - if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) { - f->f_filterData.prop.operation = FIOP_CONTAINS; - } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) { - f->f_filterData.prop.operation = FIOP_ISEQUAL; - } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isempty", 7)) { - f->f_filterData.prop.operation = FIOP_ISEMPTY; - } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "startswith", 10)) { - f->f_filterData.prop.operation = FIOP_STARTSWITH; - } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "regex", 5)) { - f->f_filterData.prop.operation = FIOP_REGEX; - } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (unsigned char*) "ereregex", 8)) { - f->f_filterData.prop.operation = FIOP_EREREGEX; - } else { - errmsg.LogError(0, NO_ERRCODE, "error: invalid compare operation '%s' - ignoring selector", - (char*) rsCStrGetSzStrNoNULL(pCSCompOp)); - } - rsCStrDestruct(&pCSCompOp); /* no longer needed */ - -dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); - if(f->f_filterData.prop.operation != FIOP_ISEMPTY) { - /* read compare value */ - iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue); - if(iRet != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d compare value property - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); - } - } - - /* skip to action part */ - if((iRet = parsSkipWhitespace(pPars)) != RS_RET_OK) { - errmsg.LogError(0, iRet, "error %d skipping to action part - ignoring selector", iRet); - rsParsDestruct(pPars); - return(iRet); - } - - /* cleanup */ - *pline = *pline + rsParsGetParsePointer(pPars) + 1; - /* we are adding one for the skipped initial ":" */ - - return rsParsDestruct(pPars); -} - - -/* - * Helper to cfline(). This function interprets a BSD host selector line - * from the config file ("+/-hostname"). It stores it for further reference. - * rgerhards 2005-10-19 - */ -static rsRetVal cflineProcessHostSelector(uchar **pline) -{ - DEFiRet; - - ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ASSERT(**pline == '-' || **pline == '+'); - - dbgprintf(" - host selector line\n"); - - /* check include/exclude setting */ - if(**pline == '+') { - eDfltHostnameCmpMode = HN_COMP_MATCH; - } else { /* we do not check for '-', it must be, else we wouldn't be here */ - eDfltHostnameCmpMode = HN_COMP_NOMATCH; - } - (*pline)++; /* eat + or - */ - - /* the below is somewhat of a quick hack, but it is efficient (this is - * why it is in here. "+*" resets the tag selector with BSD syslog. We mimic - * this, too. As it is easy to check that condition, we do not fire up a - * parser process, just make sure we do not address beyond our space. - * Order of conditions in the if-statement is vital! rgerhards 2005-10-18 - */ - if(**pline != '\0' && **pline == '*' && *(*pline+1) == '\0') { - dbgprintf("resetting BSD-like hostname filter\n"); - eDfltHostnameCmpMode = HN_NO_COMP; - if(pDfltHostnameCmp != NULL) { - CHKiRet(rsCStrSetSzStr(pDfltHostnameCmp, NULL)); - } - } else { - dbgprintf("setting BSD-like hostname filter to '%s'\n", *pline); - if(pDfltHostnameCmp == NULL) { - /* create string for parser */ - CHKiRet(rsCStrConstructFromszStr(&pDfltHostnameCmp, *pline)); - } else { /* string objects exists, just update... */ - CHKiRet(rsCStrSetSzStr(pDfltHostnameCmp, *pline)); - } - } - -finalize_it: - RETiRet; -} - - -/* - * Helper to cfline(). This function interprets a BSD tag selector line - * from the config file ("!tagname"). It stores it for further reference. - * rgerhards 2005-10-18 - */ -static rsRetVal cflineProcessTagSelector(uchar **pline) -{ - DEFiRet; - - ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ASSERT(**pline == '!'); - - dbgprintf(" - programname selector line\n"); - - (*pline)++; /* eat '!' */ - - /* the below is somewhat of a quick hack, but it is efficient (this is - * why it is in here. "!*" resets the tag selector with BSD syslog. We mimic - * this, too. As it is easy to check that condition, we do not fire up a - * parser process, just make sure we do not address beyond our space. - * Order of conditions in the if-statement is vital! rgerhards 2005-10-18 - */ - if(**pline != '\0' && **pline == '*' && *(*pline+1) == '\0') { - dbgprintf("resetting programname filter\n"); - if(pDfltProgNameCmp != NULL) { - rsCStrDestruct(&pDfltProgNameCmp); - } - } else { - dbgprintf("setting programname filter to '%s'\n", *pline); - if(pDfltProgNameCmp == NULL) { - /* create string for parser */ - CHKiRet(rsCStrConstructFromszStr(&pDfltProgNameCmp, *pline)); - } else { /* string objects exists, just update... */ - CHKiRet(rsCStrSetSzStr(pDfltProgNameCmp, *pline)); - } - } - -finalize_it: - RETiRet; -} - - -/* read the filter part of a configuration line and store the filter - * in the supplied rule_t - * rgerhards, 2007-08-01 - */ -static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) -{ - DEFiRet; - - ASSERT(pp != NULL); - ISOBJ_TYPE_assert(f, rule); - - /* check which filter we need to pull... */ - switch(**pp) { - case ':': - CHKiRet(cflineProcessPropFilter(pp, f)); - break; - case 'i': /* "if" filter? */ - if(*(*pp+1) && (*(*pp+1) == 'f') && isspace(*(*pp+2))) { - CHKiRet(cflineProcessIfFilter(pp, f)); - break; - } - /*FALLTHROUGH*/ - default: - CHKiRet(cflineProcessTradPRIFilter(pp, f)); - break; - } - - /* we now check if there are some global (BSD-style) filter conditions - * and, if so, we copy them over. rgerhards, 2005-10-18 - */ - if(pDfltProgNameCmp != NULL) { - CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp)); - } - - if(eDfltHostnameCmpMode != HN_NO_COMP) { - f->eHostnameCmpMode = eDfltHostnameCmpMode; - CHKiRet(rsCStrConstructFromCStr(&(f->pCSHostnameComp), pDfltHostnameCmp)); - } - -finalize_it: - RETiRet; -} - - -/* process the action part of a selector line - * rgerhards, 2007-08-01 - */ -static rsRetVal cflineDoAction(uchar **p, action_t **ppAction) -{ - DEFiRet; - modInfo_t *pMod; - omodStringRequest_t *pOMSR; - action_t *pAction = NULL; - void *pModData; - - ASSERT(p != NULL); - ASSERT(ppAction != NULL); - - /* loop through all modules and see if one picks up the line */ - pMod = module.GetNxtType(NULL, eMOD_OUT); - /* Note: clang static analyzer reports that pMod mybe == NULL. However, this is - * not possible, because we have the built-in output modules which are always - * present. Anyhow, we guard this by an assert. -- rgerhards, 2010-12-16 - */ - assert(pMod != NULL); - while(pMod != NULL) { - pOMSR = NULL; - iRet = pMod->mod.om.parseSelectorAct(p, &pModData, &pOMSR); - dbgprintf("tried selector action for %s: %d\n", module.GetName(pMod), iRet); - if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) { - /* advance our config parser state: we now only accept an $End as valid, - * no more action statments. - */ - if(currConfObj == eConfObjAction) - currConfObj = eConfObjActionWaitEnd; - if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { - /* now check if the module is compatible with select features */ - if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) - pAction->f_ReduceRepeated = bReduceRepeatMsgs; - else { - dbgprintf("module is incompatible with RepeatedMsgReduction - turned off\n"); - pAction->f_ReduceRepeated = 0; - } - pAction->eState = ACT_STATE_RDY; /* action is enabled */ - iNbrActions++; /* one more active action! */ - } - break; - } - else if(iRet != RS_RET_CONFLINE_UNPROCESSED) { - /* In this case, the module would have handled the config - * line, but some error occured while doing so. This error should - * already by reported by the module. We do not try any other - * modules on this line, because we found the right one. - * rgerhards, 2007-07-24 - */ - dbgprintf("error %d parsing config line\n", (int) iRet); - break; - } - pMod = module.GetNxtType(pMod, eMOD_OUT); - } - - *ppAction = pAction; - RETiRet; -} - - -/* Process a configuration file line in traditional "filter selector" format - * or one that builds upon this format. Note that ppRule may be a NULL pointer, - * which is valid and happens if there is no previous line (right at the start - * of the master config file!). - */ -static rsRetVal -cflineClassic(uchar *p, rule_t **ppRule) -{ - DEFiRet; - action_t *pAction; - - /* lines starting with '&' have no new filters and just add - * new actions to the currently processed selector. - */ - if(*p == '&') { - ++p; /* eat '&' */ - skipWhiteSpace(&p); /* on to command */ - } else { - /* we are finished with the current selector (on previous line). - * So we now need to check - * if it has any actions associated and, if so, link it to the linked - * list. If it has nothing associated with it, we can simply discard - * it. In any case, we create a fresh selector for our new filter. - * We have one special case during initialization: then, the current - * selector is NULL, which means we do not need to care about it at - * all. -- rgerhards, 2007-08-01 - */ - if(*ppRule != NULL) { - CHKiRet(ruleset.AddRule(rule.GetAssRuleset(*ppRule), ppRule)); - } - CHKiRet(rule.Construct(ppRule)); /* create "fresh" selector */ - CHKiRet(rule.SetAssRuleset(*ppRule, ruleset.GetCurrent())); /* create "fresh" selector */ - CHKiRet(rule.ConstructFinalize(*ppRule)); /* create "fresh" selector */ - CHKiRet(cflineDoFilter(&p, *ppRule)); /* pull filters */ - } - - CHKiRet(cflineDoAction(&p, &pAction)); - CHKiRet(llAppend(&(*ppRule)->llActList, NULL, (void*) pAction)); - -finalize_it: - RETiRet; -} - - -/* process a configuration line - * I re-did this functon because it was desperately time to do so - * rgerhards, 2007-08-01 - */ -static rsRetVal -cfline(uchar *line, rule_t **pfCurr) -{ - DEFiRet; - - ASSERT(line != NULL); - - dbgprintf("cfline: '%s'\n", line); - - /* check type of line and call respective processing */ - switch(*line) { - case '!': - iRet = cflineProcessTagSelector(&line); - break; - case '+': - case '-': - iRet = cflineProcessHostSelector(&line); - break; - case '$': - ++line; /* eat '$' */ - iRet = cfsysline(line); - break; - default: - iRet = cflineClassic(line, pfCurr); - break; - } - - RETiRet; -} - - -/* return the current number of active actions - * rgerhards, 2008-07-28 - */ -static rsRetVal -GetNbrActActions(int *piNbrActions) -{ - DEFiRet; - assert(piNbrActions != NULL); - *piNbrActions = iNbrActions; - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-29 - */ -BEGINobjQueryInterface(conf) -CODESTARTobjQueryInterface(conf) - if(pIf->ifVersion != confCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->doNameLine = doNameLine; - pIf->cfsysline = cfsysline; - pIf->doModLoad = doModLoad; - pIf->doIncludeLine = doIncludeLine; - pIf->cfline = cfline; - pIf->processConfFile = processConfFile; - pIf->GetNbrActActions = GetNbrActActions; - -finalize_it: -ENDobjQueryInterface(conf) - - -/* switch to a new action scope. This means that we switch the current - * mode to action, but it also means we need to clear all scope variables, - * so that we have a new environment. - * rgerhards, 2010-07-23 - */ -static inline rsRetVal -setActionScope(void) -{ - DEFiRet; - modInfo_t *pMod; - - currConfObj = eConfObjAction; - DBGPRINTF("entering action scope\n"); - CHKiRet(actionNewScope()); - - /* now tell each action to start the scope */ - pMod = NULL; - while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) { - DBGPRINTF("beginning scope on module %s\n", pMod->pszName); - pMod->mod.om.newScope(); - } - -finalize_it: - RETiRet; -} - - -/* switch back from action scope. - * rgerhards, 2010-07-27 - */ -static inline rsRetVal -unsetActionScope(void) -{ - DEFiRet; - modInfo_t *pMod; - - currConfObj = eConfObjAction; - DBGPRINTF("exiting action scope\n"); - CHKiRet(actionRestoreScope()); - - /* now tell each action to restore the scope */ - pMod = NULL; - while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) { - DBGPRINTF("exiting scope on module %s\n", pMod->pszName); - pMod->mod.om.restoreScope(); - } - -finalize_it: - RETiRet; -} - - -/* This method is called by our own handlers to begin a new config - * object ($Begin statement). This also implies a new scope. - * rgerhards, 2010-07-23 - */ -static rsRetVal -beginConfObj(void __attribute__((unused)) *pVal, uchar *pszName) -{ - DEFiRet; - - if(currConfObj != eConfObjGlobal) { - errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "not in global scope - can not nest $Begin"); - ABORT_FINALIZE(RS_RET_CONF_NOT_GLBL); - } - - if(!strcasecmp((char*)pszName, "action")) { - setActionScope(); - } else { - errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $Begin", pszName); - ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ); - } - -finalize_it: - free(pszName); /* no longer needed */ - RETiRet; -} - - -/* This method is called to end a config scope and switch - * back to global scope. - * rgerhards, 2010-07-23 - */ -static rsRetVal -endConfObj(void __attribute__((unused)) *pVal, uchar *pszName) -{ - DEFiRet; - - if(currConfObj == eConfObjGlobal) { - errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "already in global scope - dangling $End"); - ABORT_FINALIZE(RS_RET_CONF_IN_GLBL); - } - - if(!strcasecmp((char*)pszName, "action")) { - if(currConfObj == eConfObjAction) { - errmsg.LogError(0, RS_RET_CONF_END_NO_ACT, "$End action but not action specified"); - /* this is a warning, we continue processing in that case (unscope) */ - } else if(currConfObj != eConfObjActionWaitEnd) { - errmsg.LogError(0, RS_RET_CONF_INVLD_END, "$End not for active config object - " - "nesting error?"); - ABORT_FINALIZE(RS_RET_CONF_INVLD_END); - } - currConfObj = eConfObjGlobal; - CHKiRet(unsetActionScope()); - } else { - errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $End", pszName); - ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ); - } - -finalize_it: - free(pszName); /* no longer needed */ - RETiRet; -} - - -/* Reset config variables to default values. Note that - * when we are inside an scope, we simply reset this to global. - * However, $ResetConfigVariables is a global directive, and as such - * will not be honored inside a scope! - * rgerhards, 2010-07-23 - */ -static rsRetVal -resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) -{ - currConfObj = eConfObjGlobal; - bConfStrictScoping = 0; - return RS_RET_OK; -} - - -/* exit our class - * rgerhards, 2008-03-11 - */ -BEGINObjClassExit(conf, OBJ_IS_CORE_MODULE) /* CHANGE class also in END MACRO! */ -CODESTARTObjClassExit(conf) - /* free no-longer needed module-global variables */ - if(pDfltHostnameCmp != NULL) { - rsCStrDestruct(&pDfltHostnameCmp); - } - - if(pDfltProgNameCmp != NULL) { - rsCStrDestruct(&pDfltProgNameCmp); - } - - /* release objects we no longer need */ - objRelease(expr, CORE_COMPONENT); - objRelease(ctok, CORE_COMPONENT); - objRelease(ctok_token, CORE_COMPONENT); - objRelease(module, CORE_COMPONENT); - objRelease(errmsg, CORE_COMPONENT); - objRelease(net, LM_NET_FILENAME); - objRelease(rule, CORE_COMPONENT); - objRelease(ruleset, CORE_COMPONENT); -ENDObjClassExit(conf) - - -/* Initialize our class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-29 - */ -BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */ - /* request objects we use */ - CHKiRet(objUse(expr, CORE_COMPONENT)); - CHKiRet(objUse(ctok, CORE_COMPONENT)); - CHKiRet(objUse(ctok_token, CORE_COMPONENT)); - CHKiRet(objUse(module, CORE_COMPONENT)); - CHKiRet(objUse(errmsg, CORE_COMPONENT)); - CHKiRet(objUse(net, LM_NET_FILENAME)); /* TODO: make this dependcy go away! */ - CHKiRet(objUse(rule, CORE_COMPONENT)); - CHKiRet(objUse(ruleset, CORE_COMPONENT)); - - CHKiRet(regCfSysLineHdlr((uchar *)"begin", 0, eCmdHdlrGetWord, beginConfObj, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"end", 0, eCmdHdlrGetWord, endConfObj, NULL, NULL, eConfObjAlways)); - CHKiRet(regCfSysLineHdlr((uchar *)"strictscoping", 0, eCmdHdlrBinary, NULL, &bConfStrictScoping, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjAction)); -ENDObjClassInit(conf) - -/* vi:set ai: - */ diff --git a/runtime/legacyconf.h b/runtime/legacyconf.h deleted file mode 100644 index 2cfd540f..00000000 --- a/runtime/legacyconf.h +++ /dev/null @@ -1,65 +0,0 @@ -/* Definitions for the legacy config file handling (not yet an object). - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of rsyslog. - * - * Rsyslog is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Rsyslog is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Rsyslog. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - */ -#ifndef INCLUDED_CONF_H -#define INCLUDED_CONF_H - -/* definitions used for doNameLine to differentiate between different command types - * (with otherwise identical code). This is a left-over from the previous config - * system. It stays, because it is still useful. So do not wonder why it looks - * somewhat strange (at least its name). -- rgerhards, 2007-08-01 - */ -enum eDirective { DIR_TEMPLATE = 0, DIR_OUTCHANNEL = 1, DIR_ALLOWEDSENDER = 2}; -extern ecslConfObjType currConfObj; -extern int bConfStrictScoping; /* force strict scoping during config processing? */ - -/* interfaces */ -BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ - rsRetVal (*doNameLine)(uchar **pp, void* pVal); - rsRetVal (*cfsysline)(uchar *p); - rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); - rsRetVal (*doIncludeLine)(uchar **pp, __attribute__((unused)) void* pVal); - rsRetVal (*cfline)(uchar *line, rule_t **pfCurr); - rsRetVal (*processConfFile)(uchar *pConfFile); - rsRetVal (*GetNbrActActions)(int *); - /* version 4 -- 2010-07-23 rgerhards */ - /* "just" added global variables - * FYI: we reconsider repacking as a non-object, as only the core currently - * accesses this module. The current object structure complicates things without - * any real benefit. - */ -ENDinterface(conf) -#define confCURR_IF_VERSION 4 /* increment whenever you change the interface structure! */ -/* in Version 3, entry point "ReInitConf()" was removed, as we do not longer need - * to support restart-type HUP -- rgerhards, 2009-07-15 - */ - - -/* prototypes */ -PROTOTYPEObj(conf); - - -/* TODO: the following 2 need to go in conf obj interface... */ -rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName); -rsRetVal cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *pszTpl); - - -#endif /* #ifndef INCLUDED_CONF_H */ diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index 9cf32f22..bdb1c9ff 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -74,7 +74,7 @@ #include "vmprg.h" #include "datetime.h" #include "queue.h" -#include "legacyconf.h" +#include "conf.h" #include "glbl.h" #include "errmsg.h" #include "prop.h" diff --git a/runtime/strmsrv.c b/runtime/strmsrv.c index 4de58b77..e66ad717 100644 --- a/runtime/strmsrv.c +++ b/runtime/strmsrv.c @@ -64,7 +64,7 @@ #include "module-template.h" #include "net.h" #include "srUtils.h" -#include "legacyconf.h" +#include "conf.h" #include "strmsrv.h" #include "obj.h" #include "glbl.h" diff --git a/tcpsrv.c b/tcpsrv.c index a7a5e3fd..39cba5d1 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -59,7 +59,7 @@ #include "module-template.h" #include "net.h" #include "srUtils.h" -#include "legacyconf.h" +#include "conf.h" #include "tcpsrv.h" #include "obj.h" #include "glbl.h" diff --git a/tools/omfile.c b/tools/omfile.c index 5fc87330..8526cb74 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -56,7 +56,7 @@ #endif -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "template.h" diff --git a/tools/omfwd.c b/tools/omfwd.c index 3004b082..be13bf75 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -48,7 +48,7 @@ #endif #include #include "syslogd.h" -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "net.h" diff --git a/tools/ompipe.c b/tools/ompipe.c index db4de73b..01695369 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -53,7 +53,7 @@ #include "omfile.h" /* for dirty trick: access to $ActionFileDefaultTemplate value */ #include "cfsysline.h" #include "module-template.h" -#include "legacyconf.h" +#include "conf.h" #include "errmsg.h" MODULE_TYPE_OUTPUT diff --git a/tools/omshell.c b/tools/omshell.c index 046fb41d..0e4e0f24 100644 --- a/tools/omshell.c +++ b/tools/omshell.c @@ -38,7 +38,7 @@ #include #include #include -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "srUtils.h" #include "omshell.h" diff --git a/tools/omusrmsg.c b/tools/omusrmsg.c index e5477a1c..da510e08 100644 --- a/tools/omusrmsg.c +++ b/tools/omusrmsg.c @@ -74,7 +74,7 @@ #include "srUtils.h" #include "stringbuf.h" #include "syslogd-types.h" -#include "legacyconf.h" +#include "conf.h" #include "omusrmsg.h" #include "module-template.h" #include "errmsg.h" diff --git a/tools/pmrfc3164.c b/tools/pmrfc3164.c index 3876ca0b..635ca985 100644 --- a/tools/pmrfc3164.c +++ b/tools/pmrfc3164.c @@ -33,7 +33,7 @@ #include #include #include "syslogd.h" -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/tools/pmrfc5424.c b/tools/pmrfc5424.c index d39ec8e5..b06f1347 100644 --- a/tools/pmrfc5424.c +++ b/tools/pmrfc5424.c @@ -32,7 +32,7 @@ #include #include #include "syslogd.h" -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/tools/smfile.c b/tools/smfile.c index c8f66120..1e0bf091 100644 --- a/tools/smfile.c +++ b/tools/smfile.c @@ -38,7 +38,7 @@ #include #include #include "syslogd.h" -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/tools/smfwd.c b/tools/smfwd.c index 3f9a3a84..60fe94a7 100644 --- a/tools/smfwd.c +++ b/tools/smfwd.c @@ -35,7 +35,7 @@ #include #include #include "syslogd.h" -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/tools/smtradfile.c b/tools/smtradfile.c index e57d2937..5484f7be 100644 --- a/tools/smtradfile.c +++ b/tools/smtradfile.c @@ -35,7 +35,7 @@ #include #include #include "syslogd.h" -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/tools/smtradfwd.c b/tools/smtradfwd.c index be3982d7..37717434 100644 --- a/tools/smtradfwd.c +++ b/tools/smtradfwd.c @@ -35,7 +35,7 @@ #include #include #include "syslogd.h" -#include "legacyconf.h" +#include "conf.h" #include "syslogd-types.h" #include "template.h" #include "msg.h" diff --git a/tools/syslogd.c b/tools/syslogd.c index a6127305..44c88624 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -124,7 +124,7 @@ #include "wti.h" #include "queue.h" #include "stream.h" -#include "legacyconf.h" +#include "conf.h" #include "errmsg.h" #include "datetime.h" #include "parser.h" -- cgit v1.2.3 From f72bde2f701b1a1ff42273e8f9b07de47b480ce9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Apr 2011 09:43:36 +0200 Subject: milestone: templates are now in config object --- action.c | 2 +- plugins/omlibdbi/omlibdbi.c | 1 + runtime/Makefile.am | 2 + runtime/conf.c | 2 +- runtime/rsconf.c | 112 ++++++++++++++++++++++++++++++++++++++++++++ runtime/rsconf.h | 59 +++++++++++++++++++++++ runtime/rsyslog.c | 3 ++ runtime/rsyslog.h | 5 ++ runtime/typedefs.h | 2 + template.c | 50 +++++++++++--------- template.h | 14 +++--- tools/syslogd.c | 38 +++++++++------ 12 files changed, 244 insertions(+), 46 deletions(-) create mode 100644 runtime/rsconf.c create mode 100644 runtime/rsconf.h diff --git a/action.c b/action.c index 4e60ba58..69dc64f5 100644 --- a/action.c +++ b/action.c @@ -1647,7 +1647,7 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringReques /* Ok, we got everything, so it now is time to look up the template * (Hint: templates MUST be defined before they are used!) */ - if((pAction->ppTpl[i] = tplFind((char*)pTplName, strlen((char*)pTplName))) == NULL) { + if((pAction->ppTpl[i] = tplFind(ourConf, (char*)pTplName, strlen((char*)pTplName))) == NULL) { snprintf(errMsg, sizeof(errMsg) / sizeof(char), " Could not find template '%s' - action disabled\n", pTplName); diff --git a/plugins/omlibdbi/omlibdbi.c b/plugins/omlibdbi/omlibdbi.c index 2142878c..e14a0ab6 100644 --- a/plugins/omlibdbi/omlibdbi.c +++ b/plugins/omlibdbi/omlibdbi.c @@ -48,6 +48,7 @@ #include "module-template.h" #include "debug.h" #include "errmsg.h" +#include "conf.h" MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP diff --git a/runtime/Makefile.am b/runtime/Makefile.am index c8e8ce2a..c19bfe47 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -20,6 +20,8 @@ librsyslog_la_SOURCES = \ unlimited_select.h \ conf.c \ conf.h \ + rsconf.c \ + rsconf.h \ parser.h \ parser.c \ strgen.h \ diff --git a/runtime/conf.c b/runtime/conf.c index 1d28a884..bfd66e31 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -325,7 +325,7 @@ doNameLine(uchar **pp, void* pVal) switch(eDir) { case DIR_TEMPLATE: - tplAddLine(szName, &p); + tplAddLine(ourConf, szName, &p); break; case DIR_OUTCHANNEL: ochAddLine(szName, &p); diff --git a/runtime/rsconf.c b/runtime/rsconf.c new file mode 100644 index 00000000..be780251 --- /dev/null +++ b/runtime/rsconf.c @@ -0,0 +1,112 @@ +/* rsconf.c - the rsyslog configuration system. + * + * Module begun 2011-04-19 by Rainer Gerhards + * + * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library 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. + * + * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ + +#include "config.h" +#include +#include +#include + +#include "rsyslog.h" +#include "obj.h" +#include "srUtils.h" +#include "rsconf.h" + +/* static data */ +DEFobjStaticHelpers + + +/* Standard-Constructor + */ +BEGINobjConstruct(rsconf) /* be sure to specify the object type also in END macro! */ +ENDobjConstruct(rsconf) + + +/* ConstructionFinalizer + * rgerhards, 2008-01-09 + */ +rsRetVal rsconfConstructFinalize(rsconf_t __attribute__((unused)) *pThis) +{ + DEFiRet; + ISOBJ_TYPE_assert(pThis, rsconf); + RETiRet; +} + + +/* destructor for the rsconf object */ +BEGINobjDestruct(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */ +CODESTARTobjDestruct(rsconf) + pThis->templates.root = NULL; + pThis->templates.last = NULL; + pThis->templates.lastStatic = NULL; +ENDobjDestruct(rsconf) + + +/* DebugPrint support for the rsconf object */ +BEGINobjDebugPrint(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */ +CODESTARTobjDebugPrint(rsconf) +ENDobjDebugPrint(rsconf) + + + +/* queryInterface function + */ +BEGINobjQueryInterface(rsconf) +CODESTARTobjQueryInterface(rsconf) + if(pIf->ifVersion != rsconfCURR_IF_VERSION) { /* check for current version, increment on each change */ + ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); + } + + /* ok, we have the right interface, so let's fill it + * Please note that we may also do some backwards-compatibility + * work here (if we can support an older interface version - that, + * of course, also affects the "if" above). + */ + pIf->Construct = rsconfConstruct; + pIf->ConstructFinalize = rsconfConstructFinalize; + pIf->Destruct = rsconfDestruct; + pIf->DebugPrint = rsconfDebugPrint; +finalize_it: +ENDobjQueryInterface(rsconf) + + +/* Initialize the rsconf class. Must be called as the very first method + * before anything else is called inside this class. + */ +BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */ + /* request objects we use */ + + /* now set our own handlers */ + OBJSetMethodHandler(objMethod_DEBUGPRINT, rsconfDebugPrint); + OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, rsconfConstructFinalize); +ENDObjClassInit(rsconf) + + +/* De-initialize the rsconf class. + */ +BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */ +ENDObjClassExit(rsconf) + +/* vi:set ai: + */ diff --git a/runtime/rsconf.h b/runtime/rsconf.h new file mode 100644 index 00000000..4a8c143f --- /dev/null +++ b/runtime/rsconf.h @@ -0,0 +1,59 @@ +/* The rsconf object. It models a complete rsyslog configuration. + * + * Copyright 2011 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library 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. + * + * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ +#ifndef INCLUDED_RSCONF_H +#define INCLUDED_RSCONF_H + +/* --- configuration objects (the plan is to have ALL upper layers in this file) --- */ + +/* the following structure is a container for all known templates + * inside a specific configuration. -- rgerhards 2011-04-19 + */ +struct templates_s { + struct template *root; /* the root of the template list */ + struct template *last; /* points to the last element of the template list */ + struct template *lastStatic; /* last static element of the template list */ +}; + +/* --- end configuration objects --- */ + +/* the rsconf object */ +struct rsconf_s { + BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ + templates_t templates; +}; + + +/* interfaces */ +BEGINinterface(rsconf) /* name must also be changed in ENDinterface macro! */ + INTERFACEObjDebugPrint(rsconf); + rsRetVal (*Construct)(rsconf_t **ppThis); + rsRetVal (*ConstructFinalize)(rsconf_t __attribute__((unused)) *pThis); + rsRetVal (*Destruct)(rsconf_t **ppThis); +ENDinterface(rsconf) +#define rsconfCURR_IF_VERSION 1 /* increment whenever you change the interface above! */ + + +/* prototypes */ +PROTOTYPEObj(rsconf); + +#endif /* #ifndef INCLUDED_RSCONF_H */ diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index bdb1c9ff..2b8f2b64 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -75,6 +75,7 @@ #include "datetime.h" #include "queue.h" #include "conf.h" +#include "rsconf.h" #include "glbl.h" #include "errmsg.h" #include "prop.h" @@ -209,6 +210,8 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(parserClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "strgen"; CHKiRet(strgenClassInit(NULL)); + if(ppErrObj != NULL) *ppErrObj = "rsconf"; + CHKiRet(rsconfClassInit(NULL)); /* dummy "classes" */ if(ppErrObj != NULL) *ppErrObj = "str"; diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 23547535..78841410 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -486,6 +486,11 @@ rsRetVal rsrtSetErrLogger(rsRetVal (*errLogger)(int, uchar*)); */ #define EMPTY_STRUCT +/* TODO: remove this -- this is only for transition of the config system */ +extern rsconf_t *ourConf; /* defined by syslogd.c, a hack for functions that do not + yet receive a copy, so that we can incrementially + compile and change... -- rgerhars, 2011-04-19 */ + #endif /* multi-include protection */ /* vim:set ai: */ diff --git a/runtime/typedefs.h b/runtime/typedefs.h index b6cfbd57..f38bcdd4 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -80,6 +80,8 @@ typedef struct strgen_s strgen_t; typedef struct strgenList_s strgenList_t; typedef struct statsobj_s statsobj_t; typedef struct nsd_epworkset_s nsd_epworkset_t; +typedef struct templates_s templates_t; +typedef struct rsconf_s rsconf_t; typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript function */ typedef uint64 qDeqID; /* queue Dequeue order ID. 32 bits is considered dangerously few */ diff --git a/template.c b/template.c index 38b86719..697a6ad5 100644 --- a/template.c +++ b/template.c @@ -37,6 +37,7 @@ #include "obj.h" #include "errmsg.h" #include "strgen.h" +#include "rsconf.h" #include "unicode-helper.h" /* static data */ @@ -49,10 +50,12 @@ DEFobjCurrIf(regexp) static int bFirstRegexpErrmsg = 1; /**< did we already do a "can't load regexp" error message? */ #endif -static struct template *tplRoot = NULL; /* the root of the template list */ -static struct template *tplLast = NULL; /* points to the last element of the template list */ -static struct template *tplLastStatic = NULL; /* last static element of the template list */ +#if 0 +static struct template *conf->templates.root = NULL; /* the root of the template list */ +static struct template *tplLast = NULL; +static struct template *conf->templates.lastStatic = NULL; +#endif /* helper to tplToString and strgen's, extends buffer */ @@ -357,7 +360,8 @@ struct templateEntry* tpeConstruct(struct template *pTpl) /* Constructs a template list object. Returns pointer to it * or NULL (if it fails). */ -struct template* tplConstruct(void) +static struct template* +tplConstruct(rsconf_t *conf) { struct template *pTpl; if((pTpl = calloc(1, sizeof(struct template))) == NULL) @@ -366,12 +370,12 @@ struct template* tplConstruct(void) /* basic initialisation is done via calloc() - need to * initialize only values != 0. */ - if(tplLast == NULL) { + if(conf->templates.last == NULL) { /* we are the first element! */ - tplRoot = tplLast = pTpl; + conf->templates.root = conf->templates.last = pTpl; } else { - tplLast->pNext = pTpl; - tplLast = pTpl; + conf->templates.last->pNext = pTpl; + conf->templates.last = pTpl; } return(pTpl); @@ -907,7 +911,7 @@ finalize_it: /* Add a new template line * returns pointer to new object if it succeeds, NULL otherwise. */ -struct template *tplAddLine(char* pName, uchar** ppRestOfConfLine) +struct template *tplAddLine(rsconf_t *conf, char* pName, uchar** ppRestOfConfLine) { struct template *pTpl; unsigned char *p; @@ -919,7 +923,7 @@ struct template *tplAddLine(char* pName, uchar** ppRestOfConfLine) assert(pName != NULL); assert(ppRestOfConfLine != NULL); - if((pTpl = tplConstruct()) == NULL) + if((pTpl = tplConstruct(conf)) == NULL) return NULL; pTpl->iLenName = strlen(pName); @@ -1046,13 +1050,13 @@ struct template *tplAddLine(char* pName, uchar** ppRestOfConfLine) * NULL otherwise. * rgerhards 2004-11-17 */ -struct template *tplFind(char *pName, int iLenName) +struct template *tplFind(rsconf_t *conf, char *pName, int iLenName) { struct template *pTpl; assert(pName != NULL); - pTpl = tplRoot; + pTpl = conf->templates.root; while(pTpl != NULL && !(pTpl->iLenName == iLenName && !strcmp(pTpl->pszName, pName) @@ -1070,13 +1074,13 @@ struct template *tplFind(char *pName, int iLenName) * "normal" debugging. Uncomment them, if they are needed. * rgerhards, 2007-07-05 */ -void tplDeleteAll(void) +void tplDeleteAll(rsconf_t *conf) { struct template *pTpl, *pTplDel; struct templateEntry *pTpe, *pTpeDel; BEGINfunc - pTpl = tplRoot; + pTpl = conf->templates.root; while(pTpl != NULL) { /* dbgprintf("Delete Template: Name='%s'\n ", pTpl->pszName == NULL? "NULL" : pTpl->pszName);*/ pTpe = pTpl->pEntryRoot; @@ -1122,19 +1126,19 @@ void tplDeleteAll(void) /* Destroy all templates obtained from conf file * preserving hardcoded ones. This is called from init(). */ -void tplDeleteNew(void) +void tplDeleteNew(rsconf_t *conf) { struct template *pTpl, *pTplDel; struct templateEntry *pTpe, *pTpeDel; BEGINfunc - if(tplRoot == NULL || tplLastStatic == NULL) + if(conf->templates.root == NULL || conf->templates.lastStatic == NULL) return; - pTpl = tplLastStatic->pNext; - tplLastStatic->pNext = NULL; - tplLast = tplLastStatic; + pTpl = conf->templates.lastStatic->pNext; + conf->templates.lastStatic->pNext = NULL; + conf->templates.last = conf->templates.lastStatic; while(pTpl != NULL) { /* dbgprintf("Delete Template: Name='%s'\n ", pTpl->pszName == NULL? "NULL" : pTpl->pszName);*/ pTpe = pTpl->pEntryRoot; @@ -1177,20 +1181,20 @@ void tplDeleteNew(void) } /* Store the pointer to the last hardcoded teplate */ -void tplLastStaticInit(struct template *tpl) +void tplLastStaticInit(rsconf_t *conf, struct template *tpl) { - tplLastStatic = tpl; + conf->templates.lastStatic = tpl; } /* Print the template structure. This is more or less a * debug or test aid, but anyhow I think it's worth it... */ -void tplPrintList(void) +void tplPrintList(rsconf_t *conf) { struct template *pTpl; struct templateEntry *pTpe; - pTpl = tplRoot; + pTpl = conf->templates.root; while(pTpl != NULL) { dbgprintf("Template: Name='%s' ", pTpl->pszName == NULL? "NULL" : pTpl->pszName); if(pTpl->optFormatForSQL == 1) diff --git a/template.h b/template.h index 2fb8e1ae..1b58f1ef 100644 --- a/template.h +++ b/template.h @@ -117,14 +117,14 @@ ENDinterface(tpl) PROTOTYPEObj(tpl); -struct template* tplConstruct(void); -struct template *tplAddLine(char* pName, unsigned char** pRestOfConfLine); -struct template *tplFind(char *pName, int iLenName); +//struct template* tplConstruct(void); +struct template *tplAddLine(rsconf_t *conf, char* pName, unsigned char** pRestOfConfLine); +struct template *tplFind(rsconf_t *conf, char *pName, int iLenName); int tplGetEntryCount(struct template *pTpl); -void tplDeleteAll(void); -void tplDeleteNew(void); -void tplPrintList(void); -void tplLastStaticInit(struct template *tpl); +void tplDeleteAll(rsconf_t *conf); +void tplDeleteNew(rsconf_t *conf); +void tplPrintList(rsconf_t *conf); +void tplLastStaticInit(rsconf_t *conf, struct template *tpl); rsRetVal ExtendBuf(uchar **pBuf, size_t *pLenBuf, size_t iMinSize); /* note: if a compiler warning for undefined type tells you to look at this * code line below, the actual cause is that you currently MUST include template.h diff --git a/tools/syslogd.c b/tools/syslogd.c index 44c88624..d0a6df40 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -21,7 +21,7 @@ * For further information, please see http://www.rsyslog.com * * rsyslog - An Enhanced syslogd Replacement. - * Copyright 2003-2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2003-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -135,6 +135,7 @@ #include "net.h" #include "vm.h" #include "prop.h" +#include "rsconf.h" #include "sd-daemon.h" /* definitions for objects we access */ @@ -149,6 +150,7 @@ DEFobjCurrIf(rule) DEFobjCurrIf(ruleset) DEFobjCurrIf(prop) DEFobjCurrIf(parser) +DEFobjCurrIf(rsconf) DEFobjCurrIf(net) /* TODO: make go away! */ @@ -198,6 +200,8 @@ static rsRetVal GlobalClassExit(void); # define _PATH_TTY "/dev/tty" #endif +rsconf_t *ourConf; /* our config object */ + static prop_t *pInternalInputName = NULL; /* there is only one global inputName for all internally-generated messages */ static prop_t *pLocalHostIP = NULL; /* there is only one global IP for all internally-generated messages */ static uchar *ConfFile = (uchar*) _PATH_LOGCONF; /* read-only after startup */ @@ -1087,7 +1091,7 @@ die(int sig) * ourselfs, this makes finding memory leaks a lot * easier. */ - tplDeleteAll(); + tplDeleteAll(ourConf); /* de-init some modules */ modExitIminternal(); @@ -1438,7 +1442,7 @@ static void dbgPrintInitInfo(void) ruleset.DebugPrintAll(); DBGPRINTF("\n"); if(bDebugPrintTemplateList) - tplPrintList(); + tplPrintList(ourConf); if(bDebugPrintModuleList) module.PrintList(); ochPrintList(); @@ -2147,29 +2151,32 @@ static rsRetVal mainThread() DEFiRet; uchar *pTmp; + /* we need to init the config object first! */ + CHKiRet(rsconf.Construct(&ourConf)); + /* initialize the build-in templates */ pTmp = template_DebugFormat; - tplAddLine("RSYSLOG_DebugFormat", &pTmp); + tplAddLine(ourConf, "RSYSLOG_DebugFormat", &pTmp); pTmp = template_SyslogProtocol23Format; - tplAddLine("RSYSLOG_SyslogProtocol23Format", &pTmp); + tplAddLine(ourConf, "RSYSLOG_SyslogProtocol23Format", &pTmp); pTmp = template_FileFormat; /* new format for files with high-precision stamp */ - tplAddLine("RSYSLOG_FileFormat", &pTmp); + tplAddLine(ourConf, "RSYSLOG_FileFormat", &pTmp); pTmp = template_TraditionalFileFormat; - tplAddLine("RSYSLOG_TraditionalFileFormat", &pTmp); + tplAddLine(ourConf, "RSYSLOG_TraditionalFileFormat", &pTmp); pTmp = template_WallFmt; - tplAddLine(" WallFmt", &pTmp); + tplAddLine(ourConf, " WallFmt", &pTmp); pTmp = template_ForwardFormat; - tplAddLine("RSYSLOG_ForwardFormat", &pTmp); + tplAddLine(ourConf, "RSYSLOG_ForwardFormat", &pTmp); pTmp = template_TraditionalForwardFormat; - tplAddLine("RSYSLOG_TraditionalForwardFormat", &pTmp); + tplAddLine(ourConf, "RSYSLOG_TraditionalForwardFormat", &pTmp); pTmp = template_StdUsrMsgFmt; - tplAddLine(" StdUsrMsgFmt", &pTmp); + tplAddLine(ourConf, " StdUsrMsgFmt", &pTmp); pTmp = template_StdDBFmt; - tplAddLine(" StdDBFmt", &pTmp); + tplAddLine(ourConf, " StdDBFmt", &pTmp); pTmp = template_StdPgSQLFmt; - tplLastStaticInit(tplAddLine(" StdPgSQLFmt", &pTmp)); + tplAddLine(ourConf, " StdPgSQLFmt", &pTmp); pTmp = template_spoofadr; - tplLastStaticInit(tplAddLine("RSYSLOG_omudpspoofDfltSourceTpl", &pTmp)); + tplLastStaticInit(ourConf, tplAddLine(ourConf, "RSYSLOG_omudpspoofDfltSourceTpl", &pTmp)); CHKiRet(init()); @@ -2261,6 +2268,8 @@ InitGlobalClasses(void) CHKiRet(objUse(prop, CORE_COMPONENT)); pErrObj = "parser"; CHKiRet(objUse(parser, CORE_COMPONENT)); + pErrObj = "rsconf"; + CHKiRet(objUse(rsconf, CORE_COMPONENT)); /* intialize some dummy classes that are not part of the runtime */ pErrObj = "action"; @@ -2306,6 +2315,7 @@ GlobalClassExit(void) objRelease(expr, CORE_COMPONENT); vmClassExit(); /* this is hack, currently core_modules do not get this automatically called */ parserClassExit(); /* this is hack, currently core_modules do not get this automatically called */ + rsconfClassExit(); /* this is hack, currently core_modules do not get this automatically called */ objRelease(datetime, CORE_COMPONENT); /* TODO: implement the rest of the deinit */ -- cgit v1.2.3 From d348558a51402d08310d95cfd6e8a2d6b9fce1b2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Apr 2011 11:26:37 +0200 Subject: milestone: conf obj interface now utilzes rsconf_t --- runtime/conf.c | 44 ++++++++++++++++++------------------- runtime/conf.h | 18 ++++++++------- runtime/rsconf.h | 6 +++++ runtime/typedefs.h | 1 + template.c | 7 ------ tests/rscript.c | 1 + tests/rt-init.c | 1 + tools/syslogd.c | 64 +++++++++++++++++++++++++++++++++++++++++++----------- 8 files changed, 92 insertions(+), 50 deletions(-) diff --git a/runtime/conf.c b/runtime/conf.c index bfd66e31..9f4015fd 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -12,7 +12,7 @@ * the selector lines (e.g. *.info). That code is scheduled for removal * as part of RainerScript. After this is done, we can change licenses. * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. + * Copyright 2008-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -77,8 +77,8 @@ #endif /* forward definitions */ -static rsRetVal cfline(uchar *line, rule_t **pfCurr); -static rsRetVal processConfFile(uchar *pConfFile); +static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); +static rsRetVal processConfFile(rsconf_t *conf, uchar *pConfFile); /* static data */ @@ -117,7 +117,7 @@ static cstr_t *pDfltProgNameCmp = NULL; * indeed a directory. * rgerhards, 2007-08-01 */ -static rsRetVal doIncludeDirectory(uchar *pDirName) +static rsRetVal doIncludeDirectory(rsconf_t *conf, uchar *pDirName) { DEFiRet; int iEntriesDone = 0; @@ -167,7 +167,7 @@ static rsRetVal doIncludeDirectory(uchar *pDirName) memcpy(szFullFileName + iDirNameLen, res->d_name, iFileNameLen); *(szFullFileName + iDirNameLen + iFileNameLen) = '\0'; dbgprintf("including file '%s'\n", szFullFileName); - processConfFile(szFullFileName); + processConfFile(conf, szFullFileName); /* we deliberately ignore the iRet of processConfFile() - this is because * failure to process one file does not mean all files will fail. By ignoring, * we retry with the next file, which is the best thing we can do. -- rgerhards, 2007-08-01 @@ -196,7 +196,7 @@ finalize_it: * rgerhards, 2007-08-01 */ rsRetVal -doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal) +doIncludeLine(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal) { DEFiRet; char pattern[MAXFNAME]; @@ -234,10 +234,10 @@ doIncludeLine(uchar **pp, __attribute__((unused)) void* pVal) if(S_ISREG(fileInfo.st_mode)) { /* config file */ dbgprintf("requested to include config file '%s'\n", cfgFile); - iRet = processConfFile(cfgFile); + iRet = processConfFile(conf, cfgFile); } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */ dbgprintf("requested to include directory '%s'\n", cfgFile); - iRet = doIncludeDirectory(cfgFile); + iRet = doIncludeDirectory(conf, cfgFile); } else { /* TODO: shall we handle symlinks or not? */ dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile); } @@ -253,7 +253,7 @@ finalize_it: /* process a $ModLoad config line. */ rsRetVal -doModLoad(uchar **pp, __attribute__((unused)) void* pVal) +doModLoad(rsconf_t * conf, uchar **pp, __attribute__((unused)) void* pVal) { DEFiRet; uchar szName[512]; @@ -297,7 +297,7 @@ finalize_it: * generalized. */ rsRetVal -doNameLine(uchar **pp, void* pVal) +doNameLine(rsconf_t *conf, uchar **pp, void* pVal) { DEFiRet; uchar *p; @@ -356,7 +356,7 @@ finalize_it: * 2004-11-17 rgerhards */ rsRetVal -cfsysline(uchar *p) +cfsysline(rsconf_t *conf, uchar *p) { DEFiRet; uchar szCmd[64]; @@ -397,7 +397,7 @@ finalize_it: * started with code from init() by rgerhards on 2007-07-31 */ static rsRetVal -processConfFile(uchar *pConfFile) +processConfFile(rsconf_t *conf, uchar *pConfFile) { int iLnNbr = 0; FILE *cf; @@ -464,7 +464,7 @@ processConfFile(uchar *pConfFile) /* we now have the complete line, and are positioned at the first non-whitespace * character. So let's process it */ - if(cfline(cbuf, &pCurrRule) != RS_RET_OK) { + if(cfline(conf, cbuf, &pCurrRule) != RS_RET_OK) { /* we log a message, but otherwise ignore the error. After all, the next * line can be correct. -- rgerhards, 2007-08-02 */ @@ -960,7 +960,7 @@ dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); * from the config file ("+/-hostname"). It stores it for further reference. * rgerhards 2005-10-19 */ -static rsRetVal cflineProcessHostSelector(uchar **pline) +static rsRetVal cflineProcessHostSelector(rsconf_t *conf, uchar **pline) { DEFiRet; @@ -1010,7 +1010,7 @@ finalize_it: * from the config file ("!tagname"). It stores it for further reference. * rgerhards 2005-10-18 */ -static rsRetVal cflineProcessTagSelector(uchar **pline) +static rsRetVal cflineProcessTagSelector(rsconf_t *conf, uchar **pline) { DEFiRet; @@ -1160,7 +1160,7 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction) * of the master config file!). */ static rsRetVal -cflineClassic(uchar *p, rule_t **ppRule) +cflineClassic(rsconf_t *conf, uchar *p, rule_t **ppRule) { DEFiRet; action_t *pAction; @@ -1203,7 +1203,7 @@ finalize_it: * rgerhards, 2007-08-01 */ static rsRetVal -cfline(uchar *line, rule_t **pfCurr) +cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr) { DEFiRet; @@ -1214,18 +1214,18 @@ cfline(uchar *line, rule_t **pfCurr) /* check type of line and call respective processing */ switch(*line) { case '!': - iRet = cflineProcessTagSelector(&line); + iRet = cflineProcessTagSelector(conf, &line); break; case '+': case '-': - iRet = cflineProcessHostSelector(&line); + iRet = cflineProcessHostSelector(conf, &line); break; case '$': ++line; /* eat '$' */ - iRet = cfsysline(line); + iRet = cfsysline(conf, line); break; default: - iRet = cflineClassic(line, pfCurr); + iRet = cflineClassic(conf, line, pfCurr); break; } @@ -1237,7 +1237,7 @@ cfline(uchar *line, rule_t **pfCurr) * rgerhards, 2008-07-28 */ static rsRetVal -GetNbrActActions(int *piNbrActions) +GetNbrActActions(rsconf_t *conf, int *piNbrActions) { DEFiRet; assert(piNbrActions != NULL); diff --git a/runtime/conf.h b/runtime/conf.h index bc09d502..3b3d488b 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -33,21 +33,23 @@ extern int bConfStrictScoping; /* force strict scoping during config processing? /* interfaces */ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ - rsRetVal (*doNameLine)(uchar **pp, void* pVal); - rsRetVal (*cfsysline)(uchar *p); - rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); - rsRetVal (*doIncludeLine)(uchar **pp, __attribute__((unused)) void* pVal); - rsRetVal (*cfline)(uchar *line, rule_t **pfCurr); - rsRetVal (*processConfFile)(uchar *pConfFile); - rsRetVal (*GetNbrActActions)(int *); + rsRetVal (*doNameLine)(rsconf_t *conf, uchar **pp, void* pVal); + rsRetVal (*cfsysline)(rsconf_t *conf, uchar *p); + rsRetVal (*doModLoad)(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal); + rsRetVal (*doIncludeLine)(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal); + rsRetVal (*cfline)(rsconf_t *conf, uchar *line, rule_t **pfCurr); + rsRetVal (*processConfFile)(rsconf_t *conf, uchar *pConfFile); + rsRetVal (*GetNbrActActions)(rsconf_t *conf, int *); /* version 4 -- 2010-07-23 rgerhards */ /* "just" added global variables * FYI: we reconsider repacking as a non-object, as only the core currently * accesses this module. The current object structure complicates things without * any real benefit. */ + /* version 5 -- 2011-04-19 rgerhards */ + /* complete revamp, we now use the rsconf object */ ENDinterface(conf) -#define confCURR_IF_VERSION 4 /* increment whenever you change the interface structure! */ +#define confCURR_IF_VERSION 5 /* increment whenever you change the interface structure! */ /* in Version 3, entry point "ReInitConf()" was removed, as we do not longer need * to support restart-type HUP -- rgerhards, 2009-07-15 */ diff --git a/runtime/rsconf.h b/runtime/rsconf.h index 4a8c143f..e32e3d12 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -34,12 +34,18 @@ struct templates_s { struct template *lastStatic; /* last static element of the template list */ }; + +struct actions_s { + unsigned nbrActions; /* number of actions */ +}; + /* --- end configuration objects --- */ /* the rsconf object */ struct rsconf_s { BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ templates_t templates; + actions_t actions; }; diff --git a/runtime/typedefs.h b/runtime/typedefs.h index f38bcdd4..d79612bc 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -81,6 +81,7 @@ typedef struct strgenList_s strgenList_t; typedef struct statsobj_s statsobj_t; typedef struct nsd_epworkset_s nsd_epworkset_t; typedef struct templates_s templates_t; +typedef struct actions_s actions_t; typedef struct rsconf_s rsconf_t; typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript function */ typedef uint64 qDeqID; /* queue Dequeue order ID. 32 bits is considered dangerously few */ diff --git a/template.c b/template.c index 697a6ad5..93f56cd0 100644 --- a/template.c +++ b/template.c @@ -50,13 +50,6 @@ DEFobjCurrIf(regexp) static int bFirstRegexpErrmsg = 1; /**< did we already do a "can't load regexp" error message? */ #endif -#if 0 - -static struct template *conf->templates.root = NULL; /* the root of the template list */ -static struct template *tplLast = NULL; -static struct template *conf->templates.lastStatic = NULL; -#endif - /* helper to tplToString and strgen's, extends buffer */ #define ALLOC_INC 128 diff --git a/tests/rscript.c b/tests/rscript.c index 6361aec4..5baf74cc 100644 --- a/tests/rscript.c +++ b/tests/rscript.c @@ -33,6 +33,7 @@ #include "ctok.h" #include "expr.h" +rsconf_t *ourConf; MODULE_TYPE_TESTBENCH /* define addtional objects we need for our tests */ DEFobjCurrIf(expr) diff --git a/tests/rt-init.c b/tests/rt-init.c index 2d43943f..d3cf4698 100644 --- a/tests/rt-init.c +++ b/tests/rt-init.c @@ -26,6 +26,7 @@ #include "testbench.h" #include /* must be last, else we get a zlib compile error on some platforms */ +rsconf_t *ourConf; MODULE_TYPE_TESTBENCH BEGINInit diff --git a/tools/syslogd.c b/tools/syslogd.c index d0a6df40..c01fd6ad 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -898,7 +898,7 @@ void legacyOptsHook(void) errno = 0; errmsg.LogError(0, NO_ERRCODE, "Warning: backward compatibility layer added to following " "directive to rsyslog.conf: %s", pThis->line); - conf.cfsysline(pThis->line); + conf.cfsysline(ourConf, pThis->line); } pThis = pThis->next; } @@ -1618,8 +1618,8 @@ init(void) ruleset.ConstructFinalize(pRuleset); /* open the configuration file */ - localRet = conf.processConfFile(ConfFile); - CHKiRet(conf.GetNbrActActions(&iNbrActions)); + localRet = conf.processConfFile(ourConf, ConfFile); + CHKiRet(conf.GetNbrActActions(ourConf, &iNbrActions)); if(localRet != RS_RET_OK) { errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", ConfFile); @@ -1644,13 +1644,13 @@ init(void) */ char szTTYNameBuf[128]; rule_t *pRule = NULL; /* initialization to NULL is *vitally* important! */ - conf.cfline(UCHAR_CONSTANT("*.ERR\t" _PATH_CONSOLE), &pRule); - conf.cfline(UCHAR_CONSTANT("syslog.*\t" _PATH_CONSOLE), &pRule); - conf.cfline(UCHAR_CONSTANT("*.PANIC\t*"), &pRule); - conf.cfline(UCHAR_CONSTANT("syslog.*\troot"), &pRule); + conf.cfline(ourConf, UCHAR_CONSTANT("*.ERR\t" _PATH_CONSOLE), &pRule); + conf.cfline(ourConf, UCHAR_CONSTANT("syslog.*\t" _PATH_CONSOLE), &pRule); + conf.cfline(ourConf, UCHAR_CONSTANT("*.PANIC\t*"), &pRule); + conf.cfline(ourConf, UCHAR_CONSTANT("syslog.*\troot"), &pRule); if(ttyname_r(0, szTTYNameBuf, sizeof(szTTYNameBuf)) == 0) { snprintf(cbuf,sizeof(cbuf), "*.*\t%s", szTTYNameBuf); - conf.cfline((uchar*)cbuf, &pRule); + conf.cfline(ourConf, (uchar*)cbuf, &pRule); } else { DBGPRINTF("error %d obtaining controlling terminal, not using that emergency rule\n", errno); } @@ -1985,6 +1985,44 @@ mainloop(void) } +/* this method is needed to shuffle the current conf object down to the + * IncludeConfig handler. + */ +static rsRetVal +doNameLine(void *pVal, uchar *pNewVal) +{ + DEFiRet; + iRet = conf.doNameLine(ourConf, pVal, pNewVal); + free(pNewVal); + RETiRet; +} + + +/* this method is needed to shuffle the current conf object down to the + * IncludeConfig handler. + */ +static rsRetVal +doModLoad(void *pVal, uchar *pNewVal) +{ + DEFiRet; + iRet = conf.doModLoad(ourConf, pVal, pNewVal); + free(pNewVal); + RETiRet; +} + + +/* this method is needed to shuffle the current conf object down to the + * IncludeConfig handler. + */ +static rsRetVal +doIncludeLine(void *pVal, uchar *pNewVal) +{ + DEFiRet; + iRet = conf.doIncludeLine(ourConf, pVal, pNewVal); + free(pNewVal); + RETiRet; +} + /* load build-in modules * very first version begun on 2007-07-23 by rgerhards */ @@ -2071,11 +2109,11 @@ static rsRetVal loadBuildInModules(void) CHKiRet(regCfSysLineHdlr((uchar *)"abortonuncleanconfig", 0, eCmdHdlrBinary, NULL, &bAbortOnUncleanConfig, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgreduction", 0, eCmdHdlrBinary, NULL, &bReduceRepeatMsgs, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, setActionResumeInterval, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_TEMPLATE, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_OUTCHANNEL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"allowedsender", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_ALLOWEDSENDER, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, conf.doModLoad, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, conf.doIncludeLine, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler, doNameLine, (void*)DIR_TEMPLATE, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler, doNameLine, (void*)DIR_OUTCHANNEL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"allowedsender", 0, eCmdHdlrCustomHandler, doNameLine, (void*)DIR_ALLOWEDSENDER, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, doModLoad, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, doIncludeLine, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode, setUmask, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"maxopenfiles", 0, eCmdHdlrInt, setMaxFiles, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"debugprinttemplatelist", 0, eCmdHdlrBinary, NULL, &bDebugPrintTemplateList, NULL, eConfObjGlobal)); -- cgit v1.2.3 From b722cd3fe608a0bbf4a6df962f9d5c5e547fdc09 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Apr 2011 12:18:26 +0200 Subject: milestone: ruleset now supports rsconf_t --- plugins/imfile/imfile.c | 2 +- plugins/imptcp/imptcp.c | 2 +- plugins/imtcp/imtcp.c | 2 +- plugins/imttcp/imttcp.c | 2 +- plugins/imudp/imudp.c | 2 +- plugins/omruleset/omruleset.c | 2 +- runtime/conf.c | 15 ++++---- runtime/rsconf.c | 12 +++++-- runtime/rsconf.h | 9 +++++ runtime/rule.c | 2 +- runtime/ruleset.c | 79 +++++++++++++++++++++---------------------- runtime/ruleset.h | 28 +++++++++------ runtime/typedefs.h | 1 + tools/syslogd.c | 22 ++++++------ 14 files changed, 100 insertions(+), 80 deletions(-) diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index 37d3136c..67eebefe 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -543,7 +543,7 @@ setRuleset(void __attribute__((unused)) *pVal, uchar *pszName) rsRetVal localRet; DEFiRet; - localRet = ruleset.GetRuleset(&pRuleset, pszName); + localRet = ruleset.GetRuleset(ourConf, &pRuleset, pszName); if(localRet == RS_RET_NOT_FOUND) { errmsg.LogError(0, NO_ERRCODE, "error: ruleset '%s' not found - ignored", pszName); } diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 33277148..1c9450c2 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -856,7 +856,7 @@ static rsRetVal setRuleset(void __attribute__((unused)) *pVal, uchar *pszName) rsRetVal localRet; DEFiRet; - localRet = ruleset.GetRuleset(&pRuleset, pszName); + localRet = ruleset.GetRuleset(ourConf, &pRuleset, pszName); if(localRet == RS_RET_NOT_FOUND) { errmsg.LogError(0, NO_ERRCODE, "error: ruleset '%s' not found - ignored", pszName); } diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index 24c0cd7e..be95d287 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -172,7 +172,7 @@ static rsRetVal setRuleset(void __attribute__((unused)) *pVal, uchar *pszName) rsRetVal localRet; DEFiRet; - localRet = ruleset.GetRuleset(&pRuleset, pszName); + localRet = ruleset.GetRuleset(ourConf, &pRuleset, pszName); if(localRet == RS_RET_NOT_FOUND) { errmsg.LogError(0, RS_RET_RULESET_NOT_FOUND, "error: ruleset '%s' not found - ignored", pszName); } diff --git a/plugins/imttcp/imttcp.c b/plugins/imttcp/imttcp.c index 68574ad6..44dc3267 100644 --- a/plugins/imttcp/imttcp.c +++ b/plugins/imttcp/imttcp.c @@ -808,7 +808,7 @@ static rsRetVal setRuleset(void __attribute__((unused)) *pVal, uchar *pszName) rsRetVal localRet; DEFiRet; - localRet = ruleset.GetRuleset(&pRuleset, pszName); + localRet = ruleset.GetRuleset(ourConf, &pRuleset, pszName); if(localRet == RS_RET_NOT_FOUND) { errmsg.LogError(0, NO_ERRCODE, "error: ruleset '%s' not found - ignored", pszName); } diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 2b38769e..8a463320 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -265,7 +265,7 @@ setRuleset(void __attribute__((unused)) *pVal, uchar *pszName) rsRetVal localRet; DEFiRet; - localRet = ruleset.GetRuleset(&pRuleset, pszName); + localRet = ruleset.GetRuleset(ourConf, &pRuleset, pszName); if(localRet == RS_RET_NOT_FOUND) { errmsg.LogError(0, NO_ERRCODE, "error: ruleset '%s' not found - ignored", pszName); } diff --git a/plugins/omruleset/omruleset.c b/plugins/omruleset/omruleset.c index 365b405d..bb140764 100644 --- a/plugins/omruleset/omruleset.c +++ b/plugins/omruleset/omruleset.c @@ -131,7 +131,7 @@ setRuleset(void __attribute__((unused)) *pVal, uchar *pszName) rsRetVal localRet; DEFiRet; - localRet = ruleset.GetRuleset(&cs.pRuleset, pszName); + localRet = ruleset.GetRuleset(ourConf, &cs.pRuleset, pszName); if(localRet == RS_RET_NOT_FOUND) { errmsg.LogError(0, RS_RET_RULESET_NOT_FOUND, "error: ruleset '%s' not found - ignored", pszName); } diff --git a/runtime/conf.c b/runtime/conf.c index 9f4015fd..90b1b487 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -70,6 +70,7 @@ #include "ctok_token.h" #include "rule.h" #include "ruleset.h" +#include "rsconf.h" #include "unicode-helper.h" #ifdef OS_SOLARIS @@ -96,8 +97,6 @@ ecslConfObjType currConfObj = eConfObjGlobal; /* to support scoping - which conf int bConfStrictScoping = 0; /* force strict scoping during config processing? */ -static int iNbrActions = 0; /* number of currently defined actions */ - /* The following module-global variables are used for building * tag and host selector lines during startup and config reload. * This is stored as a global variable pool because of its ease. It is @@ -479,7 +478,7 @@ processConfFile(rsconf_t *conf, uchar *pConfFile) /* we probably have one selector left to be added - so let's do that now */ if(pCurrRule != NULL) { - CHKiRet(ruleset.AddRule(rule.GetAssRuleset(pCurrRule), &pCurrRule)); + CHKiRet(ruleset.AddRule(conf, rule.GetAssRuleset(pCurrRule), &pCurrRule)); } /* close the configuration file */ @@ -1095,7 +1094,7 @@ finalize_it: /* process the action part of a selector line * rgerhards, 2007-08-01 */ -static rsRetVal cflineDoAction(uchar **p, action_t **ppAction) +static rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) { DEFiRet; modInfo_t *pMod; @@ -1132,7 +1131,7 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction) pAction->f_ReduceRepeated = 0; } pAction->eState = ACT_STATE_RDY; /* action is enabled */ - iNbrActions++; /* one more active action! */ + conf->actions.nbrActions++; /* one more active action! */ } break; } @@ -1182,7 +1181,7 @@ cflineClassic(rsconf_t *conf, uchar *p, rule_t **ppRule) * all. -- rgerhards, 2007-08-01 */ if(*ppRule != NULL) { - CHKiRet(ruleset.AddRule(rule.GetAssRuleset(*ppRule), ppRule)); + CHKiRet(ruleset.AddRule(conf, rule.GetAssRuleset(*ppRule), ppRule)); } CHKiRet(rule.Construct(ppRule)); /* create "fresh" selector */ CHKiRet(rule.SetAssRuleset(*ppRule, ruleset.GetCurrent())); /* create "fresh" selector */ @@ -1190,7 +1189,7 @@ cflineClassic(rsconf_t *conf, uchar *p, rule_t **ppRule) CHKiRet(cflineDoFilter(&p, *ppRule)); /* pull filters */ } - CHKiRet(cflineDoAction(&p, &pAction)); + CHKiRet(cflineDoAction(conf, &p, &pAction)); CHKiRet(llAppend(&(*ppRule)->llActList, NULL, (void*) pAction)); finalize_it: @@ -1241,7 +1240,7 @@ GetNbrActActions(rsconf_t *conf, int *piNbrActions) { DEFiRet; assert(piNbrActions != NULL); - *piNbrActions = iNbrActions; + *piNbrActions = conf->actions.nbrActions; RETiRet; } diff --git a/runtime/rsconf.c b/runtime/rsconf.c index be780251..27d89fb6 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -27,10 +27,12 @@ #include #include #include +#include #include "rsyslog.h" #include "obj.h" #include "srUtils.h" +#include "ruleset.h" #include "rsconf.h" /* static data */ @@ -40,6 +42,12 @@ DEFobjStaticHelpers /* Standard-Constructor */ BEGINobjConstruct(rsconf) /* be sure to specify the object type also in END macro! */ + pThis->templates.root = NULL; + pThis->templates.last = NULL; + pThis->templates.lastStatic = NULL; + pThis->actions.nbrActions = 0; + CHKiRet(llInit(&pThis->rulesets.llRulesets, rulesetDestructForLinkedList, rulesetKeyDestruct, strcasecmp)); +finalize_it: ENDobjConstruct(rsconf) @@ -57,9 +65,7 @@ rsRetVal rsconfConstructFinalize(rsconf_t __attribute__((unused)) *pThis) /* destructor for the rsconf object */ BEGINobjDestruct(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */ CODESTARTobjDestruct(rsconf) - pThis->templates.root = NULL; - pThis->templates.last = NULL; - pThis->templates.lastStatic = NULL; + llDestroy(&(pThis->rulesets.llRulesets)); ENDobjDestruct(rsconf) diff --git a/runtime/rsconf.h b/runtime/rsconf.h index e32e3d12..4fd160a4 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -23,6 +23,8 @@ #ifndef INCLUDED_RSCONF_H #define INCLUDED_RSCONF_H +#include "linkedlist.h" + /* --- configuration objects (the plan is to have ALL upper layers in this file) --- */ /* the following structure is a container for all known templates @@ -39,6 +41,12 @@ struct actions_s { unsigned nbrActions; /* number of actions */ }; + +struct rulesets_s { + linkedList_t llRulesets; /* this is NOT a pointer - no typo here ;) */ +}; + + /* --- end configuration objects --- */ /* the rsconf object */ @@ -46,6 +54,7 @@ struct rsconf_s { BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ templates_t templates; actions_t actions; + rulesets_t rulesets; }; diff --git a/runtime/rule.c b/runtime/rule.c index 7c3e5131..d023bcec 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -4,7 +4,7 @@ * * Module begun 2009-06-10 by Rainer Gerhards * - * Copyright 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2009-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * diff --git a/runtime/ruleset.c b/runtime/ruleset.c index 2d4f113e..71fd76da 100644 --- a/runtime/ruleset.c +++ b/runtime/ruleset.c @@ -1,7 +1,7 @@ /* ruleset.c - rsyslog's ruleset object * - * We have a two-way structure of linked lists: one global linked list - * (llAllRulesets) hold alls rule sets that we know. Included in each + * We have a two-way structure of linked lists: one config-specifc linked list + * (conf->rulesets.llRulesets) hold alls rule sets that we know. Included in each * list is a list of rules (which contain a list of actions, but that's * a different story). * @@ -11,7 +11,7 @@ * * Module begun 2009-06-10 by Rainer Gerhards * - * Copyright 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2009-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -34,7 +34,7 @@ #include "config.h" #include -#include +////#include #include #include @@ -48,6 +48,7 @@ #include "parser.h" #include "batch.h" #include "unicode-helper.h" +#include "rsconf.h" #include "dirty.h" /* for main ruleset queue creation */ /* static data */ @@ -56,26 +57,26 @@ DEFobjCurrIf(errmsg) DEFobjCurrIf(rule) DEFobjCurrIf(parser) -linkedList_t llRulesets; /* this is NOT a pointer - no typo here ;) */ ruleset_t *pCurrRuleset = NULL; /* currently "active" ruleset */ ruleset_t *pDfltRuleset = NULL; /* current default ruleset, e.g. for binding to actions which have no other */ /* forward definitions */ static rsRetVal processBatch(batch_t *pBatch); -/* ---------- linked-list key handling functions ---------- */ + +/* ---------- linked-list key handling functions (ruleset) ---------- */ /* destructor for linked list keys. */ -static rsRetVal keyDestruct(void __attribute__((unused)) *pData) +rsRetVal +rulesetKeyDestruct(void __attribute__((unused)) *pData) { free(pData); return RS_RET_OK; } +/* ---------- END linked-list key handling functions (ruleset) ---------- */ -/* ---------- END linked-list key handling functions ---------- */ - /* driver to iterate over all of this ruleset actions */ typedef struct iterateAllActions_s { @@ -122,7 +123,7 @@ DEFFUNC_llExecFunc(doIterateAllActions) * must be done or a shutdown is pending. */ static rsRetVal -iterateAllActions(rsRetVal (*pFunc)(void*, void*), void* pParam) +iterateAllActions(rsconf_t *conf, rsRetVal (*pFunc)(void*, void*), void* pParam) { iterateAllActions_t params; DEFiRet; @@ -130,7 +131,7 @@ iterateAllActions(rsRetVal (*pFunc)(void*, void*), void* pParam) params.pFunc = pFunc; params.pParam = pParam; - CHKiRet(llExecFunc(&llRulesets, doIterateAllActions, ¶ms)); + CHKiRet(llExecFunc(&(conf->rulesets.llRulesets), doIterateAllActions, ¶ms)); finalize_it: RETiRet; @@ -255,7 +256,7 @@ GetParserList(msg_t *pMsg) * of checks and ignore the rule if it does not pass them. */ static rsRetVal -addRule(ruleset_t *pThis, rule_t **ppRule) +addRule(rsconf_t *conf, ruleset_t *pThis, rule_t **ppRule) { int iActionCnt; DEFiRet; @@ -278,7 +279,7 @@ finalize_it: /* set name for ruleset */ -static rsRetVal setName(ruleset_t *pThis, uchar *pszName) +static rsRetVal setName(rsconf_t *conf, ruleset_t *pThis, uchar *pszName) { DEFiRet; free(pThis->pszName); @@ -316,13 +317,13 @@ GetRulesetQueue(ruleset_t *pThis) /* Find the ruleset with the given name and return a pointer to its object. */ static rsRetVal -GetRuleset(ruleset_t **ppRuleset, uchar *pszName) +GetRuleset(rsconf_t *conf, ruleset_t **ppRuleset, uchar *pszName) { DEFiRet; assert(ppRuleset != NULL); assert(pszName != NULL); - CHKiRet(llFind(&llRulesets, pszName, (void*) ppRuleset)); + CHKiRet(llFind(&(conf->rulesets.llRulesets), pszName, (void*) ppRuleset)); finalize_it: RETiRet; @@ -332,13 +333,13 @@ finalize_it: /* Set a new default rule set. If the default can not be found, no change happens. */ static rsRetVal -SetDefaultRuleset(uchar *pszName) +SetDefaultRuleset(rsconf_t *conf, uchar *pszName) { ruleset_t *pRuleset; DEFiRet; assert(pszName != NULL); - CHKiRet(GetRuleset(&pRuleset, pszName)); + CHKiRet(GetRuleset(conf, &pRuleset, pszName)); pDfltRuleset = pRuleset; dbgprintf("default rule set changed to %p: '%s'\n", pRuleset, pszName); @@ -350,13 +351,13 @@ finalize_it: /* Set a new current rule set. If the ruleset can not be found, no change happens. */ static rsRetVal -SetCurrRuleset(uchar *pszName) +SetCurrRuleset(rsconf_t *conf, uchar *pszName) { ruleset_t *pRuleset; DEFiRet; assert(pszName != NULL); - CHKiRet(GetRuleset(&pRuleset, pszName)); + CHKiRet(GetRuleset(conf, &pRuleset, pszName)); pCurrRuleset = pRuleset; dbgprintf("current rule set changed to %p: '%s'\n", pRuleset, pszName); @@ -389,7 +390,7 @@ ENDobjConstruct(ruleset) * This also adds the rule set to the list of all known rulesets. */ static rsRetVal -rulesetConstructFinalize(ruleset_t *pThis) +rulesetConstructFinalize(rsconf_t *conf, ruleset_t *pThis) { uchar *keyName; DEFiRet; @@ -400,7 +401,7 @@ rulesetConstructFinalize(ruleset_t *pThis) * two separate copies. */ CHKmalloc(keyName = ustrdup(pThis->pszName)); - CHKiRet(llAppend(&llRulesets, keyName, pThis)); + CHKiRet(llAppend(&(conf->rulesets.llRulesets), keyName, pThis)); /* this now also is the new current ruleset */ pCurrRuleset = pThis; @@ -428,17 +429,6 @@ CODESTARTobjDestruct(ruleset) free(pThis->pszName); ENDobjDestruct(ruleset) -/* this is a special destructor for the linkedList class. LinkedList does NOT - * provide a pointer to the pointer, but rather the raw pointer itself. So we - * must map this, otherwise the destructor will abort. - */ -static rsRetVal -rulesetDestructForLinkedList(void *pData) -{ - ruleset_t *pThis = (ruleset_t*) pData; - return rulesetDestruct(&pThis); -} - /* destruct ALL rule sets that reside in the system. This must * be callable before unloading this module as the module may @@ -447,18 +437,29 @@ rulesetDestructForLinkedList(void *pData) * everything runs stable again. -- rgerhards, 2009-06-10 */ static rsRetVal -destructAllActions(void) +destructAllActions(rsconf_t *conf) { DEFiRet; - CHKiRet(llDestroy(&llRulesets)); - CHKiRet(llInit(&llRulesets, rulesetDestructForLinkedList, keyDestruct, strcasecmp)); + CHKiRet(llDestroy(&(conf->rulesets.llRulesets))); + CHKiRet(llInit(&(conf->rulesets.llRulesets), rulesetDestructForLinkedList, rulesetKeyDestruct, strcasecmp)); pDfltRuleset = NULL; finalize_it: RETiRet; } +/* this is a special destructor for the linkedList class. LinkedList does NOT + * provide a pointer to the pointer, but rather the raw pointer itself. So we + * must map this, otherwise the destructor will abort. + */ +rsRetVal +rulesetDestructForLinkedList(void *pData) +{ + ruleset_t *pThis = (ruleset_t*) pData; + return rulesetDestruct(&pThis); +} + /* helper for debugPrint(), initiates rule printing */ DEFFUNC_llExecFunc(doDebugPrintRule) { @@ -480,11 +481,11 @@ DEFFUNC_llExecFunc(doDebugPrintAll) /* debug print all rulesets */ static rsRetVal -debugPrintAll(void) +debugPrintAll(rsconf_t *conf) { DEFiRet; dbgprintf("All Rulesets:\n"); - llExecFunc(&llRulesets, doDebugPrintAll, NULL); + llExecFunc(&(conf->rulesets.llRulesets), doDebugPrintAll, NULL); dbgprintf("End of Rulesets.\n"); RETiRet; } @@ -604,7 +605,6 @@ ENDobjQueryInterface(ruleset) * rgerhards, 2009-04-06 */ BEGINObjClassExit(ruleset, OBJ_IS_CORE_MODULE) /* class, version */ - llDestroy(&llRulesets); objRelease(errmsg, CORE_COMPONENT); objRelease(rule, CORE_COMPONENT); objRelease(parser, CORE_COMPONENT); @@ -624,9 +624,6 @@ BEGINObjClassInit(ruleset, 1, OBJ_IS_CORE_MODULE) /* class, version */ OBJSetMethodHandler(objMethod_DEBUGPRINT, rulesetDebugPrint); OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, rulesetConstructFinalize); - /* prepare global data */ - CHKiRet(llInit(&llRulesets, rulesetDestructForLinkedList, keyDestruct, strcasecmp)); - /* config file handlers */ CHKiRet(regCfSysLineHdlr((uchar *)"rulesetparser", 0, eCmdHdlrGetWord, rulesetAddParser, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"rulesetcreatemainqueue", 0, eCmdHdlrBinary, rulesetCreateQueue, NULL, NULL, eConfObjGlobal)); diff --git a/runtime/ruleset.h b/runtime/ruleset.h index acebd17a..ab60ee07 100644 --- a/runtime/ruleset.h +++ b/runtime/ruleset.h @@ -40,27 +40,35 @@ struct ruleset_s { /* interfaces */ BEGINinterface(ruleset) /* name must also be changed in ENDinterface macro! */ INTERFACEObjDebugPrint(ruleset); - rsRetVal (*DebugPrintAll)(void); + rsRetVal (*DebugPrintAll)(rsconf_t *conf); rsRetVal (*Construct)(ruleset_t **ppThis); - rsRetVal (*ConstructFinalize)(ruleset_t __attribute__((unused)) *pThis); + rsRetVal (*ConstructFinalize)(rsconf_t *conf, ruleset_t __attribute__((unused)) *pThis); rsRetVal (*Destruct)(ruleset_t **ppThis); - rsRetVal (*IterateAllActions)(rsRetVal (*pFunc)(void*, void*), void* pParam); - rsRetVal (*DestructAllActions)(void); - rsRetVal (*AddRule)(ruleset_t *pThis, rule_t **ppRule); - rsRetVal (*SetName)(ruleset_t *pThis, uchar *pszName); + rsRetVal (*IterateAllActions)(rsconf_t *conf, rsRetVal (*pFunc)(void*, void*), void* pParam); + rsRetVal (*DestructAllActions)(rsconf_t *conf); + rsRetVal (*AddRule)(rsconf_t *conf, ruleset_t *pThis, rule_t **ppRule); + rsRetVal (*SetName)(rsconf_t *conf, ruleset_t *pThis, uchar *pszName); rsRetVal (*ProcessBatch)(batch_t*); - rsRetVal (*GetRuleset)(ruleset_t **ppThis, uchar*); - rsRetVal (*SetDefaultRuleset)(uchar*); - rsRetVal (*SetCurrRuleset)(uchar*); + rsRetVal (*GetRuleset)(rsconf_t *conf, ruleset_t **ppThis, uchar*); + rsRetVal (*SetDefaultRuleset)(rsconf_t *conf, uchar*); + rsRetVal (*SetCurrRuleset)(rsconf_t *conf, uchar*); ruleset_t* (*GetCurrent)(void); qqueue_t* (*GetRulesetQueue)(ruleset_t*); /* v3, 2009-11-04 */ parserList_t* (*GetParserList)(msg_t *); + /* v5, 2011-04-19 + * added support for the rsconf object -- fundamental change + */ ENDinterface(ruleset) -#define rulesetCURR_IF_VERSION 4 /* increment whenever you change the interface structure! */ +#define rulesetCURR_IF_VERSION 5 /* increment whenever you change the interface structure! */ /* prototypes */ PROTOTYPEObj(ruleset); +/* TODO: remove these -- currently done dirty for config file + * redo -- rgerhards, 2011-04-19 + */ +rsRetVal rulesetDestructForLinkedList(void *pData); +rsRetVal rulesetKeyDestruct(void __attribute__((unused)) *pData); #endif /* #ifndef INCLUDED_RULESET_H */ diff --git a/runtime/typedefs.h b/runtime/typedefs.h index d79612bc..11cc467d 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -81,6 +81,7 @@ typedef struct strgenList_s strgenList_t; typedef struct statsobj_s statsobj_t; typedef struct nsd_epworkset_s nsd_epworkset_t; typedef struct templates_s templates_t; +typedef struct rulesets_s rulesets_t; typedef struct actions_s actions_t; typedef struct rsconf_s rsconf_t; typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript function */ diff --git a/tools/syslogd.c b/tools/syslogd.c index c01fd6ad..dbc5ec64 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -815,7 +815,7 @@ DEFFUNC_llExecFunc(flushRptdMsgsActions) static void doFlushRptdMsgs(void) { - ruleset.IterateAllActions(flushRptdMsgsActions, NULL); + ruleset.IterateAllActions(ourConf, flushRptdMsgsActions, NULL); } @@ -1026,7 +1026,7 @@ freeAllDynMemForTermination(void) static inline void destructAllActions(void) { - ruleset.DestructAllActions(); + ruleset.DestructAllActions(ourConf); bHaveMainQueue = 0; // flag that internal messages need to be temporarily stored } @@ -1439,7 +1439,7 @@ finalize_it: */ static void dbgPrintInitInfo(void) { - ruleset.DebugPrintAll(); + ruleset.DebugPrintAll(ourConf); DBGPRINTF("\n"); if(bDebugPrintTemplateList) tplPrintList(ourConf); @@ -1614,8 +1614,8 @@ init(void) /* construct the default ruleset */ ruleset.Construct(&pRuleset); - ruleset.SetName(pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset")); - ruleset.ConstructFinalize(pRuleset); + ruleset.SetName(ourConf, pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset")); + ruleset.ConstructFinalize(ourConf, pRuleset); /* open the configuration file */ localRet = conf.processConfFile(ourConf, ConfFile); @@ -1654,7 +1654,7 @@ init(void) } else { DBGPRINTF("error %d obtaining controlling terminal, not using that emergency rule\n", errno); } - ruleset.AddRule(ruleset.GetCurrent(), &pRule); + ruleset.AddRule(ourConf, ruleset.GetCurrent(), &pRule); } legacyOptsHook(); @@ -1758,7 +1758,7 @@ setDefaultRuleset(void __attribute__((unused)) *pVal, uchar *pszName) { DEFiRet; - CHKiRet(ruleset.SetDefaultRuleset(pszName)); + CHKiRet(ruleset.SetDefaultRuleset(ourConf, pszName)); finalize_it: free(pszName); /* no longer needed */ @@ -1797,13 +1797,13 @@ setCurrRuleset(void __attribute__((unused)) *pVal, uchar *pszName) rsRetVal localRet; DEFiRet; - localRet = ruleset.SetCurrRuleset(pszName); + localRet = ruleset.SetCurrRuleset(ourConf, pszName); if(localRet == RS_RET_NOT_FOUND) { DBGPRINTF("begin new current rule set '%s'\n", pszName); CHKiRet(ruleset.Construct(&pRuleset)); - CHKiRet(ruleset.SetName(pRuleset, pszName)); - CHKiRet(ruleset.ConstructFinalize(pRuleset)); + CHKiRet(ruleset.SetName(ourConf, pRuleset, pszName)); + CHKiRet(ruleset.ConstructFinalize(ourConf, pRuleset)); } else { ABORT_FINALIZE(localRet); } @@ -1913,7 +1913,7 @@ doHUP(void) logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, (uchar*)buf, 0); } - ruleset.IterateAllActions(doHUPActions, NULL); + ruleset.IterateAllActions(ourConf, doHUPActions, NULL); } -- cgit v1.2.3 From 542fd3300671a2480ff009e060b32f08fed44b4d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Apr 2011 12:37:39 +0200 Subject: some more work was required on the ruleset modification --- runtime/conf.c | 2 +- runtime/parser.c | 2 +- runtime/rsconf.h | 4 ++++ runtime/ruleset.c | 57 +++++++++++++++++++++++++++++++------------------------ runtime/ruleset.h | 4 ++-- tools/syslogd.c | 2 +- 6 files changed, 41 insertions(+), 30 deletions(-) diff --git a/runtime/conf.c b/runtime/conf.c index 90b1b487..8e05609d 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -1184,7 +1184,7 @@ cflineClassic(rsconf_t *conf, uchar *p, rule_t **ppRule) CHKiRet(ruleset.AddRule(conf, rule.GetAssRuleset(*ppRule), ppRule)); } CHKiRet(rule.Construct(ppRule)); /* create "fresh" selector */ - CHKiRet(rule.SetAssRuleset(*ppRule, ruleset.GetCurrent())); /* create "fresh" selector */ + CHKiRet(rule.SetAssRuleset(*ppRule, ruleset.GetCurrent(conf))); /* create "fresh" selector */ CHKiRet(rule.ConstructFinalize(*ppRule)); /* create "fresh" selector */ CHKiRet(cflineDoFilter(&p, *ppRule)); /* pull filters */ } diff --git a/runtime/parser.c b/runtime/parser.c index 2e991a9d..14ccb49a 100644 --- a/runtime/parser.c +++ b/runtime/parser.c @@ -496,7 +496,7 @@ ParseMsg(msg_t *pMsg) * will cause it to happen. After that, access to the unsanitized message is no * loger possible. */ - pParserList = ruleset.GetParserList(pMsg); + pParserList = ruleset.GetParserList(ourConf, pMsg); if(pParserList == NULL) { pParserList = pDfltParsLst; } diff --git a/runtime/rsconf.h b/runtime/rsconf.h index 4fd160a4..32488d08 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -44,6 +44,10 @@ struct actions_s { struct rulesets_s { linkedList_t llRulesets; /* this is NOT a pointer - no typo here ;) */ + + /* support for legacy rsyslog.conf format */ + ruleset_t *pCurr; /* currently "active" ruleset */ + ruleset_t *pDflt; /* current default ruleset, e.g. for binding to actions which have no other */ }; diff --git a/runtime/ruleset.c b/runtime/ruleset.c index 71fd76da..d472a560 100644 --- a/runtime/ruleset.c +++ b/runtime/ruleset.c @@ -34,7 +34,6 @@ #include "config.h" #include -////#include #include #include @@ -57,9 +56,6 @@ DEFobjCurrIf(errmsg) DEFobjCurrIf(rule) DEFobjCurrIf(parser) -ruleset_t *pCurrRuleset = NULL; /* currently "active" ruleset */ -ruleset_t *pDfltRuleset = NULL; /* current default ruleset, e.g. for binding to actions which have no other */ - /* forward definitions */ static rsRetVal processBatch(batch_t *pBatch); @@ -228,7 +224,7 @@ processBatch(batch_t *pBatch) if(pBatch->bSingleRuleset) { pThis = batchGetRuleset(pBatch); if(pThis == NULL) - pThis = pDfltRuleset; + pThis = ourConf->rulesets.pDflt; ISOBJ_TYPE_assert(pThis, ruleset); CHKiRet(llExecFunc(&pThis->llRules, processBatchDoRules, pBatch)); } else { @@ -246,9 +242,9 @@ finalize_it: * rgerhards, 2009-11-04 */ static parserList_t* -GetParserList(msg_t *pMsg) +GetParserList(rsconf_t *conf, msg_t *pMsg) { - return (pMsg->pRuleset == NULL) ? pDfltRuleset->pParserLst : pMsg->pRuleset->pParserLst; + return (pMsg->pRuleset == NULL) ? conf->rulesets.pDflt->pParserLst : pMsg->pRuleset->pParserLst; } @@ -295,9 +291,9 @@ finalize_it: * is really much more natural to return the pointer directly. */ static ruleset_t* -GetCurrent(void) +GetCurrent(rsconf_t *conf) { - return pCurrRuleset; + return conf->rulesets.pCurr; } @@ -340,7 +336,7 @@ SetDefaultRuleset(rsconf_t *conf, uchar *pszName) assert(pszName != NULL); CHKiRet(GetRuleset(conf, &pRuleset, pszName)); - pDfltRuleset = pRuleset; + conf->rulesets.pDflt = pRuleset; dbgprintf("default rule set changed to %p: '%s'\n", pRuleset, pszName); finalize_it: @@ -358,7 +354,7 @@ SetCurrRuleset(rsconf_t *conf, uchar *pszName) assert(pszName != NULL); CHKiRet(GetRuleset(conf, &pRuleset, pszName)); - pCurrRuleset = pRuleset; + conf->rulesets.pCurr = pRuleset; dbgprintf("current rule set changed to %p: '%s'\n", pRuleset, pszName); finalize_it: @@ -404,11 +400,11 @@ rulesetConstructFinalize(rsconf_t *conf, ruleset_t *pThis) CHKiRet(llAppend(&(conf->rulesets.llRulesets), keyName, pThis)); /* this now also is the new current ruleset */ - pCurrRuleset = pThis; + conf->rulesets.pCurr = pThis; /* and also the default, if so far none has been set */ - if(pDfltRuleset == NULL) - pDfltRuleset = pThis; + if(conf->rulesets.pDflt == NULL) + conf->rulesets.pDflt = pThis; finalize_it: RETiRet; @@ -443,7 +439,7 @@ destructAllActions(rsconf_t *conf) CHKiRet(llDestroy(&(conf->rulesets.llRulesets))); CHKiRet(llInit(&(conf->rulesets.llRulesets), rulesetDestructForLinkedList, rulesetKeyDestruct, strcasecmp)); - pDfltRuleset = NULL; + conf->rulesets.pDflt = NULL; finalize_it: RETiRet; @@ -498,18 +494,18 @@ debugPrintAll(rsconf_t *conf) * considered acceptable for the time being. * rgerhards, 2009-10-27 */ -static rsRetVal -rulesetCreateQueue(void __attribute__((unused)) *pVal, int *pNewVal) +static inline rsRetVal +doRulesetCreateQueue(rsconf_t *conf, int *pNewVal) { DEFiRet; - if(pCurrRuleset == NULL) { + if(conf->rulesets.pCurr == NULL) { errmsg.LogError(0, RS_RET_NO_CURR_RULESET, "error: currently no specific ruleset specified, thus a " "queue can not be added to it"); ABORT_FINALIZE(RS_RET_NO_CURR_RULESET); } - if(pCurrRuleset->pQueue != NULL) { + if(conf->rulesets.pCurr->pQueue != NULL) { errmsg.LogError(0, RS_RET_RULES_QUEUE_EXISTS, "error: ruleset already has a main queue, can not " "add another one"); ABORT_FINALIZE(RS_RET_RULES_QUEUE_EXISTS); @@ -519,12 +515,17 @@ rulesetCreateQueue(void __attribute__((unused)) *pVal, int *pNewVal) FINALIZE; /* if it is turned off, we do not need to change anything ;) */ dbgprintf("adding a ruleset-specific \"main\" queue"); - CHKiRet(createMainQueue(&pCurrRuleset->pQueue, UCHAR_CONSTANT("ruleset"))); + CHKiRet(createMainQueue(&conf->rulesets.pCurr->pQueue, UCHAR_CONSTANT("ruleset"))); finalize_it: RETiRet; } +static rsRetVal +rulesetCreateQueue(void __attribute__((unused)) *pVal, int *pNewVal) +{ + return doRulesetCreateQueue(ourConf, pNewVal); +} /* Add a ruleset specific parser to the ruleset. Note that adding the first * parser automatically disables the default parsers. If they are needed as well, @@ -536,12 +537,12 @@ finalize_it: * rgerhards, 2009-11-04 */ static rsRetVal -rulesetAddParser(void __attribute__((unused)) *pVal, uchar *pName) +doRulesetAddParser(rsconf_t *conf, uchar *pName) { parser_t *pParser; DEFiRet; - assert(pCurrRuleset != NULL); + assert(conf->rulesets.pCurr != NULL); CHKiRet(objUse(parser, CORE_COMPONENT)); iRet = parser.FindParser(&pParser, pName); @@ -554,10 +555,10 @@ rulesetAddParser(void __attribute__((unused)) *pVal, uchar *pName) FINALIZE; } - CHKiRet(parser.AddParserToList(&pCurrRuleset->pParserLst, pParser)); + CHKiRet(parser.AddParserToList(&conf->rulesets.pCurr->pParserLst, pParser)); - dbgprintf("added parser '%s' to ruleset '%s'\n", pName, pCurrRuleset->pszName); -RUNLOG_VAR("%p", pCurrRuleset->pParserLst); + dbgprintf("added parser '%s' to ruleset '%s'\n", pName, conf->rulesets.pCurr->pszName); +RUNLOG_VAR("%p", conf->rulesets.pCurr->pParserLst); finalize_it: d_free(pName); /* no longer needed */ @@ -565,6 +566,12 @@ finalize_it: RETiRet; } +static rsRetVal +rulesetAddParser(void __attribute__((unused)) *pVal, uchar *pName) +{ + return doRulesetAddParser(ourConf, pName); +} + /* queryInterface function * rgerhards, 2008-02-21 diff --git a/runtime/ruleset.h b/runtime/ruleset.h index ab60ee07..8966a884 100644 --- a/runtime/ruleset.h +++ b/runtime/ruleset.h @@ -52,10 +52,10 @@ BEGINinterface(ruleset) /* name must also be changed in ENDinterface macro! */ rsRetVal (*GetRuleset)(rsconf_t *conf, ruleset_t **ppThis, uchar*); rsRetVal (*SetDefaultRuleset)(rsconf_t *conf, uchar*); rsRetVal (*SetCurrRuleset)(rsconf_t *conf, uchar*); - ruleset_t* (*GetCurrent)(void); + ruleset_t* (*GetCurrent)(rsconf_t *conf); qqueue_t* (*GetRulesetQueue)(ruleset_t*); /* v3, 2009-11-04 */ - parserList_t* (*GetParserList)(msg_t *); + parserList_t* (*GetParserList)(rsconf_t *conf, msg_t *); /* v5, 2011-04-19 * added support for the rsconf object -- fundamental change */ diff --git a/tools/syslogd.c b/tools/syslogd.c index dbc5ec64..72fb04d5 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -1654,7 +1654,7 @@ init(void) } else { DBGPRINTF("error %d obtaining controlling terminal, not using that emergency rule\n", errno); } - ruleset.AddRule(ourConf, ruleset.GetCurrent(), &pRule); + ruleset.AddRule(ourConf, ruleset.GetCurrent(ourConf), &pRule); } legacyOptsHook(); -- cgit v1.2.3 From 28e750eebd8ccb5655bdc18693b3b7c9d9ad826b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Apr 2011 14:58:31 +0200 Subject: step: slowly migrating config settings... ;) --- runtime/cfsysline.c | 10 +++++++ runtime/rsconf.c | 35 +++++++++++++++++++++++- runtime/rsconf.h | 38 ++++++++++++++++++++++++-- runtime/rsyslog.h | 1 + runtime/typedefs.h | 5 +++- tools/syslogd.c | 79 +++++++++++++++++------------------------------------ 6 files changed, 110 insertions(+), 58 deletions(-) diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c index 97b35bb2..2475c270 100644 --- a/runtime/cfsysline.c +++ b/runtime/cfsysline.c @@ -586,6 +586,13 @@ doFacility(uchar **pp, rsRetVal (*pSetHdlr)(void*, int), void *pVal) } +static rsRetVal +doGoneAway(uchar **pp, rsRetVal (*pSetHdlr)(void*, int), void *pVal) +{ + errmsg.LogError(0, RS_RET_CMD_GONE_AWAY, "config directive is no longer supported -- ignored"); + return RS_RET_CMD_GONE_AWAY; +} + /* Implements the severity syntax. * rgerhards, 2008-02-14 */ @@ -717,6 +724,9 @@ static rsRetVal cslchCallHdlr(cslCmdHdlr_t *pThis, uchar **ppConfLine) case eCmdHdlrGetWord: pHdlr = doGetWord; break; + case eCmdHdlrGoneAway: + pHdlr = doGoneAway; + break; default: iRet = RS_RET_NOT_IMPLEMENTED; goto finalize_it; diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 27d89fb6..d68420bf 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -2,7 +2,7 @@ * * Module begun 2011-04-19 by Rainer Gerhards * - * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH. + * Copyright 2011 by Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -33,15 +33,24 @@ #include "obj.h" #include "srUtils.h" #include "ruleset.h" +#include "modules.h" #include "rsconf.h" +#include "cfsysline.h" /* static data */ DEFobjStaticHelpers +DEFobjCurrIf(ruleset) +DEFobjCurrIf(module) /* Standard-Constructor */ BEGINobjConstruct(rsconf) /* be sure to specify the object type also in END macro! */ + pThis->globals.bDebugPrintTemplateList = 1; + pThis->globals.bDebugPrintModuleList = 1; + pThis->globals.bDebugPrintCfSysLineHandlerList = 1; + pThis->globals.bLogStatusMsgs = DFLT_bLogStatusMsgs; + pThis->globals.bErrMsgToStderr = 1; pThis->templates.root = NULL; pThis->templates.last = NULL; pThis->templates.lastStatic = NULL; @@ -71,6 +80,26 @@ ENDobjDestruct(rsconf) /* DebugPrint support for the rsconf object */ BEGINobjDebugPrint(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */ + dbgprintf("configuration object %p\n", pThis); + dbgprintf("Global Settings:\n"); + dbgprintf(" bDebugPrintTemplateList.............: %d\n", + pThis->globals.bDebugPrintTemplateList); + dbgprintf(" bDebugPrintModuleList : %d\n", + pThis->globals.bDebugPrintModuleList); + dbgprintf(" bDebugPrintCfSysLineHandlerList.....: %d\n", + pThis->globals.bDebugPrintCfSysLineHandlerList); + dbgprintf(" bLogStatusMsgs : %d\n", + pThis->globals.bLogStatusMsgs); + dbgprintf(" bErrMsgToStderr.....................: %d\n", + pThis->globals.bErrMsgToStderr); + ruleset.DebugPrintAll(pThis); + DBGPRINTF("\n"); + if(pThis->globals.bDebugPrintTemplateList) + tplPrintList(pThis); + if(pThis->globals.bDebugPrintModuleList) + module.PrintList(); + if(pThis->globals.bDebugPrintCfSysLineHandlerList) + dbgPrintCfSysLineHandlers(); CODESTARTobjDebugPrint(rsconf) ENDobjDebugPrint(rsconf) @@ -102,6 +131,8 @@ ENDobjQueryInterface(rsconf) */ BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ + CHKiRet(objUse(ruleset, CORE_COMPONENT)); + CHKiRet(objUse(module, CORE_COMPONENT)); /* now set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, rsconfDebugPrint); @@ -112,6 +143,8 @@ ENDObjClassInit(rsconf) /* De-initialize the rsconf class. */ BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */ + objRelease(ruleset, CORE_COMPONENT); + objRelease(module, CORE_COMPONENT); ENDObjClassExit(rsconf) /* vi:set ai: diff --git a/runtime/rsconf.h b/runtime/rsconf.h index 32488d08..68325852 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -27,9 +27,32 @@ /* --- configuration objects (the plan is to have ALL upper layers in this file) --- */ -/* the following structure is a container for all known templates - * inside a specific configuration. -- rgerhards 2011-04-19 +/* globals are data items that are really global, and can be set only + * once (at least in theory, because the legacy system permits them to + * be re-set as often as the user likes). */ +struct globals_s { + int bDebugPrintTemplateList; + int bDebugPrintModuleList; + int bDebugPrintCfSysLineHandlerList; + int bLogStatusMsgs; /* log rsyslog start/stop/HUP messages? */ + int bErrMsgToStderr; /* print error messages to stderr (in addition to everything else)? */ +}; + +/* (global) defaults are global in the sense that they are accessible + * to all code, but they can change value and other objects (like + * actions) actually copy the value a global had at the time the action + * was defined. In that sense, a global default is just that, a default, + * wich can (and will) be changed in the course of config file + * processing. Once the config file has been processed, defaults + * can be dropped. The current code does not do this for simplicity. + * That is not a problem, because the defaults do not take up much memory. + * At a later stage, we may think about dropping them. -- rgerhards, 2011-04-19 + */ +struct defaults_s { +}; + + struct templates_s { struct template *root; /* the root of the template list */ struct template *last; /* points to the last element of the template list */ @@ -56,9 +79,17 @@ struct rulesets_s { /* the rsconf object */ struct rsconf_s { BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ + globals_t globals; + defaults_t defaults; templates_t templates; actions_t actions; rulesets_t rulesets; + /* note: rulesets include the complete output part: + * - rules + * - filter (as part of the action) + * - actions + * Of course, we need to debate if we shall change that some time... + */ }; @@ -75,4 +106,7 @@ ENDinterface(rsconf) /* prototypes */ PROTOTYPEObj(rsconf); +/* some defaults (to be removed?) */ +#define DFLT_bLogStatusMsgs 1 + #endif /* #ifndef INCLUDED_RSCONF_H */ diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 78841410..fcc0d626 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -354,6 +354,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_ERR_LIBEE_INIT = -2201, /**< cannot obtain libee ctx */ RS_RET_ERR_LIBLOGNORM_INIT = -2202,/**< cannot obtain liblognorm ctx */ RS_RET_ERR_LIBLOGNORM_SAMPDB_LOAD = -2203,/**< liblognorm sampledb load failed */ + RS_RET_CMD_GONE_AWAY = -2204,/**< config directive existed, but no longer supported */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/runtime/typedefs.h b/runtime/typedefs.h index 11cc467d..e46f509b 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -82,6 +82,8 @@ typedef struct statsobj_s statsobj_t; typedef struct nsd_epworkset_s nsd_epworkset_t; typedef struct templates_s templates_t; typedef struct rulesets_s rulesets_t; +typedef struct globals_s globals_t; +typedef struct defaults_s defaults_t; typedef struct actions_s actions_t; typedef struct rsconf_s rsconf_t; typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript function */ @@ -150,7 +152,8 @@ typedef enum cslCmdHdlrType { eCmdHdlrGetChar, eCmdHdlrFacility, eCmdHdlrSeverity, - eCmdHdlrGetWord + eCmdHdlrGetWord, + eCmdHdlrGoneAway /* statment existed, but is no longer supported */ } ecslCmdHdrlType; diff --git a/tools/syslogd.c b/tools/syslogd.c index 72fb04d5..e0e5868b 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -238,12 +238,6 @@ legacyOptsLL_t *pLegacyOptsLL = NULL; int iCompatibilityMode = 0; /* version we should be compatible with; 0 means sysklogd. It is the default, so if no -c option is given, we make ourselvs as compatible to sysklogd as possible. */ -#define DFLT_bLogStatusMsgs 1 -static int bLogStatusMsgs = DFLT_bLogStatusMsgs; /* log rsyslog start/stop/HUP messages? */ -static int bDebugPrintTemplateList = 1;/* output template list in debug mode? */ -static int bDebugPrintCfSysLineHandlerList = 1;/* output cfsyslinehandler list in debug mode? */ -static int bDebugPrintModuleList = 1;/* output module list in debug mode? */ -static int bErrMsgToStderr = 1; /* print error messages to stderr (in addition to everything else)? */ int bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */ int bAbortOnUncleanConfig = 0; /* abort run (rather than starting with partial config) if there was any issue in conf */ /* end global config file state variables */ @@ -292,10 +286,10 @@ static int iMainMsgQueueDeqtWinToHr = 25; /* hour begin of time frame when que */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { - bLogStatusMsgs = DFLT_bLogStatusMsgs; - bDebugPrintTemplateList = 1; - bDebugPrintCfSysLineHandlerList = 1; - bDebugPrintModuleList = 1; + ourConf->globals.bLogStatusMsgs = DFLT_bLogStatusMsgs; + ourConf->globals.bDebugPrintTemplateList = 1; + ourConf->globals.bDebugPrintCfSysLineHandlerList = 1; + ourConf->globals.bDebugPrintModuleList = 1; bReduceRepeatMsgs = 0; bAbortOnUncleanConfig = 0; free(pszMainMsgQFName); @@ -569,7 +563,7 @@ logmsgInternal(int iErr, int pri, uchar *msg, int flags) * permits us to process unmodified config files which otherwise contain a * supressor statement. */ - if(((Debug == DEBUG_FULL || NoFork) && bErrMsgToStderr) || iConfigVerify) { + if(((Debug == DEBUG_FULL || NoFork) && ourConf->globals.bErrMsgToStderr) || iConfigVerify) { if(LOG_PRI(pri) == LOG_ERR) fprintf(stderr, "rsyslogd: %s\n", msg); } @@ -1064,7 +1058,7 @@ die(int sig) thrdTerminateAll(); /* and THEN send the termination log message (see long comment above) */ - if(sig && bLogStatusMsgs) { + if(sig && ourConf->globals.bLogStatusMsgs) { (void) snprintf(buf, sizeof(buf) / sizeof(char), " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \ "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"]" " exiting on signal %d.", @@ -1439,17 +1433,10 @@ finalize_it: */ static void dbgPrintInitInfo(void) { - ruleset.DebugPrintAll(ourConf); - DBGPRINTF("\n"); - if(bDebugPrintTemplateList) - tplPrintList(ourConf); - if(bDebugPrintModuleList) - module.PrintList(); + dbgprintf("The following is the old-style, to-be-replaced, current config dump at the end " + " of the config load process ;)\n"); ochPrintList(); - if(bDebugPrintCfSysLineHandlerList) - dbgPrintCfSysLineHandlers(); - DBGPRINTF("Messages with malicious PTR DNS Records are %sdropped.\n", glbl.GetDropMalPTRMsgs() ? "" : "not "); @@ -1621,6 +1608,9 @@ init(void) localRet = conf.processConfFile(ourConf, ConfFile); CHKiRet(conf.GetNbrActActions(ourConf, &iNbrActions)); + dbgprintf("rsyslog finished loading initial config %p\n", ourConf); + rsconf.DebugPrint(ourConf); + if(localRet != RS_RET_OK) { errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", ConfFile); bHadConfigErr = 1; @@ -1736,7 +1726,7 @@ init(void) /* we now generate the startup message. It now includes everything to * identify this instance. -- rgerhards, 2005-08-17 */ - if(bLogStatusMsgs) { + if(ourConf->globals.bLogStatusMsgs) { snprintf(bufStartUpMsg, sizeof(bufStartUpMsg)/sizeof(char), " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \ "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] start", @@ -1766,25 +1756,6 @@ finalize_it: } - -/* Put the rsyslog main thread to sleep for n seconds. This was introduced as - * a quick and dirty workaround for a privilege drop race in regard to listener - * startup, which itself was a result of the not-yet-done proper coding of - * privilege drop code (quite some effort). It may be useful for other occasions, too. - * is specified). - * rgerhards, 2009-06-12 - */ -static rsRetVal -putToSleep(void __attribute__((unused)) *pVal, int iNewVal) -{ - DEFiRet; - DBGPRINTF("rsyslog main thread put to sleep via $sleep %d directive...\n", iNewVal); - srSleep(iNewVal, 0); - DBGPRINTF("rsyslog main thread continues after $sleep %d\n", iNewVal); - RETiRet; -} - - /* Switch to either an already existing rule set or start a new one. The * named rule set becomes the new "current" rule set (what means that new * actions are added to it). @@ -1904,7 +1875,7 @@ doHUP(void) { char buf[512]; - if(bLogStatusMsgs) { + if(ourConf->globals.bLogStatusMsgs) { snprintf(buf, sizeof(buf) / sizeof(char), " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"] rsyslogd was HUPed", @@ -2026,7 +1997,7 @@ doIncludeLine(void *pVal, uchar *pNewVal) /* load build-in modules * very first version begun on 2007-07-23 by rgerhards */ -static rsRetVal loadBuildInModules(void) +static rsRetVal loadBuildInModules(rsconf_t *config) { DEFiRet; @@ -2080,10 +2051,10 @@ static rsRetVal loadBuildInModules(void) * is that rsyslog will terminate if we can not register our built-in config commands. * This, I think, is the right thing to do. -- rgerhards, 2007-07-31 */ - CHKiRet(regCfSysLineHdlr((uchar *)"logrsyslogstatusmessages", 0, eCmdHdlrBinary, NULL, &bLogStatusMsgs, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"logrsyslogstatusmessages", 0, eCmdHdlrBinary, NULL, &ourConf->globals.bLogStatusMsgs, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, setDefaultRuleset, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord, setCurrRuleset, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrInt, putToSleep, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrGoneAway, NULL, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszMainMsgQFName, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt, NULL, &iMainMsgQueueSize, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQHighWtrMark, NULL, eConfObjGlobal)); @@ -2116,14 +2087,14 @@ static rsRetVal loadBuildInModules(void) CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, doIncludeLine, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode, setUmask, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"maxopenfiles", 0, eCmdHdlrInt, setMaxFiles, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"debugprinttemplatelist", 0, eCmdHdlrBinary, NULL, &bDebugPrintTemplateList, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"debugprintmodulelist", 0, eCmdHdlrBinary, NULL, &bDebugPrintModuleList, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"debugprinttemplatelist", 0, eCmdHdlrBinary, NULL, &(config->globals.bDebugPrintTemplateList), NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"debugprintmodulelist", 0, eCmdHdlrBinary, NULL, &(config->globals.bDebugPrintModuleList), NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"debugprintcfsyslinehandlerlist", 0, eCmdHdlrBinary, - NULL, &bDebugPrintCfSysLineHandlerList, NULL, eConfObjGlobal)); + NULL, &(config->globals.bDebugPrintCfSysLineHandlerList), NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"moddir", 0, eCmdHdlrGetWord, NULL, &pModDir, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"generateconfiggraph", 0, eCmdHdlrGetWord, NULL, &pszConfDAGFile, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary, NULL, &bErrMsgToStderr, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary, NULL, &ourConf->globals.bErrMsgToStderr, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, setMaxMsgSize, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouser", 0, eCmdHdlrUID, NULL, &uidDropPriv, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouserid", 0, eCmdHdlrInt, NULL, &uidDropPriv, NULL, eConfObjGlobal)); @@ -2189,9 +2160,6 @@ static rsRetVal mainThread() DEFiRet; uchar *pTmp; - /* we need to init the config object first! */ - CHKiRet(rsconf.Construct(&ourConf)); - /* initialize the build-in templates */ pTmp = template_DebugFormat; tplAddLine(ourConf, "RSYSLOG_DebugFormat", &pTmp); @@ -2260,7 +2228,7 @@ static rsRetVal mainThread() if(!(Debug == DEBUG_FULL || NoFork)) { close(1); close(2); - bErrMsgToStderr = 0; + ourConf->globals.bErrMsgToStderr = 0; } mainloop(); @@ -2743,6 +2711,9 @@ int realMain(int argc, char **argv) for(p = LocalDomain ; *p ; p++) *p = (char)tolower((int)*p); + /* we need to init the config object first! */ + CHKiRet(rsconf.Construct(&ourConf)); + /* we now have our hostname and can set it inside the global vars. * TODO: think if all of this would better be a runtime function * rgerhards, 2008-04-17 @@ -2758,7 +2729,7 @@ int realMain(int argc, char **argv) exit(1); /* "good" exit, leaving at init for fatal error */ } - if((iRet = loadBuildInModules()) != RS_RET_OK) { + if((iRet = loadBuildInModules(ourConf)) != RS_RET_OK) { fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n", iRet); exit(1); /* "good" exit, leaving at init for fatal error */ -- cgit v1.2.3 From 82fa17ae5621849790eb39ed046d58333ede347c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Apr 2011 11:37:26 +0200 Subject: step: begun to create a "load" interface in rsconf --- runtime/rsconf.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- runtime/rsconf.h | 10 ++++- tools/syslogd.c | 42 ++++++++++-------- 3 files changed, 160 insertions(+), 21 deletions(-) diff --git a/runtime/rsconf.c b/runtime/rsconf.c index d68420bf..1f7a46c3 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -28,20 +28,29 @@ #include #include #include +#include #include "rsyslog.h" #include "obj.h" #include "srUtils.h" #include "ruleset.h" #include "modules.h" +#include "conf.h" #include "rsconf.h" #include "cfsysline.h" +#include "errmsg.h" +#include "unicode-helper.h" /* static data */ DEFobjStaticHelpers DEFobjCurrIf(ruleset) DEFobjCurrIf(module) +DEFobjCurrIf(conf) +DEFobjCurrIf(errmsg) +/* exported static data */ +rsconf_t *runConf = NULL;/* the currently running config */ +rsconf_t *loadConf = NULL;/* the config currently being loaded (no concurrent config load supported!) */ /* Standard-Constructor */ @@ -61,7 +70,6 @@ ENDobjConstruct(rsconf) /* ConstructionFinalizer - * rgerhards, 2008-01-09 */ rsRetVal rsconfConstructFinalize(rsconf_t __attribute__((unused)) *pThis) { @@ -104,6 +112,119 @@ CODESTARTobjDebugPrint(rsconf) ENDobjDebugPrint(rsconf) +/* Activate an already-loaded configuration. The configuration will become + * the new running conf (if successful). Note that in theory this method may + * be called when there already is a running conf. In practice, the current + * version of rsyslog does not support this. Future versions probably will. + * Begun 2011-04-20, rgerhards + */ +rsRetVal +activate(rsconf_t *cnf) +{ + DEFiRet; + runConf = cnf; + dbgprintf("configuration %p activated\n", cnf); + RETiRet; +} + + +/* intialize the legacy config system */ +static inline rsRetVal +initLegacyConf(void) +{ + DEFiRet; + ruleset_t *pRuleset; + + /* construct the default ruleset */ + ruleset.Construct(&pRuleset); + ruleset.SetName(loadConf, pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset")); + ruleset.ConstructFinalize(loadConf, pRuleset); + + RETiRet; +} + + +/* Load a configuration. This will do all necessary steps to create + * the in-memory representation of the configuration, including support + * for multiple configuration languages. + * Note that to support the legacy language we must provide some global + * object that holds the currently-being-loaded config ptr. + * Begun 2011-04-20, rgerhards + */ +rsRetVal +load(rsconf_t **cnf, uchar *confFile) +{ + rsRetVal localRet; + int iNbrActions; + int bHadConfigErr = 0; + char cbuf[BUFSIZ]; + DEFiRet; + + CHKiRet(rsconfConstruct(&loadConf)); +ourConf = loadConf; // TODO: remove, once ourConf is gone! + + CHKiRet(initLegacyConf()); + +#if 0 +dbgprintf("XXXX: 2, conf=%p\n", conf.processConfFile); + /* open the configuration file */ + localRet = conf.processConfFile(loadConf, confFile); + CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions)); + +dbgprintf("XXXX: 4\n"); + if(localRet != RS_RET_OK) { + errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", confFile); + bHadConfigErr = 1; + } else if(iNbrActions == 0) { + errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no active actions configured. Inputs will " + "run, but no output whatsoever is created."); + bHadConfigErr = 1; + } + +dbgprintf("XXXX: 10\n"); + if((localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) || iNbrActions == 0) { + +dbgprintf("XXXX: 20\n"); + /* rgerhards: this code is executed to set defaults when the + * config file could not be opened. We might think about + * abandoning the run in this case - but this, too, is not + * very clever... So we stick with what we have. + * We ignore any errors while doing this - we would be lost anyhow... + */ + errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!"); + + /* note: we previously used _POSIY_TTY_NAME_MAX+1, but this turned out to be + * too low on linux... :-S -- rgerhards, 2008-07-28 + */ + char szTTYNameBuf[128]; + rule_t *pRule = NULL; /* initialization to NULL is *vitally* important! */ + conf.cfline(loadConf, UCHAR_CONSTANT("*.ERR\t" _PATH_CONSOLE), &pRule); + conf.cfline(loadConf, UCHAR_CONSTANT("syslog.*\t" _PATH_CONSOLE), &pRule); + conf.cfline(loadConf, UCHAR_CONSTANT("*.PANIC\t*"), &pRule); + conf.cfline(loadConf, UCHAR_CONSTANT("syslog.*\troot"), &pRule); + if(ttyname_r(0, szTTYNameBuf, sizeof(szTTYNameBuf)) == 0) { + snprintf(cbuf,sizeof(cbuf), "*.*\t%s", szTTYNameBuf); + conf.cfline(loadConf, (uchar*)cbuf, &pRule); + } else { + DBGPRINTF("error %d obtaining controlling terminal, not using that emergency rule\n", errno); + } + ruleset.AddRule(loadConf, ruleset.GetCurrent(loadConf), &pRule); + } + +#endif + + + /* all OK, pass loaded conf to caller */ + *cnf = loadConf; + loadConf = NULL; + + dbgprintf("rsyslog finished loading initial config %p\n", loadConf); +// rsconfDebugPrint(loadConf); + +finalize_it: + RETiRet; +} + /* queryInterface function */ @@ -122,6 +243,8 @@ CODESTARTobjQueryInterface(rsconf) pIf->ConstructFinalize = rsconfConstructFinalize; pIf->Destruct = rsconfDestruct; pIf->DebugPrint = rsconfDebugPrint; + pIf->Load = load; + pIf->Activate = activate; finalize_it: ENDobjQueryInterface(rsconf) @@ -133,6 +256,8 @@ BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ CHKiRet(objUse(ruleset, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); + CHKiRet(objUse(conf, CORE_COMPONENT)); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); /* now set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, rsconfDebugPrint); @@ -145,6 +270,8 @@ ENDObjClassInit(rsconf) BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */ objRelease(ruleset, CORE_COMPONENT); objRelease(module, CORE_COMPONENT); + objRelease(conf, CORE_COMPONENT); + objRelease(errmsg, CORE_COMPONENT); ENDObjClassExit(rsconf) /* vi:set ai: diff --git a/runtime/rsconf.h b/runtime/rsconf.h index 68325852..3302e990 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -99,13 +99,21 @@ BEGINinterface(rsconf) /* name must also be changed in ENDinterface macro! */ rsRetVal (*Construct)(rsconf_t **ppThis); rsRetVal (*ConstructFinalize)(rsconf_t __attribute__((unused)) *pThis); rsRetVal (*Destruct)(rsconf_t **ppThis); + rsRetVal (*Load)(rsconf_t **ppThis, uchar *confFile); + rsRetVal (*Activate)(rsconf_t *ppThis); ENDinterface(rsconf) -#define rsconfCURR_IF_VERSION 1 /* increment whenever you change the interface above! */ +// TODO: switch version to 1 for first "complete" version!!!! 2011-04-20 +#define rsconfCURR_IF_VERSION 0 /* increment whenever you change the interface above! */ /* prototypes */ PROTOTYPEObj(rsconf); +/* globally-visible external data */ +extern rsconf_t *runConf;/* the currently running config */ +extern rsconf_t *loadConf;/* the config currently being loaded (no concurrent config load supported!) */ + + /* some defaults (to be removed?) */ #define DFLT_bLogStatusMsgs 1 diff --git a/tools/syslogd.c b/tools/syslogd.c index e0e5868b..1cf0b894 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -563,7 +563,7 @@ logmsgInternal(int iErr, int pri, uchar *msg, int flags) * permits us to process unmodified config files which otherwise contain a * supressor statement. */ - if(((Debug == DEBUG_FULL || NoFork) && ourConf->globals.bErrMsgToStderr) || iConfigVerify) { + if(((Debug == DEBUG_FULL || NoFork) && runConf->globals.bErrMsgToStderr) || iConfigVerify) { if(LOG_PRI(pri) == LOG_ERR) fprintf(stderr, "rsyslogd: %s\n", msg); } @@ -809,7 +809,7 @@ DEFFUNC_llExecFunc(flushRptdMsgsActions) static void doFlushRptdMsgs(void) { - ruleset.IterateAllActions(ourConf, flushRptdMsgsActions, NULL); + ruleset.IterateAllActions(runConf, flushRptdMsgsActions, NULL); } @@ -1020,7 +1020,7 @@ freeAllDynMemForTermination(void) static inline void destructAllActions(void) { - ruleset.DestructAllActions(ourConf); + ruleset.DestructAllActions(runConf); bHaveMainQueue = 0; // flag that internal messages need to be temporarily stored } @@ -1058,7 +1058,8 @@ die(int sig) thrdTerminateAll(); /* and THEN send the termination log message (see long comment above) */ - if(sig && ourConf->globals.bLogStatusMsgs) { +dbgprintf("XXXX: runConf %p\n", runConf); + if(sig && runConf->globals.bLogStatusMsgs) { (void) snprintf(buf, sizeof(buf) / sizeof(char), " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \ "\" x-pid=\"%d\" x-info=\"http://www.rsyslog.com\"]" " exiting on signal %d.", @@ -1085,7 +1086,7 @@ die(int sig) * ourselfs, this makes finding memory leaks a lot * easier. */ - tplDeleteAll(ourConf); + tplDeleteAll(runConf); /* de-init some modules */ modExitIminternal(); @@ -1598,11 +1599,7 @@ init(void) DEFiRet; DBGPRINTF("rsyslog %s - called init()\n", VERSION); - - /* construct the default ruleset */ - ruleset.Construct(&pRuleset); - ruleset.SetName(ourConf, pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset")); - ruleset.ConstructFinalize(ourConf, pRuleset); +#if 1 /* open the configuration file */ localRet = conf.processConfFile(ourConf, ConfFile); @@ -1646,6 +1643,7 @@ init(void) } ruleset.AddRule(ourConf, ruleset.GetCurrent(ourConf), &pRule); } +#endif legacyOptsHook(); @@ -1721,6 +1719,7 @@ init(void) sigAct.sa_handler = sighup_handler; sigaction(SIGHUP, &sigAct, NULL); + CHKiRet(rsconf.Activate(ourConf)); DBGPRINTF(" started.\n"); /* we now generate the startup message. It now includes everything to @@ -2187,7 +2186,7 @@ static rsRetVal mainThread() CHKiRet(init()); if(Debug && debugging_on) { - DBGPRINTF("Debugging enabled, SIGUSR1 to turn off debugging.\n"); + dbgprintf("Debugging enabled, SIGUSR1 to turn off debugging.\n"); } /* Send a signal to the parent so it can terminate. @@ -2711,9 +2710,6 @@ int realMain(int argc, char **argv) for(p = LocalDomain ; *p ; p++) *p = (char)tolower((int)*p); - /* we need to init the config object first! */ - CHKiRet(rsconf.Construct(&ourConf)); - /* we now have our hostname and can set it inside the global vars. * TODO: think if all of this would better be a runtime function * rgerhards, 2008-04-17 @@ -2729,11 +2725,6 @@ int realMain(int argc, char **argv) exit(1); /* "good" exit, leaving at init for fatal error */ } - if((iRet = loadBuildInModules(ourConf)) != RS_RET_OK) { - fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n", - iRet); - exit(1); /* "good" exit, leaving at init for fatal error */ - } /* END core initializations - we now come back to carrying out command line options*/ @@ -2878,11 +2869,24 @@ int realMain(int argc, char **argv) if(iRet != RS_RET_END_OF_LINKEDLIST) FINALIZE; + CHKiRet(rsconf.Load(&ourConf, ConfFile)); + + + + /* begin config load */ + if((iRet = loadBuildInModules(ourConf)) != RS_RET_OK) { + fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n", + iRet); + exit(1); /* "good" exit, leaving at init for fatal error */ + } if(iConfigVerify) { fprintf(stderr, "rsyslogd: version %s, config validation run (level %d), master config %s\n", VERSION, iConfigVerify, ConfFile); } + + + if(bChDirRoot) { if(chdir("/") != 0) fprintf(stderr, "Can not do 'cd /' - still trying to run\n"); -- cgit v1.2.3 From 13ecf8a6ef5a5b69819865a2b9b524d4c561f5de Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Apr 2011 14:27:41 +0200 Subject: step: config handler setting from syslogd.c moved to rsconf.c --- action.c | 8 +- dirty.h | 1 - runtime/cfsysline.c | 4 +- runtime/conf.c | 6 +- runtime/conf.h | 2 +- runtime/modules.c | 9 +- runtime/modules.h | 3 - runtime/rsconf.c | 386 ++++++++++++++++++++++++++++++++++++++++++++++++++- runtime/rsconf.h | 41 +++++- runtime/typedefs.h | 1 + tests/diag.sh | 2 +- tools/syslogd.c | 392 ++++++---------------------------------------------- 12 files changed, 484 insertions(+), 371 deletions(-) diff --git a/action.c b/action.c index 69dc64f5..0ec64236 100644 --- a/action.c +++ b/action.c @@ -81,6 +81,7 @@ #include "errmsg.h" #include "batch.h" #include "wti.h" +#include "rsconf.h" #include "datetime.h" #include "unicode-helper.h" #include "atomic.h" @@ -1679,9 +1680,10 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringReques pAction->pMod = pMod; pAction->pModData = pModData; /* now check if the module is compatible with select features */ - if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) - pAction->f_ReduceRepeated = bReduceRepeatMsgs; - else { + if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) { +dbgprintf("XXXX: loadConf is %p in action.c\n", loadConf); + pAction->f_ReduceRepeated = loadConf->globals.bReduceRepeatMsgs; + } else { DBGPRINTF("module is incompatible with RepeatedMsgReduction - turned off\n"); pAction->f_ReduceRepeated = 0; } diff --git a/dirty.h b/dirty.h index 0428a002..f6b99741 100644 --- a/dirty.h +++ b/dirty.h @@ -41,7 +41,6 @@ rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName); */ extern int MarkInterval; extern int repeatinterval[2]; -extern int bReduceRepeatMsgs; extern qqueue_t *pMsgQueue; /* the main message queue */ #define MAXREPEAT ((int)((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)) #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c index 2475c270..f6581ccd 100644 --- a/runtime/cfsysline.c +++ b/runtime/cfsysline.c @@ -587,7 +587,9 @@ doFacility(uchar **pp, rsRetVal (*pSetHdlr)(void*, int), void *pVal) static rsRetVal -doGoneAway(uchar **pp, rsRetVal (*pSetHdlr)(void*, int), void *pVal) +doGoneAway(__attribute__((unused)) uchar **pp, + __attribute__((unused)) rsRetVal (*pSetHdlr)(void*, int), + __attribute__((unused)) void *pVal) { errmsg.LogError(0, RS_RET_CMD_GONE_AWAY, "config directive is no longer supported -- ignored"); return RS_RET_CMD_GONE_AWAY; diff --git a/runtime/conf.c b/runtime/conf.c index 8e05609d..9fecc34d 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -296,7 +296,7 @@ finalize_it: * generalized. */ rsRetVal -doNameLine(rsconf_t *conf, uchar **pp, void* pVal) +doNameLine(uchar **pp, void* pVal) { DEFiRet; uchar *p; @@ -324,7 +324,7 @@ doNameLine(rsconf_t *conf, uchar **pp, void* pVal) switch(eDir) { case DIR_TEMPLATE: - tplAddLine(ourConf, szName, &p); + tplAddLine(loadConf, szName, &p); break; case DIR_OUTCHANNEL: ochAddLine(szName, &p); @@ -1125,7 +1125,7 @@ static rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { /* now check if the module is compatible with select features */ if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) - pAction->f_ReduceRepeated = bReduceRepeatMsgs; + pAction->f_ReduceRepeated = loadConf->globals.bReduceRepeatMsgs; else { dbgprintf("module is incompatible with RepeatedMsgReduction - turned off\n"); pAction->f_ReduceRepeated = 0; diff --git a/runtime/conf.h b/runtime/conf.h index 3b3d488b..c169a9c0 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -33,7 +33,7 @@ extern int bConfStrictScoping; /* force strict scoping during config processing? /* interfaces */ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ - rsRetVal (*doNameLine)(rsconf_t *conf, uchar **pp, void* pVal); + rsRetVal (*doNameLine)(uchar **pp, void* pVal); rsRetVal (*cfsysline)(rsconf_t *conf, uchar *p); rsRetVal (*doModLoad)(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal); rsRetVal (*doIncludeLine)(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal); diff --git a/runtime/modules.c b/runtime/modules.c index 8ede134b..7389909d 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -55,6 +55,7 @@ #endif #include "cfsysline.h" +#include "rsconf.h" #include "modules.h" #include "errmsg.h" #include "parser.h" @@ -80,9 +81,7 @@ static modInfo_t *pLoadedModulesLast = NULL; /* tail-pointer */ /* already dlopen()-ed libs */ static struct dlhandle_s *pHandles = NULL; -/* config settings */ -uchar *pModDir = NULL; /* read-only after startup */ - +static uchar *pModDir; /* directory where loadable modules are found */ /* we provide a set of dummy functions for modules that do not support the * some interfaces. @@ -801,7 +800,8 @@ Load(uchar *pModName) pModInfo = GetNxt(pModInfo); } - pModDirCurr = (uchar *)((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir); + pModDirCurr = (uchar *)((pModDir == NULL) ? + _PATH_MODDIR : (char *)pModDir); pModDirNext = NULL; pModHdlr = NULL; iLoadCnt = 0; @@ -1013,6 +1013,7 @@ CODESTARTObjClassExit(module) * TODO: add again: pthread_mutex_destroy(&mutLoadUnload); */ + free(pModDir); # ifdef DEBUG modUsrPrintAll(); /* debug aid - TODO: integrate with debug.c, at least the settings! */ # endif diff --git a/runtime/modules.h b/runtime/modules.h index c1c38a26..08e0851c 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -175,7 +175,4 @@ ENDinterface(module) /* prototypes */ PROTOTYPEObj(module); -/* TODO: remove them below (means move the config init code) -- rgerhards, 2008-02-19 */ -extern uchar *pModDir; /* read-only after startup */ - #endif /* #ifndef MODULES_H_INCLUDED */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 1f7a46c3..bebe77dd 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -29,6 +29,9 @@ #include #include #include +#include +#include +#include #include "rsyslog.h" #include "obj.h" @@ -36,9 +39,12 @@ #include "ruleset.h" #include "modules.h" #include "conf.h" +#include "queue.h" #include "rsconf.h" #include "cfsysline.h" #include "errmsg.h" +#include "action.h" +#include "glbl.h" #include "unicode-helper.h" /* static data */ @@ -47,6 +53,7 @@ DEFobjCurrIf(ruleset) DEFobjCurrIf(module) DEFobjCurrIf(conf) DEFobjCurrIf(errmsg) +DEFobjCurrIf(glbl) /* exported static data */ rsconf_t *runConf = NULL;/* the currently running config */ @@ -64,7 +71,32 @@ BEGINobjConstruct(rsconf) /* be sure to specify the object type also in END macr pThis->templates.last = NULL; pThis->templates.lastStatic = NULL; pThis->actions.nbrActions = 0; - CHKiRet(llInit(&pThis->rulesets.llRulesets, rulesetDestructForLinkedList, rulesetKeyDestruct, strcasecmp)); + CHKiRet(llInit(&pThis->rulesets.llRulesets, rulesetDestructForLinkedList, + rulesetKeyDestruct, strcasecmp)); + /* queue params */ + pThis->globals.mainQ.iMainMsgQueueSize = 10000; + pThis->globals.mainQ.iMainMsgQHighWtrMark = 8000; + pThis->globals.mainQ.iMainMsgQLowWtrMark = 2000; + pThis->globals.mainQ.iMainMsgQDiscardMark = 9800; + pThis->globals.mainQ.iMainMsgQDiscardSeverity = 8; + pThis->globals.mainQ.iMainMsgQueueNumWorkers = 1; + pThis->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY; + pThis->globals.mainQ.pszMainMsgQFName = NULL; + pThis->globals.mainQ.iMainMsgQueMaxFileSize = 1024*1024; + pThis->globals.mainQ.iMainMsgQPersistUpdCnt = 0; + pThis->globals.mainQ.bMainMsgQSyncQeueFiles = 0; + pThis->globals.mainQ.iMainMsgQtoQShutdown = 1500; + pThis->globals.mainQ.iMainMsgQtoActShutdown = 1000; + pThis->globals.mainQ.iMainMsgQtoEnq = 2000; + pThis->globals.mainQ.iMainMsgQtoWrkShutdown = 60000; + pThis->globals.mainQ.iMainMsgQWrkMinMsgs = 100; + pThis->globals.mainQ.iMainMsgQDeqSlowdown = 0; + pThis->globals.mainQ.iMainMsgQueMaxDiskSpace = 0; + pThis->globals.mainQ.iMainMsgQueDeqBatchSize = 32; + pThis->globals.mainQ.bMainMsgQSaveOnShutdown = 1; + pThis->globals.mainQ.iMainMsgQueueDeqtWinFromHr = 0; + pThis->globals.mainQ.iMainMsgQueueDeqtWinToHr = 25; + /* end queue params */ finalize_it: ENDobjConstruct(rsconf) @@ -82,6 +114,7 @@ rsRetVal rsconfConstructFinalize(rsconf_t __attribute__((unused)) *pThis) /* destructor for the rsconf object */ BEGINobjDestruct(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */ CODESTARTobjDestruct(rsconf) + free(pThis->globals.mainQ.pszMainMsgQFName); llDestroy(&(pThis->rulesets.llRulesets)); ENDobjDestruct(rsconf) @@ -108,6 +141,26 @@ BEGINobjDebugPrint(rsconf) /* be sure to specify the object type also in END and module.PrintList(); if(pThis->globals.bDebugPrintCfSysLineHandlerList) dbgPrintCfSysLineHandlers(); + // TODO: The following code needs to be "streamlined", so far just moved over... + DBGPRINTF("Main queue size %d messages.\n", pThis->globals.mainQ.iMainMsgQueueSize); + DBGPRINTF("Main queue worker threads: %d, wThread shutdown: %d, Perists every %d updates.\n", + pThis->globals.mainQ.iMainMsgQueueNumWorkers, pThis->globals.mainQ.iMainMsgQtoWrkShutdown, pThis->globals.mainQ.iMainMsgQPersistUpdCnt); + DBGPRINTF("Main queue timeouts: shutdown: %d, action completion shutdown: %d, enq: %d\n", + pThis->globals.mainQ.iMainMsgQtoQShutdown, pThis->globals.mainQ.iMainMsgQtoActShutdown, pThis->globals.mainQ.iMainMsgQtoEnq); + DBGPRINTF("Main queue watermarks: high: %d, low: %d, discard: %d, discard-severity: %d\n", + pThis->globals.mainQ.iMainMsgQHighWtrMark, pThis->globals.mainQ.iMainMsgQLowWtrMark, pThis->globals.mainQ.iMainMsgQDiscardMark, pThis->globals.mainQ.iMainMsgQDiscardSeverity); + DBGPRINTF("Main queue save on shutdown %d, max disk space allowed %lld\n", + pThis->globals.mainQ.bMainMsgQSaveOnShutdown, pThis->globals.mainQ.iMainMsgQueMaxDiskSpace); + /* TODO: add + iActionRetryCount = 0; + iActionRetryInterval = 30000; + static int iMainMsgQtoWrkMinMsgs = 100; + static int iMainMsgQbSaveOnShutdown = 1; + iMainMsgQueMaxDiskSpace = 0; + setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", 100); + setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", 1); + */ + DBGPRINTF("Work Directory: '%s'.\n", glbl.GetWorkDir()); CODESTARTobjDebugPrint(rsconf) ENDobjDebugPrint(rsconf) @@ -128,6 +181,215 @@ activate(rsconf_t *cnf) } +/* -------------------- some legacy config handlers -------------------- + * TODO: move to conf.c? + */ + +/* this method is needed to shuffle the current conf object down to the + * IncludeConfig handler. + */ +static rsRetVal +doModLoad(void *pVal, uchar *pNewVal) +{ + DEFiRet; + iRet = conf.doModLoad(ourConf, pVal, pNewVal); + free(pNewVal); + RETiRet; +} + +/* legacy config system: set the action resume interval */ +static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int iNewVal) +{ + return actionSetGlobalResumeInterval(iNewVal); +} + + +/* this method is needed to shuffle the current conf object down to the + * IncludeConfig handler. + */ +static rsRetVal +doIncludeLine(void *pVal, uchar *pNewVal) +{ + DEFiRet; + iRet = conf.doIncludeLine(ourConf, pVal, pNewVal); + free(pNewVal); + RETiRet; +} + + +/* set the processes umask (upon configuration request) */ +static rsRetVal +setUmask(void __attribute__((unused)) *pVal, int iUmask) +{ +#warning this *really* needs to be done differently! + umask(iUmask); + DBGPRINTF("umask set to 0%3.3o.\n", iUmask); + + return RS_RET_OK; +} + + +/* set the maximum message size */ +static rsRetVal setMaxMsgSize(void __attribute__((unused)) *pVal, long iNewVal) +{ + return glbl.SetMaxLine(iNewVal); +} + + +/* Switch the default ruleset (that, what servcies bind to if nothing specific + * is specified). + * rgerhards, 2009-06-12 + */ +static rsRetVal +setDefaultRuleset(void __attribute__((unused)) *pVal, uchar *pszName) +{ + DEFiRet; + + CHKiRet(ruleset.SetDefaultRuleset(ourConf, pszName)); + +finalize_it: + free(pszName); /* no longer needed */ + RETiRet; +} + + +/* Switch to either an already existing rule set or start a new one. The + * named rule set becomes the new "current" rule set (what means that new + * actions are added to it). + * rgerhards, 2009-06-12 + */ +static rsRetVal +setCurrRuleset(void __attribute__((unused)) *pVal, uchar *pszName) +{ + ruleset_t *pRuleset; + rsRetVal localRet; + DEFiRet; + + localRet = ruleset.SetCurrRuleset(ourConf, pszName); + + if(localRet == RS_RET_NOT_FOUND) { + DBGPRINTF("begin new current rule set '%s'\n", pszName); + CHKiRet(ruleset.Construct(&pRuleset)); + CHKiRet(ruleset.SetName(ourConf, pRuleset, pszName)); + CHKiRet(ruleset.ConstructFinalize(ourConf, pRuleset)); + } else { + ABORT_FINALIZE(localRet); + } + +finalize_it: + free(pszName); /* no longer needed */ + RETiRet; +} + + +/* set the main message queue mode + * rgerhards, 2008-01-03 + */ +static rsRetVal setMainMsgQueType(void __attribute__((unused)) *pVal, uchar *pszType) +{ + DEFiRet; + + if (!strcasecmp((char *) pszType, "fixedarray")) { + loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY; + DBGPRINTF("main message queue type set to FIXED_ARRAY\n"); + } else if (!strcasecmp((char *) pszType, "linkedlist")) { + loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_LINKEDLIST; + DBGPRINTF("main message queue type set to LINKEDLIST\n"); + } else if (!strcasecmp((char *) pszType, "disk")) { + loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_DISK; + DBGPRINTF("main message queue type set to DISK\n"); + } else if (!strcasecmp((char *) pszType, "direct")) { + loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_DIRECT; + DBGPRINTF("main message queue type set to DIRECT (no queueing at all)\n"); + } else { + errmsg.LogError(0, RS_RET_INVALID_PARAMS, "unknown mainmessagequeuetype parameter: %s", (char *) pszType); + iRet = RS_RET_INVALID_PARAMS; + } + free(pszType); /* no longer needed */ + + RETiRet; +} + + +/* -------------------- end legacy config handlers -------------------- */ + + +/* set the processes max number ob files (upon configuration request) + * 2009-04-14 rgerhards + */ +static rsRetVal setMaxFiles(void __attribute__((unused)) *pVal, int iFiles) +{ +// TODO this must use a local var, then carry out action during activate! + struct rlimit maxFiles; + char errStr[1024]; + DEFiRet; + + maxFiles.rlim_cur = iFiles; + maxFiles.rlim_max = iFiles; + + if(setrlimit(RLIMIT_NOFILE, &maxFiles) < 0) { + /* NOTE: under valgrind, we seem to be unable to extend the size! */ + rs_strerror_r(errno, errStr, sizeof(errStr)); + errmsg.LogError(0, RS_RET_ERR_RLIM_NOFILE, "could not set process file limit to %d: %s [kernel max %ld]", + iFiles, errStr, (long) maxFiles.rlim_max); + ABORT_FINALIZE(RS_RET_ERR_RLIM_NOFILE); + } +#ifdef USE_UNLIMITED_SELECT + glbl.SetFdSetSize(howmany(iFiles, __NFDBITS) * sizeof (fd_mask)); +#endif + DBGPRINTF("Max number of files set to %d [kernel max %ld].\n", iFiles, (long) maxFiles.rlim_max); + +finalize_it: + RETiRet; +} + + +/* legac config system: reset config variables to default values. */ +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +{ + loadConf->globals.bLogStatusMsgs = DFLT_bLogStatusMsgs; + loadConf->globals.bDebugPrintTemplateList = 1; + loadConf->globals.bDebugPrintCfSysLineHandlerList = 1; + loadConf->globals.bDebugPrintModuleList = 1; + loadConf->globals.bAbortOnUncleanConfig = 0; + loadConf->globals.bReduceRepeatMsgs = 0; + free(loadConf->globals.mainQ.pszMainMsgQFName); + loadConf->globals.mainQ.pszMainMsgQFName = NULL; + loadConf->globals.mainQ.iMainMsgQueueSize = 10000; + loadConf->globals.mainQ.iMainMsgQHighWtrMark = 8000; + loadConf->globals.mainQ.iMainMsgQLowWtrMark = 2000; + loadConf->globals.mainQ.iMainMsgQDiscardMark = 9800; + loadConf->globals.mainQ.iMainMsgQDiscardSeverity = 8; + loadConf->globals.mainQ.iMainMsgQueMaxFileSize = 1024 * 1024; + loadConf->globals.mainQ.iMainMsgQueueNumWorkers = 1; + loadConf->globals.mainQ.iMainMsgQPersistUpdCnt = 0; + loadConf->globals.mainQ.bMainMsgQSyncQeueFiles = 0; + loadConf->globals.mainQ.iMainMsgQtoQShutdown = 1500; + loadConf->globals.mainQ.iMainMsgQtoActShutdown = 1000; + loadConf->globals.mainQ.iMainMsgQtoEnq = 2000; + loadConf->globals.mainQ.iMainMsgQtoWrkShutdown = 60000; + loadConf->globals.mainQ.iMainMsgQWrkMinMsgs = 100; + loadConf->globals.mainQ.iMainMsgQDeqSlowdown = 0; + loadConf->globals.mainQ.bMainMsgQSaveOnShutdown = 1; + loadConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY; + loadConf->globals.mainQ.iMainMsgQueMaxDiskSpace = 0; + loadConf->globals.mainQ.iMainMsgQueDeqBatchSize = 32; + + return RS_RET_OK; +} + + +/* legacy config system: set the action resume interval */ +static rsRetVal +setModDir(void __attribute__((unused)) *pVal, uchar* pszNewVal) +{ + DEFiRet; + iRet = module.SetModDir(pszNewVal); + free(pszNewVal); + RETiRet; +} + + /* intialize the legacy config system */ static inline rsRetVal initLegacyConf(void) @@ -140,6 +402,123 @@ initLegacyConf(void) ruleset.SetName(loadConf, pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset")); ruleset.ConstructFinalize(loadConf, pRuleset); + /* now register config handlers */ + CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrGoneAway, + NULL, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"logrsyslogstatusmessages", 0, eCmdHdlrBinary, + NULL, &loadConf->globals.bLogStatusMsgs, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary, + NULL, &loadConf->globals.bErrMsgToStderr, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"abortonuncleanconfig", 0, eCmdHdlrBinary, + NULL, &loadConf->globals.bAbortOnUncleanConfig, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgreduction", 0, eCmdHdlrBinary, + NULL, &loadConf->globals.bReduceRepeatMsgs, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"debugprinttemplatelist", 0, eCmdHdlrBinary, + NULL, &(loadConf->globals.bDebugPrintTemplateList), NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"debugprintmodulelist", 0, eCmdHdlrBinary, + NULL, &(loadConf->globals.bDebugPrintModuleList), NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"debugprintcfsyslinehandlerlist", 0, eCmdHdlrBinary, + NULL, &(loadConf->globals.bDebugPrintCfSysLineHandlerList), NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouser", 0, eCmdHdlrUID, + NULL, &loadConf->globals.uidDropPriv, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouserid", 0, eCmdHdlrInt, + NULL, &loadConf->globals.uidDropPriv, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroup", 0, eCmdHdlrGID, + NULL, &loadConf->globals.gidDropPriv, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroupid", 0, eCmdHdlrGID, + NULL, &loadConf->globals.gidDropPriv, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"generateconfiggraph", 0, eCmdHdlrGetWord, + NULL, &loadConf->globals.pszConfDAGFile, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"maxopenfiles", 0, eCmdHdlrInt, + setMaxFiles, NULL, NULL, eConfObjGlobal)); + + CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, + setActionResumeInterval, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, + doModLoad, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, + doIncludeLine, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode, + setUmask, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, + setMaxMsgSize, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, + setDefaultRuleset, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord, + setCurrRuleset, NULL, NULL, eConfObjGlobal)); + + /* handler for "larger" config statements (tie into legacy conf system) */ + CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler, + conf.doNameLine, (void*)DIR_TEMPLATE, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler, + conf.doNameLine, (void*)DIR_OUTCHANNEL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"allowedsender", 0, eCmdHdlrCustomHandler, + conf.doNameLine, (void*)DIR_ALLOWEDSENDER, NULL, eConfObjGlobal)); + + /* the following are parameters for the main message queue. I have the + * strong feeling that this needs to go to a different space, but that + * feeling may be wrong - we'll see how things evolve. + * rgerhards, 2011-04-21 + */ + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord, + NULL, &loadConf->globals.mainQ.pszMainMsgQFName, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQueueSize, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQHighWtrMark, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuelowwatermark", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQLowWtrMark, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardmark", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQDiscardMark, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardseverity", 0, eCmdHdlrSeverity, + NULL, &loadConf->globals.mainQ.iMainMsgQDiscardSeverity, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuecheckpointinterval", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQPersistUpdCnt, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesyncqueuefiles", 0, eCmdHdlrBinary, + NULL, &loadConf->globals.mainQ.bMainMsgQSyncQeueFiles, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetype", 0, eCmdHdlrGetWord, + setMainMsgQueType, NULL, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreads", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQueueNumWorkers, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutshutdown", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQtoQShutdown, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutactioncompletion", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQtoActShutdown, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutenqueue", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQtoEnq, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkertimeoutthreadshutdown", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQtoWrkShutdown, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeueslowdown", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQDeqSlowdown, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreadminimummessages", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQWrkMinMsgs, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxfilesize", 0, eCmdHdlrSize, + NULL, &loadConf->globals.mainQ.iMainMsgQueMaxFileSize, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuebatchsize", 0, eCmdHdlrSize, + NULL, &loadConf->globals.mainQ.iMainMsgQueDeqBatchSize, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxdiskspace", 0, eCmdHdlrSize, + NULL, &loadConf->globals.mainQ.iMainMsgQueMaxDiskSpace, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesaveonshutdown", 0, eCmdHdlrBinary, + NULL, &loadConf->globals.mainQ.bMainMsgQSaveOnShutdown, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimebegin", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQueueDeqtWinFromHr, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimeend", 0, eCmdHdlrInt, + NULL, &loadConf->globals.mainQ.iMainMsgQueueDeqtWinToHr, NULL, eConfObjGlobal)); + /* moddir is a bit hard problem -- because it actually needs to + * modify a setting that is specific to module.c. The important point + * is that this action MUST actually be carried out during config load, + * because we must load modules in order to get their config extensions + * (no way around). + * TODO: think about a clean solution + */ + CHKiRet(regCfSysLineHdlr((uchar *)"moddir", 0, eCmdHdlrGetWord, + setModDir, NULL, NULL, eConfObjGlobal)); + + /* finally, the reset handler */ + CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, + resetConfigVariables, NULL, NULL, eConfObjGlobal)); + +finalize_it: RETiRet; } @@ -162,6 +541,7 @@ load(rsconf_t **cnf, uchar *confFile) CHKiRet(rsconfConstruct(&loadConf)); ourConf = loadConf; // TODO: remove, once ourConf is gone! +dbgprintf("XXXX: loadConf is %p\n", loadConf); CHKiRet(initLegacyConf()); @@ -216,7 +596,7 @@ dbgprintf("XXXX: 20\n"); /* all OK, pass loaded conf to caller */ *cnf = loadConf; - loadConf = NULL; +// TODO: enable this once all config code is moved to here! loadConf = NULL; dbgprintf("rsyslog finished loading initial config %p\n", loadConf); // rsconfDebugPrint(loadConf); @@ -258,6 +638,7 @@ BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */ CHKiRet(objUse(module, CORE_COMPONENT)); CHKiRet(objUse(conf, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); + CHKiRet(objUse(glbl, CORE_COMPONENT)); /* now set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, rsconfDebugPrint); @@ -272,6 +653,7 @@ BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */ objRelease(module, CORE_COMPONENT); objRelease(conf, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); + objRelease(glbl, CORE_COMPONENT); ENDObjClassExit(rsconf) /* vi:set ai: diff --git a/runtime/rsconf.h b/runtime/rsconf.h index 3302e990..5229b9f7 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -24,9 +24,36 @@ #define INCLUDED_RSCONF_H #include "linkedlist.h" +#include "queue.h" /* --- configuration objects (the plan is to have ALL upper layers in this file) --- */ +/* queue config parameters. TODO: move to queue.c? */ +struct queuecnf_s { + int iMainMsgQueueSize; /* size of the main message queue above */ + int iMainMsgQHighWtrMark; /* high water mark for disk-assisted queues */ + int iMainMsgQLowWtrMark; /* low water mark for disk-assisted queues */ + int iMainMsgQDiscardMark; /* begin to discard messages */ + int iMainMsgQDiscardSeverity; /* by default, discard nothing to prevent unintentional loss */ + int iMainMsgQueueNumWorkers; /* number of worker threads for the mm queue above */ + queueType_t MainMsgQueType; /* type of the main message queue above */ + uchar *pszMainMsgQFName; /* prefix for the main message queue file */ + int64 iMainMsgQueMaxFileSize; + int iMainMsgQPersistUpdCnt; /* persist queue info every n updates */ + int bMainMsgQSyncQeueFiles; /* sync queue files on every write? */ + int iMainMsgQtoQShutdown; /* queue shutdown (ms) */ + int iMainMsgQtoActShutdown; /* action shutdown (in phase 2) */ + int iMainMsgQtoEnq; /* timeout for queue enque */ + int iMainMsgQtoWrkShutdown; /* timeout for worker thread shutdown */ + int iMainMsgQWrkMinMsgs; /* minimum messages per worker needed to start a new one */ + int iMainMsgQDeqSlowdown; /* dequeue slowdown (simple rate limiting) */ + int64 iMainMsgQueMaxDiskSpace; /* max disk space allocated 0 ==> unlimited */ + int64 iMainMsgQueDeqBatchSize; /* dequeue batch size */ + int bMainMsgQSaveOnShutdown; /* save queue on shutdown (when DA enabled)? */ + int iMainMsgQueueDeqtWinFromHr; /* hour begin of time frame when queue is to be dequeued */ + int iMainMsgQueueDeqtWinToHr; /* hour begin of time frame when queue is to be dequeued */ +}; + /* globals are data items that are really global, and can be set only * once (at least in theory, because the legacy system permits them to * be re-set as often as the user likes). @@ -36,7 +63,19 @@ struct globals_s { int bDebugPrintModuleList; int bDebugPrintCfSysLineHandlerList; int bLogStatusMsgs; /* log rsyslog start/stop/HUP messages? */ - int bErrMsgToStderr; /* print error messages to stderr (in addition to everything else)? */ + int bErrMsgToStderr; /* print error messages to stderr + (in addition to everything else)? */ + int bAbortOnUncleanConfig; /* abort run (rather than starting with partial + config) if there was any issue in conf */ + int uidDropPriv; /* user-id to which priveleges should be dropped to */ + int gidDropPriv; /* group-id to which priveleges should be dropped to */ + uchar *pszConfDAGFile; /* name of config DAG file, non-NULL means generate one */ + + // TODO are the following ones defaults? + int bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */ + + //TODO: other representation for main queue? Or just load it differently? + queuecnf_t mainQ; /* main queue paramters */ }; /* (global) defaults are global in the sense that they are accessible diff --git a/runtime/typedefs.h b/runtime/typedefs.h index e46f509b..b7df0464 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -81,6 +81,7 @@ typedef struct strgenList_s strgenList_t; typedef struct statsobj_s statsobj_t; typedef struct nsd_epworkset_s nsd_epworkset_t; typedef struct templates_s templates_t; +typedef struct queuecnf_s queuecnf_t; typedef struct rulesets_s rulesets_t; typedef struct globals_s globals_t; typedef struct defaults_s defaults_t; diff --git a/tests/diag.sh b/tests/diag.sh index 8b0ad573..07537bb0 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -5,7 +5,7 @@ # not always able to convey back states to the upper-level test driver # begun 2009-05-27 by rgerhards # This file is part of the rsyslog project, released under GPLv3 -#valgrind="valgrind --malloc-fill=ff --free-fill=fe --log-fd=1" +valgrind="valgrind --malloc-fill=ff --free-fill=fe --log-fd=1" #valgrind="valgrind --tool=drd --log-fd=1" #valgrind="valgrind --tool=helgrind --log-fd=1" #valgrind="valgrind --tool=exp-ptrcheck --log-fd=1" diff --git a/tools/syslogd.c b/tools/syslogd.c index 1cf0b894..409bb4f9 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -238,8 +238,6 @@ legacyOptsLL_t *pLegacyOptsLL = NULL; int iCompatibilityMode = 0; /* version we should be compatible with; 0 means sysklogd. It is the default, so if no -c option is given, we make ourselvs as compatible to sysklogd as possible. */ -int bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */ -int bAbortOnUncleanConfig = 0; /* abort run (rather than starting with partial config) if there was any issue in conf */ /* end global config file state variables */ int MarkInterval = 20 * 60; /* interval between marks in seconds - read-only after startup */ @@ -249,73 +247,11 @@ static int bHaveMainQueue = 0;/* set to 1 if the main queue - in queueing mode - * If the main queue is either not yet ready or not running in * queueing mode (mode DIRECT!), then this is set to 0. */ -static int uidDropPriv = 0; /* user-id to which priveleges should be dropped to (AFTER init()!) */ -static int gidDropPriv = 0; /* group-id to which priveleges should be dropped to (AFTER init()!) */ extern int errno; -static uchar *pszConfDAGFile = NULL; /* name of config DAG file, non-NULL means generate one */ /* main message queue and its configuration parameters */ qqueue_t *pMsgQueue = NULL; /* the main message queue */ -static int iMainMsgQueueSize = 10000; /* size of the main message queue above */ -static int iMainMsgQHighWtrMark = 8000; /* high water mark for disk-assisted queues */ -static int iMainMsgQLowWtrMark = 2000; /* low water mark for disk-assisted queues */ -static int iMainMsgQDiscardMark = 9800; /* begin to discard messages */ -static int iMainMsgQDiscardSeverity = 8; /* by default, discard nothing to prevent unintentional loss */ -static int iMainMsgQueueNumWorkers = 1; /* number of worker threads for the mm queue above */ -static queueType_t MainMsgQueType = QUEUETYPE_FIXED_ARRAY; /* type of the main message queue above */ -static uchar *pszMainMsgQFName = NULL; /* prefix for the main message queue file */ -static int64 iMainMsgQueMaxFileSize = 1024*1024; -static int iMainMsgQPersistUpdCnt = 0; /* persist queue info every n updates */ -static int bMainMsgQSyncQeueFiles = 0; /* sync queue files on every write? */ -static int iMainMsgQtoQShutdown = 1500; /* queue shutdown (ms) */ -static int iMainMsgQtoActShutdown = 1000; /* action shutdown (in phase 2) */ -static int iMainMsgQtoEnq = 2000; /* timeout for queue enque */ -static int iMainMsgQtoWrkShutdown = 60000; /* timeout for worker thread shutdown */ -static int iMainMsgQWrkMinMsgs = 100; /* minimum messages per worker needed to start a new one */ -static int iMainMsgQDeqSlowdown = 0; /* dequeue slowdown (simple rate limiting) */ -static int64 iMainMsgQueMaxDiskSpace = 0; /* max disk space allocated 0 ==> unlimited */ -static int64 iMainMsgQueDeqBatchSize = 32; /* dequeue batch size */ -static int bMainMsgQSaveOnShutdown = 1; /* save queue on shutdown (when DA enabled)? */ -static int iMainMsgQueueDeqtWinFromHr = 0; /* hour begin of time frame when queue is to be dequeued */ -static int iMainMsgQueueDeqtWinToHr = 25; /* hour begin of time frame when queue is to be dequeued */ - - -/* Reset config variables to default values. - * rgerhards, 2007-07-17 - */ -static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) -{ - ourConf->globals.bLogStatusMsgs = DFLT_bLogStatusMsgs; - ourConf->globals.bDebugPrintTemplateList = 1; - ourConf->globals.bDebugPrintCfSysLineHandlerList = 1; - ourConf->globals.bDebugPrintModuleList = 1; - bReduceRepeatMsgs = 0; - bAbortOnUncleanConfig = 0; - free(pszMainMsgQFName); - pszMainMsgQFName = NULL; - iMainMsgQueueSize = 10000; - iMainMsgQHighWtrMark = 8000; - iMainMsgQLowWtrMark = 2000; - iMainMsgQDiscardMark = 9800; - iMainMsgQDiscardSeverity = 8; - iMainMsgQueMaxFileSize = 1024 * 1024; - iMainMsgQueueNumWorkers = 1; - iMainMsgQPersistUpdCnt = 0; - bMainMsgQSyncQeueFiles = 0; - iMainMsgQtoQShutdown = 1500; - iMainMsgQtoActShutdown = 1000; - iMainMsgQtoEnq = 2000; - iMainMsgQtoWrkShutdown = 60000; - iMainMsgQWrkMinMsgs = 100; - iMainMsgQDeqSlowdown = 0; - bMainMsgQSaveOnShutdown = 1; - MainMsgQueType = QUEUETYPE_FIXED_ARRAY; - iMainMsgQueMaxDiskSpace = 0; - iMainMsgQueDeqBatchSize = 32; - - return RS_RET_OK; -} /* hardcoded standard templates (used for defaults) */ @@ -1009,9 +945,7 @@ static void doDie(int sig) static void freeAllDynMemForTermination(void) { - free(pszMainMsgQFName); - free(pModDir); - free(pszConfDAGFile); + free(ourConf->globals.pszConfDAGFile); } @@ -1058,7 +992,6 @@ die(int sig) thrdTerminateAll(); /* and THEN send the termination log message (see long comment above) */ -dbgprintf("XXXX: runConf %p\n", runConf); if(sig && runConf->globals.bLogStatusMsgs) { (void) snprintf(buf, sizeof(buf) / sizeof(char), " [origin software=\"rsyslogd\" " "swVersion=\"" VERSION \ @@ -1138,59 +1071,6 @@ static void doexit() } -/* set the maximum message size */ -static rsRetVal setMaxMsgSize(void __attribute__((unused)) *pVal, long iNewVal) -{ - return glbl.SetMaxLine(iNewVal); -} - - -/* set the action resume interval */ -static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int iNewVal) -{ - return actionSetGlobalResumeInterval(iNewVal); -} - - -/* set the processes max number ob files (upon configuration request) - * 2009-04-14 rgerhards - */ -static rsRetVal setMaxFiles(void __attribute__((unused)) *pVal, int iFiles) -{ - struct rlimit maxFiles; - char errStr[1024]; - DEFiRet; - - maxFiles.rlim_cur = iFiles; - maxFiles.rlim_max = iFiles; - - if(setrlimit(RLIMIT_NOFILE, &maxFiles) < 0) { - /* NOTE: under valgrind, we seem to be unable to extend the size! */ - rs_strerror_r(errno, errStr, sizeof(errStr)); - errmsg.LogError(0, RS_RET_ERR_RLIM_NOFILE, "could not set process file limit to %d: %s [kernel max %ld]", - iFiles, errStr, (long) maxFiles.rlim_max); - ABORT_FINALIZE(RS_RET_ERR_RLIM_NOFILE); - } -#ifdef USE_UNLIMITED_SELECT - glbl.SetFdSetSize(howmany(iFiles, __NFDBITS) * sizeof (fd_mask)); -#endif - DBGPRINTF("Max number of files set to %d [kernel max %ld].\n", iFiles, (long) maxFiles.rlim_max); - -finalize_it: - RETiRet; -} - - -/* set the processes umask (upon configuration request) */ -static rsRetVal setUmask(void __attribute__((unused)) *pVal, int iUmask) -{ - umask(iUmask); - DBGPRINTF("umask set to 0%3.3o.\n", iUmask); - - return RS_RET_OK; -} - - /* drop to specified group * if something goes wrong, the function never returns * Note that such an abort can cause damage to on-disk structures, so we should @@ -1441,25 +1321,6 @@ static void dbgPrintInitInfo(void) DBGPRINTF("Messages with malicious PTR DNS Records are %sdropped.\n", glbl.GetDropMalPTRMsgs() ? "" : "not "); - DBGPRINTF("Main queue size %d messages.\n", iMainMsgQueueSize); - DBGPRINTF("Main queue worker threads: %d, wThread shutdown: %d, Perists every %d updates.\n", - iMainMsgQueueNumWorkers, iMainMsgQtoWrkShutdown, iMainMsgQPersistUpdCnt); - DBGPRINTF("Main queue timeouts: shutdown: %d, action completion shutdown: %d, enq: %d\n", - iMainMsgQtoQShutdown, iMainMsgQtoActShutdown, iMainMsgQtoEnq); - DBGPRINTF("Main queue watermarks: high: %d, low: %d, discard: %d, discard-severity: %d\n", - iMainMsgQHighWtrMark, iMainMsgQLowWtrMark, iMainMsgQDiscardMark, iMainMsgQDiscardSeverity); - DBGPRINTF("Main queue save on shutdown %d, max disk space allowed %lld\n", - bMainMsgQSaveOnShutdown, iMainMsgQueMaxDiskSpace); - /* TODO: add - iActionRetryCount = 0; - iActionRetryInterval = 30000; - static int iMainMsgQtoWrkMinMsgs = 100; - static int iMainMsgQbSaveOnShutdown = 1; - iMainMsgQueMaxDiskSpace = 0; - setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", 100); - setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", 1); - */ - DBGPRINTF("Work Directory: '%s'.\n", glbl.GetWorkDir()); } @@ -1528,12 +1389,12 @@ rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName) DEFiRet; /* switch the message object to threaded operation, if necessary */ - if(MainMsgQueType == QUEUETYPE_DIRECT || iMainMsgQueueNumWorkers > 1) { + if(ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DIRECT || ourConf->globals.mainQ.iMainMsgQueueNumWorkers > 1) { MsgEnableThreadSafety(); } /* create message queue */ - CHKiRet_Hdlr(qqueueConstruct(ppQueue, MainMsgQueType, iMainMsgQueueNumWorkers, iMainMsgQueueSize, msgConsumer)) { + CHKiRet_Hdlr(qqueueConstruct(ppQueue, ourConf->globals.mainQ.MainMsgQueType, ourConf->globals.mainQ.iMainMsgQueueNumWorkers, ourConf->globals.mainQ.iMainMsgQueueSize, msgConsumer)) { /* no queue is fatal, we need to give up in that case... */ errmsg.LogError(0, iRet, "could not create (ruleset) main message queue"); \ } @@ -1550,25 +1411,25 @@ rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName) errmsg.LogError(0, NO_ERRCODE, "Invalid " #directive ", error %d. Ignored, running with default setting", iRet); \ } - setQPROP(qqueueSetMaxFileSize, "$MainMsgQueueFileSize", iMainMsgQueMaxFileSize); - setQPROP(qqueueSetsizeOnDiskMax, "$MainMsgQueueMaxDiskSpace", iMainMsgQueMaxDiskSpace); - setQPROP(qqueueSetiDeqBatchSize, "$MainMsgQueueDequeueBatchSize", iMainMsgQueDeqBatchSize); - setQPROPstr(qqueueSetFilePrefix, "$MainMsgQueueFileName", pszMainMsgQFName); - setQPROP(qqueueSetiPersistUpdCnt, "$MainMsgQueueCheckpointInterval", iMainMsgQPersistUpdCnt); - setQPROP(qqueueSetbSyncQueueFiles, "$MainMsgQueueSyncQueueFiles", bMainMsgQSyncQeueFiles); - setQPROP(qqueueSettoQShutdown, "$MainMsgQueueTimeoutShutdown", iMainMsgQtoQShutdown ); - setQPROP(qqueueSettoActShutdown, "$MainMsgQueueTimeoutActionCompletion", iMainMsgQtoActShutdown); - setQPROP(qqueueSettoWrkShutdown, "$MainMsgQueueWorkerTimeoutThreadShutdown", iMainMsgQtoWrkShutdown); - setQPROP(qqueueSettoEnq, "$MainMsgQueueTimeoutEnqueue", iMainMsgQtoEnq); - setQPROP(qqueueSetiHighWtrMrk, "$MainMsgQueueHighWaterMark", iMainMsgQHighWtrMark); - setQPROP(qqueueSetiLowWtrMrk, "$MainMsgQueueLowWaterMark", iMainMsgQLowWtrMark); - setQPROP(qqueueSetiDiscardMrk, "$MainMsgQueueDiscardMark", iMainMsgQDiscardMark); - setQPROP(qqueueSetiDiscardSeverity, "$MainMsgQueueDiscardSeverity", iMainMsgQDiscardSeverity); - setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", iMainMsgQWrkMinMsgs); - setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", bMainMsgQSaveOnShutdown); - setQPROP(qqueueSetiDeqSlowdown, "$MainMsgQueueDequeueSlowdown", iMainMsgQDeqSlowdown); - setQPROP(qqueueSetiDeqtWinFromHr, "$MainMsgQueueDequeueTimeBegin", iMainMsgQueueDeqtWinFromHr); - setQPROP(qqueueSetiDeqtWinToHr, "$MainMsgQueueDequeueTimeEnd", iMainMsgQueueDeqtWinToHr); + setQPROP(qqueueSetMaxFileSize, "$MainMsgQueueFileSize", ourConf->globals.mainQ.iMainMsgQueMaxFileSize); + setQPROP(qqueueSetsizeOnDiskMax, "$MainMsgQueueMaxDiskSpace", ourConf->globals.mainQ.iMainMsgQueMaxDiskSpace); + setQPROP(qqueueSetiDeqBatchSize, "$MainMsgQueueDequeueBatchSize", ourConf->globals.mainQ.iMainMsgQueDeqBatchSize); + setQPROPstr(qqueueSetFilePrefix, "$MainMsgQueueFileName", ourConf->globals.mainQ.pszMainMsgQFName); + setQPROP(qqueueSetiPersistUpdCnt, "$MainMsgQueueCheckpointInterval", ourConf->globals.mainQ.iMainMsgQPersistUpdCnt); + setQPROP(qqueueSetbSyncQueueFiles, "$MainMsgQueueSyncQueueFiles", ourConf->globals.mainQ.bMainMsgQSyncQeueFiles); + setQPROP(qqueueSettoQShutdown, "$MainMsgQueueTimeoutShutdown", ourConf->globals.mainQ.iMainMsgQtoQShutdown ); + setQPROP(qqueueSettoActShutdown, "$MainMsgQueueTimeoutActionCompletion", ourConf->globals.mainQ.iMainMsgQtoActShutdown); + setQPROP(qqueueSettoWrkShutdown, "$MainMsgQueueWorkerTimeoutThreadShutdown", ourConf->globals.mainQ.iMainMsgQtoWrkShutdown); + setQPROP(qqueueSettoEnq, "$MainMsgQueueTimeoutEnqueue", ourConf->globals.mainQ.iMainMsgQtoEnq); + setQPROP(qqueueSetiHighWtrMrk, "$MainMsgQueueHighWaterMark", ourConf->globals.mainQ.iMainMsgQHighWtrMark); + setQPROP(qqueueSetiLowWtrMrk, "$MainMsgQueueLowWaterMark", ourConf->globals.mainQ.iMainMsgQLowWtrMark); + setQPROP(qqueueSetiDiscardMrk, "$MainMsgQueueDiscardMark", ourConf->globals.mainQ.iMainMsgQDiscardMark); + setQPROP(qqueueSetiDiscardSeverity, "$MainMsgQueueDiscardSeverity", ourConf->globals.mainQ.iMainMsgQDiscardSeverity); + setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", ourConf->globals.mainQ.iMainMsgQWrkMinMsgs); + setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", ourConf->globals.mainQ.bMainMsgQSaveOnShutdown); + setQPROP(qqueueSetiDeqSlowdown, "$MainMsgQueueDequeueSlowdown", ourConf->globals.mainQ.iMainMsgQDeqSlowdown); + setQPROP(qqueueSetiDeqtWinFromHr, "$MainMsgQueueDequeueTimeBegin", ourConf->globals.mainQ.iMainMsgQueueDeqtWinFromHr); + setQPROP(qqueueSetiDeqtWinToHr, "$MainMsgQueueDequeueTimeEnd", ourConf->globals.mainQ.iMainMsgQueueDeqtWinToHr); # undef setQPROP # undef setQPROPstr @@ -1592,7 +1453,6 @@ init(void) rsRetVal localRet; int iNbrActions; int bHadConfigErr = 0; - ruleset_t *pRuleset; char cbuf[BUFSIZ]; char bufStartUpMsg[512]; struct sigaction sigAct; @@ -1648,28 +1508,28 @@ init(void) legacyOptsHook(); /* some checks */ - if(iMainMsgQueueNumWorkers < 1) { + if(ourConf->globals.mainQ.iMainMsgQueueNumWorkers < 1) { errmsg.LogError(0, NO_ERRCODE, "$MainMsgQueueNumWorkers must be at least 1! Set to 1.\n"); - iMainMsgQueueNumWorkers = 1; + ourConf->globals.mainQ.iMainMsgQueueNumWorkers = 1; } - if(MainMsgQueType == QUEUETYPE_DISK) { + if(ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DISK) { errno = 0; /* for logerror! */ if(glbl.GetWorkDir() == NULL) { errmsg.LogError(0, NO_ERRCODE, "No $WorkDirectory specified - can not run main message queue in 'disk' mode. " "Using 'FixedArray' instead.\n"); - MainMsgQueType = QUEUETYPE_FIXED_ARRAY; + ourConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY; } - if(pszMainMsgQFName == NULL) { + if(ourConf->globals.mainQ.pszMainMsgQFName == NULL) { errmsg.LogError(0, NO_ERRCODE, "No $MainMsgQueueFileName specified - can not run main message queue in " "'disk' mode. Using 'FixedArray' instead.\n"); - MainMsgQueType = QUEUETYPE_FIXED_ARRAY; + ourConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY; } } /* check if we need to generate a config DAG and, if so, do that */ - if(pszConfDAGFile != NULL) - generateConfigDAG(pszConfDAGFile); + if(ourConf->globals.pszConfDAGFile != NULL) + generateConfigDAG(ourConf->globals.pszConfDAGFile); /* we are done checking the config - now validate if we should actually run or not. * If not, terminate. -- rgerhards, 2008-07-25 @@ -1682,7 +1542,8 @@ init(void) ABORT_FINALIZE(RS_RET_VALIDATION_RUN); } - if(bAbortOnUncleanConfig && bHadConfigErr) { +#warning restructure following if to use return value of loadConf + if(loadConf->globals.bAbortOnUncleanConfig && bHadConfigErr) { fprintf(stderr, "rsyslogd: $AbortOnUncleanConfig is set, and config is not clean.\n" "Check error log for details, fix errors and restart. As a last\n" "resort, you may want to remove $AbortOnUncleanConfig to permit a\n" @@ -1697,7 +1558,7 @@ init(void) exit(1); } - bHaveMainQueue = (MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1; + bHaveMainQueue = (ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1; DBGPRINTF("Main processing queue is initialized and running\n"); /* the output part and the queue is now ready to run. So it is a good time @@ -1738,81 +1599,6 @@ finalize_it: } -/* Switch the default ruleset (that, what servcies bind to if nothing specific - * is specified). - * rgerhards, 2009-06-12 - */ -static rsRetVal -setDefaultRuleset(void __attribute__((unused)) *pVal, uchar *pszName) -{ - DEFiRet; - - CHKiRet(ruleset.SetDefaultRuleset(ourConf, pszName)); - -finalize_it: - free(pszName); /* no longer needed */ - RETiRet; -} - - -/* Switch to either an already existing rule set or start a new one. The - * named rule set becomes the new "current" rule set (what means that new - * actions are added to it). - * rgerhards, 2009-06-12 - */ -static rsRetVal -setCurrRuleset(void __attribute__((unused)) *pVal, uchar *pszName) -{ - ruleset_t *pRuleset; - rsRetVal localRet; - DEFiRet; - - localRet = ruleset.SetCurrRuleset(ourConf, pszName); - - if(localRet == RS_RET_NOT_FOUND) { - DBGPRINTF("begin new current rule set '%s'\n", pszName); - CHKiRet(ruleset.Construct(&pRuleset)); - CHKiRet(ruleset.SetName(ourConf, pRuleset, pszName)); - CHKiRet(ruleset.ConstructFinalize(ourConf, pRuleset)); - } else { - ABORT_FINALIZE(localRet); - } - -finalize_it: - free(pszName); /* no longer needed */ - RETiRet; -} - - -/* set the main message queue mode - * rgerhards, 2008-01-03 - */ -static rsRetVal setMainMsgQueType(void __attribute__((unused)) *pVal, uchar *pszType) -{ - DEFiRet; - - if (!strcasecmp((char *) pszType, "fixedarray")) { - MainMsgQueType = QUEUETYPE_FIXED_ARRAY; - DBGPRINTF("main message queue type set to FIXED_ARRAY\n"); - } else if (!strcasecmp((char *) pszType, "linkedlist")) { - MainMsgQueType = QUEUETYPE_LINKEDLIST; - DBGPRINTF("main message queue type set to LINKEDLIST\n"); - } else if (!strcasecmp((char *) pszType, "disk")) { - MainMsgQueType = QUEUETYPE_DISK; - DBGPRINTF("main message queue type set to DISK\n"); - } else if (!strcasecmp((char *) pszType, "direct")) { - MainMsgQueType = QUEUETYPE_DIRECT; - DBGPRINTF("main message queue type set to DIRECT (no queueing at all)\n"); - } else { - errmsg.LogError(0, RS_RET_INVALID_PARAMS, "unknown mainmessagequeuetype parameter: %s", (char *) pszType); - iRet = RS_RET_INVALID_PARAMS; - } - free(pszType); /* no longer needed */ - - RETiRet; -} - - /* * The following function is resposible for handling a SIGHUP signal. Since * we are now doing mallocs/free as part of init we had better not being @@ -1913,7 +1699,7 @@ mainloop(void) * powertop, for example). In that case, we primarily wait for a signal, * but a once-a-day wakeup should be quite acceptable. -- rgerhards, 2008-06-09 */ - tvSelectTimeout.tv_sec = (bReduceRepeatMsgs == 1) ? TIMERINTVL : 86400 /*1 day*/; + tvSelectTimeout.tv_sec = (runConf->globals.bReduceRepeatMsgs == 1) ? TIMERINTVL : 86400 /*1 day*/; //tvSelectTimeout.tv_sec = TIMERINTVL; /* TODO: change this back to the above code when we have a better solution for apc */ tvSelectTimeout.tv_usec = 0; select(1, NULL, NULL, NULL, &tvSelectTimeout); @@ -1941,7 +1727,7 @@ mainloop(void) * for the time being, I think the remaining risk can be accepted. * rgerhards, 2008-01-10 */ - if(bReduceRepeatMsgs == 1) + if(runConf->globals.bReduceRepeatMsgs == 1) doFlushRptdMsgs(); if(bHadHUP) { @@ -1954,49 +1740,10 @@ mainloop(void) ENDfunc } - -/* this method is needed to shuffle the current conf object down to the - * IncludeConfig handler. - */ -static rsRetVal -doNameLine(void *pVal, uchar *pNewVal) -{ - DEFiRet; - iRet = conf.doNameLine(ourConf, pVal, pNewVal); - free(pNewVal); - RETiRet; -} - - -/* this method is needed to shuffle the current conf object down to the - * IncludeConfig handler. - */ -static rsRetVal -doModLoad(void *pVal, uchar *pNewVal) -{ - DEFiRet; - iRet = conf.doModLoad(ourConf, pVal, pNewVal); - free(pNewVal); - RETiRet; -} - - -/* this method is needed to shuffle the current conf object down to the - * IncludeConfig handler. - */ -static rsRetVal -doIncludeLine(void *pVal, uchar *pNewVal) -{ - DEFiRet; - iRet = conf.doIncludeLine(ourConf, pVal, pNewVal); - free(pNewVal); - RETiRet; -} - /* load build-in modules * very first version begun on 2007-07-23 by rgerhards */ -static rsRetVal loadBuildInModules(rsconf_t *config) +static rsRetVal loadBuildInModules() { DEFiRet; @@ -2043,63 +1790,6 @@ static rsRetVal loadBuildInModules(rsconf_t *config) CHKiRet(module.doModInit(modInitsmfwd, UCHAR_CONSTANT("builtin-smfwd"), NULL)); CHKiRet(module.doModInit(modInitsmtradfwd, UCHAR_CONSTANT("builtin-smtradfwd"), NULL)); - /* ok, initialization of the command handler probably does not 100% belong right in - * this space here. However, with the current design, this is actually quite a good - * place to put it. We might decide to shuffle it around later, but for the time - * being, the code has found its home here. A not-just-sideeffect of this decision - * is that rsyslog will terminate if we can not register our built-in config commands. - * This, I think, is the right thing to do. -- rgerhards, 2007-07-31 - */ - CHKiRet(regCfSysLineHdlr((uchar *)"logrsyslogstatusmessages", 0, eCmdHdlrBinary, NULL, &ourConf->globals.bLogStatusMsgs, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, setDefaultRuleset, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord, setCurrRuleset, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrGoneAway, NULL, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszMainMsgQFName, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt, NULL, &iMainMsgQueueSize, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQHighWtrMark, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuelowwatermark", 0, eCmdHdlrInt, NULL, &iMainMsgQLowWtrMark, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardmark", 0, eCmdHdlrInt, NULL, &iMainMsgQDiscardMark, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardseverity", 0, eCmdHdlrSeverity, NULL, &iMainMsgQDiscardSeverity, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuecheckpointinterval", 0, eCmdHdlrInt, NULL, &iMainMsgQPersistUpdCnt, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesyncqueuefiles", 0, eCmdHdlrBinary, NULL, &bMainMsgQSyncQeueFiles, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetype", 0, eCmdHdlrGetWord, setMainMsgQueType, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreads", 0, eCmdHdlrInt, NULL, &iMainMsgQueueNumWorkers, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutshutdown", 0, eCmdHdlrInt, NULL, &iMainMsgQtoQShutdown, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutactioncompletion", 0, eCmdHdlrInt, NULL, &iMainMsgQtoActShutdown, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutenqueue", 0, eCmdHdlrInt, NULL, &iMainMsgQtoEnq, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkertimeoutthreadshutdown", 0, eCmdHdlrInt, NULL, &iMainMsgQtoWrkShutdown, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeueslowdown", 0, eCmdHdlrInt, NULL, &iMainMsgQDeqSlowdown, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreadminimummessages", 0, eCmdHdlrInt, NULL, &iMainMsgQWrkMinMsgs, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxfilesize", 0, eCmdHdlrSize, NULL, &iMainMsgQueMaxFileSize, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuebatchsize", 0, eCmdHdlrSize, NULL, &iMainMsgQueDeqBatchSize, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxdiskspace", 0, eCmdHdlrSize, NULL, &iMainMsgQueMaxDiskSpace, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesaveonshutdown", 0, eCmdHdlrBinary, NULL, &bMainMsgQSaveOnShutdown, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimebegin", 0, eCmdHdlrInt, NULL, &iMainMsgQueueDeqtWinFromHr, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimeend", 0, eCmdHdlrInt, NULL, &iMainMsgQueueDeqtWinToHr, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"abortonuncleanconfig", 0, eCmdHdlrBinary, NULL, &bAbortOnUncleanConfig, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgreduction", 0, eCmdHdlrBinary, NULL, &bReduceRepeatMsgs, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, setActionResumeInterval, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler, doNameLine, (void*)DIR_TEMPLATE, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler, doNameLine, (void*)DIR_OUTCHANNEL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"allowedsender", 0, eCmdHdlrCustomHandler, doNameLine, (void*)DIR_ALLOWEDSENDER, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, doModLoad, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, doIncludeLine, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode, setUmask, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"maxopenfiles", 0, eCmdHdlrInt, setMaxFiles, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"debugprinttemplatelist", 0, eCmdHdlrBinary, NULL, &(config->globals.bDebugPrintTemplateList), NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"debugprintmodulelist", 0, eCmdHdlrBinary, NULL, &(config->globals.bDebugPrintModuleList), NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"debugprintcfsyslinehandlerlist", 0, eCmdHdlrBinary, - NULL, &(config->globals.bDebugPrintCfSysLineHandlerList), NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"moddir", 0, eCmdHdlrGetWord, NULL, &pModDir, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"generateconfiggraph", 0, eCmdHdlrGetWord, NULL, &pszConfDAGFile, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary, NULL, &ourConf->globals.bErrMsgToStderr, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, setMaxMsgSize, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouser", 0, eCmdHdlrUID, NULL, &uidDropPriv, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouserid", 0, eCmdHdlrInt, NULL, &uidDropPriv, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroup", 0, eCmdHdlrGID, NULL, &gidDropPriv, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroupid", 0, eCmdHdlrGID, NULL, &gidDropPriv, NULL, eConfObjGlobal)); - finalize_it: RETiRet; } @@ -2202,12 +1892,12 @@ static rsRetVal mainThread() * drop privileges at all. Doing it correctly, requires a change in architecture, which * we should do over time. TODO -- rgerhards, 2008-11-19 */ - if(gidDropPriv != 0) { - doDropPrivGid(gidDropPriv); + if(ourConf->globals.gidDropPriv != 0) { + doDropPrivGid(ourConf->globals.gidDropPriv); } - if(uidDropPriv != 0) { - doDropPrivUid(uidDropPriv); + if(ourConf->globals.uidDropPriv != 0) { + doDropPrivUid(ourConf->globals.uidDropPriv); } /* finally let the inputs run... */ @@ -2874,7 +2564,7 @@ int realMain(int argc, char **argv) /* begin config load */ - if((iRet = loadBuildInModules(ourConf)) != RS_RET_OK) { + if((iRet = loadBuildInModules()) != RS_RET_OK) { fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n", iRet); exit(1); /* "good" exit, leaving at init for fatal error */ -- cgit v1.2.3 From 115b15a568c050950517b8bedf067c89b3b7ac30 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 26 Apr 2011 17:10:36 +0200 Subject: shuffled even more config code from syslgod to config handler --- runtime/Makefile.am | 4 +- runtime/rsconf.c | 114 ++++++++++++++++++++++++++++++++++- tools/syslogd.c | 167 +--------------------------------------------------- 3 files changed, 116 insertions(+), 169 deletions(-) diff --git a/runtime/Makefile.am b/runtime/Makefile.am index c19bfe47..cfcfdc2c 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -112,9 +112,9 @@ librsyslog_la_SOURCES = \ # runtime or will no longer be needed. -- rgerhards, 2008-06-13 if WITH_MODDIRS -librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) +librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools else -librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) +librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools endif #librsyslog_la_LDFLAGS = -module -avoid-version librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS) $(LIBEE_LIBS) diff --git a/runtime/rsconf.c b/runtime/rsconf.c index bebe77dd..fb9d71e3 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -46,6 +46,19 @@ #include "action.h" #include "glbl.h" #include "unicode-helper.h" +#include "omshell.h" +#include "omusrmsg.h" +#include "omfwd.h" +#include "omfile.h" +#include "ompipe.h" +#include "omdiscard.h" +#include "pmrfc5424.h" +#include "pmrfc3164.h" +#include "smfile.h" +#include "smtradfile.h" +#include "smfwd.h" +#include "smtradfwd.h" +#include "parser.h" /* static data */ DEFobjStaticHelpers @@ -54,11 +67,27 @@ DEFobjCurrIf(module) DEFobjCurrIf(conf) DEFobjCurrIf(errmsg) DEFobjCurrIf(glbl) +DEFobjCurrIf(parser) /* exported static data */ rsconf_t *runConf = NULL;/* the currently running config */ rsconf_t *loadConf = NULL;/* the config currently being loaded (no concurrent config load supported!) */ +/* hardcoded standard templates (used for defaults) */ +static uchar template_DebugFormat[] = "\"Debug line with all properties:\nFROMHOST: '%FROMHOST%', fromhost-ip: '%fromhost-ip%', HOSTNAME: '%HOSTNAME%', PRI: %PRI%,\nsyslogtag '%syslogtag%', programname: '%programname%', APP-NAME: '%APP-NAME%', PROCID: '%PROCID%', MSGID: '%MSGID%',\nTIMESTAMP: '%TIMESTAMP%', STRUCTURED-DATA: '%STRUCTURED-DATA%',\nmsg: '%msg%'\nescaped msg: '%msg:::drop-cc%'\ninputname: %inputname% rawmsg: '%rawmsg%'\n\n\""; +static uchar template_SyslogProtocol23Format[] = "\"<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME% %APP-NAME% %PROCID% %MSGID% %STRUCTURED-DATA% %msg%\n\""; +static uchar template_TraditionalFileFormat[] = "=RSYSLOG_TraditionalFileFormat"; +static uchar template_FileFormat[] = "=RSYSLOG_FileFormat"; +static uchar template_ForwardFormat[] = "=RSYSLOG_ForwardFormat"; +static uchar template_TraditionalForwardFormat[] = "=RSYSLOG_TraditionalForwardFormat"; +static uchar template_WallFmt[] = "\"\r\n\7Message from syslogd@%HOSTNAME% at %timegenerated% ...\r\n %syslogtag%%msg%\n\r\""; +static uchar template_StdUsrMsgFmt[] = "\" %syslogtag%%msg%\n\r\""; +static uchar template_StdDBFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-mysql%', '%timegenerated:::date-mysql%', %iut%, '%syslogtag%')\",SQL"; +static uchar template_StdPgSQLFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-pgsql%', '%timegenerated:::date-pgsql%', %iut%, '%syslogtag%')\",STDSQL"; +static uchar template_spoofadr[] = "\"%fromhost-ip%\""; +/* end templates */ + + /* Standard-Constructor */ BEGINobjConstruct(rsconf) /* be sure to specify the object type also in END macro! */ @@ -390,13 +419,69 @@ setModDir(void __attribute__((unused)) *pVal, uchar* pszNewVal) } +/* load build-in modules + * very first version begun on 2007-07-23 by rgerhards + */ +static rsRetVal +loadBuildInModules() +{ + DEFiRet; + + CHKiRet(module.doModInit(modInitFile, UCHAR_CONSTANT("builtin-file"), NULL)); + CHKiRet(module.doModInit(modInitPipe, UCHAR_CONSTANT("builtin-pipe"), NULL)); + CHKiRet(module.doModInit(modInitShell, UCHAR_CONSTANT("builtin-shell"), NULL)); + CHKiRet(module.doModInit(modInitDiscard, UCHAR_CONSTANT("builtin-discard"), NULL)); +# ifdef SYSLOG_INET + CHKiRet(module.doModInit(modInitFwd, UCHAR_CONSTANT("builtin-fwd"), NULL)); +# endif + + /* dirty, but this must be for the time being: the usrmsg module must always be + * loaded as last module. This is because it processes any type of action selector. + * If we load it before other modules, these others will never have a chance of + * working with the config file. We may change that implementation so that a user name + * must start with an alnum, that would definitely help (but would it break backwards + * compatibility?). * rgerhards, 2007-07-23 + * User names now must begin with: + * [a-zA-Z0-9_.] + */ + CHKiRet(module.doModInit(modInitUsrMsg, (uchar*) "builtin-usrmsg", NULL)); + + /* load build-in parser modules */ + CHKiRet(module.doModInit(modInitpmrfc5424, UCHAR_CONSTANT("builtin-pmrfc5424"), NULL)); + CHKiRet(module.doModInit(modInitpmrfc3164, UCHAR_CONSTANT("builtin-pmrfc3164"), NULL)); + + /* and set default parser modules. Order is *very* important, legacy + * (3164) parser needs to go last! */ + CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc5424"))); + CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc3164"))); + + /* load build-in strgen modules */ + CHKiRet(module.doModInit(modInitsmfile, UCHAR_CONSTANT("builtin-smfile"), NULL)); + CHKiRet(module.doModInit(modInitsmtradfile, UCHAR_CONSTANT("builtin-smtradfile"), NULL)); + CHKiRet(module.doModInit(modInitsmfwd, UCHAR_CONSTANT("builtin-smfwd"), NULL)); + CHKiRet(module.doModInit(modInitsmtradfwd, UCHAR_CONSTANT("builtin-smtradfwd"), NULL)); + +finalize_it: + if(iRet != RS_RET_OK) { + /* we need to do fprintf, as we do not yet have an error reporting system + * in place. + */ + fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n", + iRet); + } + RETiRet; +} + + /* intialize the legacy config system */ static inline rsRetVal initLegacyConf(void) { DEFiRet; + uchar *pTmp; ruleset_t *pRuleset; + DBGPRINTF("doing legacy config system init\n"); /* construct the default ruleset */ ruleset.Construct(&pRuleset); ruleset.SetName(loadConf, pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset")); @@ -518,6 +603,30 @@ initLegacyConf(void) CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjGlobal)); + /* initialize the build-in templates */ + pTmp = template_DebugFormat; + tplAddLine(ourConf, "RSYSLOG_DebugFormat", &pTmp); + pTmp = template_SyslogProtocol23Format; + tplAddLine(ourConf, "RSYSLOG_SyslogProtocol23Format", &pTmp); + pTmp = template_FileFormat; /* new format for files with high-precision stamp */ + tplAddLine(ourConf, "RSYSLOG_FileFormat", &pTmp); + pTmp = template_TraditionalFileFormat; + tplAddLine(ourConf, "RSYSLOG_TraditionalFileFormat", &pTmp); + pTmp = template_WallFmt; + tplAddLine(ourConf, " WallFmt", &pTmp); + pTmp = template_ForwardFormat; + tplAddLine(ourConf, "RSYSLOG_ForwardFormat", &pTmp); + pTmp = template_TraditionalForwardFormat; + tplAddLine(ourConf, "RSYSLOG_TraditionalForwardFormat", &pTmp); + pTmp = template_StdUsrMsgFmt; + tplAddLine(ourConf, " StdUsrMsgFmt", &pTmp); + pTmp = template_StdDBFmt; + tplAddLine(ourConf, " StdDBFmt", &pTmp); + pTmp = template_StdPgSQLFmt; + tplAddLine(ourConf, " StdPgSQLFmt", &pTmp); + pTmp = template_spoofadr; + tplLastStaticInit(ourConf, tplAddLine(ourConf, "RSYSLOG_omudpspoofDfltSourceTpl", &pTmp)); + finalize_it: RETiRet; } @@ -543,9 +652,10 @@ load(rsconf_t **cnf, uchar *confFile) ourConf = loadConf; // TODO: remove, once ourConf is gone! dbgprintf("XXXX: loadConf is %p\n", loadConf); + CHKiRet(loadBuildInModules()); CHKiRet(initLegacyConf()); -#if 0 +#if 1 dbgprintf("XXXX: 2, conf=%p\n", conf.processConfFile); /* open the configuration file */ localRet = conf.processConfFile(loadConf, confFile); @@ -639,6 +749,7 @@ BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */ CHKiRet(objUse(conf, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(parser, CORE_COMPONENT)); /* now set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, rsconfDebugPrint); @@ -654,6 +765,7 @@ BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */ objRelease(conf, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); + objRelease(parser, CORE_COMPONENT); ENDObjClassExit(rsconf) /* vi:set ai: diff --git a/tools/syslogd.c b/tools/syslogd.c index 409bb4f9..0dbb3c06 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -108,18 +108,6 @@ #include "action.h" #include "iminternal.h" #include "cfsysline.h" -#include "omshell.h" -#include "omusrmsg.h" -#include "omfwd.h" -#include "omfile.h" -#include "ompipe.h" -#include "omdiscard.h" -#include "pmrfc5424.h" -#include "pmrfc3164.h" -#include "smfile.h" -#include "smtradfile.h" -#include "smfwd.h" -#include "smtradfwd.h" #include "threads.h" #include "wti.h" #include "queue.h" @@ -254,21 +242,6 @@ extern int errno; qqueue_t *pMsgQueue = NULL; /* the main message queue */ -/* hardcoded standard templates (used for defaults) */ -static uchar template_DebugFormat[] = "\"Debug line with all properties:\nFROMHOST: '%FROMHOST%', fromhost-ip: '%fromhost-ip%', HOSTNAME: '%HOSTNAME%', PRI: %PRI%,\nsyslogtag '%syslogtag%', programname: '%programname%', APP-NAME: '%APP-NAME%', PROCID: '%PROCID%', MSGID: '%MSGID%',\nTIMESTAMP: '%TIMESTAMP%', STRUCTURED-DATA: '%STRUCTURED-DATA%',\nmsg: '%msg%'\nescaped msg: '%msg:::drop-cc%'\ninputname: %inputname% rawmsg: '%rawmsg%'\n\n\""; -static uchar template_SyslogProtocol23Format[] = "\"<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME% %APP-NAME% %PROCID% %MSGID% %STRUCTURED-DATA% %msg%\n\""; -static uchar template_TraditionalFileFormat[] = "=RSYSLOG_TraditionalFileFormat"; -static uchar template_FileFormat[] = "=RSYSLOG_FileFormat"; -static uchar template_ForwardFormat[] = "=RSYSLOG_ForwardFormat"; -static uchar template_TraditionalForwardFormat[] = "=RSYSLOG_TraditionalForwardFormat"; -static uchar template_WallFmt[] = "\"\r\n\7Message from syslogd@%HOSTNAME% at %timegenerated% ...\r\n %syslogtag%%msg%\n\r\""; -static uchar template_StdUsrMsgFmt[] = "\" %syslogtag%%msg%\n\r\""; -static uchar template_StdDBFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-mysql%', '%timegenerated:::date-mysql%', %iut%, '%syslogtag%')\",SQL"; -static uchar template_StdPgSQLFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-pgsql%', '%timegenerated:::date-pgsql%', %iut%, '%syslogtag%')\",STDSQL"; -static uchar template_spoofadr[] = "\"%fromhost-ip%\""; -/* end templates */ - - /* up to the next comment, prototypes that should be removed by reordering */ /* Function prototypes. */ static char **crunch_list(char *list); @@ -499,7 +472,7 @@ logmsgInternal(int iErr, int pri, uchar *msg, int flags) * permits us to process unmodified config files which otherwise contain a * supressor statement. */ - if(((Debug == DEBUG_FULL || NoFork) && runConf->globals.bErrMsgToStderr) || iConfigVerify) { + if(((Debug == DEBUG_FULL || NoFork) && ourConf->globals.bErrMsgToStderr) || iConfigVerify) { if(LOG_PRI(pri) == LOG_ERR) fprintf(stderr, "rsyslogd: %s\n", msg); } @@ -1458,53 +1431,6 @@ init(void) struct sigaction sigAct; DEFiRet; - DBGPRINTF("rsyslog %s - called init()\n", VERSION); -#if 1 - - /* open the configuration file */ - localRet = conf.processConfFile(ourConf, ConfFile); - CHKiRet(conf.GetNbrActActions(ourConf, &iNbrActions)); - - dbgprintf("rsyslog finished loading initial config %p\n", ourConf); - rsconf.DebugPrint(ourConf); - - if(localRet != RS_RET_OK) { - errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", ConfFile); - bHadConfigErr = 1; - } else if(iNbrActions == 0) { - errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no active actions configured. Inputs will " - "run, but no output whatsoever is created."); - bHadConfigErr = 1; - } - - if((localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) || iNbrActions == 0) { - /* rgerhards: this code is executed to set defaults when the - * config file could not be opened. We might think about - * abandoning the run in this case - but this, too, is not - * very clever... So we stick with what we have. - * We ignore any errors while doing this - we would be lost anyhow... - */ - errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!"); - - /* note: we previously used _POSIY_TTY_NAME_MAX+1, but this turned out to be - * too low on linux... :-S -- rgerhards, 2008-07-28 - */ - char szTTYNameBuf[128]; - rule_t *pRule = NULL; /* initialization to NULL is *vitally* important! */ - conf.cfline(ourConf, UCHAR_CONSTANT("*.ERR\t" _PATH_CONSOLE), &pRule); - conf.cfline(ourConf, UCHAR_CONSTANT("syslog.*\t" _PATH_CONSOLE), &pRule); - conf.cfline(ourConf, UCHAR_CONSTANT("*.PANIC\t*"), &pRule); - conf.cfline(ourConf, UCHAR_CONSTANT("syslog.*\troot"), &pRule); - if(ttyname_r(0, szTTYNameBuf, sizeof(szTTYNameBuf)) == 0) { - snprintf(cbuf,sizeof(cbuf), "*.*\t%s", szTTYNameBuf); - conf.cfline(ourConf, (uchar*)cbuf, &pRule); - } else { - DBGPRINTF("error %d obtaining controlling terminal, not using that emergency rule\n", errno); - } - ruleset.AddRule(ourConf, ruleset.GetCurrent(ourConf), &pRule); - } -#endif - legacyOptsHook(); /* some checks */ @@ -1740,61 +1666,6 @@ mainloop(void) ENDfunc } -/* load build-in modules - * very first version begun on 2007-07-23 by rgerhards - */ -static rsRetVal loadBuildInModules() -{ - DEFiRet; - - if((iRet = module.doModInit(modInitFile, UCHAR_CONSTANT("builtin-file"), NULL)) != RS_RET_OK) { - RETiRet; - } - if((iRet = module.doModInit(modInitPipe, UCHAR_CONSTANT("builtin-pipe"), NULL)) != RS_RET_OK) { - RETiRet; - } -#ifdef SYSLOG_INET - if((iRet = module.doModInit(modInitFwd, UCHAR_CONSTANT("builtin-fwd"), NULL)) != RS_RET_OK) { - RETiRet; - } -#endif - if((iRet = module.doModInit(modInitShell, UCHAR_CONSTANT("builtin-shell"), NULL)) != RS_RET_OK) { - RETiRet; - } - if((iRet = module.doModInit(modInitDiscard, UCHAR_CONSTANT("builtin-discard"), NULL)) != RS_RET_OK) { - RETiRet; - } - - /* dirty, but this must be for the time being: the usrmsg module must always be - * loaded as last module. This is because it processes any type of action selector. - * If we load it before other modules, these others will never have a chance of - * working with the config file. We may change that implementation so that a user name - * must start with an alnum, that would definitely help (but would it break backwards - * compatibility?). * rgerhards, 2007-07-23 - * User names now must begin with: - * [a-zA-Z0-9_.] - */ - CHKiRet(module.doModInit(modInitUsrMsg, (uchar*) "builtin-usrmsg", NULL)); - - /* load build-in parser modules */ - CHKiRet(module.doModInit(modInitpmrfc5424, UCHAR_CONSTANT("builtin-pmrfc5424"), NULL)); - CHKiRet(module.doModInit(modInitpmrfc3164, UCHAR_CONSTANT("builtin-pmrfc3164"), NULL)); - - /* and set default parser modules (order is *very* important, legacy (3164) parse needs to go last! */ - CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc5424"))); - CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc3164"))); - - /* load build-in strgen modules */ - CHKiRet(module.doModInit(modInitsmfile, UCHAR_CONSTANT("builtin-smfile"), NULL)); - CHKiRet(module.doModInit(modInitsmtradfile, UCHAR_CONSTANT("builtin-smtradfile"), NULL)); - CHKiRet(module.doModInit(modInitsmfwd, UCHAR_CONSTANT("builtin-smfwd"), NULL)); - CHKiRet(module.doModInit(modInitsmtradfwd, UCHAR_CONSTANT("builtin-smtradfwd"), NULL)); - -finalize_it: - RETiRet; -} - - /* print version and compile-time setting information. */ static void printVersion(void) @@ -1847,31 +1718,6 @@ static void printVersion(void) static rsRetVal mainThread() { DEFiRet; - uchar *pTmp; - - /* initialize the build-in templates */ - pTmp = template_DebugFormat; - tplAddLine(ourConf, "RSYSLOG_DebugFormat", &pTmp); - pTmp = template_SyslogProtocol23Format; - tplAddLine(ourConf, "RSYSLOG_SyslogProtocol23Format", &pTmp); - pTmp = template_FileFormat; /* new format for files with high-precision stamp */ - tplAddLine(ourConf, "RSYSLOG_FileFormat", &pTmp); - pTmp = template_TraditionalFileFormat; - tplAddLine(ourConf, "RSYSLOG_TraditionalFileFormat", &pTmp); - pTmp = template_WallFmt; - tplAddLine(ourConf, " WallFmt", &pTmp); - pTmp = template_ForwardFormat; - tplAddLine(ourConf, "RSYSLOG_ForwardFormat", &pTmp); - pTmp = template_TraditionalForwardFormat; - tplAddLine(ourConf, "RSYSLOG_TraditionalForwardFormat", &pTmp); - pTmp = template_StdUsrMsgFmt; - tplAddLine(ourConf, " StdUsrMsgFmt", &pTmp); - pTmp = template_StdDBFmt; - tplAddLine(ourConf, " StdDBFmt", &pTmp); - pTmp = template_StdPgSQLFmt; - tplAddLine(ourConf, " StdPgSQLFmt", &pTmp); - pTmp = template_spoofadr; - tplLastStaticInit(ourConf, tplAddLine(ourConf, "RSYSLOG_omudpspoofDfltSourceTpl", &pTmp)); CHKiRet(init()); @@ -2561,22 +2407,11 @@ int realMain(int argc, char **argv) CHKiRet(rsconf.Load(&ourConf, ConfFile)); - - - /* begin config load */ - if((iRet = loadBuildInModules()) != RS_RET_OK) { - fprintf(stderr, "fatal error: could not activate built-in modules. Error code %d.\n", - iRet); - exit(1); /* "good" exit, leaving at init for fatal error */ - } if(iConfigVerify) { fprintf(stderr, "rsyslogd: version %s, config validation run (level %d), master config %s\n", VERSION, iConfigVerify, ConfFile); } - - - if(bChDirRoot) { if(chdir("/") != 0) fprintf(stderr, "Can not do 'cd /' - still trying to run\n"); -- cgit v1.2.3 From 8fb8c0d37b68d633e562bbc96f9971917620d181 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 26 Apr 2011 17:21:44 +0200 Subject: step: moved config validation code --- runtime/rsconf.c | 42 +++++++++++++++++++++++++++++++++--------- tools/syslogd.c | 20 -------------------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/runtime/rsconf.c b/runtime/rsconf.c index fb9d71e3..eecdbb01 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -632,6 +632,37 @@ finalize_it: } +/* validate the current configuration, generate error messages, do + * optimizations, etc, etc,... + */ +static inline rsRetVal +validateConf(void) +{ + DEFiRet; + + /* some checks */ + if(ourConf->globals.mainQ.iMainMsgQueueNumWorkers < 1) { + errmsg.LogError(0, NO_ERRCODE, "$MainMsgQueueNumWorkers must be at least 1! Set to 1.\n"); + ourConf->globals.mainQ.iMainMsgQueueNumWorkers = 1; + } + + if(ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DISK) { + errno = 0; /* for logerror! */ + if(glbl.GetWorkDir() == NULL) { + errmsg.LogError(0, NO_ERRCODE, "No $WorkDirectory specified - can not run main message queue in 'disk' mode. " + "Using 'FixedArray' instead.\n"); + ourConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY; + } + if(ourConf->globals.mainQ.pszMainMsgQFName == NULL) { + errmsg.LogError(0, NO_ERRCODE, "No $MainMsgQueueFileName specified - can not run main message queue in " + "'disk' mode. Using 'FixedArray' instead.\n"); + ourConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY; + } + } + RETiRet; +} + + /* Load a configuration. This will do all necessary steps to create * the in-memory representation of the configuration, including support * for multiple configuration languages. @@ -650,18 +681,14 @@ load(rsconf_t **cnf, uchar *confFile) CHKiRet(rsconfConstruct(&loadConf)); ourConf = loadConf; // TODO: remove, once ourConf is gone! -dbgprintf("XXXX: loadConf is %p\n", loadConf); CHKiRet(loadBuildInModules()); CHKiRet(initLegacyConf()); -#if 1 -dbgprintf("XXXX: 2, conf=%p\n", conf.processConfFile); /* open the configuration file */ localRet = conf.processConfFile(loadConf, confFile); CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions)); -dbgprintf("XXXX: 4\n"); if(localRet != RS_RET_OK) { errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", confFile); bHadConfigErr = 1; @@ -671,10 +698,8 @@ dbgprintf("XXXX: 4\n"); bHadConfigErr = 1; } -dbgprintf("XXXX: 10\n"); if((localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) || iNbrActions == 0) { -dbgprintf("XXXX: 20\n"); /* rgerhards: this code is executed to set defaults when the * config file could not be opened. We might think about * abandoning the run in this case - but this, too, is not @@ -701,15 +726,14 @@ dbgprintf("XXXX: 20\n"); ruleset.AddRule(loadConf, ruleset.GetCurrent(loadConf), &pRule); } -#endif - + CHKiRet(validateConf()); /* all OK, pass loaded conf to caller */ *cnf = loadConf; // TODO: enable this once all config code is moved to here! loadConf = NULL; dbgprintf("rsyslog finished loading initial config %p\n", loadConf); -// rsconfDebugPrint(loadConf); + rsconfDebugPrint(loadConf); finalize_it: RETiRet; diff --git a/tools/syslogd.c b/tools/syslogd.c index 0dbb3c06..63eb55b9 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -1433,26 +1433,6 @@ init(void) legacyOptsHook(); - /* some checks */ - if(ourConf->globals.mainQ.iMainMsgQueueNumWorkers < 1) { - errmsg.LogError(0, NO_ERRCODE, "$MainMsgQueueNumWorkers must be at least 1! Set to 1.\n"); - ourConf->globals.mainQ.iMainMsgQueueNumWorkers = 1; - } - - if(ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DISK) { - errno = 0; /* for logerror! */ - if(glbl.GetWorkDir() == NULL) { - errmsg.LogError(0, NO_ERRCODE, "No $WorkDirectory specified - can not run main message queue in 'disk' mode. " - "Using 'FixedArray' instead.\n"); - ourConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY; - } - if(ourConf->globals.mainQ.pszMainMsgQFName == NULL) { - errmsg.LogError(0, NO_ERRCODE, "No $MainMsgQueueFileName specified - can not run main message queue in " - "'disk' mode. Using 'FixedArray' instead.\n"); - ourConf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY; - } - } - /* check if we need to generate a config DAG and, if so, do that */ if(ourConf->globals.pszConfDAGFile != NULL) generateConfigDAG(ourConf->globals.pszConfDAGFile); -- cgit v1.2.3 From 19c8bed08dbeb9ce0313ec92d7de85c9c51c4f48 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 26 Apr 2011 17:30:59 +0200 Subject: step: outchannel list integrated into main config object --- outchannel.c | 19 +++++++---------- runtime/rsconf.c | 4 ++++ runtime/rsconf.h | 6 ++++++ runtime/typedefs.h | 1 + tools/syslogd.c | 61 ++++++++++++++++++------------------------------------ 5 files changed, 39 insertions(+), 52 deletions(-) diff --git a/outchannel.c b/outchannel.c index b9b4a6b1..9a3733d8 100644 --- a/outchannel.c +++ b/outchannel.c @@ -37,12 +37,9 @@ #include #include "stringbuf.h" #include "outchannel.h" -#include "dirty.h" +#include "rsconf.h" #include "debug.h" -static struct outchannel *ochRoot = NULL; /* the root of the outchannel list */ -static struct outchannel *ochLast = NULL; /* points to the last element of the outchannel list */ - /* Constructs a outchannel list object. Returns pointer to it * or NULL (if it fails). */ @@ -55,14 +52,14 @@ struct outchannel* ochConstruct(void) /* basic initialisaion is done via calloc() - need to * initialize only values != 0. */ - if(ochLast == NULL) + if(loadConf->och.ochLast == NULL) { /* we are the first element! */ - ochRoot = ochLast = pOch; + loadConf->och.ochRoot = loadConf->och.ochLast = pOch; } else { - ochLast->pNext = pOch; - ochLast = pOch; + loadConf->och.ochLast->pNext = pOch; + loadConf->och.ochLast = pOch; } return(pOch); @@ -251,7 +248,7 @@ struct outchannel *ochFind(char *pName, int iLenName) assert(pName != NULL); - pOch = ochRoot; + pOch = loadConf->och.ochRoot; while(pOch != NULL && !(pOch->iLenName == iLenName && !strcmp(pOch->pszName, pName) @@ -270,7 +267,7 @@ void ochDeleteAll(void) { struct outchannel *pOch, *pOchDel; - pOch = ochRoot; + pOch = loadConf->och.ochRoot; while(pOch != NULL) { dbgprintf("Delete Outchannel: Name='%s'\n ", pOch->pszName == NULL? "NULL" : pOch->pszName); pOchDel = pOch; @@ -289,7 +286,7 @@ void ochPrintList(void) { struct outchannel *pOch; - pOch = ochRoot; + pOch = loadConf->och.ochRoot; while(pOch != NULL) { dbgprintf("Outchannel: Name='%s'\n", pOch->pszName == NULL? "NULL" : pOch->pszName); dbgprintf("\tFile Template: '%s'\n", pOch->pszFileTemplate == NULL ? "NULL" : (char*) pOch->pszFileTemplate); diff --git a/runtime/rsconf.c b/runtime/rsconf.c index eecdbb01..47a6f00b 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -59,6 +59,7 @@ #include "smfwd.h" #include "smtradfwd.h" #include "parser.h" +#include "outchannel.h" /* static data */ DEFobjStaticHelpers @@ -162,6 +163,8 @@ BEGINobjDebugPrint(rsconf) /* be sure to specify the object type also in END and pThis->globals.bLogStatusMsgs); dbgprintf(" bErrMsgToStderr.....................: %d\n", pThis->globals.bErrMsgToStderr); + dbgprintf(" drop Msgs with malicious PTR Record : %d\n", + glbl.GetDropMalPTRMsgs()); ruleset.DebugPrintAll(pThis); DBGPRINTF("\n"); if(pThis->globals.bDebugPrintTemplateList) @@ -190,6 +193,7 @@ BEGINobjDebugPrint(rsconf) /* be sure to specify the object type also in END and setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", 1); */ DBGPRINTF("Work Directory: '%s'.\n", glbl.GetWorkDir()); + ochPrintList(); CODESTARTobjDebugPrint(rsconf) ENDobjDebugPrint(rsconf) diff --git a/runtime/rsconf.h b/runtime/rsconf.h index 5229b9f7..5cd6bfd0 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -91,6 +91,11 @@ struct globals_s { struct defaults_s { }; +/* outchannel-specific data */ +struct outchannels_s { + struct outchannel *ochRoot; /* the root of the outchannel list */ + struct outchannel *ochLast; /* points to the last element of the outchannel list */ +}; struct templates_s { struct template *root; /* the root of the template list */ @@ -121,6 +126,7 @@ struct rsconf_s { globals_t globals; defaults_t defaults; templates_t templates; + outchannels_t och; actions_t actions; rulesets_t rulesets; /* note: rulesets include the complete output part: diff --git a/runtime/typedefs.h b/runtime/typedefs.h index b7df0464..0d23e880 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -87,6 +87,7 @@ typedef struct globals_s globals_t; typedef struct defaults_s defaults_t; typedef struct actions_s actions_t; typedef struct rsconf_s rsconf_t; +typedef struct outchannels_s outchannels_t; typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript function */ typedef uint64 qDeqID; /* queue Dequeue order ID. 32 bits is considered dangerously few */ diff --git a/tools/syslogd.c b/tools/syslogd.c index 63eb55b9..318031a1 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -1280,23 +1280,6 @@ finalize_it: } -/* print debug information as part of init(). This pretty much - * outputs the whole config of rsyslogd. I've moved this code - * out of init() to clean it somewhat up. - * rgerhards, 2007-07-31 - */ -static void dbgPrintInitInfo(void) -{ - dbgprintf("The following is the old-style, to-be-replaced, current config dump at the end " - " of the config load process ;)\n"); - ochPrintList(); - - DBGPRINTF("Messages with malicious PTR DNS Records are %sdropped.\n", - glbl.GetDropMalPTRMsgs() ? "" : "not "); - -} - - /* Actually run the input modules. This happens after privileges are dropped, * if that is requested. */ @@ -1441,31 +1424,31 @@ init(void) * If not, terminate. -- rgerhards, 2008-07-25 */ if(iConfigVerify) { - if(bHadConfigErr) { - /* a bit dirty, but useful... */ - exit(1); - } - ABORT_FINALIZE(RS_RET_VALIDATION_RUN); + if(bHadConfigErr) { + /* a bit dirty, but useful... */ + exit(1); } + ABORT_FINALIZE(RS_RET_VALIDATION_RUN); +} #warning restructure following if to use return value of loadConf - if(loadConf->globals.bAbortOnUncleanConfig && bHadConfigErr) { - fprintf(stderr, "rsyslogd: $AbortOnUncleanConfig is set, and config is not clean.\n" - "Check error log for details, fix errors and restart. As a last\n" - "resort, you may want to remove $AbortOnUncleanConfig to permit a\n" - "startup with a dirty config.\n"); - exit(2); - } +if(loadConf->globals.bAbortOnUncleanConfig && bHadConfigErr) { + fprintf(stderr, "rsyslogd: $AbortOnUncleanConfig is set, and config is not clean.\n" + "Check error log for details, fix errors and restart. As a last\n" + "resort, you may want to remove $AbortOnUncleanConfig to permit a\n" + "startup with a dirty config.\n"); + exit(2); +} - /* create message queue */ - CHKiRet_Hdlr(createMainQueue(&pMsgQueue, UCHAR_CONSTANT("main Q"))) { - /* no queue is fatal, we need to give up in that case... */ - fprintf(stderr, "fatal error %d: could not create message queue - rsyslogd can not run!\n", iRet); - exit(1); - } +/* create message queue */ +CHKiRet_Hdlr(createMainQueue(&pMsgQueue, UCHAR_CONSTANT("main Q"))) { + /* no queue is fatal, we need to give up in that case... */ + fprintf(stderr, "fatal error %d: could not create message queue - rsyslogd can not run!\n", iRet); + exit(1); +} - bHaveMainQueue = (ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1; - DBGPRINTF("Main processing queue is initialized and running\n"); +bHaveMainQueue = (ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1; +DBGPRINTF("Main processing queue is initialized and running\n"); /* the output part and the queue is now ready to run. So it is a good time * to initialize the inputs. Please note that the net code above should be @@ -1477,10 +1460,6 @@ init(void) */ startInputModules(); - if(Debug) { - dbgPrintInitInfo(); - } - memset(&sigAct, 0, sizeof (sigAct)); sigemptyset(&sigAct.sa_mask); sigAct.sa_handler = sighup_handler; -- cgit v1.2.3 From de77494415ae8c169949d13ed0df0af3b1949b54 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 26 Apr 2011 18:23:42 +0200 Subject: bugfix: do not open files with full privileges, if privs will be dropped This make the privilege drop code more bulletproof, but breaks Ubuntu's work-around for log files created by external programs with the wrong user and/or group. Note that it was long said that this "functionality" would break once we go for serious privilege drop code, so hopefully nobody still depends on it (and, if so, they lost...). --- ChangeLog | 6 +++++ doc/rsconf1_omfileforcechown.html | 5 +++- tools/omfile.c | 51 ++++++++++++--------------------------- 3 files changed, 25 insertions(+), 37 deletions(-) diff --git a/ChangeLog b/ChangeLog index dc9c17f9..f98057a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ --------------------------------------------------------------------------- Version 5.9.0 [V5-DEVEL] (rgerhards), 2011-03-?? +- bugfix: do not open files with full privileges, if privs will be dropped + This make the privilege drop code more bulletproof, but breaks Ubuntu's + work-around for log files created by external programs with the wrong + user and/or group. Note that it was long said that this "functionality" + would break once we go for serious privilege drop code, so hopefully + nobody still depends on it (and, if so, they lost...). - this begins a new devel branch for v5 - added support for user-level PRI provided via systemd - added new config directive $InputTCPFlowControl to select if tcp diff --git a/doc/rsconf1_omfileforcechown.html b/doc/rsconf1_omfileforcechown.html index 7415a6f6..a680810b 100644 --- a/doc/rsconf1_omfileforcechown.html +++ b/doc/rsconf1_omfileforcechown.html @@ -8,7 +8,10 @@

$omfileForceChown

Type: global configuration directive

Parameter Values: boolean (on/off, yes/no)

-

Available since: 4.7.0+, 5.3.0+

+

Available: 4.7.0+, 5.3.0-5.8.x, NOT available in 5.9.x or higher

+

Note: this directive has been removed and is no longer available. The +documentation is currently being retained for historical reaons. Expect +it to go away at some later stage as well.

Default: off

Description:

Forces rsyslogd to change the ownership for output files that already exist. Please note diff --git a/tools/omfile.c b/tools/omfile.c index 08f965b3..7585ea8c 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -122,13 +122,11 @@ typedef struct s_dynaFileCacheEntry dynaFileCacheEntry; #define USE_ASYNCWRITER_DFLT 0 /* default buffer use async writer */ #define FLUSHONTX_DFLT 1 /* default for flush on TX end */ -#define DFLT_bForceChown 0 /* globals for default values */ static int iDynaFileCacheSize = 10; /* max cache for dynamic files */ static int fCreateMode = 0644; /* mode to use when creating files */ static int fDirCreateMode = 0700; /* mode to use when creating files */ static int bFailOnChown; /* fail if chown fails? */ -static int bForceChown = DFLT_bForceChown; /* Force chown() on existing files? */ static uid_t fileUID; /* UID to be used for newly created files */ static uid_t fileGID; /* GID to be used for newly created files */ static uid_t dirUID; /* UID to be used for newly created directories */ @@ -153,7 +151,6 @@ typedef struct _instanceData { int fDirCreateMode; /* creation mode for mkdir() */ int bCreateDirs; /* auto-create directories? */ int bSyncFile; /* should the file by sync()'ed? 1- yes, 0- no */ - sbool bForceChown; /* force chown() on existing files? */ uid_t fileUID; /* IDs for creation */ uid_t dirUID; gid_t fileGID; @@ -200,7 +197,6 @@ CODESTARTdbgPrintInstInfo dbgprintf("\tfile cache size=%d\n", pData->iDynaFileCacheSize); dbgprintf("\tcreate directories: %s\n", pData->bCreateDirs ? "yes" : "no"); dbgprintf("\tfile owner %d, group %d\n", (int) pData->fileUID, (int) pData->fileGID); - dbgprintf("\tforce chown() for all files: %s\n", pData->bForceChown ? "yes" : "no"); dbgprintf("\tdirectory owner %d, group %d\n", (int) pData->dirUID, (int) pData->dirGID); dbgprintf("\tdir create mode 0%3.3o, file create mode 0%3.3o\n", pData->fDirCreateMode, pData->fCreateMode); @@ -239,6 +235,12 @@ rsRetVal setDynaFileCacheSize(void __attribute__((unused)) *pVal, int iNewVal) } +rsRetVal goneAway(void __attribute__((unused)) *pVal, int iNewVal) +{ + errmsg.LogError(0, RS_RET_ERR, "directive $omfileForceChown is no longer supported"); +} + + /* Helper to cfline(). Parses a output channel name up until the first * comma and then looks for the template specifier. Tries * to find that template. Maps the output channel to the @@ -388,22 +390,7 @@ prepareFile(instanceData *pData, uchar *newFileName) int fd; DEFiRet; - if(access((char*)newFileName, F_OK) == 0) { - if(pData->bForceChown) { - /* Try to fix wrong ownership set by someone else. Note that this code - * will no longer work once we have made the $PrivDrop code fully secure. - * This change is based on an idea of Michael Terry, provided as part of - * the effort to make rsyslogd the Ubuntu default syslogd. - * rgerhards, 2009-09-11 - */ - if(chown((char*)newFileName, pData->fileUID, pData->fileGID) != 0) { - if(pData->bFailOnChown) { - int eSave = errno; - errno = eSave; - } - } - } - } else { + if(access((char*)newFileName, F_OK) != 0) { /* file does not exist, create it (and eventually parent directories */ if(pData->bCreateDirs) { /* We first need to create parent dirs if they are missing. @@ -423,7 +410,7 @@ prepareFile(instanceData *pData, uchar *newFileName) pData->fCreateMode); if(fd != -1) { /* check and set uid/gid */ - if(pData->bForceChown || pData->fileUID != (uid_t)-1 || pData->fileGID != (gid_t) -1) { + if(pData->fileUID != (uid_t)-1 || pData->fileGID != (gid_t) -1) { /* we need to set owner/group */ if(fchown(fd, pData->fileUID, pData->fileGID) != 0) { if(pData->bFailOnChown) { @@ -473,6 +460,9 @@ prepareFile(instanceData *pData, uchar *newFileName) CHKiRet(strm.ConstructFinalize(pData->pStrm)); finalize_it: + if(pData->pStrm == NULL) { + DBGPRINTF("Error opening log file: %s\n", pData->f_fname); + } RETiRet; } @@ -647,6 +637,9 @@ writeFile(uchar **ppString, unsigned iMsgOpts, instanceData *pData) } else { /* "regular", non-dynafile */ if(pData->pStrm == NULL) { CHKiRet(prepareFile(pData, pData->f_fname)); + if(pData->pStrm == NULL) { + errmsg.LogError(0, RS_RET_NO_FILE_ACCESS, "Could no open output file '%s'", pData->f_fname); + } } } @@ -790,7 +783,6 @@ CODESTARTparseSelectorAct pData->fDirCreateMode = fDirCreateMode; pData->bCreateDirs = bCreateDirs; pData->bFailOnChown = bFailOnChown; - pData->bForceChown = bForceChown; pData->fileUID = fileUID; pData->fileGID = fileGID; pData->dirUID = dirUID; @@ -800,18 +792,6 @@ CODESTARTparseSelectorAct pData->iIOBufSize = (int) iIOBufSize; pData->iFlushInterval = iFlushInterval; pData->bUseAsyncWriter = bUseAsyncWriter; - - if(pData->bDynamicName == 0) { - /* try open and emit error message if not possible. At this stage, we ignore the - * return value of prepareFile, this is taken care of in later steps. - */ - prepareFile(pData, pData->f_fname); - - if(pData->pStrm == NULL) { - DBGPRINTF("Error opening log file: %s\n", pData->f_fname); - errmsg.LogError(0, RS_RET_NO_FILE_ACCESS, "Could no open output file '%s'", pData->f_fname); - } - } CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct @@ -826,7 +806,6 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a dirUID = -1; dirGID = -1; bFailOnChown = 1; - bForceChown = DFLT_bForceChown; iDynaFileCacheSize = 10; fCreateMode = 0644; fDirCreateMode = 0700; @@ -901,7 +880,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(omsdRegCFSLineHdlr((uchar *)"filecreatemode", 0, eCmdHdlrFileCreateMode, NULL, &fCreateMode, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"createdirs", 0, eCmdHdlrBinary, NULL, &bCreateDirs, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"failonchownfailure", 0, eCmdHdlrBinary, NULL, &bFailOnChown, STD_LOADABLE_MODULE_ID)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileForceChown", 0, eCmdHdlrBinary, NULL, &bForceChown, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileforcechown", 0, eCmdHdlrBinary, goneAway, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionfileenablesync", 0, eCmdHdlrBinary, NULL, &bEnableSync, STD_LOADABLE_MODULE_ID)); CHKiRet(regCfSysLineHdlr((uchar *)"actionfiledefaulttemplate", 0, eCmdHdlrGetWord, NULL, &pszFileDfltTplName, NULL)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); -- cgit v1.2.3 From 415b95cf453403f726f654cbc03ef3984446a870 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 26 Apr 2011 18:38:42 +0200 Subject: bugfix: pipes not opened in full priv mode when privs are to be dropped --- ChangeLog | 1 + tools/ompipe.c | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index f98057a6..d4fe37a6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ Version 5.9.0 [V5-DEVEL] (rgerhards), 2011-03-?? user and/or group. Note that it was long said that this "functionality" would break once we go for serious privilege drop code, so hopefully nobody still depends on it (and, if so, they lost...). +- bugfix: pipes not opened in full priv mode when privs are to be dropped - this begins a new devel branch for v5 - added support for user-level PRI provided via systemd - added new config directive $InputTCPFlowControl to select if tcp diff --git a/tools/ompipe.c b/tools/ompipe.c index 58725fb9..cbedb559 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -72,6 +72,7 @@ DEFobjCurrIf(errmsg) typedef struct _instanceData { uchar f_fname[MAXFNAME];/* pipe or template name (display only) */ short fd; /* pipe descriptor for (current) pipe */ + sbool bHadError; /* did we already have/report an error on this pipe? */ } instanceData; @@ -101,6 +102,17 @@ preparePipe(instanceData *pData) { DEFiRet; pData->fd = open((char*) pData->f_fname, O_RDWR|O_NONBLOCK|O_CLOEXEC); + if(pData->fd < 0 ) { + pData->fd = -1; + if(!pData->bHadError) { + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + errmsg.LogError(0, RS_RET_NO_FILE_ACCESS, "Could no open output pipe '%s': %s", + pData->f_fname, errStr); + pData->bHadError = 1; + } + DBGPRINTF("Error opening log pipe: %s\n", pData->f_fname); + } RETiRet; } @@ -150,6 +162,7 @@ finalize_it: BEGINcreateInstance CODESTARTcreateInstance pData->fd = -1; + pData->bHadError = 0; ENDcreateInstance @@ -204,11 +217,6 @@ CODESTARTparseSelectorAct */ preparePipe(pData); - if(pData->fd < 0 ) { - pData->fd = -1; - DBGPRINTF("Error opening log pipe: %s\n", pData->f_fname); - errmsg.LogError(0, RS_RET_NO_FILE_ACCESS, "Could no open output pipe '%s'", pData->f_fname); - } CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct -- cgit v1.2.3 From 929c8cb04b3d8d6649a7aa71aedc02c61565119b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 26 Apr 2011 19:06:33 +0200 Subject: temporarily changed testbench to cover ongoing config changes --- ChangeLog | 7 +++++++ tests/Makefile.am | 2 +- tests/diag.sh | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index cbd0a37b..76d05e68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -12,6 +12,13 @@ Version 6.1.7 [DEVEL] (rgerhards), 2011-04-15 - bugfix: IPv6-address could not be specified in omrelp this was due to improper parsing of ":" closes: http://bugzilla.adiscon.com/show_bug.cgi?id=250 +- bugfix: do not open files with full privileges, if privs will be dropped + This make the privilege drop code more bulletproof, but breaks Ubuntu's + work-around for log files created by external programs with the wrong + user and/or group. Note that it was long said that this "functionality" + would break once we go for serious privilege drop code, so hopefully + nobody still depends on it (and, if so, they lost...). +- bugfix: pipes not opened in full priv mode when privs are to be dropped --------------------------------------------------------------------------- Version 6.1.6 [DEVEL] (rgerhards), 2011-03-14 - enhanced omhdfs to support batching mode. This permits to increase diff --git a/tests/Makefile.am b/tests/Makefile.am index c3dfac55..a72f60b9 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,5 @@ if ENABLE_TESTBENCH -TESTRUNS = rt_init rscript +# TODO: reenable TESTRUNS = rt_init rscript check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen diagtalker uxsockrcvr syslog_caller syslog_inject inputfilegen TESTS = $(TESTRUNS) cfg.sh diff --git a/tests/diag.sh b/tests/diag.sh index 07537bb0..8b0ad573 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -5,7 +5,7 @@ # not always able to convey back states to the upper-level test driver # begun 2009-05-27 by rgerhards # This file is part of the rsyslog project, released under GPLv3 -valgrind="valgrind --malloc-fill=ff --free-fill=fe --log-fd=1" +#valgrind="valgrind --malloc-fill=ff --free-fill=fe --log-fd=1" #valgrind="valgrind --tool=drd --log-fd=1" #valgrind="valgrind --tool=helgrind --log-fd=1" #valgrind="valgrind --tool=exp-ptrcheck --log-fd=1" -- cgit v1.2.3 From 706121052d2c2c0bca42b3f8f1e785dd96369772 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Apr 2011 13:33:06 +0200 Subject: step: shuffled module-related code from syslogd.c to rsconf.c ... plus some minor cleanup/code shuffle --- dirty.h | 1 + runtime/modules.c | 2 +- runtime/rsconf.c | 173 +++++++++++++++++++++++++++++++++++ tools/syslogd.c | 269 +++++++++++------------------------------------------- 4 files changed, 227 insertions(+), 218 deletions(-) diff --git a/dirty.h b/dirty.h index f6b99741..f27c5780 100644 --- a/dirty.h +++ b/dirty.h @@ -42,6 +42,7 @@ rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName); extern int MarkInterval; extern int repeatinterval[2]; extern qqueue_t *pMsgQueue; /* the main message queue */ +extern int iConfigVerify; /* is this just a config verify run? */ #define MAXREPEAT ((int)((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)) #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ diff --git a/runtime/modules.c b/runtime/modules.c index 7389909d..88a9bb79 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -11,7 +11,7 @@ * * File begun on 2007-07-22 by RGerhards * - * Copyright 2007, 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 47a6f00b..2a87756f 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -60,6 +62,8 @@ #include "smtradfwd.h" #include "parser.h" #include "outchannel.h" +#include "threads.h" +#include "dirty.h" /* static data */ DEFobjStaticHelpers @@ -198,6 +202,139 @@ CODESTARTobjDebugPrint(rsconf) ENDobjDebugPrint(rsconf) +/* drop to specified group + * if something goes wrong, the function never returns + * Note that such an abort can cause damage to on-disk structures, so we should + * re-design the "interface" in the long term. -- rgerhards, 2008-11-26 + */ +static void doDropPrivGid(int iGid) +{ + int res; + uchar szBuf[1024]; + + res = setgroups(0, NULL); /* remove all supplementary group IDs */ + if(res) { + perror("could not remove supplemental group IDs"); + exit(1); + } + DBGPRINTF("setgroups(0, NULL): %d\n", res); + res = setgid(iGid); + if(res) { + /* if we can not set the userid, this is fatal, so let's unconditionally abort */ + perror("could not set requested group id"); + exit(1); + } + DBGPRINTF("setgid(%d): %d\n", iGid, res); + snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's groupid changed to %d", iGid); + logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0); +} + + +/* drop to specified user + * if something goes wrong, the function never returns + * Note that such an abort can cause damage to on-disk structures, so we should + * re-design the "interface" in the long term. -- rgerhards, 2008-11-19 + */ +static void doDropPrivUid(int iUid) +{ + int res; + uchar szBuf[1024]; + + res = setuid(iUid); + if(res) { + /* if we can not set the userid, this is fatal, so let's unconditionally abort */ + perror("could not set requested userid"); + exit(1); + } + DBGPRINTF("setuid(%d): %d\n", iUid, res); + snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's userid changed to %d", iUid); + logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0); +} + + + +/* drop privileges. This will drop to the configured privileges, if + * set by the user. After this method has been executed, the previous + * privileges can no be re-gained. + */ +static inline rsRetVal +dropPrivileges(rsconf_t *cnf) +{ + DEFiRet; + + /* If instructed to do so, we now drop privileges. Note that this is not 100% secure, + * because outputs are already running at this time. However, we can implement + * dropping of privileges rather quickly and it will work in many cases. While it is not + * the ultimate solution, the current one is still much better than not being able to + * drop privileges at all. Doing it correctly, requires a change in architecture, which + * we should do over time. TODO -- rgerhards, 2008-11-19 + */ + if(cnf->globals.gidDropPriv != 0) { + doDropPrivGid(ourConf->globals.gidDropPriv); + } + + if(cnf->globals.uidDropPriv != 0) { + doDropPrivUid(ourConf->globals.uidDropPriv); + } + + RETiRet; +} + + +/* Actually run the input modules. This happens after privileges are dropped, + * if that is requested. + */ +static rsRetVal +runInputModules(void) +{ + modInfo_t *pMod; + int bNeedsCancel; + + BEGINfunc + /* loop through all modules and activate them (brr...) */ + pMod = module.GetNxtType(NULL, eMOD_IN); + while(pMod != NULL) { + if(pMod->mod.im.bCanRun) { + /* activate here */ + bNeedsCancel = (pMod->isCompatibleWithFeature(sFEATURENonCancelInputTermination) == RS_RET_OK) ? + 0 : 1; + thrdCreate(pMod->mod.im.runInput, pMod->mod.im.afterRun, bNeedsCancel); + } + pMod = module.GetNxtType(pMod, eMOD_IN); + } + + ENDfunc + return RS_RET_OK; /* intentional: we do not care about module errors */ +} + + +/* Start the input modules. This function will probably undergo big changes + * while we implement the input module interface. For now, it does the most + * important thing to get at least my poor initial input modules up and + * running. Almost no config option is taken. + * rgerhards, 2007-12-14 + */ +static rsRetVal +startInputModules(void) +{ + DEFiRet; + modInfo_t *pMod; + + /* loop through all modules and activate them (brr...) */ + pMod = module.GetNxtType(NULL, eMOD_IN); + while(pMod != NULL) { + iRet = pMod->mod.im.willRun(); + pMod->mod.im.bCanRun = (iRet == RS_RET_OK); + if(!pMod->mod.im.bCanRun) { + DBGPRINTF("module %lx will not run, iRet %d\n", (unsigned long) pMod, iRet); + } + pMod = module.GetNxtType(pMod, eMOD_IN); + } + + ENDfunc + return RS_RET_OK; /* intentional: we do not care about module errors */ +} + /* Activate an already-loaded configuration. The configuration will become * the new running conf (if successful). Note that in theory this method may * be called when there already is a running conf. In practice, the current @@ -208,8 +345,33 @@ rsRetVal activate(rsconf_t *cnf) { DEFiRet; + +# if 0 /* currently the DAG is not supported -- code missing! */ + /* TODO: re-enable this functionality some time later! */ + /* check if we need to generate a config DAG and, if so, do that */ + if(ourConf->globals.pszConfDAGFile != NULL) + generateConfigDAG(ourConf->globals.pszConfDAGFile); +# endif + + /* the output part and the queue is now ready to run. So it is a good time + * to initialize the inputs. Please note that the net code above should be + * shuffled to down here once we have everything in input modules. + * rgerhards, 2007-12-14 + * NOTE: as of 2009-06-29, the input modules are initialized, but not yet run. + * Keep in mind. though, that the outputs already run if the queue was + * persisted to disk. -- rgerhards + */ + startInputModules(); + + CHKiRet(dropPrivileges(cnf)); + + /* finally let the inputs run... */ + runInputModules(); + runConf = cnf; dbgprintf("configuration %p activated\n", cnf); + +finalize_it: RETiRet; } @@ -732,6 +894,14 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! CHKiRet(validateConf()); + /* we are done checking the config - now validate if we should actually run or not. + * If not, terminate. -- rgerhards, 2008-07-25 + * TODO: iConfigVerify -- should it be pulled from the config, or leave as is (option)? + */ + if(iConfigVerify) { + ABORT_FINALIZE(RS_RET_VALIDATION_RUN); + } + /* all OK, pass loaded conf to caller */ *cnf = loadConf; // TODO: enable this once all config code is moved to here! loadConf = NULL; @@ -739,6 +909,9 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! dbgprintf("rsyslog finished loading initial config %p\n", loadConf); rsconfDebugPrint(loadConf); + /* return warning state if we had some acceptable problems */ + if(bHadConfigErr) + iRet = RS_RET_NONFATAL_CONFIG_ERR; finalize_it: RETiRet; } diff --git a/tools/syslogd.c b/tools/syslogd.c index 318031a1..fc23f058 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -203,7 +203,7 @@ static int bFinished = 0; /* used by termination signal handler, read-only excep * is either 0 or the number of the signal that requested the * termination. */ -static int iConfigVerify = 0; /* is this just a config verify run? */ +int iConfigVerify = 0; /* is this just a config verify run? */ /* Intervals at which we flush out "message repeated" messages, * in seconds after previous message is logged. After each flush, @@ -1043,57 +1043,7 @@ static void doexit() exit(0); /* "good" exit, only during child-creation */ } - -/* drop to specified group - * if something goes wrong, the function never returns - * Note that such an abort can cause damage to on-disk structures, so we should - * re-design the "interface" in the long term. -- rgerhards, 2008-11-26 - */ -static void doDropPrivGid(int iGid) -{ - int res; - uchar szBuf[1024]; - - res = setgroups(0, NULL); /* remove all supplementary group IDs */ - if(res) { - perror("could not remove supplemental group IDs"); - exit(1); - } - DBGPRINTF("setgroups(0, NULL): %d\n", res); - res = setgid(iGid); - if(res) { - /* if we can not set the userid, this is fatal, so let's unconditionally abort */ - perror("could not set requested group id"); - exit(1); - } - DBGPRINTF("setgid(%d): %d\n", iGid, res); - snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's groupid changed to %d", iGid); - logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0); -} - - -/* drop to specified user - * if something goes wrong, the function never returns - * Note that such an abort can cause damage to on-disk structures, so we should - * re-design the "interface" in the long term. -- rgerhards, 2008-11-19 - */ -static void doDropPrivUid(int iUid) -{ - int res; - uchar szBuf[1024]; - - res = setuid(iUid); - if(res) { - /* if we can not set the userid, this is fatal, so let's unconditionally abort */ - perror("could not set requested userid"); - exit(1); - } - DBGPRINTF("setuid(%d): %d\n", iUid, res); - snprintf((char*)szBuf, sizeof(szBuf)/sizeof(uchar), "rsyslogd's userid changed to %d", iUid); - logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0); -} - - +#if 0 /* TODO: re-enable, currently not used */ /* helper to generateConfigDAG, to print out all actions via * the llExecFunc() facility. * rgerhards, 2007-08-02 @@ -1278,61 +1228,7 @@ generateConfigDAG(uchar *pszDAGFile) finalize_it: RETiRet; } - - -/* Actually run the input modules. This happens after privileges are dropped, - * if that is requested. - */ -static rsRetVal -runInputModules(void) -{ - modInfo_t *pMod; - int bNeedsCancel; - - BEGINfunc - /* loop through all modules and activate them (brr...) */ - pMod = module.GetNxtType(NULL, eMOD_IN); - while(pMod != NULL) { - if(pMod->mod.im.bCanRun) { - /* activate here */ - bNeedsCancel = (pMod->isCompatibleWithFeature(sFEATURENonCancelInputTermination) == RS_RET_OK) ? - 0 : 1; - thrdCreate(pMod->mod.im.runInput, pMod->mod.im.afterRun, bNeedsCancel); - } - pMod = module.GetNxtType(pMod, eMOD_IN); - } - - ENDfunc - return RS_RET_OK; /* intentional: we do not care about module errors */ -} - - -/* Start the input modules. This function will probably undergo big changes - * while we implement the input module interface. For now, it does the most - * important thing to get at least my poor initial input modules up and - * running. Almost no config option is taken. - * rgerhards, 2007-12-14 - */ -static rsRetVal -startInputModules(void) -{ - DEFiRet; - modInfo_t *pMod; - - /* loop through all modules and activate them (brr...) */ - pMod = module.GetNxtType(NULL, eMOD_IN); - while(pMod != NULL) { - iRet = pMod->mod.im.willRun(); - pMod->mod.im.bCanRun = (iRet == RS_RET_OK); - if(!pMod->mod.im.bCanRun) { - DBGPRINTF("module %lx will not run, iRet %d\n", (unsigned long) pMod, iRet); - } - pMod = module.GetNxtType(pMod, eMOD_IN); - } - - ENDfunc - return RS_RET_OK; /* intentional: we do not care about module errors */ -} +#endif /* create a main message queue, now also used for ruleset queues. This function @@ -1406,59 +1302,22 @@ rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName) static rsRetVal init(void) { - rsRetVal localRet; - int iNbrActions; - int bHadConfigErr = 0; - char cbuf[BUFSIZ]; char bufStartUpMsg[512]; struct sigaction sigAct; DEFiRet; legacyOptsHook(); - /* check if we need to generate a config DAG and, if so, do that */ - if(ourConf->globals.pszConfDAGFile != NULL) - generateConfigDAG(ourConf->globals.pszConfDAGFile); - /* we are done checking the config - now validate if we should actually run or not. - * If not, terminate. -- rgerhards, 2008-07-25 - */ - if(iConfigVerify) { - if(bHadConfigErr) { - /* a bit dirty, but useful... */ + /* create message queue */ + CHKiRet_Hdlr(createMainQueue(&pMsgQueue, UCHAR_CONSTANT("main Q"))) { + /* no queue is fatal, we need to give up in that case... */ + fprintf(stderr, "fatal error %d: could not create message queue - rsyslogd can not run!\n", iRet); exit(1); } - ABORT_FINALIZE(RS_RET_VALIDATION_RUN); -} -#warning restructure following if to use return value of loadConf -if(loadConf->globals.bAbortOnUncleanConfig && bHadConfigErr) { - fprintf(stderr, "rsyslogd: $AbortOnUncleanConfig is set, and config is not clean.\n" - "Check error log for details, fix errors and restart. As a last\n" - "resort, you may want to remove $AbortOnUncleanConfig to permit a\n" - "startup with a dirty config.\n"); - exit(2); -} - -/* create message queue */ -CHKiRet_Hdlr(createMainQueue(&pMsgQueue, UCHAR_CONSTANT("main Q"))) { - /* no queue is fatal, we need to give up in that case... */ - fprintf(stderr, "fatal error %d: could not create message queue - rsyslogd can not run!\n", iRet); - exit(1); -} - -bHaveMainQueue = (ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1; -DBGPRINTF("Main processing queue is initialized and running\n"); - - /* the output part and the queue is now ready to run. So it is a good time - * to initialize the inputs. Please note that the net code above should be - * shuffled to down here once we have everything in input modules. - * rgerhards, 2007-12-14 - * NOTE: as of 2009-06-29, the input modules are initialized, but not yet run. - * Keep in mind. though, that the outputs already run if the queue was - * persisted to disk. -- rgerhards - */ - startInputModules(); + bHaveMainQueue = (ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1; + DBGPRINTF("Main processing queue is initialized and running\n"); memset(&sigAct, 0, sizeof (sigAct)); sigemptyset(&sigAct.sa_mask); @@ -1670,67 +1529,6 @@ static void printVersion(void) } -/* This function is called after initial initalization. It is used to - * move code out of the too-long main() function. - * rgerhards, 2007-10-17 - */ -static rsRetVal mainThread() -{ - DEFiRet; - - CHKiRet(init()); - - if(Debug && debugging_on) { - dbgprintf("Debugging enabled, SIGUSR1 to turn off debugging.\n"); - } - - /* Send a signal to the parent so it can terminate. - */ - if(myPid != ppid) - kill(ppid, SIGTERM); - - - /* If instructed to do so, we now drop privileges. Note that this is not 100% secure, - * because outputs are already running at this time. However, we can implement - * dropping of privileges rather quickly and it will work in many cases. While it is not - * the ultimate solution, the current one is still much better than not being able to - * drop privileges at all. Doing it correctly, requires a change in architecture, which - * we should do over time. TODO -- rgerhards, 2008-11-19 - */ - if(ourConf->globals.gidDropPriv != 0) { - doDropPrivGid(ourConf->globals.gidDropPriv); - } - - if(ourConf->globals.uidDropPriv != 0) { - doDropPrivUid(ourConf->globals.uidDropPriv); - } - - /* finally let the inputs run... */ - runInputModules(); - - /* END OF INTIALIZATION - */ - DBGPRINTF("initialization completed, transitioning to regular run mode\n"); - - /* close stderr and stdout if they are kept open during a fork. Note that this - * may introduce subtle security issues: if we are in a jail, one may break out of - * it via these descriptors. But if I close them earlier, error messages will (once - * again) not be emitted to the user that starts the daemon. As root jail support - * is still in its infancy (and not really done), we currently accept this issue. - * rgerhards, 2009-06-29 - */ - if(!(Debug == DEBUG_FULL || NoFork)) { - close(1); - close(2); - ourConf->globals.bErrMsgToStderr = 0; - } - - mainloop(); - -finalize_it: - RETiRet; -} - /* Method to initialize all global classes and use the objects that we need. * rgerhards, 2008-01-04 @@ -2033,8 +1831,7 @@ doGlblProcessInit(void) */ int realMain(int argc, char **argv) { - DEFiRet; - + rsRetVal localRet; register uchar *p; int ch; struct hostent *hent; @@ -2050,6 +1847,7 @@ int realMain(int argc, char **argv) uchar *LocalDomain; uchar *LocalFQDNName; char cwdbuf[128]; /* buffer to obtain/display current working directory */ + DEFiRet; /* first, parse the command line options. We do not carry out any actual work, just * see what we should do. This relieves us from certain anomalies and we can process @@ -2364,19 +2162,29 @@ int realMain(int argc, char **argv) if(iRet != RS_RET_END_OF_LINKEDLIST) FINALIZE; - CHKiRet(rsconf.Load(&ourConf, ConfFile)); - if(iConfigVerify) { fprintf(stderr, "rsyslogd: version %s, config validation run (level %d), master config %s\n", VERSION, iConfigVerify, ConfFile); } + localRet = rsconf.Load(&ourConf, ConfFile); + if(localRet == RS_RET_NONFATAL_CONFIG_ERR) { + if(loadConf->globals.bAbortOnUncleanConfig) { + fprintf(stderr, "rsyslogd: $AbortOnUncleanConfig is set, and config is not clean.\n" + "Check error log for details, fix errors and restart. As a last\n" + "resort, you may want to remove $AbortOnUncleanConfig to permit a\n" + "startup with a dirty config.\n"); + exit(2); + } + iRet = RS_RET_OK; + } + CHKiRet(localRet); + if(bChDirRoot) { if(chdir("/") != 0) fprintf(stderr, "Can not do 'cd /' - still trying to run\n"); } - /* process compatibility mode settings */ if(iCompatibilityMode < 4) { errmsg.LogError(0, NO_ERRCODE, "WARNING: rsyslogd is running in compatibility mode. Automatically " @@ -2406,7 +2214,34 @@ int realMain(int argc, char **argv) if(!iConfigVerify) CHKiRet(doGlblProcessInit()); - CHKiRet(mainThread()); + CHKiRet(init()); + + if(Debug && debugging_on) { + dbgprintf("Debugging enabled, SIGUSR1 to turn off debugging.\n"); + } + + /* Send a signal to the parent so it can terminate. */ + if(myPid != ppid) + kill(ppid, SIGTERM); + + + /* END OF INTIALIZATION */ + DBGPRINTF("initialization completed, transitioning to regular run mode\n"); + + /* close stderr and stdout if they are kept open during a fork. Note that this + * may introduce subtle security issues: if we are in a jail, one may break out of + * it via these descriptors. But if I close them earlier, error messages will (once + * again) not be emitted to the user that starts the daemon. As root jail support + * is still in its infancy (and not really done), we currently accept this issue. + * rgerhards, 2009-06-29 + */ + if(!(Debug == DEBUG_FULL || NoFork)) { + close(1); + close(2); + ourConf->globals.bErrMsgToStderr = 0; + } + + mainloop(); /* do any de-init's that need to be done AFTER this comment */ -- cgit v1.2.3 From 17e3f6b49cccb99316f2907eb3c131ec998ee3c3 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Apr 2011 14:02:00 +0200 Subject: step: $ModLoad handler no longe requries conf obj re-doing the interface, global var "loadConf" now holds that data. Makes things simpler with legacy handler, as well as new functionality. --- runtime/conf.c | 5 ++--- runtime/conf.h | 2 +- runtime/rsconf.c | 16 +++------------- runtime/rsconf.h | 6 ++++++ runtime/typedefs.h | 1 + 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/runtime/conf.c b/runtime/conf.c index 9fecc34d..c8c4d938 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -249,10 +249,9 @@ finalize_it: } -/* process a $ModLoad config line. - */ +/* process a $ModLoad config line. */ rsRetVal -doModLoad(rsconf_t * conf, uchar **pp, __attribute__((unused)) void* pVal) +doModLoad(uchar **pp, __attribute__((unused)) void* pVal) { DEFiRet; uchar szName[512]; diff --git a/runtime/conf.h b/runtime/conf.h index c169a9c0..096af630 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -35,7 +35,7 @@ extern int bConfStrictScoping; /* force strict scoping during config processing? BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ rsRetVal (*doNameLine)(uchar **pp, void* pVal); rsRetVal (*cfsysline)(rsconf_t *conf, uchar *p); - rsRetVal (*doModLoad)(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal); + rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); rsRetVal (*doIncludeLine)(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal); rsRetVal (*cfline)(rsconf_t *conf, uchar *line, rule_t **pfCurr); rsRetVal (*processConfFile)(rsconf_t *conf, uchar *pConfFile); diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 2a87756f..a32205d9 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -380,18 +380,6 @@ finalize_it: * TODO: move to conf.c? */ -/* this method is needed to shuffle the current conf object down to the - * IncludeConfig handler. - */ -static rsRetVal -doModLoad(void *pVal, uchar *pNewVal) -{ - DEFiRet; - iRet = conf.doModLoad(ourConf, pVal, pNewVal); - free(pNewVal); - RETiRet; -} - /* legacy config system: set the action resume interval */ static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int iNewVal) { @@ -685,8 +673,10 @@ initLegacyConf(void) CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, setActionResumeInterval, NULL, NULL, eConfObjGlobal)); + //CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, + //doModLoad, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, - doModLoad, NULL, NULL, eConfObjGlobal)); + conf.doModLoad, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, doIncludeLine, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode, diff --git a/runtime/rsconf.h b/runtime/rsconf.h index 5cd6bfd0..2eb09851 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -91,6 +91,11 @@ struct globals_s { struct defaults_s { }; + +/* list of modules loaded in this configuration (config specific module list) */ +struct cfgmodules_s { +}; + /* outchannel-specific data */ struct outchannels_s { struct outchannel *ochRoot; /* the root of the outchannel list */ @@ -123,6 +128,7 @@ struct rulesets_s { /* the rsconf object */ struct rsconf_s { BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ + cfgmodules_t modules; globals_t globals; defaults_t defaults; templates_t templates; diff --git a/runtime/typedefs.h b/runtime/typedefs.h index 0d23e880..ca78d820 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -87,6 +87,7 @@ typedef struct globals_s globals_t; typedef struct defaults_s defaults_t; typedef struct actions_s actions_t; typedef struct rsconf_s rsconf_t; +typedef struct cfgmodules_s cfgmodules_t; typedef struct outchannels_s outchannels_t; typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript function */ typedef uint64 qDeqID; /* queue Dequeue order ID. 32 bits is considered dangerously few */ -- cgit v1.2.3 From 4f8457ffe3bc0a104a86ac79622844c4206adbbb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Apr 2011 15:38:06 +0200 Subject: step: added config-specific module list --- runtime/conf.c | 2 +- runtime/modules.c | 124 ++++++++++++++++++++++++++++++++++++++++++----------- runtime/modules.h | 9 ++-- runtime/obj.c | 2 +- runtime/rsconf.c | 65 ++++++++++++++++++---------- runtime/rsconf.h | 6 +++ runtime/typedefs.h | 1 + 7 files changed, 158 insertions(+), 51 deletions(-) diff --git a/runtime/conf.c b/runtime/conf.c index c8c4d938..67c1ed81 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -279,7 +279,7 @@ doModLoad(uchar **pp, __attribute__((unused)) void* pVal) else pModName = szName; - CHKiRet(module.Load(pModName)); + CHKiRet(module.Load(pModName, 1)); finalize_it: RETiRet; diff --git a/runtime/modules.c b/runtime/modules.c index 88a9bb79..8cdc9bb1 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -318,7 +318,7 @@ static uchar *modGetStateName(modInfo_t *pThis) /* Add a module to the loaded module linked list */ static inline void -addModToList(modInfo_t *pThis) +addModToGlblList(modInfo_t *pThis) { assert(pThis != NULL); @@ -333,6 +333,53 @@ addModToList(modInfo_t *pThis) } +/* Add a module to the config module list for current loadConf + */ +static inline rsRetVal +addModToCnfList(modInfo_t *pThis) +{ + cfgmodules_etry_t *pNew; + cfgmodules_etry_t *pLast; + DEFiRet; + assert(pThis != NULL); + + if(loadConf == NULL) { + /* we are in an early init state */ + FINALIZE; + } + + /* check for duplicates and, as a side-activity, identify last node */ + pLast = loadConf->modules.root; + if(pLast != NULL) { + while(1) { /* loop broken inside */ + if(pLast->pMod == pThis) { + DBGPRINTF("module '%s' already in this config\n", modGetName(pThis)); + FINALIZE; + } + if(pLast->next == NULL) + break; + pLast = pLast -> next; + } + } + + /* if we reach this point, pLast is the tail pointer */ + + CHKmalloc(pNew = MALLOC(sizeof(cfgmodules_etry_t))); + pNew->next = NULL; + pNew->pMod = pThis; + + if(pLast == NULL) { + loadConf->modules.root = pNew; + } else { + /* there already exist entries */ + pLast->next = pNew; + } + +finalize_it: + RETiRet; +} + + /* Get the next module pointer - this is used to traverse the list. * The function returns the next pointer or NULL, if there is no next one. * The last object must be provided to the function. If NULL is provided, @@ -407,7 +454,8 @@ finalize_it: * everything needed to fully initialize the module. */ static rsRetVal -doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_t*), uchar *name, void *pModHdlr) +doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_t*), + uchar *name, void *pModHdlr, modInfo_t **pNewModule) { rsRetVal localRet; modInfo_t *pNew = NULL; @@ -569,12 +617,14 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ } /* we initialized the structure, now let's add it to the linked list of modules */ - addModToList(pNew); + addModToGlblList(pNew); + *pNewModule = pNew; finalize_it: if(iRet != RS_RET_OK) { if(pNew != NULL) moduleDestruct(pNew); + *pNewModule = NULL; } RETiRet; @@ -753,6 +803,27 @@ modUnloadAndDestructAll(eModLinkType_t modLinkTypesToUnload) RETiRet; } +/* find module with given name in global list */ +static inline rsRetVal +findModule(uchar *pModName, int iModNameLen, modInfo_t **pMod) +{ + modInfo_t *pModInfo; + uchar *pModNameCmp; + DEFiRet; + + pModInfo = GetNxt(NULL); + while(pModInfo != NULL) { + if(!strncmp((char *) pModName, (char *) (pModNameCmp = modGetName(pModInfo)), iModNameLen) && + (!*(pModNameCmp + iModNameLen) || !strcmp((char *) pModNameCmp + iModNameLen, ".so"))) { + dbgprintf("Module '%s' found\n", pModName); + break; + } + pModInfo = GetNxt(pModInfo); + } + *pMod = pModInfo; + RETiRet; +} + /* load a module and initialize it, based on doModLoad() from conf.c * rgerhards, 2008-03-05 @@ -762,15 +833,20 @@ modUnloadAndDestructAll(eModLinkType_t modLinkTypesToUnload) * configuration file processing, which is executed on a single thread. Should we * change that design at any stage (what is unlikely), we need to find a * replacement. + * rgerhards, 2011-04-27: + * Parameter "bConfLoad" tells us if the load was triggered by a config handler, in + * which case we need to tie the loaded module to the current config. If bConfLoad == 0, + * 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. */ static rsRetVal -Load(uchar *pModName) +Load(uchar *pModName, sbool bConfLoad) { DEFiRet; size_t iPathLen, iModNameLen; uchar szPath[PATH_MAX]; - uchar *pModNameCmp; int bHasExtension; void *pModHdlr, *pModInit; modInfo_t *pModInfo; @@ -790,14 +866,12 @@ Load(uchar *pModName) } else bHasExtension = FALSE; - pModInfo = GetNxt(NULL); - while(pModInfo != NULL) { - if(!strncmp((char *) pModName, (char *) (pModNameCmp = modGetName(pModInfo)), iModNameLen) && - (!*(pModNameCmp + iModNameLen) || !strcmp((char *) pModNameCmp + iModNameLen, ".so"))) { - dbgprintf("Module '%s' already loaded\n", pModName); - ABORT_FINALIZE(RS_RET_OK); - } - pModInfo = GetNxt(pModInfo); + CHKiRet(findModule(pModName, iModNameLen, &pModInfo)); + if(pModInfo != NULL) { + if(bConfLoad) + addModToCnfList(pModInfo); + dbgprintf("Module '%s' already loaded\n", pModName); + FINALIZE; } pModDirCurr = (uchar *)((pModDir == NULL) ? @@ -825,7 +899,8 @@ Load(uchar *pModName) } break; } else if(iPathLen > sizeof(szPath) - 1) { - errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', module path too long\n", pModName); + errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', " + "module path too long\n", pModName); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); } @@ -851,17 +926,13 @@ Load(uchar *pModName) /* now see if we have an extension and, if not, append ".so" */ if(!bHasExtension) { - /* we do not have an extension and so need to add ".so" - * TODO: I guess this is highly importable, so we should change the - * algo over time... -- rgerhards, 2008-03-05 - */ - /* ... so now add the extension */ strncat((char *) szPath, ".so", sizeof(szPath) - strlen((char*) szPath) - 1); iPathLen += 3; } if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, + "could not load module '%s', path too long\n", pModName); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); } @@ -887,7 +958,8 @@ Load(uchar *pModName) if(!pModHdlr) { if(iLoadCnt) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", szPath, dlerror()); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, + "could not load module '%s', dlopen: %s\n", szPath, dlerror()); } else { errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', ModDir was '%s'\n", szPath, ((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir)); @@ -895,15 +967,19 @@ Load(uchar *pModName) ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_DLOPEN); } if(!(pModInit = dlsym(pModHdlr, "modInit"))) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_NO_INIT, "could not load module '%s', dlsym: %s\n", szPath, dlerror()); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_NO_INIT, + "could not load module '%s', dlsym: %s\n", szPath, dlerror()); dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_NO_INIT); } - if((iRet = doModInit(pModInit, (uchar*) pModName, pModHdlr)) != RS_RET_OK) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_INIT_FAILED, "could not load module '%s', rsyslog error %d\n", szPath, iRet); + if((iRet = doModInit(pModInit, (uchar*) pModName, pModHdlr, &pModInfo)) != RS_RET_OK) { + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_INIT_FAILED, + "could not load module '%s', rsyslog error %d\n", szPath, iRet); dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_INIT_FAILED); } + if(bConfLoad) + addModToCnfList(pModInfo); finalize_it: pthread_mutex_unlock(&mutLoadUnload); diff --git a/runtime/modules.h b/runtime/modules.h index 08e0851c..4da8c7a6 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -166,11 +166,14 @@ BEGINinterface(module) /* name must also be changed in ENDinterface macro! */ rsRetVal (*Release)(char *srcFile, modInfo_t **ppThis); /**< release a module (ref counting) */ void (*PrintList)(void); rsRetVal (*UnloadAndDestructAll)(eModLinkType_t modLinkTypesToUnload); - rsRetVal (*doModInit)(rsRetVal (*modInit)(), uchar *name, void *pModHdlr); - rsRetVal (*Load)(uchar *name); + rsRetVal (*doModInit)(rsRetVal (*modInit)(), uchar *name, void *pModHdlr, modInfo_t **pNew); + rsRetVal (*Load)(uchar *name, sbool bConfLoad); rsRetVal (*SetModDir)(uchar *name); ENDinterface(module) -#define moduleCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ +#define moduleCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ +/* Changes: + * v2 - added param bCondLoad to Load call - 2011-04-27 + */ /* prototypes */ PROTOTYPEObj(module); diff --git a/runtime/obj.c b/runtime/obj.c index 45dac776..b45e5588 100644 --- a/runtime/obj.c +++ b/runtime/obj.c @@ -1154,7 +1154,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)); + CHKiRet(module.Load(pObjFile, 0)); /* 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 a32205d9..bc41d57c 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -155,6 +155,8 @@ ENDobjDestruct(rsconf) /* DebugPrint support for the rsconf object */ BEGINobjDebugPrint(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */ + cfgmodules_etry_t *modNode; + dbgprintf("configuration object %p\n", pThis); dbgprintf("Global Settings:\n"); dbgprintf(" bDebugPrintTemplateList.............: %d\n", @@ -170,7 +172,7 @@ BEGINobjDebugPrint(rsconf) /* be sure to specify the object type also in END and dbgprintf(" drop Msgs with malicious PTR Record : %d\n", glbl.GetDropMalPTRMsgs()); ruleset.DebugPrintAll(pThis); - DBGPRINTF("\n"); + dbgprintf("\n"); if(pThis->globals.bDebugPrintTemplateList) tplPrintList(pThis); if(pThis->globals.bDebugPrintModuleList) @@ -178,14 +180,17 @@ BEGINobjDebugPrint(rsconf) /* be sure to specify the object type also in END and if(pThis->globals.bDebugPrintCfSysLineHandlerList) dbgPrintCfSysLineHandlers(); // TODO: The following code needs to be "streamlined", so far just moved over... - DBGPRINTF("Main queue size %d messages.\n", pThis->globals.mainQ.iMainMsgQueueSize); - DBGPRINTF("Main queue worker threads: %d, wThread shutdown: %d, Perists every %d updates.\n", - pThis->globals.mainQ.iMainMsgQueueNumWorkers, pThis->globals.mainQ.iMainMsgQtoWrkShutdown, pThis->globals.mainQ.iMainMsgQPersistUpdCnt); - DBGPRINTF("Main queue timeouts: shutdown: %d, action completion shutdown: %d, enq: %d\n", - pThis->globals.mainQ.iMainMsgQtoQShutdown, pThis->globals.mainQ.iMainMsgQtoActShutdown, pThis->globals.mainQ.iMainMsgQtoEnq); - DBGPRINTF("Main queue watermarks: high: %d, low: %d, discard: %d, discard-severity: %d\n", - pThis->globals.mainQ.iMainMsgQHighWtrMark, pThis->globals.mainQ.iMainMsgQLowWtrMark, pThis->globals.mainQ.iMainMsgQDiscardMark, pThis->globals.mainQ.iMainMsgQDiscardSeverity); - DBGPRINTF("Main queue save on shutdown %d, max disk space allowed %lld\n", + dbgprintf("Main queue size %d messages.\n", pThis->globals.mainQ.iMainMsgQueueSize); + dbgprintf("Main queue worker threads: %d, wThread shutdown: %d, Perists every %d updates.\n", + pThis->globals.mainQ.iMainMsgQueueNumWorkers, + pThis->globals.mainQ.iMainMsgQtoWrkShutdown, pThis->globals.mainQ.iMainMsgQPersistUpdCnt); + dbgprintf("Main queue timeouts: shutdown: %d, action completion shutdown: %d, enq: %d\n", + pThis->globals.mainQ.iMainMsgQtoQShutdown, + pThis->globals.mainQ.iMainMsgQtoActShutdown, pThis->globals.mainQ.iMainMsgQtoEnq); + dbgprintf("Main queue watermarks: high: %d, low: %d, discard: %d, discard-severity: %d\n", + pThis->globals.mainQ.iMainMsgQHighWtrMark, pThis->globals.mainQ.iMainMsgQLowWtrMark, + pThis->globals.mainQ.iMainMsgQDiscardMark, pThis->globals.mainQ.iMainMsgQDiscardSeverity); + dbgprintf("Main queue save on shutdown %d, max disk space allowed %lld\n", pThis->globals.mainQ.bMainMsgQSaveOnShutdown, pThis->globals.mainQ.iMainMsgQueMaxDiskSpace); /* TODO: add iActionRetryCount = 0; @@ -196,8 +201,12 @@ BEGINobjDebugPrint(rsconf) /* be sure to specify the object type also in END and setQPROP(qqueueSetiMinMsgsPerWrkr, "$MainMsgQueueWorkerThreadMinimumMessages", 100); setQPROP(qqueueSetbSaveOnShutdown, "$MainMsgQueueSaveOnShutdown", 1); */ - DBGPRINTF("Work Directory: '%s'.\n", glbl.GetWorkDir()); + dbgprintf("Work Directory: '%s'.\n", glbl.GetWorkDir()); ochPrintList(); + dbgprintf("Modules used in this configuration:\n"); + for(modNode = pThis->modules.root ; modNode != NULL ; modNode = modNode->next) { + dbgprintf(" %s\n", module.GetName(modNode->pMod)); + } CODESTARTobjDebugPrint(rsconf) ENDobjDebugPrint(rsconf) @@ -573,6 +582,18 @@ setModDir(void __attribute__((unused)) *pVal, uchar* pszNewVal) } +/* "load" a build in module and register it for the current load config */ +static rsRetVal +regBuildInModule(rsRetVal (*modInit)(), uchar *name, void *pModHdlr) +{ + modInfo_t *pMod; + DEFiRet; + CHKiRet(module.doModInit(modInit, name, pModHdlr, &pMod)); +finalize_it: + RETiRet; +} + + /* load build-in modules * very first version begun on 2007-07-23 by rgerhards */ @@ -581,12 +602,12 @@ loadBuildInModules() { DEFiRet; - CHKiRet(module.doModInit(modInitFile, UCHAR_CONSTANT("builtin-file"), NULL)); - CHKiRet(module.doModInit(modInitPipe, UCHAR_CONSTANT("builtin-pipe"), NULL)); - CHKiRet(module.doModInit(modInitShell, UCHAR_CONSTANT("builtin-shell"), NULL)); - CHKiRet(module.doModInit(modInitDiscard, UCHAR_CONSTANT("builtin-discard"), NULL)); + CHKiRet(regBuildInModule(modInitFile, UCHAR_CONSTANT("builtin-file"), NULL)); + CHKiRet(regBuildInModule(modInitPipe, UCHAR_CONSTANT("builtin-pipe"), NULL)); + CHKiRet(regBuildInModule(modInitShell, UCHAR_CONSTANT("builtin-shell"), NULL)); + CHKiRet(regBuildInModule(modInitDiscard, UCHAR_CONSTANT("builtin-discard"), NULL)); # ifdef SYSLOG_INET - CHKiRet(module.doModInit(modInitFwd, UCHAR_CONSTANT("builtin-fwd"), NULL)); + CHKiRet(regBuildInModule(modInitFwd, UCHAR_CONSTANT("builtin-fwd"), NULL)); # endif /* dirty, but this must be for the time being: the usrmsg module must always be @@ -598,11 +619,11 @@ loadBuildInModules() * User names now must begin with: * [a-zA-Z0-9_.] */ - CHKiRet(module.doModInit(modInitUsrMsg, (uchar*) "builtin-usrmsg", NULL)); + CHKiRet(regBuildInModule(modInitUsrMsg, (uchar*) "builtin-usrmsg", NULL)); /* load build-in parser modules */ - CHKiRet(module.doModInit(modInitpmrfc5424, UCHAR_CONSTANT("builtin-pmrfc5424"), NULL)); - CHKiRet(module.doModInit(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! */ @@ -610,10 +631,10 @@ loadBuildInModules() CHKiRet(parser.AddDfltParser(UCHAR_CONSTANT("rsyslog.rfc3164"))); /* load build-in strgen modules */ - CHKiRet(module.doModInit(modInitsmfile, UCHAR_CONSTANT("builtin-smfile"), NULL)); - CHKiRet(module.doModInit(modInitsmtradfile, UCHAR_CONSTANT("builtin-smtradfile"), NULL)); - CHKiRet(module.doModInit(modInitsmfwd, UCHAR_CONSTANT("builtin-smfwd"), NULL)); - CHKiRet(module.doModInit(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/rsconf.h b/runtime/rsconf.h index 2eb09851..63754e6f 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -93,7 +93,13 @@ struct defaults_s { /* list of modules loaded in this configuration (config specific module list) */ +struct cfgmodules_etry_s { + cfgmodules_etry_t *next; + modInfo_t *pMod; +}; + struct cfgmodules_s { + cfgmodules_etry_t *root; }; /* outchannel-specific data */ diff --git a/runtime/typedefs.h b/runtime/typedefs.h index ca78d820..1c8e93ce 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -88,6 +88,7 @@ typedef struct defaults_s defaults_t; typedef struct actions_s actions_t; typedef struct rsconf_s rsconf_t; typedef struct cfgmodules_s cfgmodules_t; +typedef struct cfgmodules_etry_s cfgmodules_etry_t; typedef struct outchannels_s outchannels_t; typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript function */ typedef uint64 qDeqID; /* queue Dequeue order ID. 32 bits is considered dangerously few */ -- cgit v1.2.3 From 5cd3cdf3c82ef49506124ace13d20c52afd5d44a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Apr 2011 17:11:41 +0200 Subject: step: config-specific module list used during config processing --- runtime/conf.c | 8 ++++---- runtime/modules.c | 33 +++++++++++++++++++++++---------- runtime/modules.h | 6 ++++-- runtime/rsconf.c | 20 ++++++++------------ tools/syslogd.c | 2 +- 5 files changed, 40 insertions(+), 29 deletions(-) diff --git a/runtime/conf.c b/runtime/conf.c index 67c1ed81..ea7102a6 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -1105,7 +1105,7 @@ static rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) ASSERT(ppAction != NULL); /* loop through all modules and see if one picks up the line */ - pMod = module.GetNxtType(NULL, eMOD_OUT); + pMod = module.GetNxtCnfType(conf, NULL, eMOD_OUT); /* Note: clang static analyzer reports that pMod mybe == NULL. However, this is * not possible, because we have the built-in output modules which are always * present. Anyhow, we guard this by an assert. -- rgerhards, 2010-12-16 @@ -1144,7 +1144,7 @@ static rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) dbgprintf("error %d parsing config line\n", (int) iRet); break; } - pMod = module.GetNxtType(pMod, eMOD_OUT); + pMod = module.GetNxtCnfType(conf, pMod, eMOD_OUT); } *ppAction = pAction; @@ -1287,7 +1287,7 @@ setActionScope(void) /* now tell each action to start the scope */ pMod = NULL; - while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) { + while((pMod = module.GetNxtCnfType(loadConf, pMod, eMOD_OUT)) != NULL) { DBGPRINTF("beginning scope on module %s\n", pMod->pszName); pMod->mod.om.newScope(); } @@ -1312,7 +1312,7 @@ unsetActionScope(void) /* now tell each action to restore the scope */ pMod = NULL; - while((pMod = module.GetNxtType(pMod, eMOD_OUT)) != NULL) { + while((pMod = module.GetNxtCnfType(loadConf, pMod, eMOD_OUT)) != NULL) { DBGPRINTF("exiting scope on module %s\n", pMod->pszName); pMod->mod.om.restoreScope(); } diff --git a/runtime/modules.c b/runtime/modules.c index 8cdc9bb1..69c89790 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -335,7 +335,7 @@ addModToGlblList(modInfo_t *pThis) /* Add a module to the config module list for current loadConf */ -static inline rsRetVal +rsRetVal addModToCnfList(modInfo_t *pThis) { cfgmodules_etry_t *pNew; @@ -401,18 +401,31 @@ static modInfo_t *GetNxt(modInfo_t *pThis) /* this function is like GetNxt(), but it returns pointers to - * modules of specific type only. - * rgerhards, 2007-07-24 + * modules of specific type only. Only modules from the provided + * config are returned. Note that processing speed could be improved, + * but this is really not relevant, as config file loading is not really + * something we are concerned about in regard to runtime. */ -static modInfo_t *GetNxtType(modInfo_t *pThis, eModType_t rqtdType) +static modInfo_t *GetNxtCnfType(rsconf_t *cnf, modInfo_t *pThis, eModType_t rqtdType) { - modInfo_t *pMod = pThis; + cfgmodules_etry_t *node; + + if(pThis == NULL) { /* start at beginning of module list */ + node = cnf->modules.root; + } else { /* start at last location - then we need to find the module in the config list */ + for(node = cnf->modules.root ; node != NULL && node->pMod != pThis ; node = node->next) + /*search only, all done in for() */; + if(node != NULL) + node = node->next; /* skip to NEXT element in list */ + } - do { - pMod = GetNxt(pMod); - } while(!(pMod == NULL || pMod->eType == rqtdType)); /* warning: do ... while() */ +dbgprintf("XXXX: entering node, ptr %p: %s\n", node, (node == NULL)? "":modGetName(node->pMod)); + while(node != NULL && node->pMod->eType != rqtdType) { + node = node->next; /* warning: do ... while() */ +dbgprintf("XXXX: in loop, ptr %p: %s\n", node, (node == NULL)? "":modGetName(node->pMod)); + } - return pMod; + return (node == NULL) ? NULL : node->pMod; } @@ -1111,7 +1124,7 @@ CODESTARTobjQueryInterface(module) * of course, also affects the "if" above). */ pIf->GetNxt = GetNxt; - pIf->GetNxtType = GetNxtType; + pIf->GetNxtCnfType = GetNxtCnfType; pIf->GetName = modGetName; pIf->GetStateName = modGetStateName; pIf->PrintList = modPrintList; diff --git a/runtime/modules.h b/runtime/modules.h index 4da8c7a6..37a73ecd 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -159,7 +159,7 @@ struct modInfo_s { /* interfaces */ BEGINinterface(module) /* name must also be changed in ENDinterface macro! */ modInfo_t *(*GetNxt)(modInfo_t *pThis); - modInfo_t *(*GetNxtType)(modInfo_t *pThis, eModType_t rqtdType); + modInfo_t *(*GetNxtCnfType)(rsconf_t *cnf, modInfo_t *pThis, eModType_t rqtdType); uchar *(*GetName)(modInfo_t *pThis); uchar *(*GetStateName)(modInfo_t *pThis); rsRetVal (*Use)(char *srcFile, modInfo_t *pThis); /**< must be called before a module is used (ref counting) */ @@ -172,7 +172,9 @@ BEGINinterface(module) /* name must also be changed in ENDinterface macro! */ ENDinterface(module) #define moduleCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ /* Changes: - * v2 - added param bCondLoad to Load call - 2011-04-27 + * v2 + * - added param bCondLoad to Load call - 2011-04-27 + * - removed GetNxtType, added GetNxtCnfType - 2011-04-27 */ /* prototypes */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index bc41d57c..b50b4fb6 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -301,7 +301,7 @@ runInputModules(void) BEGINfunc /* loop through all modules and activate them (brr...) */ - pMod = module.GetNxtType(NULL, eMOD_IN); + pMod = module.GetNxtCnfType(runConf, NULL, eMOD_IN); while(pMod != NULL) { if(pMod->mod.im.bCanRun) { /* activate here */ @@ -309,7 +309,7 @@ runInputModules(void) 0 : 1; thrdCreate(pMod->mod.im.runInput, pMod->mod.im.afterRun, bNeedsCancel); } - pMod = module.GetNxtType(pMod, eMOD_IN); + pMod = module.GetNxtCnfType(runConf, pMod, eMOD_IN); } ENDfunc @@ -317,11 +317,7 @@ runInputModules(void) } -/* Start the input modules. This function will probably undergo big changes - * while we implement the input module interface. For now, it does the most - * important thing to get at least my poor initial input modules up and - * running. Almost no config option is taken. - * rgerhards, 2007-12-14 +/* Make the input modules check if they are ready to start. */ static rsRetVal startInputModules(void) @@ -330,14 +326,14 @@ startInputModules(void) modInfo_t *pMod; /* loop through all modules and activate them (brr...) */ - pMod = module.GetNxtType(NULL, eMOD_IN); + pMod = module.GetNxtCnfType(runConf, NULL, eMOD_IN); while(pMod != NULL) { iRet = pMod->mod.im.willRun(); pMod->mod.im.bCanRun = (iRet == RS_RET_OK); if(!pMod->mod.im.bCanRun) { DBGPRINTF("module %lx will not run, iRet %d\n", (unsigned long) pMod, iRet); } - pMod = module.GetNxtType(pMod, eMOD_IN); + pMod = module.GetNxtCnfType(runConf, pMod, eMOD_IN); } ENDfunc @@ -355,6 +351,8 @@ activate(rsconf_t *cnf) { DEFiRet; + /* at this point, we "switch" over to the running conf */ + runConf = cnf; # if 0 /* currently the DAG is not supported -- code missing! */ /* TODO: re-enable this functionality some time later! */ /* check if we need to generate a config DAG and, if so, do that */ @@ -377,7 +375,6 @@ activate(rsconf_t *cnf) /* finally let the inputs run... */ runInputModules(); - runConf = cnf; dbgprintf("configuration %p activated\n", cnf); finalize_it: @@ -589,6 +586,7 @@ regBuildInModule(rsRetVal (*modInit)(), uchar *name, void *pModHdlr) modInfo_t *pMod; DEFiRet; CHKiRet(module.doModInit(modInit, name, pModHdlr, &pMod)); + addModToCnfList(pMod); finalize_it: RETiRet; } @@ -694,8 +692,6 @@ initLegacyConf(void) CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, setActionResumeInterval, NULL, NULL, eConfObjGlobal)); - //CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, - //doModLoad, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, conf.doModLoad, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, diff --git a/tools/syslogd.c b/tools/syslogd.c index fc23f058..dcce4d77 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -2176,7 +2176,7 @@ int realMain(int argc, char **argv) "startup with a dirty config.\n"); exit(2); } - iRet = RS_RET_OK; + localRet = RS_RET_OK; } CHKiRet(localRet); -- cgit v1.2.3 From ee346d8aec05bc79600f7d5280d88ab45d2bcab5 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Apr 2011 17:36:16 +0200 Subject: minor: some better debug instrumentation --- plugins/imudp/imudp.c | 2 +- runtime/rsconf.c | 6 ++++-- tcpsrv.c | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 8a463320..4a3560aa 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-2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * diff --git a/runtime/rsconf.c b/runtime/rsconf.c index b50b4fb6..2e2eaab6 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -280,10 +280,14 @@ dropPrivileges(rsconf_t *cnf) */ if(cnf->globals.gidDropPriv != 0) { doDropPrivGid(ourConf->globals.gidDropPriv); + DBGPRINTF("group privileges have been dropped to gid %u\n", (unsigned) + ourConf->globals.gidDropPriv); } if(cnf->globals.uidDropPriv != 0) { doDropPrivUid(ourConf->globals.uidDropPriv); + DBGPRINTF("user privileges have been dropped to uid %u\n", (unsigned) + ourConf->globals.uidDropPriv); } RETiRet; @@ -300,7 +304,6 @@ runInputModules(void) int bNeedsCancel; BEGINfunc - /* loop through all modules and activate them (brr...) */ pMod = module.GetNxtCnfType(runConf, NULL, eMOD_IN); while(pMod != NULL) { if(pMod->mod.im.bCanRun) { @@ -325,7 +328,6 @@ startInputModules(void) DEFiRet; modInfo_t *pMod; - /* loop through all modules and activate them (brr...) */ pMod = module.GetNxtCnfType(runConf, NULL, eMOD_IN); while(pMod != NULL) { iRet = pMod->mod.im.willRun(); diff --git a/tcpsrv.c b/tcpsrv.c index 39cba5d1..f1be1f87 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -898,6 +898,7 @@ tcpsrvConstructFinalize(tcpsrv_t *pThis) /* set up listeners */ CHKmalloc(pThis->ppLstn = calloc(pThis->iLstnMax, sizeof(netstrm_t*))); CHKmalloc(pThis->ppLstnPort = calloc(pThis->iLstnMax, sizeof(tcpLstnPortList_t*))); +dbgprintf("XXXX: open sockets (tcpsrv)\n"); iRet = pThis->OpenLstnSocks(pThis); finalize_it: -- cgit v1.2.3 From 6093f3110306e0575d10d09807da1e6895af4eba Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Apr 2011 17:57:47 +0200 Subject: step: moved main message queue activation to after priv drop --- action.c | 1 - dirty.h | 1 + runtime/rsconf.c | 21 +++++++++++++++++++++ tools/syslogd.c | 13 +------------ 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/action.c b/action.c index 0ec64236..baf21804 100644 --- a/action.c +++ b/action.c @@ -1681,7 +1681,6 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringReques pAction->pModData = pModData; /* now check if the module is compatible with select features */ if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) { -dbgprintf("XXXX: loadConf is %p in action.c\n", loadConf); pAction->f_ReduceRepeated = loadConf->globals.bReduceRepeatMsgs; } else { DBGPRINTF("module is incompatible with RepeatedMsgReduction - turned off\n"); diff --git a/dirty.h b/dirty.h index f27c5780..a831dd06 100644 --- a/dirty.h +++ b/dirty.h @@ -43,6 +43,7 @@ extern int MarkInterval; extern int repeatinterval[2]; extern qqueue_t *pMsgQueue; /* the main message queue */ extern int iConfigVerify; /* is this just a config verify run? */ +extern int bHaveMainQueue; #define MAXREPEAT ((int)((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1)) #define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) #define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 2e2eaab6..45822f19 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -342,6 +342,26 @@ startInputModules(void) return RS_RET_OK; /* intentional: we do not care about module errors */ } + +/* activate the main queue */ +static inline rsRetVal +activateMainQueue() +{ + DEFiRet; + /* create message queue */ + CHKiRet_Hdlr(createMainQueue(&pMsgQueue, UCHAR_CONSTANT("main Q"))) { + /* no queue is fatal, we need to give up in that case... */ + fprintf(stderr, "fatal error %d: could not create message queue - rsyslogd can not run!\n", iRet); + FINALIZE; + } + + bHaveMainQueue = (ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1; + DBGPRINTF("Main processing queue is initialized and running\n"); +finalize_it: + RETiRet; +} + + /* Activate an already-loaded configuration. The configuration will become * the new running conf (if successful). Note that in theory this method may * be called when there already is a running conf. In practice, the current @@ -374,6 +394,7 @@ activate(rsconf_t *cnf) CHKiRet(dropPrivileges(cnf)); + CHKiRet(activateMainQueue()); /* finally let the inputs run... */ runInputModules(); diff --git a/tools/syslogd.c b/tools/syslogd.c index dcce4d77..4fe6fa26 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -231,7 +231,7 @@ int iCompatibilityMode = 0; /* version we should be compatible with; 0 means sy int MarkInterval = 20 * 60; /* interval between marks in seconds - read-only after startup */ int send_to_all = 0; /* send message to all IPv4/IPv6 addresses */ static int NoFork = 0; /* don't fork - don't run in daemon mode - read-only after startup */ -static int bHaveMainQueue = 0;/* set to 1 if the main queue - in queueing mode - is available +int bHaveMainQueue = 0;/* set to 1 if the main queue - in queueing mode - is available * If the main queue is either not yet ready or not running in * queueing mode (mode DIRECT!), then this is set to 0. */ @@ -1308,17 +1308,6 @@ init(void) legacyOptsHook(); - - /* create message queue */ - CHKiRet_Hdlr(createMainQueue(&pMsgQueue, UCHAR_CONSTANT("main Q"))) { - /* no queue is fatal, we need to give up in that case... */ - fprintf(stderr, "fatal error %d: could not create message queue - rsyslogd can not run!\n", iRet); - exit(1); - } - - bHaveMainQueue = (ourConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DIRECT) ? 0 : 1; - DBGPRINTF("Main processing queue is initialized and running\n"); - memset(&sigAct, 0, sizeof (sigAct)); sigemptyset(&sigAct.sa_mask); sigAct.sa_handler = sighup_handler; -- cgit v1.2.3 From c6fc7f5ba321047aaa20a79ac47fcc2d529a3415 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Apr 2011 18:07:14 +0200 Subject: merge fix: made mistake when merging in v5-devel changes, now fixing --- tools/omfile.c | 14 +------------- tools/ompipe.c | 5 ----- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/tools/omfile.c b/tools/omfile.c index 0407efa2..d35e7df8 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -798,18 +798,6 @@ CODESTARTparseSelectorAct pData->iIOBufSize = (int) cs.iIOBufSize; pData->iFlushInterval = cs.iFlushInterval; pData->bUseAsyncWriter = cs.bUseAsyncWriter; - - if(pData->bDynamicName == 0) { - /* try open and emit error message if not possible. At this stage, we ignore the - * return value of prepareFile, this is taken care of in later steps. - */ - prepareFile(pData, pData->f_fname); - - if(pData->pStrm == NULL) { - DBGPRINTF("Error opening log file: %s\n", pData->f_fname); - errmsg.LogError(0, RS_RET_NO_FILE_ACCESS, "Could no open output file '%s'", pData->f_fname); - } - } CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct @@ -897,7 +885,7 @@ SCOPINGmodInit CHKiRet(omsdRegCFSLineHdlr((uchar *)"filecreatemode", 0, eCmdHdlrFileCreateMode, NULL, &cs.fCreateMode, STD_LOADABLE_MODULE_ID, eConfObjAction)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"createdirs", 0, eCmdHdlrBinary, NULL, &cs.bCreateDirs, STD_LOADABLE_MODULE_ID, eConfObjAction)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"failonchownfailure", 0, eCmdHdlrBinary, NULL, &cs.bFailOnChown, STD_LOADABLE_MODULE_ID, eConfObjAction)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileForceChown", 0, eCmdHdlrGoneAway, NULL, NULL, STD_LOADABLE_MODULE_ID, eConfObjAction)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"omfileforcechown", 0, eCmdHdlrGoneAway, NULL, NULL, STD_LOADABLE_MODULE_ID, eConfObjAction)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionfileenablesync", 0, eCmdHdlrBinary, NULL, &cs.bEnableSync, STD_LOADABLE_MODULE_ID, eConfObjAction)); CHKiRet(regCfSysLineHdlr((uchar *)"actionfiledefaulttemplate", 0, eCmdHdlrGetWord, NULL, &cs.pszFileDfltTplName, NULL, eConfObjAction)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjAction)); diff --git a/tools/ompipe.c b/tools/ompipe.c index d6b1f389..5d9397e1 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -221,11 +221,6 @@ CODESTARTparseSelectorAct */ CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); - - /* at this stage, we ignore the return value of preparePipe, this is taken - * care of in later steps. -- rgerhards, 2009-03-19 - */ - preparePipe(pData); CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct -- cgit v1.2.3 From 4b600b08a1160f09f35e58e6b5dae961f19e9f31 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 2 May 2011 12:31:02 +0200 Subject: cosmetic cleanup --- tcps_sess.c | 1 - tcpsrv.c | 2 -- 2 files changed, 3 deletions(-) diff --git a/tcps_sess.c b/tcps_sess.c index c64a9547..3b03f872 100644 --- a/tcps_sess.c +++ b/tcps_sess.c @@ -469,7 +469,6 @@ DataRcvd(tcps_sess_t *pThis, char *pData, size_t iLen) char *pEnd; DEFiRet; -//printf("DataRcvd: %p\n", pThis); ISOBJ_TYPE_assert(pThis, tcps_sess); assert(pData != NULL); assert(iLen > 0); diff --git a/tcpsrv.c b/tcpsrv.c index f1be1f87..938bbf7a 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -530,9 +530,7 @@ doReceive(tcpsrv_t *pThis, tcps_sess_t **ppSess, nspoll_t *pPoll) errmsg.LogError(0, RS_RET_PEER_CLOSED_CONN, "Netstream session %p closed by remote peer %s.\n", (*ppSess)->pStrm, pszPeer); } - //pthread_mutex_lock(&mut); CHKiRet(closeSess(pThis, ppSess, pPoll)); - //pthread_mutex_unlock(&mut); break; case RS_RET_RETRY: /* we simply ignore retry - this is not an error, but we also have not received anything */ -- cgit v1.2.3 From 3ad873e17adf89de8437aa5638b412e9fc730acf Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 2 May 2011 17:13:13 +0200 Subject: step: action queues now activated only AFTER privilege drop --- action.c | 31 ++++++++++++++++++++++++++++++- runtime/rsconf.c | 1 + 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/action.c b/action.c index baf21804..82b2fc43 100644 --- a/action.c +++ b/action.c @@ -85,6 +85,7 @@ #include "datetime.h" #include "unicode-helper.h" #include "atomic.h" +#include "ruleset.h" #define NO_TIME_PROVIDED 0 /* indicate we do not provide any cached time */ @@ -100,6 +101,7 @@ DEFobjCurrIf(obj) DEFobjCurrIf(datetime) DEFobjCurrIf(module) DEFobjCurrIf(errmsg) +DEFobjCurrIf(ruleset) typedef struct configSettings_s { @@ -381,7 +383,6 @@ actionConstructFinalize(action_t *pThis) cs.bActionQSaveOnShutdown, cs.iActionQueMaxDiskSpace); - CHKiRet(qqueueStart(pThis->pQueue)); DBGPRINTF("Action %p: queue %p created\n", pThis, pThis->pQueue); /* and now reset the queue params (see comment in its function header!) */ @@ -1452,6 +1453,33 @@ finalize_it: } +/* helper to activateActions, it activates a specific action. + */ +DEFFUNC_llExecFunc(doActivateActions) +{ + action_t *pThis = (action_t*) pData; + BEGINfunc + qqueueStart(pThis->pQueue); + DBGPRINTF("Action %p: queue %p started\n", pThis, pThis->pQueue); + ENDfunc + return RS_RET_OK; /* we ignore errors, we can not do anything either way */ +} + + +/* This function "activates" the action after privileges have been dropped. Currently, + * this means that the queues are started. + * rgerhards, 2011-05-02 + */ +rsRetVal +activateActions(void) +{ + DEFiRet; + iRet = ruleset.IterateAllActions(ourConf, doActivateActions, NULL); + RETiRet; +} + + + /* This submits the message to the action queue in case where we need to handle * bWriteAllMarkMessage == FALSE only. Note that we use a non-blocking CAS loop * for the synchronization. Here, we just modify the filter condition to be false when @@ -1784,6 +1812,7 @@ rsRetVal actionClassInit(void) CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); + CHKiRet(objUse(ruleset, CORE_COMPONENT)); CHKiRet(regCfSysLineHdlr((uchar *)"actionname", 0, eCmdHdlrGetWord, NULL, &cs.pszActionName, NULL, eConfObjAction)); CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuefilename", 0, eCmdHdlrGetWord, NULL, &cs.pszActionQFName, NULL, eConfObjAction)); diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 45822f19..11eea2b7 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -394,6 +394,7 @@ activate(rsconf_t *cnf) CHKiRet(dropPrivileges(cnf)); + CHKiRet(activateActions()); CHKiRet(activateMainQueue()); /* finally let the inputs run... */ runInputModules(); -- cgit v1.2.3 From 1bfaf4ac06e82c0e4008a2b851043a09aee1a2e3 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 3 May 2011 12:27:49 +0200 Subject: better handling of queue i/o errors in disk queues. This is kind of a bugfix, but a very intrusive one, thus it goes into the devel version first. Right now, "file not found" is handled and leads to the new emergency mode, in which disk action is stopped and the queue run in direct mode. An error message is emited if this happens. --- ChangeLog | 5 +++++ runtime/queue.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++----- runtime/rsyslog.h | 1 + runtime/wti.c | 5 ++++- 4 files changed, 69 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index d4fe37a6..dde6f77a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,11 @@ Version 5.9.0 [V5-DEVEL] (rgerhards), 2011-03-?? nobody still depends on it (and, if so, they lost...). - bugfix: pipes not opened in full priv mode when privs are to be dropped - this begins a new devel branch for v5 +- better handling of queue i/o errors in disk queues. This is kind of a + bugfix, but a very intrusive one, this it goes into the devel version + first. Right now, "file not found" is handled and leads to the new + emergency mode, in which disk action is stopped and the queue run + in direct mode. An error message is emited if this happens. - added support for user-level PRI provided via systemd - added new config directive $InputTCPFlowControl to select if tcp received messages shall be flagged as light delayable or not. diff --git a/runtime/queue.c b/runtime/queue.c index 50ae307c..70f0ba0c 100644 --- a/runtime/queue.c +++ b/runtime/queue.c @@ -83,6 +83,11 @@ static rsRetVal ConsumerDA(qqueue_t *pThis, wti_t *pWti); static rsRetVal batchProcessed(qqueue_t *pThis, wti_t *pWti); static rsRetVal qqueueMultiEnqObjNonDirect(qqueue_t *pThis, multi_submit_t *pMultiSub); static rsRetVal qqueueMultiEnqObjDirect(qqueue_t *pThis, multi_submit_t *pMultiSub); +static rsRetVal qAddDirect(qqueue_t *pThis, void* pUsr); +static rsRetVal qDestructDirect(qqueue_t __attribute__((unused)) *pThis); +static rsRetVal qConstructDirect(qqueue_t __attribute__((unused)) *pThis); +static rsRetVal qDelDirect(qqueue_t __attribute__((unused)) *pThis); +static rsRetVal qDestructDisk(qqueue_t *pThis); /* some constants for queuePersist () */ #define QUEUE_CHECKPOINT 1 @@ -583,6 +588,47 @@ static rsRetVal qDelLinkedList(qqueue_t *pThis) /* -------------------- disk -------------------- */ +/* The following function is used to "save" ourself from being killed by + * a fatally failed disk queue. A fatal failure is, for example, if no + * data can be read or written. In that case, the disk support is disabled, + * with all on-disk structures kept as-is as much as possible. Instead, the + * queue is switched to direct mode, so that at least + * some processing can happen. Of course, this may still have lots of + * undesired side-effects, but is probably better than aborting the + * syslogd. Note that this function *must* succeed in one way or another, as + * we can not recover from failure here. But it may emit different return + * states, which can trigger different processing in the higher layers. + * rgerhards, 2011-05-03 + */ +static inline rsRetVal +queueSwitchToEmergencyMode(qqueue_t *pThis, rsRetVal initiatingError) +{ + pThis->iQueueSize = 0; + pThis->nLogDeq = 0; + qDestructDisk(pThis); /* free disk structures */ + + pThis->qType = QUEUETYPE_DIRECT; + pThis->qConstruct = qConstructDirect; + pThis->qDestruct = qDestructDirect; + pThis->qAdd = qAddDirect; + pThis->qDel = qDelDirect; + pThis->MultiEnq = qqueueMultiEnqObjDirect; + if(pThis->pqParent != NULL) { + DBGOPRINT((obj_t*) pThis, "DA queue is in emergency mode, disabling DA in parent\n"); + pThis->pqParent->bIsDA = 0; + pThis->pqParent->pqDA = NULL; + /* This may have undesired side effects, not sure if I really evaluated + * all. So you know where to look at if you come to this point during + * troubleshooting ;) -- rgerhards, 2011-05-03 + */ + } + + errmsg.LogError(0, initiatingError, "fatal error on disk queue '%s', emergency switch to direct mode", + obj.GetName((obj_t*) pThis)); + return RS_RET_ERR_QUEUE_EMERGENCY; +} + + static rsRetVal qqueueLoadPersStrmInfoFixup(strm_t *pStrm, qqueue_t __attribute__((unused)) *pThis) { @@ -785,10 +831,7 @@ finalize_it: static rsRetVal qDeqDisk(qqueue_t *pThis, void **ppUsr) { DEFiRet; - - CHKiRet(obj.Deserialize(ppUsr, (uchar*) "msg", pThis->tVars.disk.pReadDeq, NULL, NULL)); - -finalize_it: + iRet = obj.Deserialize(ppUsr, (uchar*) "msg", pThis->tVars.disk.pReadDeq, NULL, NULL); RETiRet; } @@ -1683,7 +1726,18 @@ ConsumerReg(qqueue_t *pThis, wti_t *pWti) ISOBJ_TYPE_assert(pThis, qqueue); ISOBJ_TYPE_assert(pWti, wti); - CHKiRet(DequeueForConsumer(pThis, pWti)); + iRet = DequeueForConsumer(pThis, pWti); + if(iRet == RS_RET_FILE_NOT_FOUND) { + /* This is a fatal condition and means the queue is almost unusable */ + d_pthread_mutex_unlock(pThis->mut); + DBGOPRINT((obj_t*) pThis, "got 'file not found' error %d, queue defunct\n", iRet); + iRet = queueSwitchToEmergencyMode(pThis, iRet); + // TODO: think about what to return as iRet -- keep RS_RET_FILE_NOT_FOUND? + d_pthread_mutex_lock(pThis->mut); + } + if (iRet != RS_RET_OK) { + FINALIZE; + } /* we now have a non-idle batch of work, so we can release the queue mutex and process it */ d_pthread_mutex_unlock(pThis->mut); @@ -1774,7 +1828,6 @@ qqueueChkStopWrkrDA(qqueue_t *pThis) { DEFiRet; -//DBGPRINTF("XXXX: chkStopWrkrDA called, low watermark %d, phys Size %d\n", pThis->iLowWtrMrk, getPhysicalQueueSize(pThis)); if(pThis->bEnqOnly) { iRet = RS_RET_TERMINATE_WHEN_IDLE; } diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index d63dbe4f..d7f785f2 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -342,6 +342,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_ERR_HDFS_OPEN = -2179, /**< error during hdfsOpen (e.g. file does not exist) */ RS_RET_FILE_NOT_SPECIFIED = -2180, /**< file name not configured where this was required */ RS_RET_ERR_WRKDIR = -2181, /**< problems with the rsyslog working directory */ + RS_RET_ERR_QUEUE_EMERGENCY = -2182, /**< some fatal error caused queue to switch to emergency mode */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/runtime/wti.c b/runtime/wti.c index 9343f5c5..ec56c2d5 100644 --- a/runtime/wti.c +++ b/runtime/wti.c @@ -314,7 +314,10 @@ wtiWorker(wti_t *pThis) */ localRet = pWtp->pfDoWork(pWtp->pUsr, pThis); - if(localRet == RS_RET_IDLE) { + if(localRet == RS_RET_ERR_QUEUE_EMERGENCY) { + d_pthread_mutex_unlock(pWtp->pmutUsr); + break; /* end of loop */ + } else if(localRet == RS_RET_IDLE) { if(terminateRet == RS_RET_TERMINATE_WHEN_IDLE || bInactivityTOOccured) { d_pthread_mutex_unlock(pWtp->pmutUsr); break; /* end of loop */ -- cgit v1.2.3 From d0d9f823b79c5649dad18cb1d8d7744796ae0907 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 3 May 2011 18:02:18 +0200 Subject: step: put plumbing in place for new input module config system --- action.h | 1 + plugins/im3195/im3195.c | 30 +++++++++++ plugins/imdiag/imdiag.c | 29 ++++++++++ plugins/imfile/imfile.c | 29 ++++++++++ plugins/imgssapi/imgssapi.c | 29 ++++++++++ plugins/imklog/imklog.c | 30 +++++++++++ plugins/immark/immark.c | 65 ++++++++++++++++++----- plugins/impstats/impstats.c | 30 +++++++++++ plugins/imptcp/imptcp.c | 30 +++++++++++ plugins/imrelp/imrelp.c | 29 ++++++++++ plugins/imsolaris/imsolaris.c | 29 ++++++++++ plugins/imtcp/imtcp.c | 30 +++++++++++ plugins/imtemplate/imtemplate.c | 29 ++++++++++ plugins/imttcp/imttcp.c | 29 ++++++++++ plugins/imudp/imudp.c | 30 +++++++++++ plugins/imuxsock/imuxsock.c | 30 +++++++++++ runtime/conf.c | 34 ++++++------ runtime/module-template.h | 114 ++++++++++++++++++++++++++++++++++++++++ runtime/modules.c | 40 +++++++++----- runtime/modules.h | 16 +++--- runtime/rsconf.c | 104 ++++++++++++++++++++++++++++++------ runtime/rsconf.h | 3 ++ 22 files changed, 725 insertions(+), 65 deletions(-) diff --git a/action.h b/action.h index 749e573e..00b8cda3 100644 --- a/action.h +++ b/action.h @@ -106,5 +106,6 @@ rsRetVal actionClassInit(void); rsRetVal addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringRequest_t *pOMSR, int bSuspended); rsRetVal actionNewScope(void); rsRetVal actionRestoreScope(void); +rsRetVal activateActions(void); #endif /* #ifndef ACTION_H_INCLUDED */ diff --git a/plugins/im3195/im3195.c b/plugins/im3195/im3195.c index 156524c9..89dffacd 100644 --- a/plugins/im3195/im3195.c +++ b/plugins/im3195/im3195.c @@ -58,6 +58,11 @@ DEF_IMOD_STATIC_DATA DEFobjCurrIf(errmsg) /* configuration settings */ + +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + static int listenPort = 601; /* we use a global API object below, because this listener is @@ -89,6 +94,31 @@ void OnReceive(srAPIObj __attribute__((unused)) *pMyAPI, srSLMGObj* pSLMG) } +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + + BEGINrunInput CODESTARTrunInput /* this is an endless loop - it is terminated when the thread is diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c index 12b3318d..2595b903 100644 --- a/plugins/imdiag/imdiag.c +++ b/plugins/imdiag/imdiag.c @@ -78,6 +78,10 @@ static prop_t *pRcvIPDummy = NULL; /* config settings */ +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + static int iTCPSessMax = 20; /* max number of sessions */ static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */ static uchar *pszStrmDrvrAuthMode = NULL; /* authentication mode to use */ @@ -383,6 +387,31 @@ finalize_it: RETiRet; } + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + /* This function is called to gather input. */ BEGINrunInput diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index 67eebefe..f3aff1bb 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -83,6 +83,10 @@ typedef struct fileInfo_s { static rsRetVal persistStrmState(fileInfo_t *pInfo); /* config variables */ +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + static uchar *pszFileName = NULL; static uchar *pszFileTag = NULL; static uchar *pszStateFile = NULL; @@ -322,6 +326,31 @@ ENDrunInput * ------------------------------------------------------------------------------------------ */ +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + + /* The function is called by rsyslog before runInput() is called. It is a last chance * to set up anything specific. Most importantly, it can be used to tell rsyslog if the * input shall run or not. The idea is that if some config settings (or similiar things) diff --git a/plugins/imgssapi/imgssapi.c b/plugins/imgssapi/imgssapi.c index 41e34973..4d790cb0 100644 --- a/plugins/imgssapi/imgssapi.c +++ b/plugins/imgssapi/imgssapi.c @@ -104,6 +104,10 @@ typedef struct gss_sess_s { /* config variables */ +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + static int iTCPSessMax = 200; /* max number of sessions */ static char *gss_listen_service_name = NULL; static int bPermitPlainTcp = 0; /* plain tcp syslog allowed on GSSAPI port? */ @@ -640,6 +644,31 @@ TCPSessGSSDeinit(void) RETiRet; } + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + /* This function is called to gather input. */ BEGINrunInput diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c index 568fa8c1..05365588 100644 --- a/plugins/imklog/imklog.c +++ b/plugins/imklog/imklog.c @@ -67,6 +67,11 @@ DEFobjCurrIf(glbl) DEFobjCurrIf(prop) /* configuration settings */ + +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + int dbgPrintSymbols = 0; /* this one is extern so the helpers can access it! */ int symbols_twice = 0; int use_syscall = 0; @@ -249,6 +254,31 @@ finalize_it: ENDrunInput +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + + BEGINwillRun CODESTARTwillRun /* we need to create the inputName property (only once during our lifetime) */ diff --git a/plugins/immark/immark.c b/plugins/immark/immark.c index 609c8847..6b46b29f 100644 --- a/plugins/immark/immark.c +++ b/plugins/immark/immark.c @@ -10,7 +10,7 @@ * of the "old" message code without any modifications. However, it * helps to have things at the right place one we go to the meat of it. * - * Copyright 2007 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -54,7 +54,12 @@ MODULE_TYPE_NOKEEP /* Module static data */ DEF_IMOD_STATIC_DATA DEFobjCurrIf(glbl) +DEFobjCurrIf(errmsg) + static int iMarkMessagePeriod = DEFAULT_MARK_PERIOD; +typedef struct { + int iMarkMessagePeriod; +} modConfData_t; BEGINisCompatibleWithFeature CODESTARTisCompatibleWithFeature @@ -63,6 +68,43 @@ CODESTARTisCompatibleWithFeature ENDisCompatibleWithFeature +BEGINafterRun +CODESTARTafterRun +ENDafterRun + + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad + pModConf->iMarkMessagePeriod = iMarkMessagePeriod; +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf + if(pModConf->iMarkMessagePeriod == 0) { + errmsg.LogError(0, NO_ERRCODE, "immark: mark message period must not be 0, can not run"); + ABORT_FINALIZE(RS_RET_NO_RUN); /* we can not run with this error */ + } +finalize_it: +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf + MarkInterval = pModConf->iMarkMessagePeriod; +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + + /* This function is called to gather input. It must terminate only * a) on failure (iRet set accordingly) * b) on termination of the input module (as part of the unload process) @@ -82,7 +124,7 @@ CODESTARTrunInput * right into the sleep below. */ while(1) { - srSleep(iMarkMessagePeriod, 0); /* seconds, micro seconds */ + srSleep(MarkInterval, 0); /* seconds, micro seconds */ if(glbl.GetGlobalInputTermState() == 1) break; /* terminate input! */ @@ -95,19 +137,14 @@ ENDrunInput BEGINwillRun CODESTARTwillRun /* We set the global MarkInterval to what is configured here -- rgerhards, 2008-07-15 */ - MarkInterval = iMarkMessagePeriod; - if(iMarkMessagePeriod == 0) + if(MarkInterval == 0) iRet = RS_RET_NO_RUN; ENDwillRun -BEGINafterRun -CODESTARTafterRun -ENDafterRun - - BEGINmodExit CODESTARTmodExit + objRelease(errmsg, CORE_COMPONENT); ENDmodExit @@ -120,7 +157,6 @@ ENDqueryEtryPt static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { iMarkMessagePeriod = DEFAULT_MARK_PERIOD; - return RS_RET_OK; } @@ -129,8 +165,13 @@ CODESTARTmodInit *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(glbl, CORE_COMPONENT)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"markmessageperiod", 0, eCmdHdlrInt, NULL, &iMarkMessagePeriod, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); + + /* legacy config handlers */ + CHKiRet(omsdRegCFSLineHdlr((uchar *)"markmessageperiod", 0, eCmdHdlrInt, NULL, + &iMarkMessagePeriod, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, + resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); ENDmodInit /* vi:set ai: */ diff --git a/plugins/impstats/impstats.c b/plugins/impstats/impstats.c index 35851231..139652c1 100644 --- a/plugins/impstats/impstats.c +++ b/plugins/impstats/impstats.c @@ -69,6 +69,11 @@ typedef struct configSettings_s { int iSeverity; } configSettings_t; +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + + static configSettings_t cs; static prop_t *pInputName = NULL; @@ -139,6 +144,31 @@ generateStatsMsgs(void) } +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + + BEGINrunInput CODESTARTrunInput /* this is an endless loop - it is terminated when the thread is diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 1c9450c2..31f6fbc6 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -198,6 +198,11 @@ static int iMaxLine; /* maximum size of a single message */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); static rsRetVal addLstn(ptcpsrv_t *pSrv, int sock); +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + + /* some simple constructors/destructors */ static void @@ -1145,6 +1150,31 @@ wrkr(void *myself) } +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + + /* This function is called to gather input. */ BEGINrunInput diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c index 8650c86e..39c90849 100644 --- a/plugins/imrelp/imrelp.c +++ b/plugins/imrelp/imrelp.c @@ -60,6 +60,10 @@ static prop_t *pInputName = NULL; /* there is only one global inputName for all /* config settings */ +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + static int iTCPSessMax = 200; /* max number of sessions */ @@ -117,6 +121,31 @@ finalize_it: RETiRet; } + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + /* This function is called to gather input. */ BEGINrunInput diff --git a/plugins/imsolaris/imsolaris.c b/plugins/imsolaris/imsolaris.c index ee9ec5c6..b9701076 100644 --- a/plugins/imsolaris/imsolaris.c +++ b/plugins/imsolaris/imsolaris.c @@ -99,6 +99,10 @@ DEFobjCurrIf(prop) /* config settings */ +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + static prop_t *pInputName = NULL; /* our inputName currently is always "imuxsock", and this will hold it */ static char *LogName = NULL; /* the log socket name TODO: make configurable! */ @@ -302,6 +306,31 @@ finalize_it: } +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + + /* This function is called to gather input. */ BEGINrunInput CODESTARTrunInput diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index be95d287..b034ebe9 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -82,6 +82,11 @@ static permittedPeers_t *pPermPeersRoot = NULL; /* config settings */ + +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + static int iTCPSessMax = 200; /* max number of sessions */ static int iTCPLstnMax = 20; /* max number of sessions */ static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */ @@ -228,6 +233,31 @@ finalize_it: RETiRet; } + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + /* This function is called to gather input. */ BEGINrunInput diff --git a/plugins/imtemplate/imtemplate.c b/plugins/imtemplate/imtemplate.c index f18eba92..1f60bef7 100644 --- a/plugins/imtemplate/imtemplate.c +++ b/plugins/imtemplate/imtemplate.c @@ -95,6 +95,35 @@ DEF_IMOD_STATIC_DATA /* must be present, starts static data */ /* static int imtemplateWhateverVar = 0; */ /* config settings */ +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + + + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf /* You may add any functions that you feel are useful for your needs. No specific restrictions diff --git a/plugins/imttcp/imttcp.c b/plugins/imttcp/imttcp.c index 44dc3267..47bd071e 100644 --- a/plugins/imttcp/imttcp.c +++ b/plugins/imttcp/imttcp.c @@ -135,6 +135,10 @@ DEFobjCurrIf(ruleset) /* config settings */ +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + typedef struct configSettings_s { int bEmitMsgOnClose; /* emit an informational message on close by remote peer */ int iAddtlFrameDelim; /* addtl frame delimiter, e.g. for netscreen, default none */ @@ -984,6 +988,31 @@ startupListeners() RETiRet; } + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + /* This function is called to gather input. */ BEGINrunInput diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 4a3560aa..2fa62fd5 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -92,6 +92,11 @@ static int iTimeRequery = TIME_REQUERY_DFLT;/* how often is time to be queried i /* config settings */ +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + + static rsRetVal check_scheduling_priority(int report_error) { DEFiRet; @@ -569,6 +574,31 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) } #endif /* #if HAVE_EPOLL_CREATE1 */ + +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + /* This function is called to gather input. * Note that udpLstnSocks must be non-NULL because otherwise we would not have * indicated that we want to run (or we have a programming error ;)). -- rgerhards, 2008-10-02 diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index cbf87d7f..91f273c1 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -87,6 +87,11 @@ DEFobjCurrIf(parser) DEFobjCurrIf(datetime) DEFobjCurrIf(statsobj) + +typedef struct { + EMPTY_STRUCT; +} modConfData_t; + statsobj_t *modStats; STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit) STATSCOUNTER_DEF(ctrLostRatelimit, mutCtrLostRatelimit) @@ -684,6 +689,31 @@ finalize_it: } +BEGINbeginCnfLoad +CODESTARTbeginCnfLoad +ENDbeginCnfLoad + + +BEGINendCnfLoad +CODESTARTendCnfLoad +ENDendCnfLoad + + +BEGINcheckCnf +CODESTARTcheckCnf +ENDcheckCnf + + +BEGINactivateCnf +CODESTARTactivateCnf +ENDactivateCnf + + +BEGINfreeCnf +CODESTARTfreeCnf +ENDfreeCnf + + /* This function is called to gather input. */ BEGINrunInput int maxfds; diff --git a/runtime/conf.c b/runtime/conf.c index ea7102a6..6a2e57fa 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -1095,24 +1095,26 @@ finalize_it: */ static rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) { - DEFiRet; modInfo_t *pMod; + cfgmodules_etry_t *node; omodStringRequest_t *pOMSR; action_t *pAction = NULL; void *pModData; + DEFiRet; ASSERT(p != NULL); ASSERT(ppAction != NULL); /* loop through all modules and see if one picks up the line */ - pMod = module.GetNxtCnfType(conf, NULL, eMOD_OUT); - /* Note: clang static analyzer reports that pMod mybe == NULL. However, this is + node = module.GetNxtCnfType(conf, NULL, eMOD_OUT); + /* Note: clang static analyzer reports that node maybe == NULL. However, this is * not possible, because we have the built-in output modules which are always * present. Anyhow, we guard this by an assert. -- rgerhards, 2010-12-16 */ - assert(pMod != NULL); - while(pMod != NULL) { + assert(node != NULL); + while(node != NULL) { pOMSR = NULL; + pMod = node->pMod; iRet = pMod->mod.om.parseSelectorAct(p, &pModData, &pOMSR); dbgprintf("tried selector action for %s: %d\n", module.GetName(pMod), iRet); if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) { @@ -1144,7 +1146,7 @@ static rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) dbgprintf("error %d parsing config line\n", (int) iRet); break; } - pMod = module.GetNxtCnfType(conf, pMod, eMOD_OUT); + node = module.GetNxtCnfType(conf, node, eMOD_OUT); } *ppAction = pAction; @@ -1279,17 +1281,17 @@ static inline rsRetVal setActionScope(void) { DEFiRet; - modInfo_t *pMod; + cfgmodules_etry_t *node; currConfObj = eConfObjAction; DBGPRINTF("entering action scope\n"); CHKiRet(actionNewScope()); /* now tell each action to start the scope */ - pMod = NULL; - while((pMod = module.GetNxtCnfType(loadConf, pMod, eMOD_OUT)) != NULL) { - DBGPRINTF("beginning scope on module %s\n", pMod->pszName); - pMod->mod.om.newScope(); + node = NULL; + while((node = module.GetNxtCnfType(loadConf, node, eMOD_OUT)) != NULL) { + DBGPRINTF("beginning scope on module %s\n", node->pMod->pszName); + node->pMod->mod.om.newScope(); } finalize_it: @@ -1304,17 +1306,17 @@ static inline rsRetVal unsetActionScope(void) { DEFiRet; - modInfo_t *pMod; + cfgmodules_etry_t *node; currConfObj = eConfObjAction; DBGPRINTF("exiting action scope\n"); CHKiRet(actionRestoreScope()); /* now tell each action to restore the scope */ - pMod = NULL; - while((pMod = module.GetNxtCnfType(loadConf, pMod, eMOD_OUT)) != NULL) { - DBGPRINTF("exiting scope on module %s\n", pMod->pszName); - pMod->mod.om.restoreScope(); + node = NULL; + while((node = module.GetNxtCnfType(loadConf, node, eMOD_OUT)) != NULL) { + DBGPRINTF("exiting scope on module %s\n", node->pMod->pszName); + node->pMod->mod.om.restoreScope(); } finalize_it: diff --git a/runtime/module-template.h b/runtime/module-template.h index 2b0ed593..1ec1d8d2 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -459,6 +459,16 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\ *pEtryPoint = willRun;\ } else if(!strcmp((char*) name, "afterRun")) {\ *pEtryPoint = afterRun;\ + } else if(!strcmp((char*) name, "beginCnfLoad")) {\ + *pEtryPoint = beginCnfLoad;\ + } else if(!strcmp((char*) name, "endCnfLoad")) {\ + *pEtryPoint = endCnfLoad;\ + } else if(!strcmp((char*) name, "checkCnf")) {\ + *pEtryPoint = checkCnf;\ + } else if(!strcmp((char*) name, "activateCnf")) {\ + *pEtryPoint = activateCnf;\ + } else if(!strcmp((char*) name, "freeCnf")) {\ + *pEtryPoint = freeCnf;\ } /* the following definition is the standard block for queryEtryPt for LIBRARY @@ -600,6 +610,110 @@ static rsRetVal modExit(void)\ } +/* beginCnfLoad() + * This is a function tells an input module that a new config load begins. + * The core passes in a handle to the new module-specific module conf to + * the module. -- rgerards, 2011-05-03 + */ +#define BEGINbeginCnfLoad \ +static rsRetVal beginCnfLoad(modConfData_t **ptr)\ +{\ + modConfData_t *pModConf; \ + DEFiRet; + +#define CODESTARTbeginCnfLoad \ + if((pModConf = calloc(1, sizeof(modConfData_t))) == NULL) {\ + *ptr = NULL;\ + ENDfunc \ + return RS_RET_OUT_OF_MEMORY;\ + } + +#define ENDbeginCnfLoad \ + *ptr = pModConf;\ + 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 + * this call, the config object must no longer be changed. + * The pModConf pointer passed into the module must no longer be used. + * rgerards, 2011-05-03 + */ +#define BEGINendCnfLoad \ +static rsRetVal endCnfLoad(modConfData_t *ptr)\ +{\ + modConfData_t *pModConf = (modConfData_t*) ptr; \ + DEFiRet; + +#define CODESTARTendCnfLoad + +#define ENDendCnfLoad \ + RETiRet;\ +} + + +/* checkCnf() + * Check the provided config object for errors, inconsistencies and other things + * that do not work out. + * NOTE: no part of the config must be activated, so some checks that require + * activation can not be done in this entry point. They must be done in the + * activateConf() stage, where the caller must also be prepared for error + * returns. + * rgerhards, 2011-05-03 + */ +#define BEGINcheckCnf \ +static rsRetVal checkCnf(modConfData_t *ptr)\ +{\ + modConfData_t *pModConf = (modConfData_t*) ptr; \ + DEFiRet; + +#define CODESTARTcheckCnf + +#define ENDcheckCnf \ + RETiRet;\ +} + + +/* activateCnf() + * This activates the provided config, and may report errors if they are detected + * during activation. + * rgerhards, 2011-05-03 + */ +#define BEGINactivateCnf \ +static rsRetVal activateCnf(modConfData_t *ptr)\ +{\ + modConfData_t *pModConf = (modConfData_t*) ptr; \ + DEFiRet; + +#define CODESTARTactivateCnf + +#define ENDactivateCnf \ + RETiRet;\ +} + + +/* freeCnf() + * This is a function tells an input module that it must free all data + * associated with the passed-in module config. + * rgerhards, 2011-05-03 + */ +#define BEGINfreeCnf \ +static rsRetVal freeCnf(void *ptr)\ +{\ + modConfData_t *pModConf = (modConfData_t*) ptr; \ + DEFiRet; + +#define CODESTARTfreeCnf + +#define ENDfreeCnf \ + if(pModConf != NULL)\ + free(pModConf); /* we need to free this in any case */\ + RETiRet;\ +} + + /* runInput() * This is the main function for input modules. It is used to gather data from the * input source and submit it to the message queue. Each runInput() instance has its own diff --git a/runtime/modules.c b/runtime/modules.c index 69c89790..67f16e65 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -362,12 +362,19 @@ addModToCnfList(modInfo_t *pThis) } } - /* if we reach this point, pLast is the tail pointer */ + /* if we reach this point, pLast is the tail pointer and this module is new + * inside the currently loaded config. So, iff it is an input module, let's + * pass it a pointer which it can populate with a pointer to its module conf. + */ CHKmalloc(pNew = MALLOC(sizeof(cfgmodules_etry_t))); pNew->next = NULL; pNew->pMod = pThis; + if(pThis->eType == eMOD_IN) { + CHKiRet(pThis->mod.im.beginCnfLoad(&pNew->modCnf)); + } + if(pLast == NULL) { loadConf->modules.root = pNew; } else { @@ -401,31 +408,27 @@ static modInfo_t *GetNxt(modInfo_t *pThis) /* this function is like GetNxt(), but it returns pointers to + * the configmodules entry, which than can be used to obtain the + * actual module pointer. Note that it returns those for * modules of specific type only. Only modules from the provided * config are returned. Note that processing speed could be improved, * but this is really not relevant, as config file loading is not really * something we are concerned about in regard to runtime. */ -static modInfo_t *GetNxtCnfType(rsconf_t *cnf, modInfo_t *pThis, eModType_t rqtdType) +static cfgmodules_etry_t +*GetNxtCnfType(rsconf_t *cnf, cfgmodules_etry_t *node, eModType_t rqtdType) { - cfgmodules_etry_t *node; - - if(pThis == NULL) { /* start at beginning of module list */ + if(node == NULL) { /* start at beginning of module list */ node = cnf->modules.root; - } else { /* start at last location - then we need to find the module in the config list */ - for(node = cnf->modules.root ; node != NULL && node->pMod != pThis ; node = node->next) - /*search only, all done in for() */; - if(node != NULL) - node = node->next; /* skip to NEXT element in list */ + } else { + node = node->next; } -dbgprintf("XXXX: entering node, ptr %p: %s\n", node, (node == NULL)? "":modGetName(node->pMod)); while(node != NULL && node->pMod->eType != rqtdType) { node = node->next; /* warning: do ... while() */ -dbgprintf("XXXX: in loop, ptr %p: %s\n", node, (node == NULL)? "":modGetName(node->pMod)); } - return (node == NULL) ? NULL : node->pMod; + return node; } @@ -518,6 +521,11 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ /* ... and now the module-specific interfaces */ switch(pNew->eType) { case eMOD_IN: + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"beginCnfLoad", &pNew->mod.im.beginCnfLoad)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"endCnfLoad", &pNew->mod.im.endCnfLoad)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeCnf", &pNew->mod.im.freeCnf)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"checkCnf", &pNew->mod.im.checkCnf)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"activateCnf", &pNew->mod.im.activateCnf)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"runInput", &pNew->mod.im.runInput)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"willRun", &pNew->mod.im.willRun)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"afterRun", &pNew->mod.im.afterRun)); @@ -697,6 +705,9 @@ static void modPrintList(void) break; case eMOD_IN: dbgprintf("Input Module Entry Points\n"); + dbgprintf("\tbeginCnfLoad: 0x%lx\n", (unsigned long) pMod->mod.im.beginCnfLoad); + dbgprintf("\tendCnfLoad: 0x%lx\n", (unsigned long) pMod->mod.im.endCnfLoad); + dbgprintf("\tfreeCnf: 0x%lx\n", (unsigned long) pMod->mod.im.freeCnf); dbgprintf("\trunInput: 0x%lx\n", (unsigned long) pMod->mod.im.runInput); dbgprintf("\twillRun: 0x%lx\n", (unsigned long) pMod->mod.im.willRun); dbgprintf("\tafterRun: 0x%lx\n", (unsigned long) pMod->mod.im.afterRun); @@ -928,7 +939,8 @@ Load(uchar *pModName, sbool bConfLoad) szPath[iPathLen++] = '/'; szPath[iPathLen] = '\0'; } else { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, + "could not load module '%s', path too long\n", pModName); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); } } diff --git a/runtime/modules.h b/runtime/modules.h index 37a73ecd..759e3350 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -110,19 +110,19 @@ struct modInfo_s { rsRetVal (*modExit)(void); /* called before termination or module unload */ rsRetVal (*modGetID)(void **); /* get its unique ID from module */ rsRetVal (*doHUP)(void *); /* non-restart type HUP handler */ - /* below: parse a configuration line - return if processed - * or not. If not, must be parsed to next module. - */ - rsRetVal (*parseConfigLine)(uchar **pConfLine); /* below: create an instance of this module. Most importantly the module * can allocate instance memory in this call. */ rsRetVal (*createInstance)(); - /* TODO: pass pointer to msg submit function to IM rger, 2007-12-14 */ union { struct {/* data for input modules */ + rsRetVal (*beginCnfLoad)(void*newCnf); + rsRetVal (*endCnfLoad)(void*Cnf); + rsRetVal (*checkCnf)(void*Cnf); + rsRetVal (*activateCnf)(void*Cnf); /* make provided config the running conf */ + rsRetVal (*freeCnf)(void*Cnf); +/* 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 (*willRun)(void); /* function to gather input and submit to queue */ rsRetVal (*afterRun)(thrdInfo_t*); /* function to gather input and submit to queue */ int bCanRun; /* cached value of whether willRun() succeeded */ } im; @@ -159,7 +159,7 @@ struct modInfo_s { /* interfaces */ BEGINinterface(module) /* name must also be changed in ENDinterface macro! */ modInfo_t *(*GetNxt)(modInfo_t *pThis); - modInfo_t *(*GetNxtCnfType)(rsconf_t *cnf, modInfo_t *pThis, eModType_t rqtdType); + cfgmodules_etry_t *(*GetNxtCnfType)(rsconf_t *cnf, cfgmodules_etry_t *pThis, eModType_t rqtdType); uchar *(*GetName)(modInfo_t *pThis); uchar *(*GetStateName)(modInfo_t *pThis); rsRetVal (*Use)(char *srcFile, modInfo_t *pThis); /**< must be called before a module is used (ref counting) */ @@ -180,4 +180,6 @@ ENDinterface(module) /* prototypes */ PROTOTYPEObj(module); +/* 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 11eea2b7..1e427d42 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -294,25 +294,94 @@ dropPrivileges(rsconf_t *cnf) } +/* Tell input modules that the config parsing stage is over. */ +static rsRetVal +tellInputsConfigLoadDone(void) +{ + cfgmodules_etry_t *node; + + BEGINfunc + DBGPRINTF("telling inputs that config load for %p is done\n", loadConf); + node = module.GetNxtCnfType(loadConf, NULL, eMOD_IN); + while(node != NULL) { + node->pMod->mod.im.endCnfLoad(node->modCnf); + node = module.GetNxtCnfType(runConf, node, eMOD_IN); + } + + ENDfunc + return RS_RET_OK; /* intentional: we do not care about module errors */ +} + + +/* Tell input modules to verify config object */ +static rsRetVal +tellInputsCheckConfig(void) +{ + cfgmodules_etry_t *node; + rsRetVal localRet; + + BEGINfunc + DBGPRINTF("telling inputs to check config %p\n", loadConf); + node = module.GetNxtCnfType(loadConf, NULL, eMOD_IN); + while(node != NULL) { + localRet = node->pMod->mod.im.checkCnf(node->modCnf); + DBGPRINTF("module %s tells us config can %sbe activated\n", + node->pMod->pszName, (localRet == RS_RET_OK) ? "" : "NOT "); + if(localRet == RS_RET_OK) { + node->canActivate = 1; + } else { + node->canActivate = 0; + } + node = module.GetNxtCnfType(runConf, node, eMOD_IN); + } + + ENDfunc + return RS_RET_OK; /* intentional: we do not care about module errors */ +} + + +/* Tell input modules to activate current running config */ +static rsRetVal +tellInputsActivateConfig(void) +{ + cfgmodules_etry_t *node; + + BEGINfunc + DBGPRINTF("telling inputs to activate config %p\n", runConf); + node = module.GetNxtCnfType(runConf, NULL, eMOD_IN); + while(node != NULL) { + if(node->canActivate) { + DBGPRINTF("activating config %p for module %s\n", + runConf, node->pMod->pszName); + node->pMod->mod.im.activateCnf(node->modCnf); + } + node = module.GetNxtCnfType(runConf, node, eMOD_IN); + } + + ENDfunc + return RS_RET_OK; /* intentional: we do not care about module errors */ +} + + /* Actually run the input modules. This happens after privileges are dropped, * if that is requested. */ static rsRetVal runInputModules(void) { - modInfo_t *pMod; + cfgmodules_etry_t *node; int bNeedsCancel; BEGINfunc - pMod = module.GetNxtCnfType(runConf, NULL, eMOD_IN); - while(pMod != NULL) { - if(pMod->mod.im.bCanRun) { + node = module.GetNxtCnfType(runConf, NULL, eMOD_IN); + while(node != NULL) { + if(node->pMod->mod.im.bCanRun) { /* activate here */ - bNeedsCancel = (pMod->isCompatibleWithFeature(sFEATURENonCancelInputTermination) == RS_RET_OK) ? + bNeedsCancel = (node->pMod->isCompatibleWithFeature(sFEATURENonCancelInputTermination) == RS_RET_OK) ? 0 : 1; - thrdCreate(pMod->mod.im.runInput, pMod->mod.im.afterRun, bNeedsCancel); + thrdCreate(node->pMod->mod.im.runInput, node->pMod->mod.im.afterRun, bNeedsCancel); } - pMod = module.GetNxtCnfType(runConf, pMod, eMOD_IN); + node = module.GetNxtCnfType(runConf, node, eMOD_IN); } ENDfunc @@ -326,16 +395,16 @@ static rsRetVal startInputModules(void) { DEFiRet; - modInfo_t *pMod; - - pMod = module.GetNxtCnfType(runConf, NULL, eMOD_IN); - while(pMod != NULL) { - iRet = pMod->mod.im.willRun(); - pMod->mod.im.bCanRun = (iRet == RS_RET_OK); - if(!pMod->mod.im.bCanRun) { - DBGPRINTF("module %lx will not run, iRet %d\n", (unsigned long) pMod, iRet); + cfgmodules_etry_t *node; + + node = module.GetNxtCnfType(runConf, NULL, eMOD_IN); + while(node != NULL) { + iRet = node->pMod->mod.im.willRun(); + node->pMod->mod.im.bCanRun = (iRet == RS_RET_OK); + if(!node->pMod->mod.im.bCanRun) { + DBGPRINTF("module %lx will not run, iRet %d\n", (unsigned long) node->pMod, iRet); } - pMod = module.GetNxtCnfType(runConf, pMod, eMOD_IN); + node = module.GetNxtCnfType(runConf, node, eMOD_IN); } ENDfunc @@ -381,6 +450,8 @@ activate(rsconf_t *cnf) if(ourConf->globals.pszConfDAGFile != NULL) generateConfigDAG(ourConf->globals.pszConfDAGFile); # endif + tellInputsConfigLoadDone(); + tellInputsCheckConfig(); /* the output part and the queue is now ready to run. So it is a good time * to initialize the inputs. Please note that the net code above should be @@ -390,6 +461,7 @@ activate(rsconf_t *cnf) * Keep in mind. though, that the outputs already run if the queue was * persisted to disk. -- rgerhards */ + tellInputsActivateConfig(); startInputModules(); CHKiRet(dropPrivileges(cnf)); diff --git a/runtime/rsconf.h b/runtime/rsconf.h index 63754e6f..0718566a 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -96,6 +96,9 @@ 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 */ + sbool canActivate; /* OK to activate this config? */ }; struct cfgmodules_s { -- cgit v1.2.3 From b7315fc8369993d462389412b29b132fd2963d72 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 3 May 2011 18:29:09 +0200 Subject: step: small improvements to input mod config plumbing --- plugins/immark/immark.c | 3 --- runtime/rsconf.c | 16 ++++++++++------ runtime/rsconf.h | 1 + 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/plugins/immark/immark.c b/plugins/immark/immark.c index 6b46b29f..ae793e80 100644 --- a/plugins/immark/immark.c +++ b/plugins/immark/immark.c @@ -136,9 +136,6 @@ ENDrunInput BEGINwillRun CODESTARTwillRun - /* We set the global MarkInterval to what is configured here -- rgerhards, 2008-07-15 */ - if(MarkInterval == 0) - iRet = RS_RET_NO_RUN; ENDwillRun diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 1e427d42..482622a1 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -375,8 +375,8 @@ runInputModules(void) BEGINfunc node = module.GetNxtCnfType(runConf, NULL, eMOD_IN); while(node != NULL) { - if(node->pMod->mod.im.bCanRun) { - /* activate here */ + 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; thrdCreate(node->pMod->mod.im.runInput, node->pMod->mod.im.afterRun, bNeedsCancel); @@ -399,10 +399,14 @@ startInputModules(void) node = module.GetNxtCnfType(runConf, NULL, eMOD_IN); while(node != NULL) { - iRet = node->pMod->mod.im.willRun(); - node->pMod->mod.im.bCanRun = (iRet == RS_RET_OK); - if(!node->pMod->mod.im.bCanRun) { - DBGPRINTF("module %lx will not run, iRet %d\n", (unsigned long) node->pMod, iRet); + if(node->canActivate) { + iRet = node->pMod->mod.im.willRun(); + node->canRun = (iRet == RS_RET_OK); + if(!node->canRun) { + DBGPRINTF("module %s will not run, iRet %d\n", node->pMod->pszName, iRet); + } + } else { + node->canRun = 0; } node = module.GetNxtCnfType(runConf, node, eMOD_IN); } diff --git a/runtime/rsconf.h b/runtime/rsconf.h index 0718566a..e26b1df6 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -99,6 +99,7 @@ struct cfgmodules_etry_s { /* the following data is input module specific */ void *modCnf; /* pointer to the input module conf */ sbool canActivate; /* OK to activate this config? */ + sbool canRun; /* OK to run this config? */ }; struct cfgmodules_s { -- cgit v1.2.3 From 79d46017e49d39b5de2d783cc3bcbeb696535bfc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 4 May 2011 14:41:08 +0200 Subject: step: imudp utilizes interim new input module interface --- plugins/imudp/imudp.c | 428 ++++++++++++++++++++++++++++------------------ runtime/module-template.h | 2 +- runtime/modules.c | 2 +- runtime/modules.h | 2 +- runtime/rsconf.c | 8 +- runtime/rsyslog.h | 1 + 6 files changed, 277 insertions(+), 166 deletions(-) diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 2fa62fd5..f2a5811d 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -76,124 +76,94 @@ static time_t ttLastDiscard = 0; /* timestamp when a message from a non-permitte static int *udpLstnSocks = NULL; /* Internet datagram sockets, first element is nbr of elements * read-only after init(), but beware of restart! */ static ruleset_t **udpRulesets = NULL; /* ruleset to be used with sockets in question (entry 0 is empty) */ -static uchar *pszBindAddr = NULL; /* IP to bind socket to */ static uchar *pRcvBuf = NULL; /* receive buffer (for a single packet). We use a global and alloc * it so that we can check available memory in willRun() and request * termination if we can not get it. -- rgerhards, 2007-12-27 */ static prop_t *pInputName = NULL; /* our inputName currently is always "imudp", and this will hold it */ -static uchar *pszSchedPolicy = NULL; /* scheduling policy string */ -static int iSchedPolicy; /* scheduling policy as SCHED_xxx */ -static int iSchedPrio; /* scheduling priority */ -static int seen_iSchedPrio = 0; /* have we seen scheduling priority in the config file? */ -static ruleset_t *pBindRuleset = NULL; /* ruleset to bind listener to (use system default if unspecified) */ + #define TIME_REQUERY_DFLT 2 -static int iTimeRequery = TIME_REQUERY_DFLT;/* how often is time to be queried inside tight recv loop? 0=always */ +#define SCHED_PRIO_UNSET -12345678 /* a value that indicates that the scheduling priority has not been set */ +/* config vars for legacy config system */ +static struct configSettings_s { + uchar *pszBindAddr; /* IP to bind socket to */ + uchar *pszSchedPolicy; /* scheduling policy string */ + uchar *pszBindRuleset; /* name of Ruleset to bind to */ + int iSchedPrio; /* scheduling priority */ + int iTimeRequery; /* how often is time to be queried inside tight recv loop? 0=always */ +} cs; /* config settings */ +typedef struct instanceConf_s { + uchar *pszBindAddr; /* IP to bind socket to */ + uchar *pszBindPort; /* Port to bind socket to */ + uchar *pszBindRuleset; /* name of ruleset to bind to */ + ruleset_t *pBindRuleset; /* ruleset to bind listener to (use system default if unspecified) */ + struct instanceConf_s *next; +} instanceConf_t; + typedef struct { - EMPTY_STRUCT; + rsconf_t *pConf; /* our overall config object */ + instanceConf_t *root, *tail; + uchar *pszSchedPolicy; /* scheduling policy string */ + 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 */ } modConfData_t; +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 rsRetVal check_scheduling_priority(int report_error) -{ - DEFiRet; - -#ifdef HAVE_SCHED_GET_PRIORITY_MAX - if (iSchedPrio < sched_get_priority_min(iSchedPolicy) || - iSchedPrio > sched_get_priority_max(iSchedPolicy)) { - if (report_error) - errmsg.LogError(errno, NO_ERRCODE, - "imudp: scheduling priority %d out of range (%d - %d)" - " for scheduling policy '%s' - ignoring settings", - iSchedPrio, - sched_get_priority_min(iSchedPolicy), - sched_get_priority_max(iSchedPolicy), - pszSchedPolicy); - ABORT_FINALIZE(RS_RET_VALIDATION_RUN); - } -#endif -finalize_it: - RETiRet; -} -/* Set scheduling priority in the supplied variable (will be iSchedPrio) - * and record that we have seen the directive (in seen_iSchedPrio). +/* 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. + * rgerhards, 2011-05-04 */ -static rsRetVal set_scheduling_priority(void *pVal, int value) -{ - DEFiRet; - - if (seen_iSchedPrio) { - errmsg.LogError(0, NO_ERRCODE, "directive already seen"); - ABORT_FINALIZE(RS_RET_VALIDATION_RUN); - } - *(int *)pVal = value; - seen_iSchedPrio = 1; - if (pszSchedPolicy != NULL) - CHKiRet(check_scheduling_priority(1)); - -finalize_it: - RETiRet; -} - -/* Set scheduling policy in iSchedPolicy */ -static rsRetVal set_scheduling_policy(void *pVal, uchar *pNewVal) +static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) { - int have_sched_policy = 0; + instanceConf_t *inst; DEFiRet; - - if (pszSchedPolicy != NULL) { - errmsg.LogError(0, NO_ERRCODE, "directive already seen"); - ABORT_FINALIZE(RS_RET_VALIDATION_RUN); + CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + CHKmalloc(inst->pszBindPort = ustrdup((pNewVal == NULL || *pNewVal == '\0') + ? (uchar*) "514" : pNewVal)); + if((cs.pszBindAddr == NULL) || (cs.pszBindAddr[0] == '\0')) { + inst->pszBindAddr = NULL; + } else { + CHKmalloc(inst->pszBindAddr = ustrdup(cs.pszBindAddr)); } - *((uchar**)pVal) = pNewVal; /* pVal is pszSchedPolicy */ - if (0) { /* trick to use conditional compilation */ -#ifdef SCHED_FIFO - } else if (!strcasecmp((char*)pszSchedPolicy, "fifo")) { - iSchedPolicy = SCHED_FIFO; - have_sched_policy = 1; -#endif -#ifdef SCHED_RR - } else if (!strcasecmp((char*)pszSchedPolicy, "rr")) { - iSchedPolicy = SCHED_RR; - have_sched_policy = 1; -#endif -#ifdef SCHED_OTHER - } else if (!strcasecmp((char*)pszSchedPolicy, "other")) { - iSchedPolicy = SCHED_OTHER; - have_sched_policy = 1; -#endif + if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) { + inst->pszBindRuleset = NULL; } else { - errmsg.LogError(errno, NO_ERRCODE, - "imudp: invalid scheduling policy '%s' " - "- ignoring setting", pszSchedPolicy); + CHKmalloc(inst->pszBindRuleset = ustrdup(cs.pszBindRuleset)); } - if (have_sched_policy == 0) { - free(pszSchedPolicy); - pszSchedPolicy = NULL; - ABORT_FINALIZE(RS_RET_VALIDATION_RUN); + 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; } - if (seen_iSchedPrio) - CHKiRet(check_scheduling_priority(1)); finalize_it: + free(pNewVal); RETiRet; } /* This function is called when a new listener shall be added. It takes - * the configured parameters, tries to bind the socket and, if that + * the instance config description, tries to bind the socket and, if that * succeeds, adds it to the list of existing listen sockets. - * rgerhards, 2007-12-27 */ -static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal) +static inline rsRetVal +addListner(instanceConf_t *inst) { DEFiRet; - uchar *bindAddr; int *newSocks; int *tmpSocks; int iSrc, iDst; @@ -202,17 +172,11 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal) /* 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(pszBindAddr == NULL) - bindAddr = NULL; - else if(pszBindAddr[0] == '*' && pszBindAddr[1] == '\0') - bindAddr = NULL; - else - bindAddr = pszBindAddr; - DBGPRINTF("Trying to open syslog UDP ports at %s:%s.\n", - (bindAddr == NULL) ? (uchar*)"*" : bindAddr, pNewVal); + DBGPRINTF("imudp: trying to open port at %s:%s.\n", + (inst->pszBindAddr == NULL) ? (uchar*)"*" : inst->pszBindAddr, inst->pszBindPort); - newSocks = net.create_udp_socket(bindAddr, (pNewVal == NULL || *pNewVal == '\0') ? (uchar*) "514" : pNewVal, 1); + 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) { @@ -220,7 +184,7 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal) udpLstnSocks = newSocks; CHKmalloc(udpRulesets = (ruleset_t**) MALLOC(sizeof(ruleset_t*) * (newSocks[0] + 1))); for(iDst = 1 ; iDst <= newSocks[0] ; ++iDst) - udpRulesets[iDst] = pBindRuleset; + udpRulesets[iDst] = inst->pBindRuleset; } else { /* we need to add them */ tmpSocks = (int*) MALLOC(sizeof(int) * (1 + newSocks[0] + udpLstnSocks[0])); @@ -243,7 +207,7 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal) } for(iSrc = 1 ; iSrc <= newSocks[0] ; ++iSrc, ++iDst) { tmpSocks[iDst] = newSocks[iSrc]; - tmpRulesets[iDst] = pBindRuleset; + tmpRulesets[iDst] = inst->pBindRuleset; } tmpSocks[0] = udpLstnSocks[0] + newSocks[0]; free(newSocks); @@ -256,30 +220,34 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal) } finalize_it: - free(pNewVal); /* in any case, this is no longer needed */ - RETiRet; } -/* accept a new ruleset to bind. Checks if it exists and complains, if not */ -static rsRetVal -setRuleset(void __attribute__((unused)) *pVal, uchar *pszName) +/* Check provided ruleset name in conf and store a direct + * pointer to it, if valid. + */ +static inline rsRetVal +checkRuleset(modConfData_t *modConf, instanceConf_t *inst) { ruleset_t *pRuleset; rsRetVal localRet; DEFiRet; - localRet = ruleset.GetRuleset(ourConf, &pRuleset, pszName); + if(inst->pszBindRuleset == NULL) + FINALIZE; + + localRet = ruleset.GetRuleset(modConf->pConf, &pRuleset, inst->pszBindRuleset); if(localRet == RS_RET_NOT_FOUND) { - errmsg.LogError(0, NO_ERRCODE, "error: ruleset '%s' not found - ignored", pszName); + errmsg.LogError(0, NO_ERRCODE, "imudp: ruleset '%s' for %s:%s not found - " + "using default ruleset instead", inst->pszBindRuleset, + inst->pszBindAddr == NULL ? "*" : inst->pszBindAddr, + inst->pszBindPort); } CHKiRet(localRet); - pBindRuleset = pRuleset; - DBGPRINTF("imudp current bind ruleset %p: '%s'\n", pRuleset, pszName); + inst->pBindRuleset = pRuleset; finalize_it: - free(pszName); /* no longer needed */ RETiRet; } @@ -368,7 +336,7 @@ processSocket(thrdInfo_t *pThrd, int fd, struct sockaddr_storage *frominetPrev, DBGPRINTF("recv(%d,%d),acl:%d,msg:%s\n", fd, (int) lenRcvBuf, *pbIsPermitted, pRcvBuf); if(*pbIsPermitted != 0) { - if((iTimeRequery == 0) || (iNbrTimeUsed++ % iTimeRequery) == 0) { + if((runModConf->iTimeRequery == 0) || (iNbrTimeUsed++ % runModConf->iTimeRequery) == 0) { datetime.getCurrTime(&stTime, &ttGenTime); } /* we now create our own message object and submit it to the queue */ @@ -394,42 +362,128 @@ finalize_it: RETiRet; } -static void set_thread_schedparam(void) + +/* check configured scheduling priority. + * Precondition: iSchedPolicy must have been set + */ +static inline rsRetVal +checkSchedulingPriority(modConfData_t *modConf) { - struct sched_param sparam; + DEFiRet; - if (pszSchedPolicy != NULL && seen_iSchedPrio == 0) { +#ifdef HAVE_SCHED_GET_PRIORITY_MAX + if( modConf->iSchedPrio < sched_get_priority_min(modConf->iSchedPolicy) + || modConf->iSchedPrio > sched_get_priority_max(modConf->iSchedPolicy)) { errmsg.LogError(0, NO_ERRCODE, + "imudp: scheduling priority %d out of range (%d - %d)" + " for scheduling policy '%s' - ignoring settings", + modConf->iSchedPrio, + sched_get_priority_min(modConf->iSchedPolicy), + sched_get_priority_max(modConf->iSchedPolicy), + modConf->pszSchedPolicy); + ABORT_FINALIZE(RS_RET_VALIDATION_RUN); + } +#endif + +finalize_it: + RETiRet; +} + + +/* check scheduling policy string and, if valid, set its + * numeric equivalent in current load config + */ +static rsRetVal +checkSchedulingPolicy(modConfData_t *modConf) +{ + DEFiRet; + + if (0) { /* trick to use conditional compilation */ +#ifdef SCHED_FIFO + } else if (!strcasecmp((char*)modConf->pszSchedPolicy, "fifo")) { + modConf->iSchedPolicy = SCHED_FIFO; +#endif +#ifdef SCHED_RR + } else if (!strcasecmp((char*)modConf->pszSchedPolicy, "rr")) { + modConf->iSchedPolicy = SCHED_RR; +#endif +#ifdef SCHED_OTHER + } else if (!strcasecmp((char*)modConf->pszSchedPolicy, "other")) { + modConf->iSchedPolicy = SCHED_OTHER; +#endif + } else { + errmsg.LogError(errno, NO_ERRCODE, + "imudp: invalid scheduling policy '%s' " + "- ignoring setting", modConf->pszSchedPolicy); + ABORT_FINALIZE(RS_RET_ERR_SCHED_PARAMS); + } +finalize_it: + RETiRet; +} + +/* checks scheduling parameters during config check phase */ +static rsRetVal +checkSchedParam(modConfData_t *modConf) +{ + DEFiRet; + + if(modConf->pszSchedPolicy != NULL && modConf->iSchedPrio == SCHED_PRIO_UNSET) { + errmsg.LogError(0, RS_RET_ERR_SCHED_PARAMS, "imudp: scheduling policy set, but without priority - ignoring settings"); - } else if (pszSchedPolicy == NULL && seen_iSchedPrio != 0) { - errmsg.LogError(0, NO_ERRCODE, + ABORT_FINALIZE(RS_RET_ERR_SCHED_PARAMS); + } else if(modConf->pszSchedPolicy == NULL && modConf->iSchedPrio != SCHED_PRIO_UNSET) { + errmsg.LogError(0, RS_RET_ERR_SCHED_PARAMS, "imudp: scheduling priority set, but without policy - ignoring settings"); - } else if (pszSchedPolicy != NULL && seen_iSchedPrio != 0 && - check_scheduling_priority(0) == 0) { + ABORT_FINALIZE(RS_RET_ERR_SCHED_PARAMS); + } else if(modConf->pszSchedPolicy != NULL && modConf->iSchedPrio != SCHED_PRIO_UNSET) { + /* we have parameters set, so check them */ + CHKiRet(checkSchedulingPolicy(modConf)); + CHKiRet(checkSchedulingPriority(modConf)); + } else { /* nothing set */ + modConf->iSchedPrio = SCHED_PRIO_UNSET; /* prevents doing the activation call */ + } #ifndef HAVE_PTHREAD_SETSCHEDPARAM - errmsg.LogError(0, NO_ERRCODE, - "imudp: cannot set thread scheduling policy, " - "pthread_setschedparam() not available"); -#else - int err; - - memset(&sparam, 0, sizeof sparam); - sparam.sched_priority = iSchedPrio; - dbgprintf("imudp trying to set sched policy to '%s', prio %d\n", - pszSchedPolicy, iSchedPrio); - err = pthread_setschedparam(pthread_self(), iSchedPolicy, &sparam); - if (err != 0) { - errmsg.LogError(err, NO_ERRCODE, "imudp: pthread_setschedparam() failed"); - } + errmsg.LogError(0, NO_ERRCODE, + "imudp: cannot set thread scheduling policy, " + "pthread_setschedparam() not available"); + ABORT_FINALIZE(RS_RET_ERR_SCHED_PARAMS); #endif - } - if (pszSchedPolicy != NULL) { - free(pszSchedPolicy); - pszSchedPolicy = NULL; +finalize_it: + if(iRet != RS_RET_OK) + modConf->iSchedPrio = SCHED_PRIO_UNSET; /* prevents doing the activation call */ + + RETiRet; +} + +/* set the configured scheduling policy (if possible) */ +static rsRetVal +setSchedParams(modConfData_t *modConf) +{ + DEFiRet; + +# ifdef HAVE_PTHREAD_SETSCHEDPARAM + int err; + struct sched_param sparam; + + if(modConf->iSchedPrio == SCHED_PRIO_UNSET) + FINALIZE; + + memset(&sparam, 0, sizeof sparam); + sparam.sched_priority = modConf->iSchedPrio; + dbgprintf("imudp trying to set sched policy to '%s', prio %d\n", + modConf->pszSchedPolicy, modConf->iSchedPrio); + err = pthread_setschedparam(pthread_self(), modConf->iSchedPolicy, &sparam); + if(err != 0) { + errmsg.LogError(err, NO_ERRCODE, "imudp: pthread_setschedparam() failed - ignoring"); } +# endif + +finalize_it: + RETiRet; } + /* This function implements the main reception loop. Depending on the environment, * we either use the traditional (but slower) select() or the Linux-specific epoll() * interface. ./configure settings control which one is used. @@ -452,7 +506,6 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) /* start "name caching" algo by making sure the previous system indicator * is invalidated. */ - set_thread_schedparam(); bIsPermitted = 0; memset(&frominetPrev, 0, sizeof(frominetPrev)); @@ -523,14 +576,12 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) /* start "name caching" algo by making sure the previous system indicator * is invalidated. */ - set_thread_schedparam(); bIsPermitted = 0; memset(&frominetPrev, 0, sizeof(frominetPrev)); DBGPRINTF("imudp uses select()\n"); while(1) { - /* Add the Unix Domain Sockets to the list of read - * descriptors. + /* Add the Unix Domain Sockets to the list of read descriptors. * rgerhards 2005-08-01: we must now check if there are * any local sockets to listen to at all. If the -o option * is given without -a, we do not need to listen at all.. @@ -577,21 +628,73 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) BEGINbeginCnfLoad CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + /* init legacy config vars */ + cs.pszBindRuleset = NULL; + cs.pszSchedPolicy = NULL; + cs.pszBindAddr = NULL; + cs.iSchedPrio = SCHED_PRIO_UNSET; + cs.iTimeRequery = TIME_REQUERY_DFLT; ENDbeginCnfLoad 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)); + } + +finalize_it: + loadModConf = NULL; /* done loading */ + /* free legacy config vars */ + free(cs.pszBindRuleset); + free(cs.pszSchedPolicy); + free(cs.pszBindAddr); ENDendCnfLoad BEGINcheckCnf + instanceConf_t *inst; CODESTARTcheckCnf + checkSchedParam(pModConf); /* this can not cause fatal errors */ + for(inst = pModConf->root ; inst != NULL ; inst = inst->next) { + checkRuleset(pModConf, inst); + } ENDcheckCnf 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(udpLstnSocks == NULL) { + errmsg.LogError(errno, NO_ERRCODE, "imudp: no listeners could be started, " + "input not activated.\n"); + ABORT_FINALIZE(RS_RET_NO_RUN); + } + + setSchedParams(pModConf); + + /* caching various settings */ + iMaxLine = glbl.GetMaxLine(); + CHKmalloc(pRcvBuf = MALLOC((iMaxLine + 1) * sizeof(char))); +finalize_it: ENDactivateCnf @@ -612,22 +715,8 @@ ENDrunInput /* initialize and return if will run or not */ BEGINwillRun CODESTARTwillRun - /* we need to create the inputName property (only once during our lifetime) */ - CHKiRet(prop.Construct(&pInputName)); - CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imudp"), sizeof("imudp") - 1)); - CHKiRet(prop.ConstructFinalize(pInputName)); - net.PrintAllowedSenders(1); /* UDP */ net.HasRestrictions(UCHAR_CONSTANT("UDP"), &bDoACLCheck); /* UDP */ - - /* if we could not set up any listners, there is no point in running... */ - if(udpLstnSocks == NULL) - ABORT_FINALIZE(RS_RET_NO_RUN); - - iMaxLine = glbl.GetMaxLine(); - - CHKmalloc(pRcvBuf = MALLOC((iMaxLine + 1) * sizeof(char))); -finalize_it: ENDwillRun @@ -645,13 +734,14 @@ CODESTARTafterRun free(pRcvBuf); pRcvBuf = NULL; } - if(pInputName != NULL) - prop.Destruct(&pInputName); ENDafterRun BEGINmodExit CODESTARTmodExit + if(pInputName != NULL) + prop.Destruct(&pInputName); + /* release what we no longer need */ objRelease(errmsg, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); @@ -677,11 +767,20 @@ ENDqueryEtryPt static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { - if(pszBindAddr != NULL) { - free(pszBindAddr); - pszBindAddr = NULL; + if(cs.pszBindAddr != NULL) { + free(cs.pszBindAddr); + cs.pszBindAddr = NULL; + } + if(cs.pszSchedPolicy != NULL) { + free(cs.pszSchedPolicy); + cs.pszSchedPolicy = NULL; } - iTimeRequery = TIME_REQUERY_DFLT;/* the default is to query only every second time */ + if(cs.pszBindRuleset != 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; } @@ -697,19 +796,24 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(ruleset, CORE_COMPONENT)); CHKiRet(objUse(net, LM_NET_FILENAME)); + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.Construct(&pInputName)); + CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imudp"), sizeof("imudp") - 1)); + CHKiRet(prop.ConstructFinalize(pInputName)); + /* register config file handlers */ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputudpserverbindruleset", 0, eCmdHdlrGetWord, - setRuleset, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.pszBindRuleset, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpserverrun", 0, eCmdHdlrGetWord, - addListner, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + addInstance, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpserveraddress", 0, eCmdHdlrGetWord, - NULL, &pszBindAddr, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.pszBindAddr, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"imudpschedulingpolicy", 0, eCmdHdlrGetWord, - &set_scheduling_policy, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.pszSchedPolicy, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"imudpschedulingpriority", 0, eCmdHdlrInt, - &set_scheduling_priority, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.iSchedPrio, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"udpservertimerequery", 0, eCmdHdlrInt, - NULL, &iTimeRequery, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.iTimeRequery, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); ENDmodInit diff --git a/runtime/module-template.h b/runtime/module-template.h index 1ec1d8d2..38cda4ba 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -616,7 +616,7 @@ static rsRetVal modExit(void)\ * the module. -- rgerards, 2011-05-03 */ #define BEGINbeginCnfLoad \ -static rsRetVal beginCnfLoad(modConfData_t **ptr)\ +static rsRetVal beginCnfLoad(modConfData_t **ptr, rsconf_t *pConf)\ {\ modConfData_t *pModConf; \ DEFiRet; diff --git a/runtime/modules.c b/runtime/modules.c index 67f16e65..e2e12a3b 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -372,7 +372,7 @@ addModToCnfList(modInfo_t *pThis) pNew->pMod = pThis; if(pThis->eType == eMOD_IN) { - CHKiRet(pThis->mod.im.beginCnfLoad(&pNew->modCnf)); + CHKiRet(pThis->mod.im.beginCnfLoad(&pNew->modCnf, loadConf)); } if(pLast == NULL) { diff --git a/runtime/modules.h b/runtime/modules.h index 759e3350..45fffdad 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -116,7 +116,7 @@ struct modInfo_s { rsRetVal (*createInstance)(); union { struct {/* data for input modules */ - rsRetVal (*beginCnfLoad)(void*newCnf); + rsRetVal (*beginCnfLoad)(void*newCnf, rsconf_t *pConf); rsRetVal (*endCnfLoad)(void*Cnf); rsRetVal (*checkCnf)(void*Cnf); rsRetVal (*activateCnf)(void*Cnf); /* make provided config the running conf */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 482622a1..8fc30cf3 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -345,6 +345,7 @@ static rsRetVal tellInputsActivateConfig(void) { cfgmodules_etry_t *node; + rsRetVal localRet; BEGINfunc DBGPRINTF("telling inputs to activate config %p\n", runConf); @@ -353,7 +354,12 @@ tellInputsActivateConfig(void) if(node->canActivate) { DBGPRINTF("activating config %p for module %s\n", runConf, node->pMod->pszName); - node->pMod->mod.im.activateCnf(node->modCnf); + localRet = node->pMod->mod.im.activateCnf(node->modCnf); + if(localRet != RS_RET_OK) { + errmsg.LogError(0, localRet, "activation of module %s failed", + node->pMod->pszName); + node->canActivate = 0; /* in a sense, could not activate... */ + } } node = module.GetNxtCnfType(runConf, node, eMOD_IN); } diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index fcc0d626..fbcdc253 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -355,6 +355,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_ERR_LIBLOGNORM_INIT = -2202,/**< cannot obtain liblognorm ctx */ RS_RET_ERR_LIBLOGNORM_SAMPDB_LOAD = -2203,/**< liblognorm sampledb load failed */ RS_RET_CMD_GONE_AWAY = -2204,/**< config directive existed, but no longer supported */ + RS_RET_ERR_SCHED_PARAMS = -2205,/**< there is a problem with configured thread scheduling params */ /* 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 c0d1334f6e23b1cfb21d302e3a4b32c449c26547 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 5 May 2011 11:36:05 +0200 Subject: step: imtcp moved to new config interface as far as we know that new interface right now ;) --- plugins/im3195/im3195.c | 4 +- plugins/imdiag/imdiag.c | 4 +- plugins/imfile/imfile.c | 4 +- plugins/imgssapi/imgssapi.c | 4 +- plugins/imklog/imklog.c | 4 +- plugins/immark/immark.c | 4 +- plugins/impstats/impstats.c | 4 +- plugins/imptcp/imptcp.c | 4 +- plugins/imrelp/imrelp.c | 4 +- plugins/imsolaris/imsolaris.c | 4 +- plugins/imtcp/imtcp.c | 242 +++++++++++++++++++++++++++------------- plugins/imtemplate/imtemplate.c | 5 +- plugins/imttcp/imttcp.c | 4 +- plugins/imudp/imudp.c | 44 +++----- plugins/imuxsock/imuxsock.c | 4 +- runtime/Makefile.am | 1 + runtime/im-helper.h | 66 +++++++++++ runtime/module-template.h | 3 +- runtime/typedefs.h | 2 + 19 files changed, 273 insertions(+), 138 deletions(-) create mode 100644 runtime/im-helper.h diff --git a/plugins/im3195/im3195.c b/plugins/im3195/im3195.c index 89dffacd..1daad3dd 100644 --- a/plugins/im3195/im3195.c +++ b/plugins/im3195/im3195.c @@ -59,9 +59,9 @@ DEFobjCurrIf(errmsg) /* configuration settings */ -typedef struct { +struct modConfData_s { EMPTY_STRUCT; -} modConfData_t; +}; static int listenPort = 601; diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c index 2595b903..57fa08e5 100644 --- a/plugins/imdiag/imdiag.c +++ b/plugins/imdiag/imdiag.c @@ -78,9 +78,9 @@ static prop_t *pRcvIPDummy = NULL; /* config settings */ -typedef struct { +struct modConfData_s { EMPTY_STRUCT; -} modConfData_t; +}; static int iTCPSessMax = 20; /* max number of sessions */ static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */ diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index f3aff1bb..321abbda 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -83,9 +83,9 @@ typedef struct fileInfo_s { static rsRetVal persistStrmState(fileInfo_t *pInfo); /* config variables */ -typedef struct { +struct modConfData_s { EMPTY_STRUCT; -} modConfData_t; +}; static uchar *pszFileName = NULL; static uchar *pszFileTag = NULL; diff --git a/plugins/imgssapi/imgssapi.c b/plugins/imgssapi/imgssapi.c index 4d790cb0..5f69a0b6 100644 --- a/plugins/imgssapi/imgssapi.c +++ b/plugins/imgssapi/imgssapi.c @@ -104,9 +104,9 @@ typedef struct gss_sess_s { /* config variables */ -typedef struct { +struct modConfData_s { EMPTY_STRUCT; -} modConfData_t; +}; static int iTCPSessMax = 200; /* max number of sessions */ static char *gss_listen_service_name = NULL; diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c index 05365588..425dec7f 100644 --- a/plugins/imklog/imklog.c +++ b/plugins/imklog/imklog.c @@ -68,9 +68,9 @@ DEFobjCurrIf(prop) /* configuration settings */ -typedef struct { +struct modConfData_s { EMPTY_STRUCT; -} modConfData_t; +}; int dbgPrintSymbols = 0; /* this one is extern so the helpers can access it! */ int symbols_twice = 0; diff --git a/plugins/immark/immark.c b/plugins/immark/immark.c index ae793e80..a3c0981b 100644 --- a/plugins/immark/immark.c +++ b/plugins/immark/immark.c @@ -57,9 +57,9 @@ DEFobjCurrIf(glbl) DEFobjCurrIf(errmsg) static int iMarkMessagePeriod = DEFAULT_MARK_PERIOD; -typedef struct { +struct modConfData_s { int iMarkMessagePeriod; -} modConfData_t; +}; BEGINisCompatibleWithFeature CODESTARTisCompatibleWithFeature diff --git a/plugins/impstats/impstats.c b/plugins/impstats/impstats.c index 139652c1..59d62d18 100644 --- a/plugins/impstats/impstats.c +++ b/plugins/impstats/impstats.c @@ -69,9 +69,9 @@ typedef struct configSettings_s { int iSeverity; } configSettings_t; -typedef struct { +struct modConfData_s { EMPTY_STRUCT; -} modConfData_t; +}; static configSettings_t cs; diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 31f6fbc6..82e64576 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -198,9 +198,9 @@ static int iMaxLine; /* maximum size of a single message */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); static rsRetVal addLstn(ptcpsrv_t *pSrv, int sock); -typedef struct { +struct modConfData_s { EMPTY_STRUCT; -} modConfData_t; +}; diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c index 39c90849..414c5995 100644 --- a/plugins/imrelp/imrelp.c +++ b/plugins/imrelp/imrelp.c @@ -60,9 +60,9 @@ static prop_t *pInputName = NULL; /* there is only one global inputName for all /* config settings */ -typedef struct { +struct modConfData_s { EMPTY_STRUCT; -} modConfData_t; +}; static int iTCPSessMax = 200; /* max number of sessions */ diff --git a/plugins/imsolaris/imsolaris.c b/plugins/imsolaris/imsolaris.c index b9701076..05827a18 100644 --- a/plugins/imsolaris/imsolaris.c +++ b/plugins/imsolaris/imsolaris.c @@ -99,9 +99,9 @@ DEFobjCurrIf(prop) /* config settings */ -typedef struct { +struct modConfData_s { EMPTY_STRUCT; -} modConfData_t; +}; static prop_t *pInputName = NULL; /* our inputName currently is always "imuxsock", and this will hold it */ static char *LogName = NULL; /* the log socket name TODO: make configurable! */ diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index b034ebe9..67fa1557 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -76,28 +76,53 @@ DEFobjCurrIf(netstrm) DEFobjCurrIf(errmsg) DEFobjCurrIf(ruleset) +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); + /* Module static data */ static tcpsrv_t *pOurTcpsrv = NULL; /* our TCP server(listener) TODO: change for multiple instances */ static permittedPeers_t *pPermPeersRoot = NULL; /* config settings */ - -typedef struct { - EMPTY_STRUCT; -} modConfData_t; - -static int iTCPSessMax = 200; /* max number of sessions */ -static int iTCPLstnMax = 20; /* max number of sessions */ -static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */ -static int bEmitMsgOnClose = 0; /* emit an informational message on close by remote peer */ -static int iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; /* addtl frame delimiter, e.g. for netscreen, default none */ -static int bDisableLFDelim = 0; /* disbale standard LF delimiter */ -static int bUseFlowControl = 1; /* use flow control, what means indicate ourselfs a "light delayable" */ -static uchar *pszStrmDrvrAuthMode = NULL; /* authentication mode to use */ -static uchar *pszInputName = NULL; /* value for inputname property, NULL is OK and handled by core engine */ -static ruleset_t *pBindRuleset = NULL; /* ruleset to bind listener to (use system default if unspecified) */ - +static struct configSettings_s { + int iTCPSessMax; + int iTCPLstnMax; + int iStrmDrvrMode; + int bEmitMsgOnClose; + int iAddtlFrameDelim; + int bDisableLFDelim; + int bUseFlowControl; + uchar *pszStrmDrvrAuthMode; + uchar *pszInputName; + uchar *pszBindRuleset; +} cs; + +struct instanceConf_s { + uchar *pszBindPort; /* port to bind to */ + uchar *pszBindRuleset; /* name of ruleset to bind to */ + ruleset_t *pBindRuleset; /* ruleset to bind listener to (use system default if unspecified) */ + uchar *pszInputName; /* value for inputname property, NULL is OK and handled by core engine */ + struct instanceConf_s *next; +}; + + +struct modConfData_s { + rsconf_t *pConf; /* our overall config object */ + instanceConf_t *root, *tail; + int iTCPSessMax; /* max number of sessions */ + int iTCPLstnMax; /* max number of sessions */ + int iStrmDrvrMode; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */ + int bEmitMsgOnClose; /* emit an informational message on close by remote peer */ + int iAddtlFrameDelim; /* addtl frame delimiter, e.g. for netscreen, default none */ + int bDisableLFDelim; /* disable standard LF delimiter */ + int bUseFlowControl; /* use flow control, what means indicate ourselfs a "light delayable" */ + uchar *pszStrmDrvrAuthMode; /* authentication mode to use */ +}; + +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 */ + +#include "im-helper.h" /* must be included AFTER the type definitions! */ /* callbacks */ /* this shall go into a specific ACL module! */ @@ -170,48 +195,70 @@ finalize_it: } -/* accept a new ruleset to bind. Checks if it exists and complains, if not */ -static rsRetVal setRuleset(void __attribute__((unused)) *pVal, uchar *pszName) +/* 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. + * rgerhards, 2011-05-04 + */ +static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) { - ruleset_t *pRuleset; - rsRetVal localRet; + instanceConf_t *inst; DEFiRet; - localRet = ruleset.GetRuleset(ourConf, &pRuleset, pszName); - if(localRet == RS_RET_NOT_FOUND) { - errmsg.LogError(0, RS_RET_RULESET_NOT_FOUND, "error: ruleset '%s' not found - ignored", pszName); + CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + + CHKmalloc(inst->pszBindPort = ustrdup((pNewVal == NULL || *pNewVal == '\0') + ? (uchar*) "10514" : pNewVal)); + if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) { + inst->pszBindRuleset = NULL; + } else { + CHKmalloc(inst->pszBindRuleset = ustrdup(cs.pszBindRuleset)); + } + if((cs.pszInputName == NULL) || (cs.pszInputName[0] == '\0')) { + inst->pszInputName = NULL; + } else { + CHKmalloc(inst->pszInputName = ustrdup(cs.pszInputName)); + } + 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; } - CHKiRet(localRet); - pBindRuleset = pRuleset; - DBGPRINTF("imtcp current bind ruleset %p: '%s'\n", pRuleset, pszName); finalize_it: - free(pszName); /* no longer needed */ + free(pNewVal); RETiRet; } -static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVal) +static rsRetVal +addListner(modConfData_t *modConf, instanceConf_t *inst) { DEFiRet; if(pOurTcpsrv == NULL) { CHKiRet(tcpsrv.Construct(&pOurTcpsrv)); - CHKiRet(tcpsrv.SetSessMax(pOurTcpsrv, iTCPSessMax)); - CHKiRet(tcpsrv.SetLstnMax(pOurTcpsrv, iTCPLstnMax)); + /* callbacks */ CHKiRet(tcpsrv.SetCBIsPermittedHost(pOurTcpsrv, isPermittedHost)); CHKiRet(tcpsrv.SetCBRcvData(pOurTcpsrv, doRcvData)); CHKiRet(tcpsrv.SetCBOpenLstnSocks(pOurTcpsrv, doOpenLstnSocks)); CHKiRet(tcpsrv.SetCBOnRegularClose(pOurTcpsrv, onRegularClose)); CHKiRet(tcpsrv.SetCBOnErrClose(pOurTcpsrv, onErrClose)); - CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, iStrmDrvrMode)); - CHKiRet(tcpsrv.SetUseFlowControl(pOurTcpsrv, bUseFlowControl)); - CHKiRet(tcpsrv.SetAddtlFrameDelim(pOurTcpsrv, iAddtlFrameDelim)); - CHKiRet(tcpsrv.SetbDisableLFDelim(pOurTcpsrv, bDisableLFDelim)); - CHKiRet(tcpsrv.SetNotificationOnRemoteClose(pOurTcpsrv, bEmitMsgOnClose)); + /* params */ + CHKiRet(tcpsrv.SetSessMax(pOurTcpsrv, modConf->iTCPSessMax)); + CHKiRet(tcpsrv.SetLstnMax(pOurTcpsrv, modConf->iTCPLstnMax)); + CHKiRet(tcpsrv.SetDrvrMode(pOurTcpsrv, modConf->iStrmDrvrMode)); + CHKiRet(tcpsrv.SetUseFlowControl(pOurTcpsrv, modConf->bUseFlowControl)); + CHKiRet(tcpsrv.SetAddtlFrameDelim(pOurTcpsrv, modConf->iAddtlFrameDelim)); + CHKiRet(tcpsrv.SetbDisableLFDelim(pOurTcpsrv, modConf->bDisableLFDelim)); + CHKiRet(tcpsrv.SetNotificationOnRemoteClose(pOurTcpsrv, modConf->bEmitMsgOnClose)); /* now set optional params, but only if they were actually configured */ - if(pszStrmDrvrAuthMode != NULL) { - CHKiRet(tcpsrv.SetDrvrAuthMode(pOurTcpsrv, pszStrmDrvrAuthMode)); + if(modConf->pszStrmDrvrAuthMode != NULL) { + CHKiRet(tcpsrv.SetDrvrAuthMode(pOurTcpsrv, modConf->pszStrmDrvrAuthMode)); } if(pPermPeersRoot != NULL) { CHKiRet(tcpsrv.SetDrvrPermPeers(pOurTcpsrv, pPermPeersRoot)); @@ -219,16 +266,14 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa } /* initialized, now add socket and listener params */ - CHKiRet(tcpsrv.SetRuleset(pOurTcpsrv, pBindRuleset)); - CHKiRet(tcpsrv.SetInputName(pOurTcpsrv, pszInputName == NULL ? - UCHAR_CONSTANT("imtcp") : pszInputName)); - tcpsrv.configureTCPListen(pOurTcpsrv, pNewVal); + CHKiRet(tcpsrv.SetRuleset(pOurTcpsrv, inst->pBindRuleset)); + CHKiRet(tcpsrv.SetInputName(pOurTcpsrv, inst->pszInputName == NULL ? + UCHAR_CONSTANT("imtcp") : inst->pszInputName)); + tcpsrv.configureTCPListen(pOurTcpsrv, inst->pszBindPort); finalize_it: if(iRet != RS_RET_OK) { - errmsg.LogError(0, NO_ERRCODE, "error %d trying to add listener", iRet); - if(pOurTcpsrv != NULL) - tcpsrv.Destruct(&pOurTcpsrv); + errmsg.LogError(0, NO_ERRCODE, "imtcp: error %d trying to add listener", iRet); } RETiRet; } @@ -236,21 +281,64 @@ finalize_it: BEGINbeginCnfLoad CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + /* init legacy config variables */ + cs.pszStrmDrvrAuthMode = NULL; + resetConfigVariables(NULL, NULL); /* dummy parameters just to fulfill interface def */ ENDbeginCnfLoad 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->iAddtlFrameDelim = cs.iAddtlFrameDelim; + pModConf->bDisableLFDelim = cs.bDisableLFDelim; + pModConf->bUseFlowControl = cs.bUseFlowControl; + if((cs.pszStrmDrvrAuthMode == NULL) || (cs.pszStrmDrvrAuthMode[0] == '\0')) { + loadModConf->pszStrmDrvrAuthMode = NULL; + free(cs.pszStrmDrvrAuthMode); + } else { + loadModConf->pszStrmDrvrAuthMode = cs.pszStrmDrvrAuthMode; + } + cs.pszStrmDrvrAuthMode = NULL; + + loadModConf = NULL; /* done loading */ ENDendCnfLoad +/* function to generate error message if framework does not find requested ruleset */ +static inline void +std_checkRuleset_genErrMsg(__attribute__((unused)) modConfData_t *modConf, instanceConf_t *inst) +{ + errmsg.LogError(0, NO_ERRCODE, "imtcp: ruleset '%s' for port %s not found - " + "using default ruleset instead", inst->pszBindRuleset, + inst->pszBindPort); +} + BEGINcheckCnf + instanceConf_t *inst; CODESTARTcheckCnf + for(inst = pModConf->root ; inst != NULL ; inst = inst->next) { + std_checkRuleset(pModConf, inst); + } ENDcheckCnf BEGINactivateCnf + instanceConf_t *inst; CODESTARTactivateCnf + runModConf = pModConf; + for(inst = runModConf->root ; inst != NULL ; inst = inst->next) { + addListner(pModConf, inst); + } + if(pOurTcpsrv == NULL) + ABORT_FINALIZE(RS_RET_NO_RUN); +finalize_it: ENDactivateCnf @@ -274,11 +362,7 @@ ENDrunInput /* initialize and return if will run or not */ BEGINwillRun CODESTARTwillRun - /* first apply some config settings */ net.PrintAllowedSenders(2); /* TCP */ - if(pOurTcpsrv == NULL) - ABORT_FINALIZE(RS_RET_NO_RUN); -finalize_it: ENDwillRun @@ -318,17 +402,17 @@ ENDmodExit static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { - iTCPSessMax = 200; - iTCPLstnMax = 20; - iStrmDrvrMode = 0; - bUseFlowControl = 0; - bEmitMsgOnClose = 0; - iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; - bDisableLFDelim = 0; - free(pszInputName); - pszInputName = NULL; - free(pszStrmDrvrAuthMode); - pszStrmDrvrAuthMode = NULL; + cs.iTCPSessMax = 200; + cs.iTCPLstnMax = 20; + cs.iStrmDrvrMode = 0; + cs.bUseFlowControl = 0; + cs.bEmitMsgOnClose = 0; + cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; + cs.bDisableLFDelim = 0; + free(cs.pszInputName); + cs.pszInputName = NULL; + free(cs.pszStrmDrvrAuthMode); + cs.pszStrmDrvrAuthMode = NULL; return RS_RET_OK; } @@ -356,31 +440,31 @@ CODEmodInit_QueryRegCFSLineHdlr /* register config file handlers */ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverrun"), 0, eCmdHdlrGetWord, - addTCPListener, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + addInstance, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpmaxsessions"), 0, eCmdHdlrInt, - NULL, &iTCPSessMax, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.iTCPSessMax, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpmaxlisteners"), 0, eCmdHdlrInt, - NULL, &iTCPLstnMax, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpservernotifyonconnectionclose"), 0, - eCmdHdlrBinary, NULL, &bEmitMsgOnClose, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdrivermode"), 0, - eCmdHdlrInt, NULL, &iStrmDrvrMode, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdriverauthmode"), 0, - eCmdHdlrGetWord, NULL, &pszStrmDrvrAuthMode, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdriverpermittedpeer"), 0, - eCmdHdlrGetWord, setPermittedPeer, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.iTCPLstnMax, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpservernotifyonconnectionclose"), 0, eCmdHdlrBinary, + NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdrivermode"), 0, eCmdHdlrInt, + NULL, &cs.iStrmDrvrMode, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdriverauthmode"), 0, eCmdHdlrGetWord, + NULL, &cs.pszStrmDrvrAuthMode, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverstreamdriverpermittedpeer"), 0, eCmdHdlrGetWord, + setPermittedPeer, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserveraddtlframedelimiter"), 0, eCmdHdlrInt, - NULL, &iAddtlFrameDelim, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.iAddtlFrameDelim, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverdisablelfdelimiter"), 0, eCmdHdlrBinary, - NULL, &bDisableLFDelim, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverinputname"), 0, - eCmdHdlrGetWord, NULL, &pszInputName, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverbindruleset"), 0, - eCmdHdlrGetWord, setRuleset, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpflowcontrol"), 0, - eCmdHdlrBinary, NULL, &bUseFlowControl, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.bDisableLFDelim, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverinputname"), 0, eCmdHdlrGetWord, + NULL, &cs.pszInputName, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverbindruleset"), 0, eCmdHdlrGetWord, + NULL, &cs.pszBindRuleset, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpflowcontrol"), 0, eCmdHdlrBinary, + NULL, &cs.bUseFlowControl, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("resetconfigvariables"), 1, eCmdHdlrCustomHandler, - resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); ENDmodInit diff --git a/plugins/imtemplate/imtemplate.c b/plugins/imtemplate/imtemplate.c index 1f60bef7..0cc9451e 100644 --- a/plugins/imtemplate/imtemplate.c +++ b/plugins/imtemplate/imtemplate.c @@ -95,10 +95,9 @@ DEF_IMOD_STATIC_DATA /* must be present, starts static data */ /* static int imtemplateWhateverVar = 0; */ /* config settings */ -typedef struct { +struct modConfData_s { EMPTY_STRUCT; -} modConfData_t; - +}; BEGINbeginCnfLoad diff --git a/plugins/imttcp/imttcp.c b/plugins/imttcp/imttcp.c index 47bd071e..e62360bd 100644 --- a/plugins/imttcp/imttcp.c +++ b/plugins/imttcp/imttcp.c @@ -135,9 +135,9 @@ DEFobjCurrIf(ruleset) /* config settings */ -typedef struct { +struct modConfData_s { EMPTY_STRUCT; -} modConfData_t; +}; typedef struct configSettings_s { int bEmitMsgOnClose; /* emit an informational message on close by remote peer */ diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index f2a5811d..e0cb3f34 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -93,27 +93,26 @@ static struct configSettings_s { int iTimeRequery; /* how often is time to be queried inside tight recv loop? 0=always */ } cs; -/* config settings */ - -typedef struct instanceConf_s { +struct instanceConf_s { uchar *pszBindAddr; /* IP to bind socket to */ uchar *pszBindPort; /* Port to bind socket to */ uchar *pszBindRuleset; /* name of ruleset to bind to */ ruleset_t *pBindRuleset; /* ruleset to bind listener to (use system default if unspecified) */ struct instanceConf_s *next; -} instanceConf_t; +}; -typedef struct { +struct modConfData_s { rsconf_t *pConf; /* our overall config object */ instanceConf_t *root, *tail; uchar *pszSchedPolicy; /* scheduling policy string */ 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 */ -} modConfData_t; +}; 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 */ +#include "im-helper.h" /* must be included AFTER the type definitions! */ @@ -126,6 +125,7 @@ static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) { instanceConf_t *inst; DEFiRet; + CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); CHKmalloc(inst->pszBindPort = ustrdup((pNewVal == NULL || *pNewVal == '\0') ? (uchar*) "514" : pNewVal)); @@ -224,31 +224,13 @@ finalize_it: } -/* Check provided ruleset name in conf and store a direct - * pointer to it, if valid. - */ -static inline rsRetVal -checkRuleset(modConfData_t *modConf, instanceConf_t *inst) +static inline void +std_checkRuleset_genErrMsg(__attribute__((unused)) modConfData_t *modConf, instanceConf_t *inst) { - ruleset_t *pRuleset; - rsRetVal localRet; - DEFiRet; - - if(inst->pszBindRuleset == NULL) - FINALIZE; - - localRet = ruleset.GetRuleset(modConf->pConf, &pRuleset, inst->pszBindRuleset); - if(localRet == RS_RET_NOT_FOUND) { - errmsg.LogError(0, NO_ERRCODE, "imudp: ruleset '%s' for %s:%s not found - " - "using default ruleset instead", inst->pszBindRuleset, - inst->pszBindAddr == NULL ? "*" : inst->pszBindAddr, - inst->pszBindPort); - } - CHKiRet(localRet); - inst->pBindRuleset = pRuleset; - -finalize_it: - RETiRet; + errmsg.LogError(0, NO_ERRCODE, "imudp: ruleset '%s' for %s:%s not found - " + "using default ruleset instead", inst->pszBindRuleset, + inst->pszBindAddr == NULL ? "*" : (char*) inst->pszBindAddr, + inst->pszBindPort); } @@ -670,7 +652,7 @@ BEGINcheckCnf CODESTARTcheckCnf checkSchedParam(pModConf); /* this can not cause fatal errors */ for(inst = pModConf->root ; inst != NULL ; inst = inst->next) { - checkRuleset(pModConf, inst); + std_checkRuleset(pModConf, inst); } ENDcheckCnf diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 91f273c1..21550264 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -88,9 +88,9 @@ DEFobjCurrIf(datetime) DEFobjCurrIf(statsobj) -typedef struct { +struct modConfData_s { EMPTY_STRUCT; -} modConfData_t; +}; statsobj_t *modStats; STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit) diff --git a/runtime/Makefile.am b/runtime/Makefile.am index cfcfdc2c..a107e21a 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -13,6 +13,7 @@ librsyslog_la_SOURCES = \ batch.h \ syslogd-types.h \ module-template.h \ + im-helper.h \ obj-types.h \ nsd.h \ glbl.h \ diff --git a/runtime/im-helper.h b/runtime/im-helper.h new file mode 100644 index 00000000..6bbd6d70 --- /dev/null +++ b/runtime/im-helper.h @@ -0,0 +1,66 @@ +/* im-helper.h + * This file contains helper constructs that save time writing input modules. It + * assumes some common field names and plumbing. It is intended to be used together + * with module-template.h + * + * File begun on 2011-05-04 by RGerhards + * + * Copyright 2011 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library 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. + * + * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ +#ifndef IM_HELPER_H_INCLUDED +#define IM_HELPER_H_INCLUDED 1 + + +/* The following function provides a complete implementation to check a + * ruleset and set the actual ruleset pointer. The macro assumes that + * standard field names are used. A functon std_checkRuleset_genErrMsg() + * must be defined to generate error messages in case the ruleset cannot + * be found. + */ +static inline void std_checkRuleset_genErrMsg(modConfData_t *modConf, instanceConf_t *inst); +static inline rsRetVal +std_checkRuleset(modConfData_t *modConf, instanceConf_t *inst) +{ + ruleset_t *pRuleset; + rsRetVal localRet; + DEFiRet; + + inst->pBindRuleset = NULL; /* assume default ruleset */ + + 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) { + std_checkRuleset_genErrMsg(modConf, inst); + } + CHKiRet(localRet); + inst->pBindRuleset = pRuleset; + +finalize_it: + RETiRet; +} + +#endif /* #ifndef IM_HELPER_H_INCLUDED */ + +/* vim:set ai: + */ diff --git a/runtime/module-template.h b/runtime/module-template.h index 38cda4ba..965d48d0 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -584,7 +584,6 @@ finalize_it:\ #define CODEmodInit_QueryRegCFSLineHdlr \ CHKiRet(pHostQueryEtryPt((uchar*)"regCfSysLineHdlr", &omsdRegCFSLineHdlr)); -#endif /* #ifndef MODULE_TEMPLATE_H_INCLUDED */ /* modExit() * This is the counterpart to modInit(). It destroys a module and makes it ready for @@ -853,5 +852,7 @@ static rsRetVal GetStrgenName(uchar **ppSz)\ } +#endif /* #ifndef MODULE_TEMPLATE_H_INCLUDED */ + /* vim:set ai: */ diff --git a/runtime/typedefs.h b/runtime/typedefs.h index 1c8e93ce..11061e14 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -90,6 +90,8 @@ typedef struct rsconf_s rsconf_t; typedef struct cfgmodules_s cfgmodules_t; typedef struct cfgmodules_etry_s cfgmodules_etry_t; typedef struct outchannels_s outchannels_t; +typedef struct modConfData_s modConfData_t; +typedef struct instanceConf_s instanceConf_t; typedef rsRetVal (*prsf_t)(struct vmstk_s*, int); /* pointer to a RainerScript function */ typedef uint64 qDeqID; /* queue Dequeue order ID. 32 bits is considered dangerously few */ -- cgit v1.2.3 From b056c258d7bab528034ec8c8749cdcf0d0102268 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 6 May 2011 08:43:15 +0200 Subject: step: generalized new config interface for all module types --- plugins/im3195/im3195.c | 2 ++ plugins/imdiag/imdiag.c | 2 ++ plugins/imgssapi/imgssapi.c | 2 ++ plugins/immark/immark.c | 1 + plugins/imtcp/imtcp.c | 1 + plugins/imtemplate/imtemplate.c | 2 ++ plugins/imudp/imudp.c | 1 + runtime/module-template.h | 9 ++++++++- runtime/modules.c | 44 ++++++++++++++++++++++++++++++----------- runtime/modules.h | 15 ++++++++------ runtime/rsconf.c | 35 +++++++++++++++++--------------- 11 files changed, 79 insertions(+), 35 deletions(-) diff --git a/plugins/im3195/im3195.c b/plugins/im3195/im3195.c index 1daad3dd..fd642aaa 100644 --- a/plugins/im3195/im3195.c +++ b/plugins/im3195/im3195.c @@ -94,6 +94,7 @@ void OnReceive(srAPIObj __attribute__((unused)) *pMyAPI, srSLMGObj* pSLMG) } +#if 0 BEGINbeginCnfLoad CODESTARTbeginCnfLoad ENDbeginCnfLoad @@ -117,6 +118,7 @@ ENDactivateCnf BEGINfreeCnf CODESTARTfreeCnf ENDfreeCnf +#endif BEGINrunInput diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c index 57fa08e5..770b3437 100644 --- a/plugins/imdiag/imdiag.c +++ b/plugins/imdiag/imdiag.c @@ -388,6 +388,7 @@ finalize_it: } +#if 0 /* can be used to integrate into new config system */ BEGINbeginCnfLoad CODESTARTbeginCnfLoad ENDbeginCnfLoad @@ -411,6 +412,7 @@ ENDactivateCnf BEGINfreeCnf CODESTARTfreeCnf ENDfreeCnf +#endif /* This function is called to gather input. */ diff --git a/plugins/imgssapi/imgssapi.c b/plugins/imgssapi/imgssapi.c index 5f69a0b6..868fca75 100644 --- a/plugins/imgssapi/imgssapi.c +++ b/plugins/imgssapi/imgssapi.c @@ -645,6 +645,7 @@ TCPSessGSSDeinit(void) } +#if 0 /* can be used to integrate into new config system */ BEGINbeginCnfLoad CODESTARTbeginCnfLoad ENDbeginCnfLoad @@ -668,6 +669,7 @@ ENDactivateCnf BEGINfreeCnf CODESTARTfreeCnf ENDfreeCnf +#endif /* This function is called to gather input. */ diff --git a/plugins/immark/immark.c b/plugins/immark/immark.c index a3c0981b..c7d6b554 100644 --- a/plugins/immark/immark.c +++ b/plugins/immark/immark.c @@ -148,6 +148,7 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index 67fa1557..75987aed 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -421,6 +421,7 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt diff --git a/plugins/imtemplate/imtemplate.c b/plugins/imtemplate/imtemplate.c index 0cc9451e..f2b4752d 100644 --- a/plugins/imtemplate/imtemplate.c +++ b/plugins/imtemplate/imtemplate.c @@ -100,6 +100,7 @@ struct modConfData_s { }; +#if 0 /* can be used to integrate into new config system */ BEGINbeginCnfLoad CODESTARTbeginCnfLoad ENDbeginCnfLoad @@ -123,6 +124,7 @@ ENDactivateCnf BEGINfreeCnf CODESTARTfreeCnf ENDfreeCnf +#endif /* You may add any functions that you feel are useful for your needs. No specific restrictions diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index e0cb3f34..ee5c39e5 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -744,6 +744,7 @@ ENDisCompatibleWithFeature BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt diff --git a/runtime/module-template.h b/runtime/module-template.h index 965d48d0..f44cb54a 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -459,7 +459,14 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\ *pEtryPoint = willRun;\ } else if(!strcmp((char*) name, "afterRun")) {\ *pEtryPoint = afterRun;\ - } else if(!strcmp((char*) name, "beginCnfLoad")) {\ + } + + +/* the following block is to be added for modules that support the v2 + * config system. + */ +#define CODEqueryEtryPt_STD_CONF2_QUERIES \ + else if(!strcmp((char*) name, "beginCnfLoad")) {\ *pEtryPoint = beginCnfLoad;\ } else if(!strcmp((char*) name, "endCnfLoad")) {\ *pEtryPoint = endCnfLoad;\ diff --git a/runtime/modules.c b/runtime/modules.c index e2e12a3b..bf944dba 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -371,8 +371,9 @@ addModToCnfList(modInfo_t *pThis) pNew->next = NULL; pNew->pMod = pThis; - if(pThis->eType == eMOD_IN) { - CHKiRet(pThis->mod.im.beginCnfLoad(&pNew->modCnf, loadConf)); +dbgprintf("XXXX: beginCnfLoad %p\n", pThis->beginCnfLoad); + if(pThis->beginCnfLoad != NULL) { + CHKiRet(pThis->beginCnfLoad(&pNew->modCnf, loadConf)); } if(pLast == NULL) { @@ -424,8 +425,10 @@ static cfgmodules_etry_t node = node->next; } - while(node != NULL && node->pMod->eType != rqtdType) { - node = node->next; /* warning: do ... while() */ + if(rqtdType != eMOD_ANY) { /* if any, we already have the right one! */ + while(node != NULL && node->pMod->eType != rqtdType) { + node = node->next; /* warning: do ... while() */ + } } return node; @@ -518,14 +521,21 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ else if(localRet != RS_RET_OK) ABORT_FINALIZE(localRet); + /* optional calls for new config system */ + localRet = (*pNew->modQueryEtryPt)((uchar*)"beginCnfLoad", &pNew->beginCnfLoad); + if(localRet == RS_RET_OK) { + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"endCnfLoad", &pNew->endCnfLoad)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeCnf", &pNew->freeCnf)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"checkCnf", &pNew->checkCnf)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"activateCnf", &pNew->activateCnf)); + } else if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { + pNew->beginCnfLoad = NULL; /* flag as non-present */ + } else { + ABORT_FINALIZE(localRet); + } /* ... and now the module-specific interfaces */ switch(pNew->eType) { case eMOD_IN: - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"beginCnfLoad", &pNew->mod.im.beginCnfLoad)); - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"endCnfLoad", &pNew->mod.im.endCnfLoad)); - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeCnf", &pNew->mod.im.freeCnf)); - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"checkCnf", &pNew->mod.im.checkCnf)); - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"activateCnf", &pNew->mod.im.activateCnf)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"runInput", &pNew->mod.im.runInput)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"willRun", &pNew->mod.im.willRun)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"afterRun", &pNew->mod.im.afterRun)); @@ -602,6 +612,10 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet(strgen.SetModPtr(pStrgen, pNew)); CHKiRet(strgen.ConstructFinalize(pStrgen)); break; + case eMOD_ANY: /* this is mostly to keep the compiler happy! */ + DBGPRINTF("PROGRAM ERROR: eMOD_ANY set as module type\n"); + assert(0); + break; } pNew->pszName = (uchar*) strdup((char*)name); /* we do not care if strdup() fails, we can accept that */ @@ -681,12 +695,19 @@ static void modPrintList(void) case eMOD_STRGEN: dbgprintf("strgen"); break; + case eMOD_ANY: /* this is mostly to keep the compiler happy! */ + DBGPRINTF("PROGRAM ERROR: eMOD_ANY set as module type\n"); + assert(0); + break; } dbgprintf(" module.\n"); dbgprintf("Entry points:\n"); dbgprintf("\tqueryEtryPt: 0x%lx\n", (unsigned long) pMod->modQueryEtryPt); 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("\tendCnfLoad: 0x%lx\n", (unsigned long) pMod->endCnfLoad); + dbgprintf("\tfreeCnf: 0x%lx\n", (unsigned long) pMod->freeCnf); switch(pMod->eType) { case eMOD_OUT: dbgprintf("Output Module Entry Points:\n"); @@ -705,9 +726,6 @@ static void modPrintList(void) break; case eMOD_IN: dbgprintf("Input Module Entry Points\n"); - dbgprintf("\tbeginCnfLoad: 0x%lx\n", (unsigned long) pMod->mod.im.beginCnfLoad); - dbgprintf("\tendCnfLoad: 0x%lx\n", (unsigned long) pMod->mod.im.endCnfLoad); - dbgprintf("\tfreeCnf: 0x%lx\n", (unsigned long) pMod->mod.im.freeCnf); dbgprintf("\trunInput: 0x%lx\n", (unsigned long) pMod->mod.im.runInput); dbgprintf("\twillRun: 0x%lx\n", (unsigned long) pMod->mod.im.willRun); dbgprintf("\tafterRun: 0x%lx\n", (unsigned long) pMod->mod.im.afterRun); @@ -722,6 +740,8 @@ static void modPrintList(void) dbgprintf("Strgen Module Entry Points\n"); dbgprintf("\tstrgen: 0x%lx\n", (unsigned long) pMod->mod.sm.strgen); break; + case eMOD_ANY: /* this is mostly to keep the compiler happy! */ + break; } dbgprintf("\n"); pMod = GetNxt(pMod); /* done, go next */ diff --git a/runtime/modules.h b/runtime/modules.h index 45fffdad..e3af1ad9 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -57,7 +57,8 @@ typedef enum eModType_ { eMOD_OUT = 1, /* output module */ eMOD_LIB = 2, /* library module */ eMOD_PARSER = 3,/* parser module */ - eMOD_STRGEN = 4 /* strgen module */ + eMOD_STRGEN = 4,/* strgen module */ + eMOD_ANY = 5 /* meta-name for "any type of module" -- to be used in function calls */ } eModType_t; @@ -110,17 +111,19 @@ struct modInfo_s { rsRetVal (*modExit)(void); /* called before termination or module unload */ rsRetVal (*modGetID)(void **); /* get its unique ID from module */ rsRetVal (*doHUP)(void *); /* non-restart type HUP handler */ + /* v2 config system specific */ + rsRetVal (*beginCnfLoad)(void*newCnf, rsconf_t *pConf); + rsRetVal (*endCnfLoad)(void*Cnf); + rsRetVal (*checkCnf)(void*Cnf); + rsRetVal (*activateCnf)(void*Cnf); /* make provided config the running conf */ + rsRetVal (*freeCnf)(void*Cnf); + /* end v2 config system specific */ /* below: create an instance of this module. Most importantly the module * can allocate instance memory in this call. */ rsRetVal (*createInstance)(); union { struct {/* data for input modules */ - rsRetVal (*beginCnfLoad)(void*newCnf, rsconf_t *pConf); - rsRetVal (*endCnfLoad)(void*Cnf); - rsRetVal (*checkCnf)(void*Cnf); - rsRetVal (*activateCnf)(void*Cnf); /* make provided config the running conf */ - rsRetVal (*freeCnf)(void*Cnf); /* 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 */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 8fc30cf3..92c17b5c 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -301,10 +301,11 @@ tellInputsConfigLoadDone(void) cfgmodules_etry_t *node; BEGINfunc - DBGPRINTF("telling inputs that config load for %p is done\n", loadConf); - node = module.GetNxtCnfType(loadConf, NULL, eMOD_IN); + DBGPRINTF("telling modules that config load for %p is done\n", loadConf); + node = module.GetNxtCnfType(loadConf, NULL, eMOD_ANY); while(node != NULL) { - node->pMod->mod.im.endCnfLoad(node->modCnf); + if(node->pMod->beginCnfLoad != NULL) + node->pMod->endCnfLoad(node->modCnf); node = module.GetNxtCnfType(runConf, node, eMOD_IN); } @@ -321,16 +322,18 @@ tellInputsCheckConfig(void) rsRetVal localRet; BEGINfunc - DBGPRINTF("telling inputs to check config %p\n", loadConf); - node = module.GetNxtCnfType(loadConf, NULL, eMOD_IN); + DBGPRINTF("telling modules to check config %p\n", loadConf); + node = module.GetNxtCnfType(loadConf, NULL, eMOD_ANY); while(node != NULL) { - localRet = node->pMod->mod.im.checkCnf(node->modCnf); - DBGPRINTF("module %s tells us config can %sbe activated\n", - node->pMod->pszName, (localRet == RS_RET_OK) ? "" : "NOT "); - if(localRet == RS_RET_OK) { - node->canActivate = 1; - } else { - node->canActivate = 0; + if(node->pMod->beginCnfLoad != NULL) { + localRet = node->pMod->checkCnf(node->modCnf); + DBGPRINTF("module %s tells us config can %sbe activated\n", + node->pMod->pszName, (localRet == RS_RET_OK) ? "" : "NOT "); + if(localRet == RS_RET_OK) { + node->canActivate = 1; + } else { + node->canActivate = 0; + } } node = module.GetNxtCnfType(runConf, node, eMOD_IN); } @@ -348,13 +351,13 @@ tellInputsActivateConfig(void) rsRetVal localRet; BEGINfunc - DBGPRINTF("telling inputs to activate config %p\n", runConf); - node = module.GetNxtCnfType(runConf, NULL, eMOD_IN); + DBGPRINTF("telling modules to activate config %p\n", runConf); + node = module.GetNxtCnfType(runConf, NULL, eMOD_ANY); while(node != NULL) { - if(node->canActivate) { + if(node->pMod->beginCnfLoad != NULL && node->canActivate) { DBGPRINTF("activating config %p for module %s\n", runConf, node->pMod->pszName); - localRet = node->pMod->mod.im.activateCnf(node->modCnf); + localRet = node->pMod->activateCnf(node->modCnf); if(localRet != RS_RET_OK) { errmsg.LogError(0, localRet, "activation of module %s failed", node->pMod->pszName); -- cgit v1.2.3 From ff2bb192f2c566f189a9d104d83d7a70c7888774 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 6 May 2011 10:06:32 +0200 Subject: step: conf interface now natively supports priv drop --- doc/design.tex | 74 +++++++++++++++++++++++++++++++++++++++++++++-- plugins/imtcp/imtcp.c | 12 ++++++-- plugins/imudp/imudp.c | 10 +++++-- runtime/module-template.h | 37 +++++++++++++++++++++--- runtime/modules.c | 11 +++++-- runtime/modules.h | 1 + runtime/rsconf.c | 50 ++++++++++++++++++++++++++------ 7 files changed, 174 insertions(+), 21 deletions(-) diff --git a/doc/design.tex b/doc/design.tex index a3ec8f45..1def3fb7 100644 --- a/doc/design.tex +++ b/doc/design.tex @@ -811,10 +811,80 @@ b) we push the failed message back to the main queue, but with an indication that it failed in an action. This is harder to implement and most importantly harder to understand/configure, but more flexible +\section{Configuration System} +The configration system found in all versions up to v5 is based on sysklogd's +legacy. It does not have any clear distinction between config load and +activation. Starting with v6, a new config system is build. That new system +offers the necessary distinction. In the long term, the configuration language +will be enhanced towards the more flexible and easy to use RainerScript idea. + +\section{Plugin Interface} +This section describes some aspects of the plugin interface. +\subsection{Configuration Related} +To support the new v2 config system, plugins need to publish a number of entry +points that will be called by the rsyslog configuration section at various +stages of the configration load, activation and deactivation process. This list +may be extended as the configuration interface evolves. + +Plugins must not necessarily implement support for the v2 config system. If +they do, the ``beginCnfLoad'' entry point serves as a flag telling that support +is available. In that case, all other entry points need to be defined as well. +If a module does not support the v2 config system, it can still be run, but be +configured only via the legacy config system. Note that with the old system +there are also problems with droping privileges. So a legacy module may not +work correctly if privileges are dropped. + +The following entry points are available: +\begin{enumerate} + \item \emph{beginCnfLoad} -- called when a new config load begins. Only one +config load can be active at one time (no concurrent loads). + \item \emph{endCnfLoad} -- called when config load ends. This gives the module +a chance to do final changes and some cleanup. + \item \emph{checkCnf} -- called by the framework to verify a configuration. + \item \emph{activateCnfPrePrivDrop} -- called by the framework to activate a +configuration before privileges are dropped. This is an optional entry point +that shall only be implemented by plugins that need the do some processing +before rsyslog drops privileges. Processing inside this entry point should be +limited to what is absolutely necessary. The main activation work should be +done in activateCnf() as usual. + \item \emph{activateCnf} -- called by the framework to activate a +configuration. +\item \emph{freeCnf} -- called by the framework to free +(deallocate) a configuration. +\end{enumerate} + +In the current implementation, entry points are sequentially called as given +above. However, this will change. It is guaranteed that +\begin{itemize} + \item beginCnfLoad() will be followed by a matching endCnfLoad() and there +will be no new call to beginCnfLoad() before endCnfLoad() has been called. This +means no nested config load needs to be supported, + \item checkCnf() may be called at any time, even during a config load phase. +However, the config to check is a fully loaded one. + \item activateCnfPrePrivDrop(), if provided, will always be called before +activateCnf() is called. No other config-related calls will be made in between. +\end{itemize} + +\subsubsection{Output Modules} +The v1 config load system for output modules seems to provide all functionality +necessary to support the v2 system as well. As such, we currently do not +require output modules to implement the new calls to be fully supported by the +v2 system. + \section{Network Stream Subsystem} -The idea of network streams was introduced when we implemented RFC5425 (syslog over TLS) in 2008. The core idea is to encapsulate all stream-oriented network data transfer into a single transport layer and make the upper layers independent of actual transport being used. This is in line with the traditional layer approaches in communication systems. +The idea of network streams was introduced when we implemented RFC5425 (syslog +over TLS) in 2008. The core idea is to encapsulate all stream-oriented network +data transfer into a single transport layer and make the upper layers +independent of actual transport being used. This is in line with the traditional +layer approaches in communication systems. + +Under this system, the upper layer provides plugins to send and receive streams +of syslog data. Framing is provided by the upper layer. The upper layer itself +is integrated in input and output plugins, which then are used to provide +application-level syslog message objects to and from the rsyslog core. To these +upper layers, the netstream layer provides reliable and sequenced message +delivery with much of the same semantics as a usual TCP stream. -Under this system, the upper layer provides plugins to send and receive streams of syslog data. Framing is provided by the upper layer. The upper layer itself is integrated in input and output plugins, which then are used to provide application-level syslog message objects to and from the rsyslog core. To these upper layers, the netstream layer provides reliable and sequenced message delivery with much of the same semantics as a usual TCP stream. \begin{figure} \begin{center} diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index 75987aed..3978ff5d 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -266,6 +266,7 @@ addListner(modConfData_t *modConf, instanceConf_t *inst) } /* initialized, now add socket and listener params */ + DBGPRINTF("imtcp: trying to add port *:%s\n", inst->pszBindPort); CHKiRet(tcpsrv.SetRuleset(pOurTcpsrv, inst->pBindRuleset)); CHKiRet(tcpsrv.SetInputName(pOurTcpsrv, inst->pszInputName == NULL ? UCHAR_CONSTANT("imtcp") : inst->pszInputName)); @@ -329,9 +330,9 @@ CODESTARTcheckCnf ENDcheckCnf -BEGINactivateCnf +BEGINactivateCnfPrePrivDrop instanceConf_t *inst; -CODESTARTactivateCnf +CODESTARTactivateCnfPrePrivDrop runModConf = pModConf; for(inst = runModConf->root ; inst != NULL ; inst = inst->next) { addListner(pModConf, inst); @@ -339,6 +340,12 @@ CODESTARTactivateCnf if(pOurTcpsrv == NULL) ABORT_FINALIZE(RS_RET_NO_RUN); finalize_it: +ENDactivateCnfPrePrivDrop + + +BEGINactivateCnf +CODESTARTactivateCnf + /* sorry, nothing to do here... */ ENDactivateCnf @@ -422,6 +429,7 @@ BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index ee5c39e5..0df80e87 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -657,9 +657,9 @@ CODESTARTcheckCnf ENDcheckCnf -BEGINactivateCnf +BEGINactivateCnfPrePrivDrop instanceConf_t *inst; -CODESTARTactivateCnf +CODESTARTactivateCnfPrePrivDrop runModConf = pModConf; for(inst = runModConf->root ; inst != NULL ; inst = inst->next) { addListner(inst); @@ -672,7 +672,12 @@ CODESTARTactivateCnf } setSchedParams(pModConf); +finalize_it: +ENDactivateCnfPrePrivDrop + +BEGINactivateCnf +CODESTARTactivateCnf /* caching various settings */ iMaxLine = glbl.GetMaxLine(); CHKmalloc(pRcvBuf = MALLOC((iMaxLine + 1) * sizeof(char))); @@ -745,6 +750,7 @@ 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/module-template.h b/runtime/module-template.h index f44cb54a..0440d02d 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -478,6 +478,15 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\ *pEtryPoint = freeCnf;\ } + +/* the following block is to be added for modules that require + * pre priv drop activation support. + */ +#define CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES \ + else if(!strcmp((char*) name, "activateCnfPrePrivDrop")) {\ + *pEtryPoint = activateCnfPrePrivDrop;\ + } + /* the following definition is the standard block for queryEtryPt for LIBRARY * modules. This can be used if no specific handling (e.g. to cover version * differences) is needed. @@ -622,7 +631,7 @@ static rsRetVal modExit(void)\ * the module. -- rgerards, 2011-05-03 */ #define BEGINbeginCnfLoad \ -static rsRetVal beginCnfLoad(modConfData_t **ptr, rsconf_t *pConf)\ +static rsRetVal beginCnfLoad(modConfData_t **ptr, __attribute__((unused)) rsconf_t *pConf)\ {\ modConfData_t *pModConf; \ DEFiRet; @@ -650,7 +659,7 @@ static rsRetVal beginCnfLoad(modConfData_t **ptr, rsconf_t *pConf)\ #define BEGINendCnfLoad \ static rsRetVal endCnfLoad(modConfData_t *ptr)\ {\ - modConfData_t *pModConf = (modConfData_t*) ptr; \ + modConfData_t __attribute__((unused)) *pModConf = (modConfData_t*) ptr; \ DEFiRet; #define CODESTARTendCnfLoad @@ -672,7 +681,7 @@ static rsRetVal endCnfLoad(modConfData_t *ptr)\ #define BEGINcheckCnf \ static rsRetVal checkCnf(modConfData_t *ptr)\ {\ - modConfData_t *pModConf = (modConfData_t*) ptr; \ + modConfData_t __attribute__((unused)) *pModConf = (modConfData_t*) ptr; \ DEFiRet; #define CODESTARTcheckCnf @@ -682,6 +691,26 @@ static rsRetVal checkCnf(modConfData_t *ptr)\ } +/* activateCnfPrePrivDrop() + * Initial config activation, before dropping privileges. This is an optional + * entry points that should only be implemented by those module that really need + * it. Processing should be limited to the minimum possible. Main activation + * should happen in the normal activateCnf() call. + * rgerhards, 2011-05-06 + */ +#define BEGINactivateCnfPrePrivDrop \ +static rsRetVal activateCnfPrePrivDrop(modConfData_t *ptr)\ +{\ + modConfData_t *pModConf = (modConfData_t*) ptr; \ + DEFiRet; + +#define CODESTARTactivateCnfPrePrivDrop + +#define ENDactivateCnfPrePrivDrop \ + RETiRet;\ +} + + /* activateCnf() * This activates the provided config, and may report errors if they are detected * during activation. @@ -690,7 +719,7 @@ static rsRetVal checkCnf(modConfData_t *ptr)\ #define BEGINactivateCnf \ static rsRetVal activateCnf(modConfData_t *ptr)\ {\ - modConfData_t *pModConf = (modConfData_t*) ptr; \ + modConfData_t __attribute__((unused)) *pModConf = (modConfData_t*) ptr; \ DEFiRet; #define CODESTARTactivateCnf diff --git a/runtime/modules.c b/runtime/modules.c index bf944dba..4cd1ef4f 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -371,7 +371,6 @@ addModToCnfList(modInfo_t *pThis) pNew->next = NULL; pNew->pMod = pThis; -dbgprintf("XXXX: beginCnfLoad %p\n", pThis->beginCnfLoad); if(pThis->beginCnfLoad != NULL) { CHKiRet(pThis->beginCnfLoad(&pNew->modCnf, loadConf)); } @@ -528,6 +527,12 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeCnf", &pNew->freeCnf)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"checkCnf", &pNew->checkCnf)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"activateCnf", &pNew->activateCnf)); + localRet = (*pNew->modQueryEtryPt)((uchar*)"activateCnfPrePrivDrop", &pNew->activateCnfPrePrivDrop); + if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { + pNew->activateCnfPrePrivDrop = NULL; + } else { + CHKiRet(localRet); + } } else if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { pNew->beginCnfLoad = NULL; /* flag as non-present */ } else { @@ -706,7 +711,9 @@ 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("\tendCnfLoad: 0x%lx\n", (unsigned long) pMod->endCnfLoad); + 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); dbgprintf("\tfreeCnf: 0x%lx\n", (unsigned long) pMod->freeCnf); switch(pMod->eType) { case eMOD_OUT: diff --git a/runtime/modules.h b/runtime/modules.h index e3af1ad9..a62b1750 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -115,6 +115,7 @@ struct modInfo_s { rsRetVal (*beginCnfLoad)(void*newCnf, rsconf_t *pConf); rsRetVal (*endCnfLoad)(void*Cnf); rsRetVal (*checkCnf)(void*Cnf); + rsRetVal (*activateCnfPrePrivDrop)(void*Cnf); rsRetVal (*activateCnf)(void*Cnf); /* make provided config the running conf */ rsRetVal (*freeCnf)(void*Cnf); /* end v2 config system specific */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 92c17b5c..94190d76 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -296,7 +296,7 @@ dropPrivileges(rsconf_t *cnf) /* Tell input modules that the config parsing stage is over. */ static rsRetVal -tellInputsConfigLoadDone(void) +tellModulesConfigLoadDone(void) { cfgmodules_etry_t *node; @@ -316,7 +316,7 @@ tellInputsConfigLoadDone(void) /* Tell input modules to verify config object */ static rsRetVal -tellInputsCheckConfig(void) +tellModulesCheckConfig(void) { cfgmodules_etry_t *node; rsRetVal localRet; @@ -343,9 +343,40 @@ tellInputsCheckConfig(void) } -/* Tell input modules to activate current running config */ +/* Tell modules to activate current running config (pre privilege drop) */ static rsRetVal -tellInputsActivateConfig(void) +tellModulesActivateConfigPrePrivDrop(void) +{ + cfgmodules_etry_t *node; + rsRetVal localRet; + + BEGINfunc + DBGPRINTF("telling modules to activate config (before dropping privs) %p\n", runConf); + node = module.GetNxtCnfType(runConf, NULL, eMOD_ANY); + while(node != NULL) { + if( node->pMod->beginCnfLoad != NULL + && node->pMod->activateCnfPrePrivDrop != NULL + && node->canActivate) { + DBGPRINTF("activating config %p for module %s\n", + runConf, node->pMod->pszName); + localRet = node->pMod->activateCnfPrePrivDrop(node->modCnf); + if(localRet != RS_RET_OK) { + errmsg.LogError(0, localRet, "activation of module %s failed", + node->pMod->pszName); + node->canActivate = 0; /* in a sense, could not activate... */ + } + } + node = module.GetNxtCnfType(runConf, node, eMOD_IN); + } + + ENDfunc + return RS_RET_OK; /* intentional: we do not care about module errors */ +} + + +/* Tell modules to activate current running config */ +static rsRetVal +tellModulesActivateConfig(void) { cfgmodules_etry_t *node; rsRetVal localRet; @@ -398,7 +429,7 @@ runInputModules(void) } -/* Make the input modules check if they are ready to start. +/* Make the modules check if they are ready to start. */ static rsRetVal startInputModules(void) @@ -463,8 +494,8 @@ activate(rsconf_t *cnf) if(ourConf->globals.pszConfDAGFile != NULL) generateConfigDAG(ourConf->globals.pszConfDAGFile); # endif - tellInputsConfigLoadDone(); - tellInputsCheckConfig(); + tellModulesConfigLoadDone(); + tellModulesCheckConfig(); /* the output part and the queue is now ready to run. So it is a good time * to initialize the inputs. Please note that the net code above should be @@ -474,11 +505,12 @@ activate(rsconf_t *cnf) * Keep in mind. though, that the outputs already run if the queue was * persisted to disk. -- rgerhards */ - tellInputsActivateConfig(); - startInputModules(); + tellModulesActivateConfigPrePrivDrop(); CHKiRet(dropPrivileges(cnf)); + tellModulesActivateConfig(); + startInputModules(); CHKiRet(activateActions()); CHKiRet(activateMainQueue()); /* finally let the inputs run... */ -- cgit v1.2.3 From 759904862dab6e580c6b890fd9ed75e1f29271f1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 6 May 2011 10:30:10 +0200 Subject: step: imtcp did not properly handle privilege drop --- plugins/imtcp/imtcp.c | 6 +----- runtime/nsd_ptcp.c | 6 +++--- runtime/rsconf.c | 2 +- tcpsrv.c | 1 - 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index 3978ff5d..976fbf1f 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -339,6 +339,7 @@ CODESTARTactivateCnfPrePrivDrop } if(pOurTcpsrv == NULL) ABORT_FINALIZE(RS_RET_NO_RUN); + CHKiRet(tcpsrv.ConstructFinalize(pOurTcpsrv)); finalize_it: ENDactivateCnfPrePrivDrop @@ -357,12 +358,7 @@ ENDfreeCnf */ BEGINrunInput CODESTARTrunInput - /* TODO: we must be careful to start the listener here. Currently, tcpsrv.c seems to - * do that in ConstructFinalize - */ - CHKiRet(tcpsrv.ConstructFinalize(pOurTcpsrv)); iRet = tcpsrv.Run(pOurTcpsrv); -finalize_it: ENDrunInput diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c index c8915231..dd6764fa 100644 --- a/runtime/nsd_ptcp.c +++ b/runtime/nsd_ptcp.c @@ -486,7 +486,7 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), #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; @@ -498,7 +498,7 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), * to a fixed, reasonable, limit that should work. Only if * that fails, too, we give up. */ - dbgprintf("listen with a backlog of %d failed - retrying with default of 32.", + dbgprintf("listen with a backlog of %d failed - retrying with default of 32.\n", iSessMax / 10 + 5); if(listen(sock, 32) < 0) { dbgprintf("tcp listen error %d, suspending\n", errno); @@ -531,7 +531,7 @@ LstnInit(netstrms_t *pNS, void *pUsr, rsRetVal(*fAddLstn)(void*,netstrm_t*), "- this may or may not be an error indication.\n", numSocks, maxs); if(numSocks == 0) { - dbgprintf("No TCP listen sockets could successfully be initialized"); + dbgprintf("No TCP listen sockets could successfully be initialized\n"); ABORT_FINALIZE(RS_RET_COULD_NOT_BIND); } diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 94190d76..0f944539 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -357,7 +357,7 @@ tellModulesActivateConfigPrePrivDrop(void) if( node->pMod->beginCnfLoad != NULL && node->pMod->activateCnfPrePrivDrop != NULL && node->canActivate) { - DBGPRINTF("activating config %p for module %s\n", + DBGPRINTF("pre priv drop activating config %p for module %s\n", runConf, node->pMod->pszName); localRet = node->pMod->activateCnfPrePrivDrop(node->modCnf); if(localRet != RS_RET_OK) { diff --git a/tcpsrv.c b/tcpsrv.c index 80c29387..a8f69512 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -897,7 +897,6 @@ tcpsrvConstructFinalize(tcpsrv_t *pThis) /* set up listeners */ CHKmalloc(pThis->ppLstn = calloc(pThis->iLstnMax, sizeof(netstrm_t*))); CHKmalloc(pThis->ppLstnPort = calloc(pThis->iLstnMax, sizeof(tcpLstnPortList_t*))); -dbgprintf("XXXX: open sockets (tcpsrv)\n"); iRet = pThis->OpenLstnSocks(pThis); finalize_it: -- cgit v1.2.3 From 6625a8790d3e89b3ecc0612cf08fc917b9631398 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 9 May 2011 10:07:23 +0200 Subject: added capability for imtcp to activate keep-alive packets at the socket layer. reference: http://kb.monitorware.com/post20791.html --- ChangeLog | 3 +++ doc/imtcp.html | 3 +++ plugins/imtcp/imtcp.c | 5 +++++ runtime/strmsrv.c | 2 +- tcpsrv.c | 14 ++++++++++++++ tcpsrv.h | 5 ++++- 6 files changed, 30 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1a0634d9..f4303d8d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ --------------------------------------------------------------------------- Version 5.9.0 [V5-DEVEL] (rgerhards), 2011-03-?? +- added capability for imtcp to activate keep-alive packets at the + socket layer. + reference: http://kb.monitorware.com/post20791.html - bugfix: do not open files with full privileges, if privs will be dropped This make the privilege drop code more bulletproof, but breaks Ubuntu's work-around for log files created by external programs with the wrong diff --git a/doc/imtcp.html b/doc/imtcp.html index b0aaa3c1..7653f601 100644 --- a/doc/imtcp.html +++ b/doc/imtcp.html @@ -55,6 +55,9 @@ so be prepared to wrangle with that! instructs imtcp to emit a message if the remote peer closes a connection.
Important: This directive is global to all listeners and must be given right after loading imtcp, otherwise it may have no effect. +

  • $InputTCPServerKeepAlive <on/off>
    +enable of disable keep-alive packets at the tcp socket layer. The default is +to disable them.
  • $InputTCPServerRun <port>
    Starts a TCP server on selected port
  • $InputTCPFlowControl <on/off>
    diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index 1a62d82e..c939e1d6 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -82,6 +82,7 @@ static permittedPeers_t *pPermPeersRoot = NULL; /* config settings */ +static int bKeepAlive = 0; /* support keep-alive packets */ static int iTCPSessMax = 200; /* max number of sessions */ static int iTCPLstnMax = 20; /* max number of sessions */ static int iStrmDrvrMode = 0; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */ @@ -192,6 +193,7 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa if(pOurTcpsrv == NULL) { CHKiRet(tcpsrv.Construct(&pOurTcpsrv)); + CHKiRet(tcpsrv.SetKeepAlive(pOurTcpsrv, bKeepAlive)); CHKiRet(tcpsrv.SetSessMax(pOurTcpsrv, iTCPSessMax)); CHKiRet(tcpsrv.SetLstnMax(pOurTcpsrv, iTCPLstnMax)); CHKiRet(tcpsrv.SetCBIsPermittedHost(pOurTcpsrv, isPermittedHost)); @@ -289,6 +291,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { iTCPSessMax = 200; + bKeepAlive = 0; iTCPLstnMax = 20; iStrmDrvrMode = 0; bUseFlowControl = 0; @@ -327,6 +330,8 @@ CODEmodInit_QueryRegCFSLineHdlr /* register config file handlers */ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverrun"), 0, eCmdHdlrGetWord, addTCPListener, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpserverkeepalive"), 0, eCmdHdlrBinary, + NULL, &bKeepAlive, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpmaxsessions"), 0, eCmdHdlrInt, NULL, &iTCPSessMax, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputtcpmaxlisteners"), 0, eCmdHdlrInt, diff --git a/runtime/strmsrv.c b/runtime/strmsrv.c index f448cd4f..03691de6 100644 --- a/runtime/strmsrv.c +++ b/runtime/strmsrv.c @@ -767,7 +767,7 @@ static rsRetVal SetKeepAlive(strmsrv_t *pThis, int iVal) { DEFiRet; - dbgprintf("keep-alive set to %d\n", iVal); + dbgprintf("strmsrv: keep-alive set to %d\n", iVal); pThis->bUseKeepAlive = iVal; RETiRet; } diff --git a/tcpsrv.c b/tcpsrv.c index fde6044d..4658555f 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -396,6 +396,10 @@ SessAccept(tcpsrv_t *pThis, tcpLstnPortList_t *pLstnInfo, tcps_sess_t **ppSess, ABORT_FINALIZE(RS_RET_MAX_SESS_REACHED); } + if(pThis->bUseKeepAlive) { + CHKiRet(netstrm.EnableKeepAlive(pNewStrm)); + } + /* we found a free spot and can construct our session object */ CHKiRet(tcps_sess.Construct(&pSess)); CHKiRet(tcps_sess.SetTcpsrv(pSess, pThis)); @@ -863,6 +867,15 @@ SetUsrP(tcpsrv_t *pThis, void *pUsr) RETiRet; } +static rsRetVal +SetKeepAlive(tcpsrv_t *pThis, int iVal) +{ + DEFiRet; + dbgprintf("tcpsrv: keep-alive set to %d\n", iVal); + pThis->bUseKeepAlive = iVal; + RETiRet; +} + static rsRetVal SetOnMsgReceive(tcpsrv_t *pThis, rsRetVal (*OnMsgReceive)(tcps_sess_t*, uchar*, int)) { @@ -1042,6 +1055,7 @@ CODESTARTobjQueryInterface(tcpsrv) pIf->create_tcp_socket = create_tcp_socket; pIf->Run = Run; + pIf->SetKeepAlive = SetKeepAlive; pIf->SetUsrP = SetUsrP; pIf->SetInputName = SetInputName; pIf->SetAddtlFrameDelim = SetAddtlFrameDelim; diff --git a/tcpsrv.h b/tcpsrv.h index 6c2bad45..9dc06e3e 100644 --- a/tcpsrv.h +++ b/tcpsrv.h @@ -48,6 +48,7 @@ struct tcpLstnPortList_s { /* the tcpsrv object */ struct tcpsrv_s { BEGINobjInstance; /**< Data to implement generic object - MUST be the first data element! */ + int bUseKeepAlive; /**< use socket layer KEEPALIVE handling? */ netstrms_t *pNS; /**< pointer to network stream subsystem */ int iDrvrMode; /**< mode of the stream driver to use */ uchar *pszDrvrAuthMode; /**< auth mode of the stream driver to use */ @@ -124,8 +125,10 @@ BEGINinterface(tcpsrv) /* name must also be changed in ENDinterface macro! */ rsRetVal (*SetbDisableLFDelim)(tcpsrv_t*, int); /* added v10 -- rgerhards, 2011-04-01 */ rsRetVal (*SetUseFlowControl)(tcpsrv_t*, int); + /* added v11 -- rgerhards, 2011-05-09 */ + rsRetVal (*SetKeepAlive)(tcpsrv_t*, int); ENDinterface(tcpsrv) -#define tcpsrvCURR_IF_VERSION 10 /* increment whenever you change the interface structure! */ +#define tcpsrvCURR_IF_VERSION 11 /* increment whenever you change the interface structure! */ /* change for v4: * - SetAddtlFrameDelim() added -- rgerhards, 2008-12-10 * - SetInputName() added -- rgerhards, 2008-12-10 -- cgit v1.2.3 From 1d39d21c62efacb39862d89755ae49ecf0cb7e23 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 11 May 2011 12:24:40 +0200 Subject: imptcp: added capability to activate keep-alive at socket layer --- ChangeLog | 5 +++-- doc/imptcp.html | 5 ++++- plugins/imptcp/imptcp.c | 41 +++++++++++++++++++++++++++++++++++++---- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index ca076bae..69a91ce0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,8 @@ --------------------------------------------------------------------------- Version 5.9.0 [V5-DEVEL] (rgerhards), 2011-03-?? -- added capability for imtcp to activate keep-alive packets at the - socket layer. +- added capability for imtcp and imptcp to activate keep-alive packets + at the socket layer. This has not been added to imttcp, as the latter is + only an experimental module, and one which did not prove to be useful. reference: http://kb.monitorware.com/post20791.html - bugfix: do not open files with full privileges, if privs will be dropped This make the privilege drop code more bulletproof, but breaks Ubuntu's diff --git a/doc/imptcp.html b/doc/imptcp.html index d4228185..8784391e 100644 --- a/doc/imptcp.html +++ b/doc/imptcp.html @@ -45,7 +45,10 @@ can be found at the Cisco tcp page.
  • $InputPTCPServerNotifyOnConnectionClose [on/off]
    instructs imptcp to emit a message if the remote peer closes a connection.
    -
  • $InputPTCPServerRun <port>
    +
  • $InputPTCPServerKeepAlive <on/off>
    +enable of disable keep-alive packets at the tcp socket layer. The default is +to disable them.
  • +
  • $InputPTCPServerRun <port>
    Starts a TCP server on selected port
  • $InputPTCPServerInputName <name>
    Sets a name for the inputname property. If no name is set "imptcp" is used by default. Setting a diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index e8cffbb0..8333e050 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -88,6 +88,7 @@ DEFobjCurrIf(ruleset) /* config settings */ typedef struct configSettings_s { + int bKeepAlive; /* support keep-alive packets */ int bEmitMsgOnClose; /* emit an informational message on close by remote peer */ int iAddtlFrameDelim; /* addtl frame delimiter, e.g. for netscreen, default none */ uchar *pszInputName; /* value for inputname property, NULL is OK and handled by core engine */ @@ -111,13 +112,14 @@ struct ptcpsrv_s { ptcpsrv_t *pNext; /* linked list maintenance */ uchar *port; /* Port to listen to */ uchar *lstnIP; /* which IP we should listen on? */ - int bEmitMsgOnClose; int iAddtlFrameDelim; uchar *pszInputName; prop_t *pInputName; /* InputName in (fast to process) property format */ ruleset_t *pRuleset; ptcplstn_t *pLstn; /* root of our listeners */ ptcpsess_t *pSess; /* root of our sessions */ + sbool bKeepAlive; /* support keep-alive packets */ + sbool bEmitMsgOnClose; }; /* the ptcp session object. Describes a single active session. @@ -429,12 +431,35 @@ finalize_it: } +/* Enable KEEPALIVE handling on the socket. */ +static inline rsRetVal +EnableKeepAlive(int sock) +{ + int ret; + int optval; + socklen_t optlen; + DEFiRet; + + optval = 1; + optlen = sizeof(optval); + ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen); + if(ret < 0) { + dbgprintf("EnableKeepAlive socket call returns error %d\n", ret); + ABORT_FINALIZE(RS_RET_ERR); + } + + dbgprintf("KEEPALIVE enabled for socket %d\n", sock); + +finalize_it: + RETiRet; +} + /* accept an incoming connection request * rgerhards, 2008-04-22 */ static rsRetVal -AcceptConnReq(int sock, int *newSock, prop_t **peerName, prop_t **peerIP) +AcceptConnReq(ptcplstn_t *pLstn, int *newSock, prop_t **peerName, prop_t **peerIP) { int sockflags; struct sockaddr_storage addr; @@ -443,13 +468,17 @@ AcceptConnReq(int sock, int *newSock, prop_t **peerName, prop_t **peerIP) DEFiRet; - iNewSock = accept(sock, (struct sockaddr*) &addr, &addrlen); + iNewSock = accept(pLstn->sock, (struct sockaddr*) &addr, &addrlen); if(iNewSock < 0) { if(errno == EAGAIN || errno == EWOULDBLOCK) ABORT_FINALIZE(RS_RET_NO_MORE_DATA); ABORT_FINALIZE(RS_RET_ACCEPT_ERR); } + if(pLstn->pSrv->bKeepAlive) + EnableKeepAlive(iNewSock); /* we ignore errors, best to do! */ + + CHKiRet(getPeerNames(peerName, peerIP, (struct sockaddr*) &addr)); /* set the new socket to non-blocking IO */ @@ -883,6 +912,7 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa CHKmalloc(pSrv = malloc(sizeof(ptcpsrv_t))); pSrv->pSess = NULL; pSrv->pLstn = NULL; + pSrv->bKeepAlive = cs.bKeepAlive; pSrv->bEmitMsgOnClose = cs.bEmitMsgOnClose; pSrv->port = pNewVal; pSrv->iAddtlFrameDelim = cs.iAddtlFrameDelim; @@ -946,7 +976,7 @@ lstnActivity(ptcplstn_t *pLstn) DBGPRINTF("imptcp: new connection on listen socket %d\n", pLstn->sock); while(1) { - localRet = AcceptConnReq(pLstn->sock, &newSock, &peerName, &peerIP); + localRet = AcceptConnReq(pLstn, &newSock, &peerName, &peerIP); if(localRet == RS_RET_NO_MORE_DATA) break; CHKiRet(localRet); @@ -1145,6 +1175,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { cs.bEmitMsgOnClose = 0; + cs.bKeepAlive = 0; cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; free(cs.pszInputName); cs.pszInputName = NULL; @@ -1177,6 +1208,8 @@ CODEmodInit_QueryRegCFSLineHdlr /* register config file handlers */ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverrun"), 0, eCmdHdlrGetWord, addTCPListener, NULL, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverkeepalive"), 0, eCmdHdlrBinary, + NULL, &cs.bKeepAlive, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpservernotifyonconnectionclose"), 0, eCmdHdlrBinary, NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserveraddtlframedelimiter"), 0, eCmdHdlrInt, -- cgit v1.2.3 From 054837a480a3a5b15f48b8d0bdcde5a687d98c54 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 12 May 2011 12:55:25 +0200 Subject: imttcp: will not be upgraded to v2 config system This was an experimental module which did not work out well, so there is no point in enhancing it. --- plugins/imttcp/imttcp.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/plugins/imttcp/imttcp.c b/plugins/imttcp/imttcp.c index e62360bd..89c1dfd2 100644 --- a/plugins/imttcp/imttcp.c +++ b/plugins/imttcp/imttcp.c @@ -989,30 +989,6 @@ startupListeners() } -BEGINbeginCnfLoad -CODESTARTbeginCnfLoad -ENDbeginCnfLoad - - -BEGINendCnfLoad -CODESTARTendCnfLoad -ENDendCnfLoad - - -BEGINcheckCnf -CODESTARTcheckCnf -ENDcheckCnf - - -BEGINactivateCnf -CODESTARTactivateCnf -ENDactivateCnf - - -BEGINfreeCnf -CODESTARTfreeCnf -ENDfreeCnf - /* This function is called to gather input. */ BEGINrunInput -- cgit v1.2.3 From b4daf5a03d57bbf4a9254dcff73e0b95f2688081 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 12 May 2011 14:04:09 +0200 Subject: step: imuxsock changed to new config system now also properly works with privilege drop --- ChangeLog | 2 + plugins/imuxsock/imuxsock.c | 392 ++++++++++++++++++++++++++++---------------- runtime/rsyslog.h | 1 + 3 files changed, 252 insertions(+), 143 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9586a939..84c2d439 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ --------------------------------------------------------------------------- +Version 6.3.0 [DEVEL] (rgerhards), 2011-??-?? +--------------------------------------------------------------------------- Version 6.1.7 [DEVEL] (rgerhards), 2011-04-15 - added log classification capabilities (via mmnormalize & tags) - speeded up tcp forwarding by reducing number of API calls diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 21550264..64477620 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-2010 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -68,6 +68,9 @@ MODULE_TYPE_NOKEEP #endif #endif +/* forward definitions */ +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); + /* emulate struct ucred for platforms that do not have it */ #ifndef HAVE_SCM_CREDENTIALS struct ucred { int pid; }; @@ -88,10 +91,6 @@ DEFobjCurrIf(datetime) DEFobjCurrIf(statsobj) -struct modConfData_s { - EMPTY_STRUCT; -}; - statsobj_t *modStats; STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit) STATSCOUNTER_DEF(ctrLostRatelimit, mutCtrLostRatelimit) @@ -153,26 +152,56 @@ 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 */ -/* config settings */ -static int bOmitLocalLogging = 0; -static uchar *pLogSockName = NULL; -static uchar *pLogHostName = NULL; /* host name to use with this socket */ -static int bUseFlowCtl = 0; /* use flow control or not (if yes, only LIGHT is used! */ -static int bIgnoreTimestamp = 1; /* ignore timestamps present in the incoming message? */ -static int bWritePid = 0; /* use credentials from recvmsg() and fixup PID in TAG */ -static int bWritePidSysSock = 0; /* use credentials from recvmsg() and fixup PID in TAG */ +/* config vars for legacy config system */ #define DFLT_bCreatePath 0 -static int bCreatePath = DFLT_bCreatePath; /* auto-create socket path? */ #define DFLT_ratelimitInterval 5 -static int ratelimitInterval = DFLT_ratelimitInterval; /* interval in seconds, 0 = off */ -static int ratelimitIntervalSysSock = DFLT_ratelimitInterval; #define DFLT_ratelimitBurst 200 -static int ratelimitBurst = DFLT_ratelimitBurst; /* max nbr of messages in interval */ -static int ratelimitBurstSysSock = DFLT_ratelimitBurst; /* max nbr of messages in interval */ #define DFLT_ratelimitSeverity 1 /* do not rate-limit emergency messages */ -static int ratelimitSeverity = DFLT_ratelimitSeverity; -static int ratelimitSeveritySysSock = DFLT_ratelimitSeverity; +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 bIgnoreTimestamp; /* ignore timestamps present in the incoming message? */ + int bWritePid; /* use credentials from recvmsg() and fixup PID in TAG */ + int bWritePidSysSock; /* use credentials from recvmsg() and fixup PID in TAG */ + int bCreatePath; /* auto-create socket path? */ + int ratelimitInterval; /* interval in seconds, 0 = off */ + int ratelimitIntervalSysSock; + int ratelimitBurst; /* max nbr of messages in interval */ + int ratelimitBurstSysSock; + int ratelimitSeverity; + int ratelimitSeveritySysSock; +} cs; + +struct instanceConf_s { + uchar *sockName; + uchar *pLogHostName; /* host name to use with this socket */ + int bUseFlowCtl; /* use flow control or not (if yes, only LIGHT is used! */ + int bIgnoreTimestamp; /* ignore timestamps present in the incoming message? */ + int bWritePid; /* use credentials from recvmsg() and fixup PID in TAG */ + int bCreatePath; /* auto-create socket path? */ + int ratelimitInterval; /* interval in seconds, 0 = off */ + int ratelimitBurst; /* max nbr of messages in interval */ + int ratelimitSeverity; + struct instanceConf_s *next; +}; +struct modConfData_s { + rsconf_t *pConf; /* our overall config object */ + instanceConf_t *root, *tail; + uchar *pLogSockName; + int bOmitLocalLogging; + int bWritePidSysSock; + int ratelimitIntervalSysSock; + int ratelimitBurstSysSock; + int ratelimitSeveritySysSock; +}; +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 */ + +/* 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 @@ -261,6 +290,53 @@ static rsRetVal setSystemLogFlowControl(void __attribute__((unused)) *pVal, int 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. + * rgerhards, 2011-05-12 + */ +static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) +{ + instanceConf_t *inst; + DEFiRet; + + if(pNewVal == NULL || pNewVal[0] == '\0') { + errmsg.LogError(0, RS_RET_SOCKNAME_MISSING , "imuxsock: socket name must be specified, " + "but is not - listener not created\n"); + if(pNewVal != NULL) + free(pNewVal); + ABORT_FINALIZE(RS_RET_SOCKNAME_MISSING); + } + + CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + inst->sockName = pNewVal; + inst->ratelimitInterval = cs.ratelimitInterval; + inst->ratelimitBurst = cs.ratelimitBurst; + inst->ratelimitSeverity = cs.ratelimitSeverity; + inst->bUseFlowCtl = cs.bUseFlowCtl; + inst->bIgnoreTimestamp = cs.bIgnoreTimestamp; + inst->bCreatePath = cs.bCreatePath; + inst->bWritePid = cs.bWritePid; + 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; + +finalize_it: + RETiRet; +} + + /* add an additional listen socket. Socket names are added * until the array is filled up. It is never reset, only at * module unload. @@ -270,47 +346,45 @@ static rsRetVal setSystemLogFlowControl(void __attribute__((unused)) *pVal, int * added capability to specify hostname for socket -- rgerhards, 2008-08-01 */ static rsRetVal -addLstnSocketName(void __attribute__((unused)) *pVal, uchar *pNewVal) +addListner(instanceConf_t *inst) { DEFiRet; if(nfd < MAXFUNIX) { - if(*pNewVal == ':') { + if(*inst->sockName == ':') { listeners[nfd].bParseHost = 1; } else { listeners[nfd].bParseHost = 0; } CHKiRet(prop.Construct(&(listeners[nfd].hostName))); - if(pLogHostName == NULL) { - CHKiRet(prop.SetString(listeners[nfd].hostName, glbl.GetLocalHostName(), ustrlen(glbl.GetLocalHostName()))); + if(inst->pLogHostName == NULL) { + CHKiRet(prop.SetString(listeners[nfd].hostName, glbl.GetLocalHostName(), + ustrlen(glbl.GetLocalHostName()))); } else { - CHKiRet(prop.SetString(listeners[nfd].hostName, pLogHostName, ustrlen(pLogHostName))); - /* reset hostname for next socket */ - free(pLogHostName); - pLogHostName = NULL; + CHKiRet(prop.SetString(listeners[nfd].hostName, inst->pLogHostName, ustrlen(inst->pLogHostName))); } CHKiRet(prop.ConstructFinalize(listeners[nfd].hostName)); - if(ratelimitInterval > 0) { + 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 of rate-limiting */ + /* in this case, we simply turn off rate-limiting */ dbgprintf("imuxsock: turning off rate limiting because we could not " "create hash table\n"); - ratelimitInterval = 0; + inst->ratelimitInterval = 0; } } - listeners[nfd].ratelimitInterval = ratelimitInterval; - listeners[nfd].ratelimitBurst = ratelimitBurst; - listeners[nfd].ratelimitSev = ratelimitSeverity; - listeners[nfd].flowCtl = bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; - listeners[nfd].flags = bIgnoreTimestamp ? IGNDATE : NOFLAG; - listeners[nfd].bCreatePath = bCreatePath; - listeners[nfd].sockName = pNewVal; - listeners[nfd].bUseCreds = (bWritePid || ratelimitInterval) ? 1 : 0; - listeners[nfd].bWritePid = bWritePid; + listeners[nfd].ratelimitInterval = inst->ratelimitInterval; + listeners[nfd].ratelimitBurst = inst->ratelimitBurst; + listeners[nfd].ratelimitSev = inst->ratelimitSeverity; + listeners[nfd].flowCtl = inst->bUseFlowCtl ? eFLOWCTL_LIGHT_DELAY : eFLOWCTL_NO_DELAY; + listeners[nfd].flags = inst->bIgnoreTimestamp ? IGNDATE : NOFLAG; + listeners[nfd].bCreatePath = inst->bCreatePath; + listeners[nfd].sockName = ustrdup(inst->sockName); + listeners[nfd].bUseCreds = (inst->bWritePid || inst->ratelimitInterval) ? 1 : 0; + listeners[nfd].bWritePid = inst->bWritePid; nfd++; } else { errmsg.LogError(0, NO_ERRCODE, "Out of unix socket name descriptors, ignoring %s\n", - pNewVal); + inst->sockName); } finalize_it: @@ -689,13 +763,88 @@ finalize_it: } +/* activate current listeners */ +static inline rsRetVal +activateListeners() +{ + register int i; + int actSocks; + DEFiRet; + + /* first apply some config settings */ +# ifdef OS_SOLARIS + /* under solaris, we must NEVER process the local log socket, because + * it is implemented there differently. If we used it, we would actually + * delete it and render the system partly unusable. So don't do that. + * rgerhards, 2010-03-26 + */ + startIndexUxLocalSockets = 1; +# else + startIndexUxLocalSockets = runModConf->bOmitLocalLogging ? 1 : 0; +# endif + if(runModConf->pLogSockName != NULL) + listeners[0].sockName = runModConf->pLogSockName; + if(runModConf->ratelimitIntervalSysSock > 0) { + if((listeners[0].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn, NULL)) == NULL) { + /* in this case, we simply turn of rate-limiting */ + errmsg.LogError(0, NO_ERRCODE, "imuxsock: turning off rate limiting because we could not " + "create hash table\n"); + runModConf->ratelimitIntervalSysSock = 0; + } + } + 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].bWritePid = runModConf->bWritePidSysSock; + + sd_fds = sd_listen_fds(0); + if(sd_fds < 0) { + errmsg.LogError(-sd_fds, NO_ERRCODE, "imuxsock: Failed to acquire systemd socket"); + ABORT_FINALIZE(RS_RET_ERR_CRE_AFUX); + } + + /* initialize and return if will run or not */ + actSocks = 0; + for (i = startIndexUxLocalSockets ; i < nfd ; i++) { + if(openLogSocket(&(listeners[i])) == RS_RET_OK) { + ++actSocks; + dbgprintf("imuxsock: Opened UNIX socket '%s' (fd %d).\n", + listeners[i].sockName, listeners[i].fd); + } + } + + if(actSocks == 0) { + errmsg.LogError(0, NO_ERRCODE, "imuxsock does not run because we could not aquire any socket\n"); + ABORT_FINALIZE(RS_RET_ERR); + } + +finalize_it: + RETiRet; +} + + + BEGINbeginCnfLoad CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + /* reset legacy config vars */ + resetConfigVariables(NULL, NULL); ENDbeginCnfLoad BEGINendCnfLoad CODESTARTendCnfLoad + /* persist module-specific settings from legacy config system */ + loadModConf->bOmitLocalLogging = cs.bOmitLocalLogging; + loadModConf->pLogSockName = cs.pLogSockName; + + loadModConf = NULL; /* done loading */ + /* free legacy config vars */ + free(cs.pLogHostName); + cs.pLogSockName = NULL; + cs.pLogHostName = NULL; ENDendCnfLoad @@ -704,6 +853,18 @@ CODESTARTcheckCnf ENDcheckCnf +BEGINactivateCnfPrePrivDrop + instanceConf_t *inst; +CODESTARTactivateCnfPrePrivDrop + runModConf = pModConf; + for(inst = runModConf->root ; inst != NULL ; inst = inst->next) { + addListner(inst); + } + CHKiRet(activateListeners()); +finalize_it: +ENDactivateCnfPrePrivDrop + + BEGINactivateCnf CODESTARTactivateCnf ENDactivateCnf @@ -711,6 +872,7 @@ ENDactivateCnf BEGINfreeCnf CODESTARTfreeCnf + free(pModConf->pLogSockName); ENDfreeCnf @@ -781,68 +943,12 @@ ENDrunInput BEGINwillRun CODESTARTwillRun - register int i; - int actSocks; - - /* first apply some config settings */ -# ifdef OS_SOLARIS - /* under solaris, we must NEVER process the local log socket, because - * it is implemented there differently. If we used it, we would actually - * delete it and render the system partly unusable. So don't do that. - * rgerhards, 2010-03-26 - */ - startIndexUxLocalSockets = 1; -# else - startIndexUxLocalSockets = bOmitLocalLogging ? 1 : 0; -# endif - if(pLogSockName != NULL) - listeners[0].sockName = pLogSockName; - if(ratelimitIntervalSysSock > 0) { - if((listeners[0].ht = create_hashtable(100, hash_from_key_fn, key_equals_fn, NULL)) == NULL) { - /* in this case, we simply turn of rate-limiting */ - dbgprintf("imuxsock: turning off rate limiting because we could not " - "create hash table\n"); - ratelimitIntervalSysSock = 0; - } - } - listeners[0].ratelimitInterval = ratelimitIntervalSysSock; - listeners[0].ratelimitBurst = ratelimitBurstSysSock; - listeners[0].ratelimitSev = ratelimitSeveritySysSock; - listeners[0].bUseCreds = (bWritePidSysSock || ratelimitIntervalSysSock) ? 1 : 0; - listeners[0].bWritePid = bWritePidSysSock; - - sd_fds = sd_listen_fds(0); - if (sd_fds < 0) { - errmsg.LogError(-sd_fds, NO_ERRCODE, "imuxsock: Failed to acquire systemd socket"); - ABORT_FINALIZE(RS_RET_ERR_CRE_AFUX); - } - - /* initialize and return if will run or not */ - actSocks = 0; - for (i = startIndexUxLocalSockets ; i < nfd ; i++) { - if(openLogSocket(&(listeners[i])) == RS_RET_OK) { - ++actSocks; - dbgprintf("imuxsock: Opened UNIX socket '%s' (fd %d).\n", listeners[i].sockName, listeners[i].fd); - } - } - - if(actSocks == 0) { - errmsg.LogError(0, NO_ERRCODE, "imuxsock does not run because we could not aquire any socket\n"); - ABORT_FINALIZE(RS_RET_ERR); - } - - /* we need to create the inputName property (only once during our lifetime) */ - CHKiRet(prop.Construct(&pInputName)); - CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imuxsock"), sizeof("imuxsock") - 1)); - CHKiRet(prop.ConstructFinalize(pInputName)); - -finalize_it: ENDwillRun BEGINafterRun -CODESTARTafterRun int i; +CODESTARTafterRun /* do cleanup here */ /* Close the UNIX sockets. */ for (i = 0; i < nfd; i++) @@ -865,21 +971,17 @@ CODESTARTafterRun DBGPRINTF("imuxsock: unlinking unix socket file[%d] %s\n", i, listeners[i].sockName); unlink((char*) listeners[i].sockName); } - /* free no longer needed string */ - free(pLogSockName); - free(pLogHostName); discardLogSockets(); nfd = 1; - - if(pInputName != NULL) - prop.Destruct(&pInputName); - ENDafterRun BEGINmodExit CODESTARTmodExit + if(pInputName != NULL) + prop.Destruct(&pInputName); + statsobj.Destruct(&modStats); objRelease(parser, CORE_COMPONENT); @@ -901,34 +1003,29 @@ ENDisCompatibleWithFeature BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { - bOmitLocalLogging = 0; - if(pLogSockName != NULL) { - free(pLogSockName); - pLogSockName = NULL; - } - if(pLogHostName != NULL) { - free(pLogHostName); - pLogHostName = NULL; - } - - discardLogSockets(); - nfd = 1; - bIgnoreTimestamp = 1; - bUseFlowCtl = 0; - bWritePid = 0; - bWritePidSysSock = 0; - bCreatePath = DFLT_bCreatePath; - ratelimitInterval = DFLT_ratelimitInterval; - ratelimitIntervalSysSock = DFLT_ratelimitInterval; - ratelimitBurst = DFLT_ratelimitBurst; - ratelimitBurstSysSock = DFLT_ratelimitBurst; - ratelimitSeverity = DFLT_ratelimitSeverity; - ratelimitSeveritySysSock = DFLT_ratelimitSeverity; + free(cs.pLogSockName); + cs.pLogSockName = NULL; + free(cs.pLogHostName); + cs.bOmitLocalLogging = 0; + cs.pLogHostName = NULL; + cs.bIgnoreTimestamp = 1; + cs.bUseFlowCtl = 0; + cs.bWritePid = 0; + cs.bWritePidSysSock = 0; + cs.bCreatePath = DFLT_bCreatePath; + cs.ratelimitInterval = DFLT_ratelimitInterval; + cs.ratelimitIntervalSysSock = DFLT_ratelimitInterval; + cs.ratelimitBurst = DFLT_ratelimitBurst; + cs.ratelimitBurstSysSock = DFLT_ratelimitBurst; + cs.ratelimitSeverity = DFLT_ratelimitSeverity; + cs.ratelimitSeveritySysSock = DFLT_ratelimitSeverity; return RS_RET_OK; } @@ -948,6 +1045,15 @@ CODEmodInit_QueryRegCFSLineHdlr dbgprintf("imuxsock version %s initializing\n", PACKAGE_VERSION); + /* init legacy config vars */ + cs.pLogSockName = NULL; + cs.pLogHostName = NULL; /* host name to use with this socket */ + + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.Construct(&pInputName)); + CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imuxsock"), sizeof("imuxsock") - 1)); + CHKiRet(prop.ConstructFinalize(pInputName)); + /* init system log socket settings */ listeners[0].flags = IGNDATE; listeners[0].sockName = UCHAR_CONSTANT(_PATH_LOG); @@ -975,27 +1081,27 @@ CODEmodInit_QueryRegCFSLineHdlr /* register config file handlers */ CHKiRet(omsdRegCFSLineHdlr((uchar *)"omitlocallogging", 0, eCmdHdlrBinary, - NULL, &bOmitLocalLogging, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.bOmitLocalLogging, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketignoremsgtimestamp", 0, eCmdHdlrBinary, - NULL, &bIgnoreTimestamp, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.bIgnoreTimestamp, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketname", 0, eCmdHdlrGetWord, - NULL, &pLogSockName, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.pLogSockName, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensockethostname", 0, eCmdHdlrGetWord, - NULL, &pLogHostName, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.pLogHostName, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketflowcontrol", 0, eCmdHdlrBinary, - NULL, &bUseFlowCtl, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.bUseFlowCtl, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketcreatepath", 0, eCmdHdlrBinary, - NULL, &bCreatePath, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.bCreatePath, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"addunixlistensocket", 0, eCmdHdlrGetWord, - addLstnSocketName, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + addInstance, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketusepidfromsystem", 0, eCmdHdlrBinary, - NULL, &bWritePid, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.bWritePid, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"imuxsockratelimitinterval", 0, eCmdHdlrInt, - NULL, &ratelimitInterval, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.ratelimitInterval, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"imuxsockratelimitburst", 0, eCmdHdlrInt, - NULL, &ratelimitBurst, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.ratelimitBurst, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"imuxsockratelimitseverity", 0, eCmdHdlrInt, - NULL, &ratelimitSeverity, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.ratelimitSeverity, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); /* the following one is a (dirty) trick: the system log socket is not added via @@ -1009,13 +1115,13 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketflowcontrol", 0, eCmdHdlrBinary, setSystemLogFlowControl, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogusepidfromsystem", 0, eCmdHdlrBinary, - NULL, &bWritePidSysSock, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.bWritePidSysSock, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogratelimitinterval", 0, eCmdHdlrInt, - NULL, &ratelimitIntervalSysSock, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.ratelimitIntervalSysSock, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogratelimitburst", 0, eCmdHdlrInt, - NULL, &ratelimitBurstSysSock, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.ratelimitBurstSysSock, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogratelimitseverity", 0, eCmdHdlrInt, - NULL, &ratelimitSeveritySysSock, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + NULL, &cs.ratelimitSeveritySysSock, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); /* support statistics gathering */ CHKiRet(statsobj.Construct(&modStats)); diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index fbcdc253..1eff279d 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -356,6 +356,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_ERR_LIBLOGNORM_SAMPDB_LOAD = -2203,/**< liblognorm sampledb load failed */ RS_RET_CMD_GONE_AWAY = -2204,/**< config directive existed, but no longer supported */ RS_RET_ERR_SCHED_PARAMS = -2205,/**< there is a problem with configured thread scheduling params */ + RS_RET_SOCKNAME_MISSING = -2206,/**< no socket name configured where one is required */ /* 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 2b56e6051d4d2bb03886dbad47458d1843aa9ebe Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 12 May 2011 15:04:50 +0200 Subject: regression fix: activation for legacy modules handled incorrectly --- runtime/modules.c | 1 + 1 file changed, 1 insertion(+) diff --git a/runtime/modules.c b/runtime/modules.c index 4cd1ef4f..ad93ff38 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -368,6 +368,7 @@ addModToCnfList(modInfo_t *pThis) */ CHKmalloc(pNew = MALLOC(sizeof(cfgmodules_etry_t))); + pNew->canActivate = 1; pNew->next = NULL; pNew->pMod = pThis; -- cgit v1.2.3 From 0f5186ad01d1c429c9ed78a2a3ed3e28e1e67d00 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 13 May 2011 11:07:20 +0200 Subject: added support to control KEEPALIVE settings in imptcp this has not yet been added to imtcp, but could be done on request --- ChangeLog | 2 ++ doc/imptcp.html | 15 +++++++++++ plugins/imptcp/imptcp.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 69a91ce0..a9084201 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,8 @@ Version 5.9.0 [V5-DEVEL] (rgerhards), 2011-03-?? at the socket layer. This has not been added to imttcp, as the latter is only an experimental module, and one which did not prove to be useful. reference: http://kb.monitorware.com/post20791.html +- added support to control KEEPALIVE settings in imptcp + this has not yet been added to imtcp, but could be done on request. - bugfix: do not open files with full privileges, if privs will be dropped This make the privilege drop code more bulletproof, but breaks Ubuntu's work-around for log files created by external programs with the wrong diff --git a/doc/imptcp.html b/doc/imptcp.html index 8784391e..386e691a 100644 --- a/doc/imptcp.html +++ b/doc/imptcp.html @@ -48,6 +48,21 @@ instructs imptcp to emit a message if the remote peer closes a connection.
  • $InputPTCPServerKeepAlive <on/off>
    enable of disable keep-alive packets at the tcp socket layer. The default is to disable them.
  • +
  • $InputPTCPServerKeepAlive_probes <number>
    +The number of unacknowledged probes to send before considering the connection dead and notifying the application layer. +The default, 0, means that the operating system defaults are used. This has only +effect if keep-alive is enabled. The functionality may not be available on +all platforms. +
  • $InputPTCPServerKeepAlive_intvl <number>
    +The interval between subsequential keepalive probes, regardless of what the connection has exchanged in the meantime. +The default, 0, means that the operating system defaults are used. This has only +effect if keep-alive is enabled. The functionality may not be available on +all platforms. +
  • $InputPTCPServerKeepAlive_time <number>
    +The interval between the last data packet sent (simple ACKs are not considered data) and the first keepalive probe; after the connection is marked to need keepalive, this counter is not used any further. +The default, 0, means that the operating system defaults are used. This has only +effect if keep-alive is enabled. The functionality may not be available on +all platforms.
  • $InputPTCPServerRun <port>
    Starts a TCP server on selected port
  • $InputPTCPServerInputName <name>
    diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 8333e050..8751637d 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -50,6 +50,7 @@ #include #include #include +#include #if HAVE_FCNTL_H #include #endif @@ -89,6 +90,9 @@ DEFobjCurrIf(ruleset) /* config settings */ typedef struct configSettings_s { int bKeepAlive; /* support keep-alive packets */ + int iKeepAliveIntvl; + int iKeepAliveProbes; + int iKeepAliveTime; int bEmitMsgOnClose; /* emit an informational message on close by remote peer */ int iAddtlFrameDelim; /* addtl frame delimiter, e.g. for netscreen, default none */ uchar *pszInputName; /* value for inputname property, NULL is OK and handled by core engine */ @@ -113,6 +117,9 @@ struct ptcpsrv_s { uchar *port; /* Port to listen to */ uchar *lstnIP; /* which IP we should listen on? */ int iAddtlFrameDelim; + int iKeepAliveIntvl; + int iKeepAliveProbes; + int iKeepAliveTime; uchar *pszInputName; prop_t *pInputName; /* InputName in (fast to process) property format */ ruleset_t *pRuleset; @@ -433,7 +440,7 @@ finalize_it: /* Enable KEEPALIVE handling on the socket. */ static inline rsRetVal -EnableKeepAlive(int sock) +EnableKeepAlive(ptcplstn_t *pLstn, int sock) { int ret; int optval; @@ -448,6 +455,51 @@ EnableKeepAlive(int sock) ABORT_FINALIZE(RS_RET_ERR); } +# if defined(TCP_KEEPCNT) + if(pLstn->pSrv->iKeepAliveProbes > 0) { + optval = pLstn->pSrv->iKeepAliveProbes; + optlen = sizeof(optval); + ret = setsockopt(sock, SOL_TCP, TCP_KEEPCNT, &optval, optlen); + } else { + ret = 0; + } +# else + ret = -1; +# endif + if(ret < 0) { + errmsg.LogError(ret, NO_ERRCODE, "imptcp cannot set keepalive probes - ignored"); + } + +# if defined(TCP_KEEPCNT) + if(pLstn->pSrv->iKeepAliveTime > 0) { + optval = pLstn->pSrv->iKeepAliveTime; + optlen = sizeof(optval); + ret = setsockopt(sock, SOL_TCP, TCP_KEEPIDLE, &optval, optlen); + } else { + ret = 0; + } +# else + ret = -1; +# endif + if(ret < 0) { + errmsg.LogError(ret, NO_ERRCODE, "imptcp cannot set keepalive time - ignored"); + } + +# if defined(TCP_KEEPCNT) + if(pLstn->pSrv->iKeepAliveIntvl > 0) { + optval = pLstn->pSrv->iKeepAliveIntvl; + optlen = sizeof(optval); + ret = setsockopt(sock, SOL_TCP, TCP_KEEPINTVL, &optval, optlen); + } else { + ret = 0; + } +# else + ret = -1; +# endif + if(ret < 0) { + errmsg.LogError(errno, NO_ERRCODE, "imptcp cannot set keepalive intvl - ignored"); + } + dbgprintf("KEEPALIVE enabled for socket %d\n", sock); finalize_it: @@ -476,7 +528,7 @@ AcceptConnReq(ptcplstn_t *pLstn, int *newSock, prop_t **peerName, prop_t **peerI } if(pLstn->pSrv->bKeepAlive) - EnableKeepAlive(iNewSock); /* we ignore errors, best to do! */ + EnableKeepAlive(pLstn, iNewSock);/* we ignore errors, best to do! */ CHKiRet(getPeerNames(peerName, peerIP, (struct sockaddr*) &addr)); @@ -913,6 +965,9 @@ static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVa pSrv->pSess = NULL; pSrv->pLstn = NULL; pSrv->bKeepAlive = cs.bKeepAlive; + pSrv->iKeepAliveIntvl = cs.iKeepAliveTime; + pSrv->iKeepAliveProbes = cs.iKeepAliveProbes; + pSrv->iKeepAliveTime = cs.iKeepAliveTime; pSrv->bEmitMsgOnClose = cs.bEmitMsgOnClose; pSrv->port = pNewVal; pSrv->iAddtlFrameDelim = cs.iAddtlFrameDelim; @@ -1176,6 +1231,9 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus { cs.bEmitMsgOnClose = 0; cs.bKeepAlive = 0; + cs.iKeepAliveProbes = 0; + cs.iKeepAliveTime = 0; + cs.iKeepAliveIntvl = 0; cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; free(cs.pszInputName); cs.pszInputName = NULL; @@ -1210,6 +1268,12 @@ CODEmodInit_QueryRegCFSLineHdlr addTCPListener, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverkeepalive"), 0, eCmdHdlrBinary, NULL, &cs.bKeepAlive, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverkeepalive_probes"), 0, eCmdHdlrInt, + NULL, &cs.iKeepAliveProbes, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverkeepalive_time"), 0, eCmdHdlrInt, + NULL, &cs.iKeepAliveTime, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverkeepalive_intvl"), 0, eCmdHdlrInt, + NULL, &cs.iKeepAliveIntvl, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpservernotifyonconnectionclose"), 0, eCmdHdlrBinary, NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserveraddtlframedelimiter"), 0, eCmdHdlrInt, -- cgit v1.2.3 From 4de5aa20bc9620562d93658858903aac86b1ce00 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 13 May 2011 14:11:34 +0200 Subject: mmsnmptrapd: doc bugfix and fix issue with config stmt handler --- doc/mmsnmptrapd.html | 9 ++++++--- plugins/mmsnmptrapd/mmsnmptrapd.c | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/doc/mmsnmptrapd.html b/doc/mmsnmptrapd.html index e69bc241..5dfb392b 100644 --- a/doc/mmsnmptrapd.html +++ b/doc/mmsnmptrapd.html @@ -51,8 +51,11 @@ to control output modules are also available to mmsnmptrapd.
    • $mmsnmptrapdTag [tagname]
      tells the module which start string inside the tag to look for. The default is -"snmptrap/" -
    • $mmsnmptrapdSevertiyMapping [severtiymap]
      +"snmptrap". Note that a slash is automatically added to this tag when it comes to +matching incoming messages. It MUST not be given, except if two slashes are required +for whatever reasons (so "tag/" results in a check for "tag//" at the start of +the tag field). +
    • $mmsnmptrapdSeverityMapping [severtiymap]
      This specifies the severity mapping table. It needs to be specified as a list. Note that due to the current config system no whitespace is supported inside the list, so be sure not to use any whitespace inside it.
      @@ -76,7 +79,7 @@ severities. The default tag is used.
      # ... other module loads and listener setup ... *.* /path/to/file/with/orignalMessage # this file receives *un*modified messages $mmsnmptrapdSeverityMapping warning/4,error/3 -*.* ::mmsnmptrapd: # *now* message is modified +*.* :mmsnmptrapd: # *now* message is modified *.* /path/to/file/with/modifiedMessage # this file receives modified messages # ... rest of config ... diff --git a/plugins/mmsnmptrapd/mmsnmptrapd.c b/plugins/mmsnmptrapd/mmsnmptrapd.c index 8f996832..9311d5c6 100644 --- a/plugins/mmsnmptrapd/mmsnmptrapd.c +++ b/plugins/mmsnmptrapd/mmsnmptrapd.c @@ -421,7 +421,7 @@ CODEmodInit_QueryRegCFSLineHdlr cs.pszTagName = NULL; cs.pszSeverityMapping = NULL; - CHKiRet(omsdRegCFSLineHdlr((uchar *)"mmsnmptrapdtag", 0, eCmdHdlrInt, + CHKiRet(omsdRegCFSLineHdlr((uchar *)"mmsnmptrapdtag", 0, eCmdHdlrGetWord, NULL, &cs.pszTagName, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"mmsnmptrapdseveritymapping", 0, eCmdHdlrGetWord, NULL, &cs.pszSeverityMapping, STD_LOADABLE_MODULE_ID)); -- cgit v1.2.3 From 1cd5224a9cd3a036053b185ef3af1be7e0a455d0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 13 May 2011 14:17:02 +0200 Subject: doc bugfix: yet another typo ... am I really that dumb... ;) --- configure.ac | 2 +- doc/mmsnmptrapd.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 6ac6ff65..fb0cff8d 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],[5.8.0],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.8.1-pre3],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) diff --git a/doc/mmsnmptrapd.html b/doc/mmsnmptrapd.html index 5dfb392b..699049d3 100644 --- a/doc/mmsnmptrapd.html +++ b/doc/mmsnmptrapd.html @@ -51,7 +51,7 @@ to control output modules are also available to mmsnmptrapd.
      • $mmsnmptrapdTag [tagname]
        tells the module which start string inside the tag to look for. The default is -"snmptrap". Note that a slash is automatically added to this tag when it comes to +"snmptrapd". Note that a slash is automatically added to this tag when it comes to matching incoming messages. It MUST not be given, except if two slashes are required for whatever reasons (so "tag/" results in a check for "tag//" at the start of the tag field). -- cgit v1.2.3 From 3e8ee7a6d2c37dc426be692be0065d9d2a4a9c1d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 20 May 2011 10:55:11 +0200 Subject: move impstats to new config interface --- plugins/impstats/impstats.c | 46 +++++++++++++++++++++++++++++++-------------- 1 file changed, 32 insertions(+), 14 deletions(-) diff --git a/plugins/impstats/impstats.c b/plugins/impstats/impstats.c index 59d62d18..5e60d073 100644 --- a/plugins/impstats/impstats.c +++ b/plugins/impstats/impstats.c @@ -70,8 +70,13 @@ typedef struct configSettings_s { } configSettings_t; struct modConfData_s { - EMPTY_STRUCT; + rsconf_t *pConf; /* our overall config object */ + int iStatsInterval; + int iFacility; + int iSeverity; }; +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; @@ -110,8 +115,8 @@ doSubmitMsg(uchar *line) MsgSetRcvFromIP(pMsg, pLocalHostIP); MsgSetMSGoffs(pMsg, 0); MsgSetTAG(pMsg, UCHAR_CONSTANT("rsyslogd-pstats:"), sizeof("rsyslogd-pstats:") - 1); - pMsg->iFacility = cs.iFacility; - pMsg->iSeverity = cs.iSeverity; + pMsg->iFacility = runModConf->iFacility; + pMsg->iSeverity = runModConf->iSeverity; pMsg->msgFlags = 0; submitMsg(pMsg); @@ -146,21 +151,43 @@ generateStatsMsgs(void) BEGINbeginCnfLoad CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + /* init legacy config vars */ + initConfigSettings(); ENDbeginCnfLoad BEGINendCnfLoad CODESTARTendCnfLoad + /* persist module-specific settings from legacy config system */ + loadModConf->iStatsInterval = cs.iStatsInterval; + loadModConf->iFacility = cs.iFacility; + loadModConf->iSeverity = cs.iSeverity; ENDendCnfLoad 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); + pModConf->iStatsInterval = DEFAULT_STATS_PERIOD; + } ENDcheckCnf BEGINactivateCnf + rsRetVal localRet; CODESTARTactivateCnf + runModConf = pModConf; + DBGPRINTF("impstats: stats interval %d seconds\n", runModConf->iStatsInterval); + localRet = statsobj.EnableStats(); + if(localRet != RS_RET_OK) { + errmsg.LogError(0, localRet, "impstats: error enabling statistics gathering"); + ABORT_FINALIZE(RS_RET_NO_RUN); + } +finalize_it: ENDactivateCnf @@ -176,7 +203,7 @@ CODESTARTrunInput * right into the sleep below. */ while(1) { - srSleep(cs.iStatsInterval, 0); /* seconds, micro seconds */ + srSleep(runModConf->iStatsInterval, 0); /* seconds, micro seconds */ if(glbl.GetGlobalInputTermState() == 1) break; /* terminate input! */ @@ -187,17 +214,7 @@ ENDrunInput BEGINwillRun - rsRetVal localRet; CODESTARTwillRun - DBGPRINTF("impstats: stats interval %d seconds\n", cs.iStatsInterval); - if(cs.iStatsInterval == 0) - ABORT_FINALIZE(RS_RET_NO_RUN); - localRet = statsobj.EnableStats(); - if(localRet != RS_RET_OK) { - errmsg.LogError(0, localRet, "impstat: error enabling statistics gathering"); - ABORT_FINALIZE(RS_RET_NO_RUN); - } -finalize_it: ENDwillRun @@ -222,6 +239,7 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From 503dec99f2e21fba336c989b209fadbf201e6f7e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 20 May 2011 11:30:31 +0200 Subject: imfile is being totally refactored -- add new conf system when done otherwise we may waste a lot of effort... --- plugins/imfile/imfile.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index 321abbda..4425c949 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -326,30 +326,6 @@ ENDrunInput * ------------------------------------------------------------------------------------------ */ -BEGINbeginCnfLoad -CODESTARTbeginCnfLoad -ENDbeginCnfLoad - - -BEGINendCnfLoad -CODESTARTendCnfLoad -ENDendCnfLoad - - -BEGINcheckCnf -CODESTARTcheckCnf -ENDcheckCnf - - -BEGINactivateCnf -CODESTARTactivateCnf -ENDactivateCnf - - -BEGINfreeCnf -CODESTARTfreeCnf -ENDfreeCnf - /* The function is called by rsyslog before runInput() is called. It is a last chance * to set up anything specific. Most importantly, it can be used to tell rsyslog if the -- cgit v1.2.3 From 6e15840df59b32da46ed313730b7ee538617e0af Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 21 May 2011 04:51:49 +0200 Subject: implemented support for v2 config system in imrelp --- plugins/imrelp/imrelp.c | 129 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 92 insertions(+), 37 deletions(-) diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c index 725a40bb..1b03dcd3 100644 --- a/plugins/imrelp/imrelp.c +++ b/plugins/imrelp/imrelp.c @@ -39,6 +39,7 @@ #include #include "rsyslog.h" #include "dirty.h" +#include "errmsg.h" #include "cfsysline.h" #include "module-template.h" #include "net.h" @@ -53,29 +54,42 @@ MODULE_TYPE_NOKEEP DEF_IMOD_STATIC_DATA DEFobjCurrIf(net) DEFobjCurrIf(prop) +DEFobjCurrIf(errmsg) + +/* forward definitions */ +static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); + /* Module static data */ static relpEngine_t *pRelpEngine; /* our relp engine */ static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this module */ +struct instanceConf_s { + uchar *pszBindPort; /* port to bind to */ + struct instanceConf_s *next; +}; + -/* config settings */ struct modConfData_s { - EMPTY_STRUCT; + rsconf_t *pConf; /* our overall config object */ + instanceConf_t *root, *tail; + int iTCPSessMax; /* max number of sessions */ + int iTCPLstnMax; /* max number of sessions */ + int iStrmDrvrMode; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */ + int bEmitMsgOnClose; /* emit an informational message on close by remote peer */ + int iAddtlFrameDelim; /* addtl frame delimiter, e.g. for netscreen, default none */ + int bDisableLFDelim; /* disable standard LF delimiter */ + int bUseFlowControl; /* use flow control, what means indicate ourselfs a "light delayable" */ + uchar *pszStrmDrvrAuthMode; /* authentication mode to use */ }; +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 */ -/* ------------------------------ callbacks ------------------------------ */ -#if 0 -/* this shall go into a specific ACL module! */ -static int -isPermittedHost(struct sockaddr *addr, char *fromHostFQDN, void __attribute__((unused)) *pUsrSrv, - void __attribute__((unused)) *pUsrSess) -{ - return net.isAllowedSender(net.pAllowedSenders_TCP, addr, fromHostFQDN); -} +//#include "im-helper.h" /* must be included AFTER the type definitions! */ -#endif // #if 0 + +/* ------------------------------ callbacks ------------------------------ */ /* callback for receiving syslog messages. This function is invoked from the * RELP engine when a syslog message arrived. It must return a relpRetVal, @@ -101,7 +115,39 @@ onSyslogRcv(uchar *pHostname, uchar *pIP, uchar *pMsg, size_t lenMsg) /* ------------------------------ end callbacks ------------------------------ */ -static rsRetVal addListener(void __attribute__((unused)) *pVal, uchar *pNewVal) +/* 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. + * rgerhards, 2011-05-04 + */ +static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) +{ + instanceConf_t *inst; + DEFiRet; + + CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + + 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; +} + + +static rsRetVal +addListner(modConfData_t __attribute__((unused)) *modConf, instanceConf_t *inst) { DEFiRet; if(pRelpEngine == NULL) { @@ -111,9 +157,7 @@ static rsRetVal addListener(void __attribute__((unused)) *pVal, uchar *pNewVal) CHKiRet(relpEngineSetSyslogRcv(pRelpEngine, onSyslogRcv)); } - CHKiRet(relpEngineAddListner(pRelpEngine, pNewVal)); - - free(pNewVal); /* we do no longer need it */ + CHKiRet(relpEngineAddListner(pRelpEngine, inst->pszBindPort)); finalize_it: RETiRet; @@ -122,19 +166,37 @@ finalize_it: BEGINbeginCnfLoad CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + /* init legacy config variables */ + resetConfigVariables(NULL, NULL); /* dummy parameters just to fulfill interface def */ ENDbeginCnfLoad BEGINendCnfLoad CODESTARTendCnfLoad + loadModConf = NULL; /* done loading */ ENDendCnfLoad BEGINcheckCnf CODESTARTcheckCnf + /* so far, we have nothing to check... */ ENDcheckCnf +BEGINactivateCnfPrePrivDrop + instanceConf_t *inst; +CODESTARTactivateCnfPrePrivDrop + runModConf = pModConf; + for(inst = runModConf->root ; inst != NULL ; inst = inst->next) { + addListner(pModConf, inst); + } + if(pRelpEngine == NULL) + ABORT_FINALIZE(RS_RET_NO_RUN); +finalize_it: +ENDactivateCnfPrePrivDrop + BEGINactivateCnf CODESTARTactivateCnf ENDactivateCnf @@ -155,34 +217,14 @@ CODESTARTrunInput ENDrunInput -/* initialize and return if will run or not */ BEGINwillRun CODESTARTwillRun - /* first apply some config settings */ - //net.PrintAllowedSenders(2); /* TCP */ - if(pRelpEngine == NULL) - 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("imrelp"), sizeof("imrelp") - 1)); - CHKiRet(prop.ConstructFinalize(pInputName)); -finalize_it: ENDwillRun BEGINafterRun CODESTARTafterRun /* do cleanup here */ -#if 0 - if(net.pAllowedSenders_TCP != NULL) { - net.clearAllowedSenders(net.pAllowedSenders_TCP); - net.pAllowedSenders_TCP = NULL; - } -#endif - - if(pInputName != NULL) - prop.Destruct(&pInputName); ENDafterRun @@ -191,9 +233,14 @@ CODESTARTmodExit if(pRelpEngine != NULL) iRet = relpEngineDestruct(&pRelpEngine); + /* global variable cleanup */ + if(pInputName != NULL) + prop.Destruct(&pInputName); + /* release objects we used */ objRelease(prop, CORE_COMPONENT); objRelease(net, LM_NET_FILENAME); + objRelease(errmsg, CORE_COMPONENT); ENDmodExit @@ -208,6 +255,8 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES ENDqueryEtryPt @@ -218,13 +267,19 @@ CODEmodInit_QueryRegCFSLineHdlr pRelpEngine = NULL; /* request objects we use */ CHKiRet(objUse(prop, CORE_COMPONENT)); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(net, LM_NET_FILENAME)); /* register config file handlers */ CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputrelpserverrun", 0, eCmdHdlrGetWord, - addListener, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + addInstance, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.Construct(&pInputName)); + CHKiRet(prop.SetString(pInputName, UCHAR_CONSTANT("imrelp"), sizeof("imrelp") - 1)); + CHKiRet(prop.ConstructFinalize(pInputName)); ENDmodInit -- cgit v1.2.3 From 0c9ff64a62d3ac84eef48c577d6ab8aa754fd8c3 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 23 May 2011 22:11:42 +0200 Subject: step: imptcp ported to v2 config system --- plugins/imptcp/imptcp.c | 252 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 182 insertions(+), 70 deletions(-) diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 82e64576..25936deb 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -93,12 +93,33 @@ typedef struct configSettings_s { int iAddtlFrameDelim; /* addtl frame delimiter, e.g. for netscreen, default none */ uchar *pszInputName; /* value for inputname property, NULL is OK and handled by core engine */ uchar *lstnIP; /* which IP we should listen on? */ - ruleset_t *pRuleset; /* ruleset to bind listener to (use system default if unspecified) */ + uchar *pszBindRuleset; int wrkrMax; /* max number of workers (actually "helper workers") */ } configSettings_t; - static configSettings_t cs; +struct instanceConf_s { + int bEmitMsgOnClose; + int iAddtlFrameDelim; + uchar *pszBindPort; /* port to bind to */ + uchar *pszBindAddr; /* IP to bind socket to */ + uchar *pszBindRuleset; /* name of ruleset to bind to */ + uchar *pszInputName; /* value for inputname property, NULL is OK and handled by core engine */ + ruleset_t *pBindRuleset; /* ruleset to bind listener to (use system default if unspecified) */ + struct instanceConf_s *next; +}; + + +struct modConfData_s { + rsconf_t *pConf; /* our overall config object */ + instanceConf_t *root, *tail; + int wrkrMax; +}; + +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 */ + +#include "im-helper.h" /* must be included AFTER the type definitions! */ /* data elements describing our running config */ typedef struct ptcpsrv_s ptcpsrv_t; typedef struct ptcplstn_s ptcplstn_t; @@ -198,11 +219,6 @@ static int iMaxLine; /* maximum size of a single message */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); static rsRetVal addLstn(ptcpsrv_t *pSrv, int sock); -struct modConfData_s { - EMPTY_STRUCT; -}; - - /* some simple constructors/destructors */ static void @@ -250,7 +266,7 @@ startupSrv(ptcpsrv_t *pSrv) lstnIP = pSrv->lstnIP == NULL ? UCHAR_CONSTANT("") : pSrv->lstnIP; - DBGPRINTF("imptcp creating listen socket on server '%s', port %s\n", lstnIP, pSrv->port); + DBGPRINTF("imptcp: creating listen socket on server '%s', port %s\n", lstnIP, pSrv->port); memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; @@ -695,7 +711,8 @@ initConfigSettings(void) cs.wrkrMax = 2; cs.iAddtlFrameDelim = TCPSRV_NO_ADDTL_DELIMITER; cs.pszInputName = NULL; - cs.pRuleset = NULL; + cs.pszBindRuleset = NULL; + cs.pszInputName = NULL; cs.lstnIP = NULL; } @@ -854,44 +871,78 @@ finalize_it: } -/* accept a new ruleset to bind. Checks if it exists and complains, if not */ -static rsRetVal setRuleset(void __attribute__((unused)) *pVal, uchar *pszName) +/* 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. + */ +static rsRetVal addInstance(void __attribute__((unused)) *pVal, uchar *pNewVal) { - ruleset_t *pRuleset; - rsRetVal localRet; + instanceConf_t *inst; 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); + CHKmalloc(inst = MALLOC(sizeof(instanceConf_t))); + if(pNewVal == NULL || *pNewVal == '\0') { + errmsg.LogError(0, NO_ERRCODE, "imptcp: port number must be specified, listener ignored"); + } + if((pNewVal == NULL) || (pNewVal == '\0')) { + inst->pszBindPort = NULL; + } else { + CHKmalloc(inst->pszBindPort = ustrdup(pNewVal)); + } + if((cs.lstnIP == NULL) || (cs.lstnIP[0] == '\0')) { + inst->pszBindAddr = NULL; + } else { + CHKmalloc(inst->pszBindAddr = ustrdup(cs.lstnIP)); + } + if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) { + inst->pszBindRuleset = NULL; + } else { + CHKmalloc(inst->pszBindRuleset = ustrdup(cs.pszBindRuleset)); + } + if((cs.pszInputName == NULL) || (cs.pszInputName[0] == '\0')) { + inst->pszInputName = NULL; + } else { + CHKmalloc(inst->pszInputName = ustrdup(cs.pszInputName)); + } + inst->pBindRuleset = NULL; + 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; } - CHKiRet(localRet); - cs.pRuleset = pRuleset; - DBGPRINTF("imptcp current bind ruleset %p: '%s'\n", pRuleset, pszName); finalize_it: - free(pszName); /* no longer needed */ + free(pNewVal); RETiRet; } -static rsRetVal addTCPListener(void __attribute__((unused)) *pVal, uchar *pNewVal) +static inline rsRetVal +addListner(modConfData_t __attribute__((unused)) *modConf, instanceConf_t *inst) { DEFiRet; ptcpsrv_t *pSrv; - CHKmalloc(pSrv = malloc(sizeof(ptcpsrv_t))); + CHKmalloc(pSrv = MALLOC(sizeof(ptcpsrv_t))); pthread_mutex_init(&pSrv->mutSessLst, NULL); pSrv->pSess = NULL; pSrv->pLstn = NULL; - pSrv->bEmitMsgOnClose = cs.bEmitMsgOnClose; - pSrv->port = pNewVal; - pSrv->iAddtlFrameDelim = cs.iAddtlFrameDelim; - cs.pszInputName = NULL; /* moved over to pSrv, we do not own */ - pSrv->lstnIP = cs.lstnIP; - cs.lstnIP = NULL; /* moved over to pSrv, we do not own */ - pSrv->pRuleset = cs.pRuleset; - pSrv->pszInputName = (cs.pszInputName == NULL) ? UCHAR_CONSTANT("imptcp") : cs.pszInputName; + pSrv->bEmitMsgOnClose = inst->bEmitMsgOnClose; + CHKmalloc(pSrv->port = ustrdup(inst->pszBindPort)); + pSrv->iAddtlFrameDelim = inst->iAddtlFrameDelim; + if(inst->pszBindAddr == NULL) + pSrv->lstnIP = NULL; + else { + CHKmalloc(pSrv->lstnIP = ustrdup(inst->pszBindAddr)); + } + pSrv->pRuleset = inst->pBindRuleset; + pSrv->pszInputName = (inst->pszInputName == NULL) ? UCHAR_CONSTANT("imptcp") : ustrdup(inst->pszInputName); CHKiRet(prop.Construct(&pSrv->pInputName)); CHKiRet(prop.SetString(pSrv->pInputName, pSrv->pszInputName, ustrlen(pSrv->pszInputName))); CHKiRet(prop.ConstructFinalize(pSrv->pInputName)); @@ -920,11 +971,11 @@ startWorkerPool(void) { int i; wrkrRunning = 0; - if(cs.wrkrMax > 16) - cs.wrkrMax = 16; /* TODO: make dynamic? */ + if(runModConf->wrkrMax > 16) + runModConf->wrkrMax = 16; /* TODO: make dynamic? */ pthread_mutex_init(&wrkrMut, NULL); pthread_cond_init(&wrkrIdle, NULL); - for(i = 0 ; i < cs.wrkrMax ; ++i) { + for(i = 0 ; i < runModConf->wrkrMax ; ++i) { /* init worker info structure! */ pthread_cond_init(&wrkrInfo[i].run, NULL); wrkrInfo[i].event = NULL; @@ -940,7 +991,7 @@ static inline void stopWorkerPool(void) { int i; - for(i = 0 ; i < cs.wrkrMax ; ++i) { + for(i = 0 ; i < runModConf->wrkrMax ; ++i) { pthread_cond_signal(&wrkrInfo[i].run); /* awake wrkr if not running */ pthread_join(wrkrInfo[i].tid, NULL); DBGPRINTF("imptcp: info: worker %d was called %llu times\n", i, wrkrInfo[i].numCalled); @@ -960,15 +1011,29 @@ static inline rsRetVal startupServers() { DEFiRet; + rsRetVal localRet, lastErr; + int iOK; + int iAll; ptcpsrv_t *pSrv; + iAll = iOK = 0; + lastErr = RS_RET_ERR; pSrv = pSrvRoot; while(pSrv != NULL) { DBGPRINTF("imptcp: starting up server for port %s, name '%s'\n", pSrv->port, pSrv->pszInputName); - startupSrv(pSrv); + localRet = startupSrv(pSrv); + if(localRet == RS_RET_OK) + iOK++; + else + lastErr = localRet; + ++iAll; pSrv = pSrv->pNext; } + DBGPRINTF("imptcp: %d out of %d servers started successfully\n", iOK, iAll); + if(iOK == 0) /* iff all fails, we report an error */ + iRet = lastErr; + RETiRet; } @@ -1088,9 +1153,9 @@ processWorkSet(int nEvents, struct epoll_event events[]) } else { pthread_mutex_lock(&wrkrMut); /* check if there is a free worker */ - for(i = 0 ; (i < cs.wrkrMax) && (wrkrInfo[i].event != NULL) ; ++i) + for(i = 0 ; (i < runModConf->wrkrMax) && (wrkrInfo[i].event != NULL) ; ++i) /*do search*/; - if(i < cs.wrkrMax) { + if(i < runModConf->wrkrMax) { /* worker free -> use it! */ wrkrInfo[i].event = events+iEvt; ++wrkrRunning; @@ -1152,26 +1217,99 @@ wrkr(void *myself) BEGINbeginCnfLoad CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + /* init legacy config vars */ + initConfigSettings(); ENDbeginCnfLoad BEGINendCnfLoad CODESTARTendCnfLoad + /* persist module-specific settings from legacy config system */ + loadModConf->wrkrMax = cs.wrkrMax; + + loadModConf = NULL; /* done loading */ + /* free legacy config vars */ + free(cs.pszInputName); + free(cs.lstnIP); ENDendCnfLoad +/* function to generate error message if framework does not find requested ruleset */ +static inline void +std_checkRuleset_genErrMsg(__attribute__((unused)) modConfData_t *modConf, instanceConf_t *inst) +{ + errmsg.LogError(0, NO_ERRCODE, "imptcp: ruleset '%s' for port %s not found - " + "using default ruleset instead", inst->pszBindRuleset, + inst->pszBindPort); +} BEGINcheckCnf + instanceConf_t *inst; CODESTARTcheckCnf + for(inst = pModConf->root ; inst != NULL ; inst = inst->next) { + std_checkRuleset(pModConf, inst); + } ENDcheckCnf +BEGINactivateCnfPrePrivDrop + instanceConf_t *inst; +CODESTARTactivateCnfPrePrivDrop + iMaxLine = glbl.GetMaxLine(); /* get maximum size we currently support */ + + runModConf = pModConf; + for(inst = runModConf->root ; inst != NULL ; inst = inst->next) { + addListner(pModConf, inst); + } + if(pSrvRoot == NULL) { + errmsg.LogError(0, RS_RET_NO_LSTN_DEFINED, "imptcp: no ptcp server defined, module can not run."); + ABORT_FINALIZE(RS_RET_NO_RUN); + } +#if defined(EPOLL_CLOEXEC) && defined(HAVE_EPOLL_CREATE1) + DBGPRINTF("imptcp uses epoll_create1()\n"); + epollfd = epoll_create1(EPOLL_CLOEXEC); + if(epollfd < 0 && errno == ENOSYS) +#endif + { + DBGPRINTF("imptcp uses epoll_create()\n"); + /* reading the docs, the number of epoll events passed to + * epoll_create() seems not to be used at all in kernels. So + * we just provide "a" number, happens to be 10. + */ + epollfd = epoll_create(10); + } + + if(epollfd < 0) { + errmsg.LogError(0, RS_RET_EPOLL_CR_FAILED, "error: epoll_create() failed"); + ABORT_FINALIZE(RS_RET_NO_RUN); + } + + /* start up servers, but do not yet read input data */ + CHKiRet(startupServers()); + DBGPRINTF("imptcp started up, but not yet receiving data\n"); +finalize_it: +ENDactivateCnfPrePrivDrop + + BEGINactivateCnf CODESTARTactivateCnf + /* nothing to do, all done pre priv drop */ ENDactivateCnf BEGINfreeCnf + instanceConf_t *inst, *del; CODESTARTfreeCnf + for(inst = pModConf->root ; inst != NULL ; ) { + free(inst->pszBindPort); + free(inst->pszBindAddr); + free(inst->pszBindRuleset); + free(inst->pszInputName); + del = inst; + inst = inst->next; + free(del); + } ENDfreeCnf @@ -1197,37 +1335,6 @@ ENDrunInput /* initialize and return if will run or not */ BEGINwillRun CODESTARTwillRun - /* first apply some config settings */ - iMaxLine = glbl.GetMaxLine(); /* get maximum size we currently support */ - - if(pSrvRoot == NULL) { - errmsg.LogError(0, RS_RET_NO_LSTN_DEFINED, "error: no ptcp server defined, module can not run."); - ABORT_FINALIZE(RS_RET_NO_RUN); - } - -#if defined(EPOLL_CLOEXEC) && defined(HAVE_EPOLL_CREATE1) - DBGPRINTF("imptcp uses epoll_create1()\n"); - epollfd = epoll_create1(EPOLL_CLOEXEC); - if(epollfd < 0 && errno == ENOSYS) -#endif - { - DBGPRINTF("imptcp uses epoll_create()\n"); - /* reading the docs, the number of epoll events passed to - * epoll_create() seems not to be used at all in kernels. So - * we just provide "a" number, happens to be 10. - */ - epollfd = epoll_create(10); - } - - if(epollfd < 0) { - errmsg.LogError(0, RS_RET_EPOLL_CR_FAILED, "error: epoll_create() failed"); - ABORT_FINALIZE(RS_RET_NO_RUN); - } - - /* start up servers, but do not yet read input data */ - CHKiRet(startupServers()); - DBGPRINTF("imptcp started up, but not yet receiving data\n"); -finalize_it: ENDwillRun @@ -1318,6 +1425,8 @@ ENDisCompatibleWithFeature BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES ENDqueryEtryPt @@ -1339,9 +1448,12 @@ CODEmodInit_QueryRegCFSLineHdlr pthread_attr_init(&wrkrThrdAttr); pthread_attr_setstacksize(&wrkrThrdAttr, 2048*1024); + /* init legacy config settings */ + initConfigSettings(); + /* register config file handlers */ CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverrun"), 0, eCmdHdlrGetWord, - addTCPListener, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + addInstance, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpservernotifyonconnectionclose"), 0, eCmdHdlrBinary, NULL, &cs.bEmitMsgOnClose, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserveraddtlframedelimiter"), 0, eCmdHdlrInt, @@ -1353,7 +1465,7 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverlistenip"), 0, eCmdHdlrGetWord, NULL, &cs.lstnIP, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("inputptcpserverbindruleset"), 0, - eCmdHdlrGetWord, setRuleset, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + eCmdHdlrGetWord, NULL, cs.pszBindRuleset, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr(UCHAR_CONSTANT("resetconfigvariables"), 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); ENDmodInit -- cgit v1.2.3 From 59056371156616274d9970300b3ab02432201422 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 24 May 2011 09:34:14 +0200 Subject: enhanced imfile to support input batching --- ChangeLog | 1 + plugins/imfile/imfile.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 665ed184..0d35ce0f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ +- enhanced imfile to support input batching --------------------------------------------------------------------------- Version 5.8.1 [V5-stable] (rgerhards), 2011-05-19 - bugfix: invalid processing in QUEUE_FULL condition diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index cac3a55d..415eb137 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -64,6 +64,7 @@ DEFobjCurrIf(strm) DEFobjCurrIf(prop) DEFobjCurrIf(ruleset) +#define NUM_MULTISUB 1024 /* max number of submits -- TODO: make configurable */ typedef struct fileInfo_s { uchar *pszFileName; uchar *pszTag; @@ -76,6 +77,7 @@ typedef struct fileInfo_s { strm_t *pStrm; /* its stream (NULL if not assigned) */ int readMode; /* which mode to use in ReadMulteLine call? */ ruleset_t *pRuleset; /* ruleset to bind listener to (use system default if unspecified) */ + multi_submit_t multiSub; } fileInfo_t; @@ -122,7 +124,9 @@ static rsRetVal enqLine(fileInfo_t *pInfo, cstr_t *cstrLine) pMsg->iFacility = LOG_FAC(pInfo->iFacility); pMsg->iSeverity = LOG_PRI(pInfo->iSeverity); MsgSetRuleset(pMsg, pInfo->pRuleset); - CHKiRet(submitMsg(pMsg)); + pInfo->multiSub.ppMsgs[pInfo->multiSub.nElem++] = pMsg; + if(pInfo->multiSub.nElem == pInfo->multiSub.maxElem) + CHKiRet(multiSubmitMsg(&pInfo->multiSub)); finalize_it: RETiRet; } @@ -229,8 +233,13 @@ static rsRetVal pollFile(fileInfo_t *pThis, int *pbHadFileData) pThis->nRecords = 0; } } + /* NOTE: This is usually not reached due to loop exit via CHKiRet() only! */ finalize_it: + if(pThis->multiSub.nElem > 0) { + /* submit everything that was not yet submitted */ + CHKiRet(multiSubmitMsg(&pThis->multiSub)); + } ; /*EMPTY STATEMENT - needed to keep compiler happy - see below! */ /* Note: the problem above is that pthread:cleanup_pop() is a macro which * evaluates to something like "} while(0);". So the code would become @@ -513,6 +522,9 @@ static rsRetVal addMonitor(void __attribute__((unused)) *pVal, uchar *pNewVal) 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->iPersistStateInterval = iPersistStateInterval; -- cgit v1.2.3 From ffdc33e3f178ad85ba5c2c9f7fcee98b743e9d5e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 24 May 2011 10:09:43 +0200 Subject: imfile: added $InputFileMaxLinesAtOnce directive --- ChangeLog | 1 + doc/imfile.html | 11 +++++++++-- plugins/imfile/imfile.c | 11 ++++++++++- tests/inputfilegen.c | 1 + 4 files changed, 21 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0d35ce0f..d139f5b3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ +- imfile: added $InputFileMaxLinesAtOnce directive - enhanced imfile to support input batching --------------------------------------------------------------------------- Version 5.8.1 [V5-stable] (rgerhards), 2011-05-19 diff --git a/doc/imfile.html b/doc/imfile.html index 60726ceb..60bbbeea 100644 --- a/doc/imfile.html +++ b/doc/imfile.html @@ -98,9 +98,16 @@ performance, especially when set to a low value. Frequently writing the state file is very time consuming.
      • $InputFileReadMode [mode]
        Available in 5.7.5+ +
      • $InputFileMaxLinesAtOnce [number]
        +Available in 5.9.0+
        -Mode to be used when reading lines. 0 (the default) means that each line is forwarded -as its own log message. +This is useful if multiple files need to be monitored. If set to 0, each file +will be fully processed and then processing switches to the next file +(this was the default in previous versions). If it is set, a maximum of +[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>
        Available in 5.7.5+, 6.1.5+ Binds the listener to a specific
        ruleset.
      • diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index 415eb137..9bc84220 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -72,6 +72,7 @@ typedef struct fileInfo_s { uchar *pszStateFile; /* file in which state between runs is to be stored */ int iFacility; int iSeverity; + int maxLinesAtOnce; int nRecords; /**< How many records did we process before persisting the stream? */ int iPersistStateInterval; /**< how often should state be persisted? (0=on close only) */ strm_t *pStrm; /* its stream (NULL if not assigned) */ @@ -93,6 +94,7 @@ static int iPersistStateInterval = 0; /* how often if state file to be persisted 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 int iFilPtr = 0; /* number of files to be monitored; pointer to next free spot during config */ @@ -210,6 +212,7 @@ static void pollFileCancelCleanup(void *pArg) static rsRetVal pollFile(fileInfo_t *pThis, int *pbHadFileData) { cstr_t *pCStr = NULL; + int nProcessed = 0; DEFiRet; ASSERT(pbHadFileData != NULL); @@ -224,7 +227,10 @@ static rsRetVal pollFile(fileInfo_t *pThis, int *pbHadFileData) /* loop below will be exited when strmReadLine() returns EOF */ while(glbl.GetGlobalInputTermState() == 0) { + if(pThis->maxLinesAtOnce != 0 && nProcessed >= pThis->maxLinesAtOnce) + break; CHKiRet(strm.ReadLine(pThis->pStrm, &pCStr, pThis->readMode)); + ++nProcessed; *pbHadFileData = 1; /* this is just a flag, so set it and forget it */ CHKiRet(enqLine(pThis, pCStr)); /* process line */ rsCStrDestruct(&pCStr); /* discard string (must be done by us!) */ @@ -233,7 +239,6 @@ static rsRetVal pollFile(fileInfo_t *pThis, int *pbHadFileData) pThis->nRecords = 0; } } - /* NOTE: This is usually not reached due to loop exit via CHKiRet() only! */ finalize_it: if(pThis->multiSub.nElem > 0) { @@ -484,6 +489,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a iSeverity = 5; /* notice, as of rfc 3164 */ readMode = 0; pBindRuleset = NULL; + maxLinesAtOnce = 10240; RETiRet; } @@ -527,6 +533,7 @@ static rsRetVal addMonitor(void __attribute__((unused)) *pVal, uchar *pNewVal) pThis->multiSub.nElem = 0; pThis->iSeverity = iSeverity; pThis->iFacility = iFacility; + pThis->maxLinesAtOnce = maxLinesAtOnce; pThis->iPersistStateInterval = iPersistStateInterval; pThis->nRecords = 0; pThis->readMode = readMode; @@ -604,6 +611,8 @@ CODEmodInit_QueryRegCFSLineHdlr NULL, &iPollInterval, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilereadmode", 0, eCmdHdlrInt, NULL, &readMode, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilemaxlinesatonce", 0, eCmdHdlrSize, + NULL, &maxLinesAtOnce, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilepersiststateinterval", 0, eCmdHdlrInt, NULL, &iPersistStateInterval, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputfilebindruleset", 0, eCmdHdlrGetWord, diff --git a/tests/inputfilegen.c b/tests/inputfilegen.c index 26fb79af..0ff8d049 100644 --- a/tests/inputfilegen.c +++ b/tests/inputfilegen.c @@ -1,5 +1,6 @@ /* generate an input file suitable for use by the testbench * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH. + * usage: ./inputfilegen num-lines > file * Part of rsyslog, licensed under GPLv3 */ #include -- cgit v1.2.3 From a9223031a6effeaf3673beb752c12a29f5e8f83d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 25 May 2011 14:04:14 +0200 Subject: step: imklog (linux) moved to v2 config system --- plugins/imklog/imklog.c | 182 ++++++++++++++++++++++++++++++++---------------- plugins/imklog/imklog.h | 26 +++++-- plugins/imklog/ksym.c | 32 ++++----- plugins/imklog/linux.c | 59 ++++++++-------- plugins/imptcp/imptcp.c | 1 - 5 files changed, 188 insertions(+), 112 deletions(-) diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c index 425dec7f..65a4cd57 100644 --- a/plugins/imklog/imklog.c +++ b/plugins/imklog/imklog.c @@ -18,7 +18,10 @@ * Please note that this file replaces the klogd daemon that was * also present in pre-v3 versions of rsyslog. * - * Copyright (C) 2008, 2009 by Rainer Gerhards and Adiscon GmbH + * To test under Linux: + * echo test1 > /dev/kmsg + * + * Copyright (C) 2008-2011 by Rainer Gerhards and Adiscon GmbH * * This file is part of rsyslog. * @@ -66,32 +69,43 @@ DEFobjCurrIf(datetime) DEFobjCurrIf(glbl) DEFobjCurrIf(prop) -/* configuration settings */ - -struct modConfData_s { - EMPTY_STRUCT; -}; - -int dbgPrintSymbols = 0; /* this one is extern so the helpers can access it! */ -int symbols_twice = 0; -int use_syscall = 0; -int symbol_lookup = 0; /* on recent kernels > 2.6, the kernel does this */ -int bPermitNonKernel = 0; /* permit logging of messages not having LOG_KERN facility */ -int iFacilIntMsg; /* the facility to use for internal messages (set by driver) */ -uchar *pszPath = NULL; -int console_log_level = -1; -/* TODO: configuration for the following directives must be implemented. It - * was not done yet because we either do not yet have a config handler for - * that type or I thought it was acceptable to push it to a later stage when - * I gained more handson experience with the input module interface (and the - * changes resulting from that). -- rgerhards, 2007-12-20 - */ -char *symfile = NULL; +/* 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 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! */ +} 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 prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this module */ 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; + cs.symfile = NULL; + cs.iFacilIntMsg = klogFacilIntMsg(); +} + + /* enqueue the the kernel message into the message queue. * The provided msg string is not freed - thus must be done * by the caller. @@ -178,8 +192,7 @@ rsRetVal imklogLogIntMsg(int priority, char *fmt, ...) pLogMsg = msgBuf; va_end(ap); - iRet = enqMsg((uchar*)pLogMsg, (uchar*) ((iFacilIntMsg == LOG_KERN) ? "kernel:" : "imklog:"), - iFacilIntMsg, LOG_PRI(priority)); + logmsgInternal(NO_ERRCODE ,priority, msgBuf, 0); RETiRet; } @@ -216,7 +229,7 @@ rsRetVal Syslog(int priority, uchar *pMsg) /* if we don't get the pri, we use whatever we were supplied */ /* ignore non-kernel messages if not permitted */ - if(bPermitNonKernel == 0 && LOG_FAC(priority) != LOG_KERN) + if(cs.bPermitNonKernel == 0 && LOG_FAC(priority) != LOG_KERN) FINALIZE; /* silently ignore */ iRet = enqMsg((uchar*)pMsg, (uchar*) "kernel:", LOG_FAC(priority), LOG_PRI(priority)); @@ -248,7 +261,7 @@ CODESTARTrunInput * and then submits it to the rsyslog main queue. * rgerhards, 2008-04-09 */ - CHKiRet(klogLogKMsg()); + CHKiRet(klogLogKMsg(runModConf)); } finalize_it: ENDrunInput @@ -256,11 +269,45 @@ ENDrunInput BEGINbeginCnfLoad CODESTARTbeginCnfLoad + loadModConf = pModConf; + pModConf->pConf = pConf; + /* init legacy config vars */ + initConfigSettings(); ENDbeginCnfLoad 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; + } + cs.symfile = NULL; + + loadModConf = NULL; /* done loading */ + /* free legacy config vars */ + free(cs.pszPath); + cs.pszPath = NULL; + free(cs.symfile); + cs.symfile = NULL; ENDendCnfLoad @@ -269,6 +316,13 @@ CODESTARTcheckCnf ENDcheckCnf +BEGINactivateCnfPrePrivDrop +CODESTARTactivateCnfPrePrivDrop + runModConf = pModConf; + iRet = klogWillRun(runModConf); +ENDactivateCnfPrePrivDrop + + BEGINactivateCnf CODESTARTactivateCnf ENDactivateCnf @@ -281,55 +335,49 @@ ENDfreeCnf BEGINwillRun CODESTARTwillRun - /* we need to create the inputName property (only once during our lifetime) */ - CHKiRet(prop.CreateStringProp(&pInputName, UCHAR_CONSTANT("imklog"), sizeof("imklog") - 1)); - CHKiRet(prop.CreateStringProp(&pLocalHostIP, UCHAR_CONSTANT("127.0.0.1"), sizeof("127.0.0.1") - 1)); - - iRet = klogWillRun(); -finalize_it: ENDwillRun BEGINafterRun CODESTARTafterRun - iRet = klogAfterRun(); + iRet = klogAfterRun(runModConf); +ENDafterRun + +BEGINmodExit +CODESTARTmodExit if(pInputName != NULL) prop.Destruct(&pInputName); if(pLocalHostIP != NULL) prop.Destruct(&pLocalHostIP); -ENDafterRun - -BEGINmodExit -CODESTARTmodExit /* release objects we used */ objRelease(glbl, CORE_COMPONENT); objRelease(datetime, CORE_COMPONENT); objRelease(prop, CORE_COMPONENT); - if(pszPath != NULL) - free(pszPath); ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_IMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_QUERIES +CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES ENDqueryEtryPt static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { - dbgPrintSymbols = 0; - symbols_twice = 0; - use_syscall = 0; - symfile = NULL; - symbol_lookup = 0; - bPermitNonKernel = 0; - if(pszPath != NULL) { - free(pszPath); - pszPath = NULL; + cs.dbgPrintSymbols = 0; + cs.symbols_twice = 0; + cs.use_syscall = 0; + cs.symfile = NULL; + cs.symbol_lookup = 0; + cs.bPermitNonKernel = 0; + if(cs.pszPath != NULL) { + free(cs.pszPath); + cs.pszPath = NULL; } - iFacilIntMsg = klogFacilIntMsg(); + cs.iFacilIntMsg = klogFacilIntMsg(); return RS_RET_OK; } @@ -341,17 +389,31 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(glbl, CORE_COMPONENT)); CHKiRet(objUse(prop, CORE_COMPONENT)); - iFacilIntMsg = klogFacilIntMsg(); - - CHKiRet(omsdRegCFSLineHdlr((uchar *)"debugprintkernelsymbols", 0, eCmdHdlrBinary, NULL, &dbgPrintSymbols, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogpath", 0, eCmdHdlrGetWord, NULL, &pszPath, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbollookup", 0, eCmdHdlrBinary, NULL, &symbol_lookup, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbolstwice", 0, eCmdHdlrBinary, NULL, &symbols_twice, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogusesyscallinterface", 0, eCmdHdlrBinary, NULL, &use_syscall, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogpermitnonkernelfacility", 0, eCmdHdlrBinary, NULL, &bPermitNonKernel, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogconsoleloglevel", 0, eCmdHdlrInt, NULL, &console_log_level, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"kloginternalmsgfacility", 0, eCmdHdlrFacility, NULL, &iFacilIntMsg, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + /* we need to create the inputName property (only once during our lifetime) */ + CHKiRet(prop.CreateStringProp(&pInputName, UCHAR_CONSTANT("imklog"), sizeof("imklog") - 1)); + CHKiRet(prop.CreateStringProp(&pLocalHostIP, UCHAR_CONSTANT("127.0.0.1"), sizeof("127.0.0.1") - 1)); + + /* init legacy config settings */ + initConfigSettings(); + + CHKiRet(omsdRegCFSLineHdlr((uchar *)"debugprintkernelsymbols", 0, eCmdHdlrBinary, + NULL, &cs.dbgPrintSymbols, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogpath", 0, eCmdHdlrGetWord, + NULL, &cs.pszPath, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbollookup", 0, eCmdHdlrBinary, + NULL, &cs.symbol_lookup, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogsymbolstwice", 0, eCmdHdlrBinary, + NULL, &cs.symbols_twice, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogusesyscallinterface", 0, eCmdHdlrBinary, + NULL, &cs.use_syscall, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogpermitnonkernelfacility", 0, eCmdHdlrBinary, + NULL, &cs.bPermitNonKernel, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"klogconsoleloglevel", 0, eCmdHdlrInt, + NULL, &cs.console_log_level, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"kloginternalmsgfacility", 0, eCmdHdlrFacility, + NULL, &cs.iFacilIntMsg, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, + resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); ENDmodInit /* vim:set ai: */ diff --git a/plugins/imklog/imklog.h b/plugins/imklog/imklog.h index c183026d..447211dc 100644 --- a/plugins/imklog/imklog.h +++ b/plugins/imklog/imklog.h @@ -30,22 +30,37 @@ #include "rsyslog.h" #include "dirty.h" +/* we need to have the modConf type present in all submodules */ +struct modConfData_s { + int dbgPrintSymbols; + int symbols_twice; + int use_syscall; + int symbol_lookup; + int bPermitNonKernel; + int iFacilIntMsg; + uchar *pszPath; + int console_log_level; + char *symfile; + rsconf_t *pConf; +}; + /* interface to "drivers" * the platform specific drivers must implement these entry points. Only one * driver may be active at any given time, thus we simply rely on the linker * to resolve the addresses. * rgerhards, 2008-04-09 */ -rsRetVal klogLogKMsg(void); -rsRetVal klogWillRun(void); -rsRetVal klogAfterRun(void); -int klogFacilIntMsg(void); +rsRetVal klogLogKMsg(modConfData_t *pModConf); +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; @@ -53,6 +68,7 @@ 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))); @@ -60,7 +76,7 @@ rsRetVal Syslog(int priority, uchar *msg); /* prototypes */ extern int klog_getMaxLine(void); /* work-around for klog drivers to get configured max line size */ -extern int InitKsyms(char *); +extern int InitKsyms(modConfData_t*); extern void DeinitKsyms(void); extern int InitMsyms(void); extern void DeinitMsyms(void); diff --git a/plugins/imklog/ksym.c b/plugins/imklog/ksym.c index ebaec011..beb5c637 100644 --- a/plugins/imklog/ksym.c +++ b/plugins/imklog/ksym.c @@ -139,11 +139,11 @@ static char *system_maps[] = /* Function prototypes. */ -static char *FindSymbolFile(void); +static char *FindSymbolFile(modConfData_t *); static int AddSymbol(unsigned long, char*); static void FreeSymbols(void); static int CheckVersion(char *); -static int CheckMapVersion(char *); +static int CheckMapVersion(modConfData_t *, char *); /************************************************************************* @@ -152,7 +152,7 @@ static int CheckMapVersion(char *); * Purpose: This function is responsible for initializing and loading * the data tables used by the kernel address translations. * - * Arguements: (char *) mapfile + * Arguements: (char *) mapfile (taken from config) * * mapfile:-> A pointer to a complete path * specification of the file containing @@ -163,7 +163,7 @@ static int CheckMapVersion(char *); * A boolean style context is returned. The return value will * be true if initialization was successful. False if not. **************************************************************************/ -extern int InitKsyms(char *mapfile) +extern int InitKsyms(modConfData_t *pModConf) { auto char type, sym[512]; @@ -182,20 +182,20 @@ extern int InitKsyms(char *mapfile) /* Search for and open the file containing the kernel symbols. */ - if ( mapfile != NULL ) { - if ( (sym_file = fopen(mapfile, "r")) == NULL ) + if ( pModConf->symfile != NULL ) { + if ( (sym_file = fopen(pModConf->symfile, "r")) == NULL ) { - imklogLogIntMsg(LOG_WARNING, "Cannot open map file: %s.", mapfile); + imklogLogIntMsg(LOG_WARNING, "Cannot open map file: %s.", pModConf->symfile); return(0); } } else { - if ( (mapfile = FindSymbolFile()) == NULL ) { + if ( (pModConf->symfile = FindSymbolFile(pModConf)) == NULL ) { imklogLogIntMsg(LOG_WARNING, "Cannot find map file."); dbgprintf("Cannot find map file.\n"); return(0); } - if ( (sym_file = fopen(mapfile, "r")) == NULL ) { + if ( (sym_file = fopen(pModConf->symfile, "r")) == NULL ) { imklogLogIntMsg(LOG_WARNING, "Cannot open map file."); dbgprintf("Cannot open map file.\n"); return(0); @@ -216,7 +216,7 @@ extern int InitKsyms(char *mapfile) fclose(sym_file); return(0); } - if(dbgPrintSymbols) + if(pModConf->dbgPrintSymbols) dbgprintf("Address: %lx, Type: %c, Symbol: %s\n", address, type, sym); if ( AddSymbol(address, sym) == 0 ) { @@ -230,7 +230,7 @@ extern int InitKsyms(char *mapfile) } - imklogLogIntMsg(LOG_INFO, "Loaded %d symbols from %s.", num_syms, mapfile); + imklogLogIntMsg(LOG_INFO, "Loaded %d symbols from %s.", num_syms, pModConf->symfile); switch(version) { case -1: imklogLogIntMsg(LOG_WARNING, "Symbols do not match kernel version."); @@ -290,7 +290,7 @@ extern void DeinitKsyms(void) * caller which points to the name of the file containing * the symbol table to be used. **************************************************************************/ -static char *FindSymbolFile(void) +static char *FindSymbolFile(modConfData_t *pModConf) { auto char *file = NULL, **mf = system_maps; @@ -310,7 +310,7 @@ static char *FindSymbolFile(void) snprintf(mysymfile, sizeof(mysymfile), "%s-%s", *mf, utsname.release); dbgprintf("Trying %s.\n", mysymfile); if((sym_file = fopen(mysymfile, "r")) != NULL) { - if(CheckMapVersion(mysymfile) == 1) + if(CheckMapVersion(pModConf, mysymfile) == 1) file = mysymfile; fclose(sym_file); } @@ -318,7 +318,7 @@ static char *FindSymbolFile(void) sprintf (mysymfile, "%s", *mf); dbgprintf("Trying %s.\n", mysymfile); if((sym_file = fopen(mysymfile, "r")) != NULL ) { - if (CheckMapVersion(mysymfile) == 1) + if (CheckMapVersion(pModConf, mysymfile) == 1) file = mysymfile; fclose(sym_file); } @@ -454,7 +454,7 @@ static int CheckVersion(char *version) * 1:-> The executing kernel is of the same version * as the version of the map file. **************************************************************************/ -static int CheckMapVersion(char *fname) +static int CheckMapVersion(modConfData_t *pModConf, char *fname) { int version; FILE *sym_file; @@ -477,7 +477,7 @@ static int CheckMapVersion(char *fname) fclose(sym_file); return(0); } - if(dbgPrintSymbols) + if(pModConf->dbgPrintSymbols) dbgprintf("Address: %lx, Type: %c, Symbol: %s\n", address, type, sym); version = CheckVersion(sym); } diff --git a/plugins/imklog/linux.c b/plugins/imklog/linux.c index 727708a5..97171e4f 100644 --- a/plugins/imklog/linux.c +++ b/plugins/imklog/linux.c @@ -85,15 +85,15 @@ static enum LOGSRC {none, proc, kernel} logsrc; extern int ksyslog(int type, char *buf, int len); -static uchar *GetPath(void) +static uchar *GetPath(modConfData_t *pModConf) { - return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG); + return pModConf->pszPath ? pModConf->pszPath : UCHAR_CONSTANT(_PATH_KLOG); } -static void CloseLogSrc(void) +static void CloseLogSrc(modConfData_t *pModConf) { /* Turn on logging of messages to console, but only if a log level was speficied */ - if(console_log_level != -1) + if(pModConf->console_log_level != -1) ksyslog(7, NULL, 0); /* Shutdown the log sources. */ @@ -114,13 +114,13 @@ static void CloseLogSrc(void) } -static enum LOGSRC GetKernelLogSrc(void) +static enum LOGSRC GetKernelLogSrc(modConfData_t *pModConf) { auto struct stat sb; /* Set level of kernel console messaging.. */ - if ( (console_log_level != -1) && - (ksyslog(8, NULL, console_log_level) < 0) && + if ( (pModConf->console_log_level != -1) && + (ksyslog(8, NULL, pModConf->console_log_level) < 0) && (errno == EINVAL) ) { /* @@ -137,8 +137,8 @@ static enum LOGSRC GetKernelLogSrc(void) * First do a stat to determine whether or not the proc based * file system is available to get kernel messages from. */ - if ( use_syscall || - ((stat((char*)GetPath(), &sb) < 0) && (errno == ENOENT)) ) + if ( pModConf->use_syscall || + ((stat((char*)GetPath(pModConf), &sb) < 0) && (errno == ENOENT)) ) { /* Initialize kernel logging. */ ksyslog(1, NULL, 0); @@ -147,14 +147,14 @@ static enum LOGSRC GetKernelLogSrc(void) return(kernel); } - if ( (kmsg = open((char*)GetPath(), O_RDONLY|O_CLOEXEC)) < 0 ) + if ( (kmsg = open((char*)GetPath(pModConf), O_RDONLY|O_CLOEXEC)) < 0 ) { imklogLogIntMsg(LOG_ERR, "imklog: Cannot open proc file system, %d.\n", errno); ksyslog(7, NULL, 0); return(none); } - imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, GetPath()); + imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, GetPath(pModConf)); return(proc); } @@ -200,7 +200,7 @@ static int copyin( uchar *line, int space, * original text. Just in case somebody wants to run their own Oops * analysis on the syslog, e.g. ksymoops. */ -static void LogLine(char *ptr, int len) +static void LogLine(modConfData_t *pModConf, char *ptr, int len) { enum parse_state_enum { PARSING_TEXT, @@ -278,7 +278,7 @@ static void LogLine(char *ptr, int len) Syslog(LOG_INFO, line_buff); line = line_buff; space = sizeof(line_buff)-1; - if (symbols_twice) { + if(pModConf->symbols_twice) { if (symbols_expanded) { /* reprint this line without symbol lookup */ symbols_expanded = 0; @@ -376,8 +376,7 @@ static void LogLine(char *ptr, int len) value = strtoul((char*)(sym_start+1), (char **) 0, 16); *(line-1) = '>'; /* put back delim */ - if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 ) - { + if(!pModConf->symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 ) { parse_state = PARSING_TEXT; break; } @@ -415,7 +414,7 @@ static void LogLine(char *ptr, int len) } -static void LogKernelLine(void) +static void LogKernelLine(modConfData_t *pModConf) { auto int rdcnt; @@ -433,12 +432,12 @@ static void LogKernelLine(void) imklogLogIntMsg(LOG_ERR, "imklog Error return from sys_sycall: %d\n", errno); } else - LogLine(log_buffer, rdcnt); + LogLine(pModConf, log_buffer, rdcnt); return; } -static void LogProcLine(void) +static void LogProcLine(modConfData_t *pModConf) { auto int rdcnt; @@ -454,7 +453,7 @@ static void LogProcLine(void) return; imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno)); } else { - LogLine(log_buffer, rdcnt); + LogLine(pModConf, log_buffer, rdcnt); } return; @@ -464,15 +463,15 @@ static void LogProcLine(void) /* to be called in the module's WillRun entry point * rgerhards, 2008-04-09 */ -rsRetVal klogLogKMsg(void) +rsRetVal klogLogKMsg(modConfData_t *pModConf) { DEFiRet; switch(logsrc) { case kernel: - LogKernelLine(); + LogKernelLine(pModConf); break; case proc: - LogProcLine(); + LogProcLine(pModConf); break; case none: /* TODO: We need to handle this case here somewhat more intelligent @@ -489,19 +488,19 @@ rsRetVal klogLogKMsg(void) /* to be called in the module's WillRun entry point * rgerhards, 2008-04-09 */ -rsRetVal klogWillRun(void) +rsRetVal klogWillRun(modConfData_t *pModConf) { DEFiRet; /* Initialize this module. If that fails, we tell the engine we don't like to run */ /* Determine where kernel logging information is to come from. */ - logsrc = GetKernelLogSrc(); + logsrc = GetKernelLogSrc(pModConf); if(logsrc == none) { iRet = RS_RET_NO_KERNEL_LOGSRC; } else { - if (symbol_lookup) { - symbol_lookup = (InitKsyms(symfile) == 1); - symbol_lookup |= InitMsyms(); - if (symbol_lookup == 0) { + if(pModConf->symbol_lookup) { + pModConf->symbol_lookup = (InitKsyms(pModConf) == 1); + pModConf->symbol_lookup |= InitMsyms(); + if(pModConf->symbol_lookup == 0) { imklogLogIntMsg(LOG_WARNING, "cannot find any symbols, turning off symbol lookups"); } } @@ -514,12 +513,12 @@ rsRetVal klogWillRun(void) /* to be called in the module's AfterRun entry point * rgerhards, 2008-04-09 */ -rsRetVal klogAfterRun(void) +rsRetVal klogAfterRun(modConfData_t *pModConf) { DEFiRet; /* cleanup here */ if(logsrc != none) - CloseLogSrc(); + CloseLogSrc(pModConf); DeinitKsyms(); DeinitMsyms(); diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 25936deb..713ee83c 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -1435,7 +1435,6 @@ BEGINmodInit() CODESTARTmodInit *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr - initConfigSettings(); /* request objects we use */ CHKiRet(objUse(glbl, CORE_COMPONENT)); CHKiRet(objUse(prop, CORE_COMPONENT)); -- cgit v1.2.3 From 7c12000d865b0885c2d5125f14742a54e41a270c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 30 May 2011 08:37:35 +0200 Subject: regression fix: config validation code affected by recent changes did not return with proper return value --- runtime/rsconf.c | 15 ++++++++++----- tests/validation-run.sh | 3 +++ tools/syslogd.c | 4 ++++ 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 0f944539..ed6e9ee7 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -1003,7 +1003,7 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! localRet = conf.processConfFile(loadConf, confFile); CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions)); - if(localRet != RS_RET_OK) { + if(localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) { errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", confFile); bHadConfigErr = 1; } else if(iNbrActions == 0) { @@ -1042,12 +1042,20 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! CHKiRet(validateConf()); + + /* return warning state if we had some acceptable problems */ + if(bHadConfigErr) { + iRet = RS_RET_NONFATAL_CONFIG_ERR; + } + /* we are done checking the config - now validate if we should actually run or not. * If not, terminate. -- rgerhards, 2008-07-25 * TODO: iConfigVerify -- should it be pulled from the config, or leave as is (option)? */ if(iConfigVerify) { - ABORT_FINALIZE(RS_RET_VALIDATION_RUN); + if(iRet == RS_RET_OK) + iRet = RS_RET_VALIDATION_RUN; + FINALIZE; } /* all OK, pass loaded conf to caller */ @@ -1057,9 +1065,6 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! dbgprintf("rsyslog finished loading initial config %p\n", loadConf); rsconfDebugPrint(loadConf); - /* return warning state if we had some acceptable problems */ - if(bHadConfigErr) - iRet = RS_RET_NONFATAL_CONFIG_ERR; finalize_it: RETiRet; } diff --git a/tests/validation-run.sh b/tests/validation-run.sh index cc29482a..a68ee8ae 100755 --- a/tests/validation-run.sh +++ b/tests/validation-run.sh @@ -25,16 +25,19 @@ echo \[validation-run.sh\]: testing configuraton validation echo "testing a failed configuration verification run" ../tools/rsyslogd -dn -u2 -c4 -N1 -f$srcdir/testsuites/invalid.conf -M../runtime/.libs:../.libs if [ $? -ne 1 ]; then + echo "after test 1: return code ne 1" exit 1 fi echo testing a valid config verification run ../tools/rsyslogd -u2 -c4 -N1 -f$srcdir/testsuites/valid.conf -M../runtime/.libs:../.libs if [ $? -ne 0 ]; then + echo "after test 2: return code ne 0" exit 1 fi echo testing empty config file ../tools/rsyslogd -u2 -c4 -N1 -f/dev/null -M../runtime/.libs:../.libs if [ $? -ne 1 ]; then + echo "after test 3: return code ne 1" exit 1 fi echo SUCCESS: validation run tests diff --git a/tools/syslogd.c b/tools/syslogd.c index 4fe6fa26..4c512ac2 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -2165,6 +2165,10 @@ int realMain(int argc, char **argv) "startup with a dirty config.\n"); exit(2); } + if(iConfigVerify) { + /* a bit dirty, but useful... */ + exit(1); + } localRet = RS_RET_OK; } CHKiRet(localRet); -- cgit v1.2.3 From 21307645db3b938982b5d2b7b6f48648f62e77e5 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 30 May 2011 08:42:55 +0200 Subject: fixed broken testbench actually, this test was missing the module path all the time, but we didn't notice it because previously no module needed to be loaded. --- tests/cfg.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cfg.sh b/tests/cfg.sh index f850c4d1..7610407a 100755 --- a/tests/cfg.sh +++ b/tests/cfg.sh @@ -37,7 +37,7 @@ echo "local directory" # # check empty config file # -../tools/rsyslogd -c4 -N1 -f/dev/null 2>&1 |./ourtail |head -2 > tmp +../tools/rsyslogd -c4 -N1 -f/dev/null -M../runtime/.libs:../.libs 2>&1 |./ourtail |head -2 > tmp cmp tmp $srcdir/DevNull.cfgtest if [ ! $? -eq 0 ]; then echo "DevNull.cfgtest failed" @@ -52,7 +52,7 @@ fi; # # check missing config file # -../tools/rsyslogd -c4 -N1 -f/This/does/not/exist 2>&1 |./ourtail |head -2 > tmp +../tools/rsyslogd -c4 -N1 -M../runtime/.libs:../.libs -f/This/does/not/exist 2>&1 |./ourtail |head -2 > tmp cmp tmp $srcdir/NoExistFile.cfgtest if [ ! $? -eq 0 ]; then echo "NoExistFile.cfgtest failed" -- cgit v1.2.3 From 0f1808aad1a0be91d4cc2cd9ddfc6e2c0cf2590f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 1 Jun 2011 09:11:18 +0200 Subject: cleaned-up umask handling --- runtime/rsconf.c | 31 +++++++++++++++++-------------- runtime/rsconf.h | 1 + 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/runtime/rsconf.c b/runtime/rsconf.c index ed6e9ee7..cb76e6da 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -101,6 +101,7 @@ BEGINobjConstruct(rsconf) /* be sure to specify the object type also in END macr pThis->globals.bDebugPrintCfSysLineHandlerList = 1; pThis->globals.bLogStatusMsgs = DFLT_bLogStatusMsgs; pThis->globals.bErrMsgToStderr = 1; + pThis->globals.umask = -1; pThis->templates.root = NULL; pThis->templates.last = NULL; pThis->templates.lastStatic = NULL; @@ -475,6 +476,19 @@ finalize_it: } +/* set the processes umask (upon configuration request) */ +static inline rsRetVal +setUmask(int iUmask) +{ + if(iUmask != -1) { + umask(iUmask); + DBGPRINTF("umask set to 0%3.3o.\n", iUmask); + } + + return RS_RET_OK; +} + + /* Activate an already-loaded configuration. The configuration will become * the new running conf (if successful). Note that in theory this method may * be called when there already is a running conf. In practice, the current @@ -495,6 +509,7 @@ activate(rsconf_t *cnf) generateConfigDAG(ourConf->globals.pszConfDAGFile); # endif tellModulesConfigLoadDone(); + setUmask(cnf->globals.umask); tellModulesCheckConfig(); /* the output part and the queue is now ready to run. So it is a good time @@ -547,18 +562,6 @@ doIncludeLine(void *pVal, uchar *pNewVal) } -/* set the processes umask (upon configuration request) */ -static rsRetVal -setUmask(void __attribute__((unused)) *pVal, int iUmask) -{ -#warning this *really* needs to be done differently! - umask(iUmask); - DBGPRINTF("umask set to 0%3.3o.\n", iUmask); - - return RS_RET_OK; -} - - /* set the maximum message size */ static rsRetVal setMaxMsgSize(void __attribute__((unused)) *pVal, long iNewVal) { @@ -828,6 +831,8 @@ initLegacyConf(void) NULL, &loadConf->globals.gidDropPriv, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"generateconfiggraph", 0, eCmdHdlrGetWord, NULL, &loadConf->globals.pszConfDAGFile, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode, + NULL, &loadConf->globals.umask, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"maxopenfiles", 0, eCmdHdlrInt, setMaxFiles, NULL, NULL, eConfObjGlobal)); @@ -837,8 +842,6 @@ initLegacyConf(void) conf.doModLoad, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, doIncludeLine, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode, - setUmask, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, setMaxMsgSize, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, diff --git a/runtime/rsconf.h b/runtime/rsconf.h index e26b1df6..8715cf1b 100644 --- a/runtime/rsconf.h +++ b/runtime/rsconf.h @@ -69,6 +69,7 @@ struct globals_s { config) if there was any issue in conf */ int uidDropPriv; /* user-id to which priveleges should be dropped to */ int gidDropPriv; /* group-id to which priveleges should be dropped to */ + int umask; /* umask to use */ uchar *pszConfDAGFile; /* name of config DAG file, non-NULL means generate one */ // TODO are the following ones defaults? -- cgit v1.2.3 From 223b103ccca416effbed2d61798e4aad7d421cc3 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 1 Jun 2011 09:49:44 +0200 Subject: preparing for 6.3.0 --- ChangeLog | 4 +++- configure.ac | 2 +- doc/manual.html | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 988f600a..796ea032 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ --------------------------------------------------------------------------- -Version 6.3.0 [DEVEL] (rgerhards), 2011-??-?? +Version 6.3.0 [DEVEL] (rgerhards), 2011-06-01 +- introduced new config system + http://blog.gerhards.net/2011/06/new-rsyslog-config-system-materializes.html --------------------------------------------------------------------------- Version 6.1.8 [BETA] (rgerhards), 2011-05-20 - official new beta version (note that in a sense 6.1.7 was already beta, diff --git a/configure.ac b/configure.ac index f6a09fa7..3ca34c11 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.1.8],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[6.3.0],[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 798680ba..9601f515 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.1.8 (devel branch) of rsyslog. +

        This documentation is for version 6.3.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 2b9e5ac193ea91817ff17851a4a16a42a5b87fdb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 6 Jun 2011 16:41:55 +0200 Subject: added a first implementation of a DNS name cache this still has a couple of weaknesses, like no size limit, no expiration of entries, suboptimal algorithms -- but it should perform better than what we had previously. Implementation will be improved based on feedback during the next couple of releases --- ChangeLog | 7 ++ runtime/Makefile.am | 2 + runtime/dnscache.c | 295 ++++++++++++++++++++++++++++++++++++++++++++++++++++ runtime/dnscache.h | 31 ++++++ runtime/net.c | 107 +------------------ runtime/nsd_ptcp.c | 34 +----- tools/syslogd.c | 3 + 7 files changed, 343 insertions(+), 136 deletions(-) create mode 100644 runtime/dnscache.c create mode 100644 runtime/dnscache.h diff --git a/ChangeLog b/ChangeLog index 796ea032..fe37c8c8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,11 @@ --------------------------------------------------------------------------- +Version 6.3.1 [DEVEL] (rgerhards), 2011-06-01 +- added a first implementation of a DNS name cache + this still has a couple of weaknesses, like no size limit, no expiration + of entries, suboptimal algorithms -- but it should perform better than + what we had previously. Implementation will be improved based on + feedback during the next couple of releases +--------------------------------------------------------------------------- Version 6.3.0 [DEVEL] (rgerhards), 2011-06-01 - introduced new config system http://blog.gerhards.net/2011/06/new-rsyslog-config-system-materializes.html diff --git a/runtime/Makefile.am b/runtime/Makefile.am index a107e21a..232d8f03 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -8,6 +8,8 @@ librsyslog_la_SOURCES = \ rsyslog.c \ rsyslog.h \ typedefs.h \ + dnscache.c \ + dnscache.h \ unicode-helper.h \ atomic.h \ batch.h \ diff --git a/runtime/dnscache.c b/runtime/dnscache.c new file mode 100644 index 00000000..b47a30b8 --- /dev/null +++ b/runtime/dnscache.c @@ -0,0 +1,295 @@ +/* dnscache.c + * Implementation of a real DNS cache + * + * File begun on 2011-06-06 by RGerhards + * The initial implementation is far from being optimal. The idea is to + * first get somethting that'S functionally OK, and then evolve the algorithm. + * In any case, even the initial implementaton is far faster than what we had + * before. -- rgerhards, 2011-06-06 + * + * Copyright 2011 by Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library 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. + * + * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ +#include "config.h" + +#include "rsyslog.h" +#include +#include +#include +#include + +#include "syslogd-types.h" +#include "glbl.h" +#include "errmsg.h" +#include "obj.h" +#include "unicode-helper.h" +#include "net.h" + +/* in this initial implementation, we use a simple, non-optimized at all + * linear list. + */ +/* module data structures */ +struct dnscache_entry_s { + struct sockaddr_storage addr; + uchar *pszHostFQDN; + uchar *ip; + struct dnscache_entry_s *next; +}; +typedef struct dnscache_entry_s dnscache_entry_t; +struct dnscache_s { + pthread_rwlock_t rwlock; + dnscache_entry_t *root; +}; +typedef struct dnscache_s dnscache_t; + + +/* static data */ +DEFobjStaticHelpers +DEFobjCurrIf(glbl) +DEFobjCurrIf(errmsg) +static dnscache_t dnsCache; + + +/* init function (must be called once) */ +rsRetVal +dnscacheInit(void) +{ + DEFiRet; + dnsCache.root = NULL; + pthread_rwlock_init(&dnsCache.rwlock, NULL); + CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */ + CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(errmsg, CORE_COMPONENT)); +finalize_it: + RETiRet; +} + +/* deinit function (must be called once) */ +rsRetVal +dnscacheDeinit(void) +{ + DEFiRet; + //TODO: free cache elements dnsCache.root = NULL; + pthread_rwlock_destroy(&dnsCache.rwlock); + objRelease(glbl, CORE_COMPONENT); + objRelease(errmsg, CORE_COMPONENT); + RETiRet; +} + + +static inline dnscache_entry_t* +findEntry(struct sockaddr_storage *addr) +{ + dnscache_entry_t *etry; + for( etry = dnsCache.root + ; etry != NULL && !memcmp(addr, &etry->addr, sizeof(struct sockaddr_storage)) + ; etry = etry->next) + /* just search, no other processing necessary */; + return etry; +} + + +/* This is a cancel-safe getnameinfo() version, because we learned + * (via drd/valgrind) that getnameinfo() seems to have some issues + * when being cancelled, at least if the module was dlloaded. + * rgerhards, 2008-09-30 + */ +static inline int +mygetnameinfo(const struct sockaddr *sa, socklen_t salen, + char *host, size_t hostlen, + char *serv, size_t servlen, int flags) +{ + int iCancelStateSave; + int i; + + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &iCancelStateSave); + i = getnameinfo(sa, salen, host, hostlen, serv, servlen, flags); + pthread_setcancelstate(iCancelStateSave, NULL); + return i; +} + + +/* resolve an address. + * + * Please see http://www.hmug.org/man/3/getnameinfo.php (under Caveats) + * for some explanation of the code found below. We do by default not + * discard message where we detected malicouos DNS PTR records. However, + * there is a user-configurabel option that will tell us if + * we should abort. For this, the return value tells the caller if the + * message should be processed (1) or discarded (0). + */ +static rsRetVal +resolveAddr(struct sockaddr_storage *addr, uchar *pszHostFQDN, uchar *ip) +{ + DEFiRet; + int error; + sigset_t omask, nmask; + struct addrinfo hints, *res; + + assert(addr != NULL); + assert(pszHostFQDN != NULL); + + error = mygetnameinfo((struct sockaddr *)addr, SALEN((struct sockaddr *)addr), + (char*) ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); + if(error) { + dbgprintf("Malformed from address %s\n", gai_strerror(error)); + ABORT_FINALIZE(RS_RET_INVALID_SOURCE); + } + + if(!glbl.GetDisableDNS()) { + sigemptyset(&nmask); + sigaddset(&nmask, SIGHUP); + pthread_sigmask(SIG_BLOCK, &nmask, &omask); + + error = mygetnameinfo((struct sockaddr *)addr, SALEN((struct sockaddr *) addr), + (char*)pszHostFQDN, NI_MAXHOST, NULL, 0, NI_NAMEREQD); + + if(error == 0) { + memset (&hints, 0, sizeof (struct addrinfo)); + hints.ai_flags = AI_NUMERICHOST; + + /* we now do a lookup once again. This one should fail, + * because we should not have obtained a non-numeric address. If + * we got a numeric one, someone messed with DNS! + */ + if(getaddrinfo ((char*)pszHostFQDN, NULL, &hints, &res) == 0) { + uchar szErrMsg[1024]; + freeaddrinfo (res); + /* OK, we know we have evil. The question now is what to do about + * it. One the one hand, the message might probably be intended + * to harm us. On the other hand, losing the message may also harm us. + * Thus, the behaviour is controlled by the $DropMsgsWithMaliciousDnsPTRRecords + * option. If it tells us we should discard, we do so, else we proceed, + * but log an error message together with it. + * time being, we simply drop the name we obtained and use the IP - that one + * is OK in any way. We do also log the error message. rgerhards, 2007-07-16 + */ + if(glbl.GetDropMalPTRMsgs() == 1) { + snprintf((char*)szErrMsg, sizeof(szErrMsg) / sizeof(uchar), + "Malicious PTR record, message dropped " + "IP = \"%s\" HOST = \"%s\"", + ip, pszHostFQDN); + errmsg.LogError(0, RS_RET_MALICIOUS_ENTITY, "%s", szErrMsg); + pthread_sigmask(SIG_SETMASK, &omask, NULL); + ABORT_FINALIZE(RS_RET_MALICIOUS_ENTITY); + } + + /* Please note: we deal with a malicous entry. Thus, we have crafted + * the snprintf() below so that all text is in front of the entry - maybe + * it contains characters that make the message unreadable + * (OK, I admit this is more or less impossible, but I am paranoid...) + * rgerhards, 2007-07-16 + */ + snprintf((char*)szErrMsg, sizeof(szErrMsg) / sizeof(uchar), + "Malicious PTR record (message accepted, but used IP " + "instead of PTR name: IP = \"%s\" HOST = \"%s\"", + ip, pszHostFQDN); + errmsg.LogError(0, NO_ERRCODE, "%s", szErrMsg); + + error = 1; /* that will trigger using IP address below. */ + } + } + pthread_sigmask(SIG_SETMASK, &omask, NULL); + } + + if(error || glbl.GetDisableDNS()) { + dbgprintf("Host name for your address (%s) unknown\n", ip); + strcpy((char*) pszHostFQDN, (char*)ip); + ABORT_FINALIZE(RS_RET_ADDRESS_UNKNOWN); + } + +finalize_it: + RETiRet; +} + +/* add a new entry to the cache. This means the address is resolved and + * then added to the cache. + */ +//static inline rsRetVal +static rsRetVal +addEntry(struct sockaddr_storage *addr, dnscache_entry_t **pEtry) +{ + uchar pszHostFQDN[NI_MAXHOST]; + uchar ip[80]; /* 80 is safe for larges IPv6 addr */ + dnscache_entry_t *etry; + DEFiRet; + CHKiRet(resolveAddr(addr, pszHostFQDN, ip)); + CHKmalloc(etry = MALLOC(sizeof(dnscache_entry_t))); + CHKmalloc(etry->pszHostFQDN = ustrdup(pszHostFQDN)); + CHKmalloc(etry->ip = ustrdup(ip)); + *pEtry = etry; + + /* add to list. Currently, we place the new element always at + * the root node. This needs to be optimized later. 2011-06-06 + */ + pthread_rwlock_unlock(&dnsCache.rwlock); /* release read lock */ + pthread_rwlock_wrlock(&dnsCache.rwlock); /* and re-aquire for writing */ + etry->next = dnsCache.root; + dnsCache.root = etry; + pthread_rwlock_unlock(&dnsCache.rwlock); + pthread_rwlock_rdlock(&dnsCache.rwlock); /* TODO: optimize this! */ + +finalize_it: + RETiRet; +} + + +/* validate if an entry is still valid and, if not, re-query it. + * In the initial implementation, this is a dummy! + * TODO: implement! + */ +static inline rsRetVal +validateEntry(dnscache_entry_t *etry, struct sockaddr_storage *addr) +{ + return RS_RET_OK; +} + + +/* This is the main function: it looks up an entry and returns it's name + * and IP address. If the entry is not yet inside the cache, it is added. + * If the entry can not be resolved, an error is reported back. + */ +rsRetVal +dnscacheLookup(struct sockaddr_storage *addr, uchar *pszHostFQDN, uchar *ip) +{ + dnscache_entry_t *etry; + DEFiRet; + + pthread_rwlock_rdlock(&dnsCache.rwlock); /* TODO: optimize this! */ + etry = findEntry(addr); + dbgprintf("dnscache: entry %p found\n", etry); + if(etry == NULL) { + CHKiRet(addEntry(addr, &etry)); + } else { + CHKiRet(validateEntry(etry, addr)); + } + // TODO/QUESTION: can we get rid of the strcpy? +dbgprintf("XXXX: hostn '%s', ip '%s'\n", etry->pszHostFQDN, etry->ip); + strcpy((char*)pszHostFQDN, (char*)etry->pszHostFQDN); + strcpy((char*)ip, (char*)etry->ip); + +finalize_it: + pthread_rwlock_unlock(&dnsCache.rwlock); + if(iRet != RS_RET_OK) { + strcpy((char*) pszHostFQDN, "???"); + strcpy((char*) ip, "???"); + } + RETiRet; +} diff --git a/runtime/dnscache.h b/runtime/dnscache.h new file mode 100644 index 00000000..9eee07ba --- /dev/null +++ b/runtime/dnscache.h @@ -0,0 +1,31 @@ +/* Definitions for dnscache module. + * + * Copyright 2011 by Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library 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. + * + * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ + +#ifndef INCLUDED_DNSCACHE_H +#define INCLUDED_DNSCACHE_H + +rsRetVal dnscacheInit(void); +rsRetVal dnscacheDeinit(void); +rsRetVal dnscacheLookup(struct sockaddr_storage *addr, uchar *pszHostFQDN, uchar *ip); + +#endif /* #ifndef INCLUDED_DNSCACHE_H */ diff --git a/runtime/net.c b/runtime/net.c index 789790f6..41a344ab 100644 --- a/runtime/net.c +++ b/runtime/net.c @@ -12,7 +12,7 @@ * long term, but it is good to have it out of syslogd.c. Maybe this here is * an interim location ;) * - * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * rgerhards, 2008-04-16: I changed this code to LGPL today. I carefully analyzed * that it does not borrow code from the original sysklogd and that I have @@ -62,6 +62,7 @@ #include "obj.h" #include "errmsg.h" #include "net.h" +#include "dnscache.h" #ifdef OS_SOLARIS # define s6_addr32 _S6_un._S6_u32 @@ -1064,108 +1065,6 @@ should_use_so_bsdcompat(void) #define SO_BSDCOMPAT 0 #endif -/* get the hostname of the message source. This was originally in cvthname() - * but has been moved out of it because of clarity and fuctional separation. - * It must be provided by the socket we received the message on as well as - * a NI_MAXHOST size large character buffer for the FQDN. - * 2008-05-16 rgerhards: added field for IP address representation. Must also - * be NI_MAXHOST size large. - * - * Please see http://www.hmug.org/man/3/getnameinfo.php (under Caveats) - * for some explanation of the code found below. We do by default not - * discard message where we detected malicouos DNS PTR records. However, - * there is a user-configurabel option that will tell us if - * we should abort. For this, the return value tells the caller if the - * message should be processed (1) or discarded (0). - */ -static rsRetVal -gethname(struct sockaddr_storage *f, uchar *pszHostFQDN, uchar *ip) -{ - DEFiRet; - int error; - sigset_t omask, nmask; - struct addrinfo hints, *res; - - assert(f != NULL); - assert(pszHostFQDN != NULL); - - error = mygetnameinfo((struct sockaddr *)f, SALEN((struct sockaddr *)f), - (char*) ip, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); - - if (error) { - dbgprintf("Malformed from address %s\n", gai_strerror(error)); - strcpy((char*) pszHostFQDN, "???"); - strcpy((char*) ip, "???"); - ABORT_FINALIZE(RS_RET_INVALID_SOURCE); - } - - if(!glbl.GetDisableDNS()) { - sigemptyset(&nmask); - sigaddset(&nmask, SIGHUP); - pthread_sigmask(SIG_BLOCK, &nmask, &omask); - - error = mygetnameinfo((struct sockaddr *)f, SALEN((struct sockaddr *) f), - (char*)pszHostFQDN, NI_MAXHOST, NULL, 0, NI_NAMEREQD); - - if (error == 0) { - memset (&hints, 0, sizeof (struct addrinfo)); - hints.ai_flags = AI_NUMERICHOST; - - /* we now do a lookup once again. This one should fail, - * because we should not have obtained a non-numeric address. If - * we got a numeric one, someone messed with DNS! - */ - if (getaddrinfo ((char*)pszHostFQDN, NULL, &hints, &res) == 0) { - uchar szErrMsg[1024]; - freeaddrinfo (res); - /* OK, we know we have evil. The question now is what to do about - * it. One the one hand, the message might probably be intended - * to harm us. On the other hand, losing the message may also harm us. - * Thus, the behaviour is controlled by the $DropMsgsWithMaliciousDnsPTRRecords - * option. If it tells us we should discard, we do so, else we proceed, - * but log an error message together with it. - * time being, we simply drop the name we obtained and use the IP - that one - * is OK in any way. We do also log the error message. rgerhards, 2007-07-16 - */ - if(glbl.GetDropMalPTRMsgs() == 1) { - snprintf((char*)szErrMsg, sizeof(szErrMsg) / sizeof(uchar), - "Malicious PTR record, message dropped " - "IP = \"%s\" HOST = \"%s\"", - ip, pszHostFQDN); - errmsg.LogError(0, RS_RET_MALICIOUS_ENTITY, "%s", szErrMsg); - pthread_sigmask(SIG_SETMASK, &omask, NULL); - ABORT_FINALIZE(RS_RET_MALICIOUS_ENTITY); - } - - /* Please note: we deal with a malicous entry. Thus, we have crafted - * the snprintf() below so that all text is in front of the entry - maybe - * it contains characters that make the message unreadable - * (OK, I admit this is more or less impossible, but I am paranoid...) - * rgerhards, 2007-07-16 - */ - snprintf((char*)szErrMsg, sizeof(szErrMsg) / sizeof(uchar), - "Malicious PTR record (message accepted, but used IP " - "instead of PTR name: IP = \"%s\" HOST = \"%s\"", - ip, pszHostFQDN); - errmsg.LogError(0, NO_ERRCODE, "%s", szErrMsg); - - error = 1; /* that will trigger using IP address below. */ - } - } - pthread_sigmask(SIG_SETMASK, &omask, NULL); - } - - if(error || glbl.GetDisableDNS()) { - dbgprintf("Host name for your address (%s) unknown\n", ip); - strcpy((char*) pszHostFQDN, (char*)ip); - ABORT_FINALIZE(RS_RET_ADDRESS_UNKNOWN); - } - -finalize_it: - RETiRet; -} - - /* print out which socket we are listening on. This is only * a debug aid. rgerhards, 2007-07-02 @@ -1229,7 +1128,7 @@ rsRetVal cvthname(struct sockaddr_storage *f, uchar *pszHost, uchar *pszHostFQDN assert(pszHost != NULL); assert(pszHostFQDN != NULL); - iRet = gethname(f, pszHostFQDN, pszIP); + iRet = dnscacheLookup(f, pszHostFQDN, pszIP); if(iRet == RS_RET_INVALID_SOURCE || iRet == RS_RET_ADDRESS_UNKNOWN) { strcpy((char*) pszHost, (char*) pszHostFQDN); /* we use whatever was provided as replacement */ diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c index dd6764fa..7dd489e9 100644 --- a/runtime/nsd_ptcp.c +++ b/runtime/nsd_ptcp.c @@ -50,6 +50,7 @@ #include "nsdsel_ptcp.h" #include "nsdpoll_ptcp.h" #include "nsd_ptcp.h" +#include "dnscache.h" MODULE_TYPE_LIB MODULE_TYPE_NOKEEP @@ -260,38 +261,7 @@ FillRemHost(nsd_ptcp_t *pThis, struct sockaddr *pAddr) ISOBJ_TYPE_assert(pThis, nsd_ptcp); assert(pAddr != NULL); - error = getnameinfo(pAddr, SALEN(pAddr), (char*)szIP, sizeof(szIP), NULL, 0, NI_NUMERICHOST); - - if(error) { - dbgprintf("Malformed from address %s\n", gai_strerror(error)); - strcpy((char*)szHname, "???"); - strcpy((char*)szIP, "???"); - ABORT_FINALIZE(RS_RET_INVALID_HNAME); - } - - if(!glbl.GetDisableDNS()) { - error = getnameinfo(pAddr, SALEN(pAddr), (char*)szHname, NI_MAXHOST, NULL, 0, NI_NAMEREQD); - if(error == 0) { - memset (&hints, 0, sizeof (struct addrinfo)); - hints.ai_flags = AI_NUMERICHOST; - hints.ai_socktype = SOCK_STREAM; - /* we now do a lookup once again. This one should fail, - * because we should not have obtained a non-numeric address. If - * we got a numeric one, someone messed with DNS! - */ - if(getaddrinfo((char*)szHname, NULL, &hints, &res) == 0) { - freeaddrinfo (res); - /* OK, we know we have evil, so let's indicate this to our caller */ - snprintf((char*)szHname, NI_MAXHOST, "[MALICIOUS:IP=%s]", szIP); - dbgprintf("Malicious PTR record, IP = \"%s\" HOST = \"%s\"", szIP, szHname); - iRet = RS_RET_MALICIOUS_HNAME; - } - } else { - strcpy((char*)szHname, (char*)szIP); - } - } else { - strcpy((char*)szHname, (char*)szIP); - } + CHKiRet(dnscacheLookup(pAddr, szHname, szIP)); /* We now have the names, so now let's allocate memory and store them permanently. * (side note: we may hold on to these values for quite a while, thus we trim their diff --git a/tools/syslogd.c b/tools/syslogd.c index 4c512ac2..bbace3de 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -124,6 +124,7 @@ #include "vm.h" #include "prop.h" #include "rsconf.h" +#include "dnscache.h" #include "sd-daemon.h" /* definitions for objects we access */ @@ -1567,6 +1568,7 @@ InitGlobalClasses(void) /* TODO: the dependency on net shall go away! -- rgerhards, 2008-03-07 */ pErrObj = "net"; CHKiRet(objUse(net, LM_NET_FILENAME)); + dnscacheInit(); finalize_it: if(iRet != RS_RET_OK) { @@ -1615,6 +1617,7 @@ GlobalClassExit(void) CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); #endif + dnscacheDeinit(); rsrtExit(); /* *THIS* *MUST/SHOULD?* always be the first class initilizer being called (except debug)! */ RETiRet; -- cgit v1.2.3 From ddad5b3299191142f500b25e01b827e40e873cd7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 7 Jun 2011 10:01:48 +0200 Subject: added upper limit on # of dns cache entries to prevent DoS --- ChangeLog | 2 +- runtime/dnscache.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- runtime/nsd_ptcp.c | 2 -- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index fe37c8c8..296c11d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ --------------------------------------------------------------------------- Version 6.3.1 [DEVEL] (rgerhards), 2011-06-01 - added a first implementation of a DNS name cache - this still has a couple of weaknesses, like no size limit, no expiration + this still has a couple of weaknesses, like no expiration of entries, suboptimal algorithms -- but it should perform better than what we had previously. Implementation will be improved based on feedback during the next couple of releases diff --git a/runtime/dnscache.c b/runtime/dnscache.c index b47a30b8..5bee47c4 100644 --- a/runtime/dnscache.c +++ b/runtime/dnscache.c @@ -31,6 +31,7 @@ #include "rsyslog.h" #include +#include #include #include #include @@ -51,13 +52,16 @@ struct dnscache_entry_s { uchar *pszHostFQDN; uchar *ip; struct dnscache_entry_s *next; + unsigned nUsed; }; typedef struct dnscache_entry_s dnscache_entry_t; struct dnscache_s { pthread_rwlock_t rwlock; dnscache_entry_t *root; + unsigned nEntries; }; typedef struct dnscache_s dnscache_t; +#define MAX_CACHE_ENTRIES 1000 /* static data */ @@ -73,6 +77,7 @@ dnscacheInit(void) { DEFiRet; dnsCache.root = NULL; + dnsCache.nEntries = 0; pthread_rwlock_init(&dnsCache.rwlock, NULL); CHKiRet(objGetObjInterface(&obj)); /* this provides the root pointer for all other queries */ CHKiRet(objUse(glbl, CORE_COMPONENT)); @@ -94,6 +99,18 @@ dnscacheDeinit(void) } +/* destruct a cache entry. + * Precondition: entry must already be unlinked from list + */ +static inline void +entryDestruct(dnscache_entry_t *etry) +{ + free(etry->pszHostFQDN); + free(etry->ip); + free(etry); +} + + static inline dnscache_entry_t* findEntry(struct sockaddr_storage *addr) { @@ -102,6 +119,8 @@ findEntry(struct sockaddr_storage *addr) ; etry != NULL && !memcmp(addr, &etry->addr, sizeof(struct sockaddr_storage)) ; etry = etry->next) /* just search, no other processing necessary */; + if(etry != NULL) + ++etry->nUsed; /* this is *not* atomic, but we can live with an occasional loss! */ return etry; } @@ -219,11 +238,45 @@ finalize_it: RETiRet; } + +/* evict an entry from the cache. We should try to evict one that does + * not decrease the hit rate that much, but we do not try to hard currently + * (as the base cache data structure may change). + * This MUST NOT be called when the cache is empty! + * rgerhards, 2011-06-06 + */ +static inline void +evictEntry(void) +{ + dnscache_entry_t *prev, *evict, *prevEvict, *etry; + unsigned lowest; + + prev = prevEvict = NULL; + evict = dnsCache.root; + lowest = evict->nUsed; + for(etry = dnsCache.root->next ; etry != NULL ; etry = etry->next) { + if(etry->nUsed < lowest) { + evict = etry; + lowest = etry->nUsed; + prevEvict = prev; + } + prev = etry; + } + + /* found lowest, unlink */ + if(prevEvict == NULL) { /* remove root? */ + dnsCache.root = evict->next; + } else { + prevEvict = evict->next; + } + entryDestruct(evict); +} + + /* add a new entry to the cache. This means the address is resolved and * then added to the cache. */ -//static inline rsRetVal -static rsRetVal +static inline rsRetVal addEntry(struct sockaddr_storage *addr, dnscache_entry_t **pEtry) { uchar pszHostFQDN[NI_MAXHOST]; @@ -234,6 +287,7 @@ addEntry(struct sockaddr_storage *addr, dnscache_entry_t **pEtry) CHKmalloc(etry = MALLOC(sizeof(dnscache_entry_t))); CHKmalloc(etry->pszHostFQDN = ustrdup(pszHostFQDN)); CHKmalloc(etry->ip = ustrdup(ip)); + etry->nUsed = 0; *pEtry = etry; /* add to list. Currently, we place the new element always at @@ -241,6 +295,9 @@ addEntry(struct sockaddr_storage *addr, dnscache_entry_t **pEtry) */ pthread_rwlock_unlock(&dnsCache.rwlock); /* release read lock */ pthread_rwlock_wrlock(&dnsCache.rwlock); /* and re-aquire for writing */ + if(dnsCache.nEntries >= MAX_CACHE_ENTRIES) { + evictEntry(); + } etry->next = dnsCache.root; dnsCache.root = etry; pthread_rwlock_unlock(&dnsCache.rwlock); diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c index 7dd489e9..06f62b7e 100644 --- a/runtime/nsd_ptcp.c +++ b/runtime/nsd_ptcp.c @@ -251,10 +251,8 @@ Abort(nsd_t *pNsd) static rsRetVal FillRemHost(nsd_ptcp_t *pThis, struct sockaddr *pAddr) { - int error; uchar szIP[NI_MAXHOST] = ""; uchar szHname[NI_MAXHOST] = ""; - struct addrinfo hints, *res; size_t len; DEFiRet; -- cgit v1.2.3 From 363c16b9de007b2abb72edc08fc600a59e0fb1a1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 7 Jun 2011 10:47:06 +0200 Subject: dnscache: bugfix, potentially grabagge data accessed This was a bug of the new implementation, never released code. --- runtime/dnscache.c | 10 ++++++---- runtime/nsd_ptcp.c | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/runtime/dnscache.c b/runtime/dnscache.c index 5bee47c4..6cea43dc 100644 --- a/runtime/dnscache.c +++ b/runtime/dnscache.c @@ -115,10 +115,11 @@ static inline dnscache_entry_t* findEntry(struct sockaddr_storage *addr) { dnscache_entry_t *etry; - for( etry = dnsCache.root - ; etry != NULL && !memcmp(addr, &etry->addr, sizeof(struct sockaddr_storage)) - ; etry = etry->next) - /* just search, no other processing necessary */; + for(etry = dnsCache.root ; etry != NULL ; etry = etry->next) { + if(SALEN((struct sockaddr*)addr) == SALEN((struct sockaddr*) &etry->addr) + && !memcmp(addr, &etry->addr, SALEN((struct sockaddr*) addr))) + break; /* in this case, we found our entry */ + } if(etry != NULL) ++etry->nUsed; /* this is *not* atomic, but we can live with an occasional loss! */ return etry; @@ -287,6 +288,7 @@ addEntry(struct sockaddr_storage *addr, dnscache_entry_t **pEtry) CHKmalloc(etry = MALLOC(sizeof(dnscache_entry_t))); CHKmalloc(etry->pszHostFQDN = ustrdup(pszHostFQDN)); CHKmalloc(etry->ip = ustrdup(ip)); + memcpy(&etry->addr, addr, SALEN((struct sockaddr*) addr)); etry->nUsed = 0; *pEtry = etry; diff --git a/runtime/nsd_ptcp.c b/runtime/nsd_ptcp.c index 06f62b7e..fd883d21 100644 --- a/runtime/nsd_ptcp.c +++ b/runtime/nsd_ptcp.c @@ -249,7 +249,7 @@ Abort(nsd_t *pNsd) * rgerhards, 2008-03-31 */ static rsRetVal -FillRemHost(nsd_ptcp_t *pThis, struct sockaddr *pAddr) +FillRemHost(nsd_ptcp_t *pThis, struct sockaddr_storage *pAddr) { uchar szIP[NI_MAXHOST] = ""; uchar szHname[NI_MAXHOST] = ""; @@ -314,7 +314,7 @@ AcceptConnReq(nsd_t *pNsd, nsd_t **ppNew) * of this function. -- rgerhards, 2008-12-01 */ memcpy(&pNew->remAddr, &addr, sizeof(struct sockaddr_storage)); - CHKiRet(FillRemHost(pNew, (struct sockaddr*) &addr)); + CHKiRet(FillRemHost(pNew, &addr)); /* set the new socket to non-blocking IO -TODO:do we really need to do this here? Do we always want it? */ if((sockflags = fcntl(iNewSock, F_GETFL)) != -1) { -- cgit v1.2.3 From 209948aa4da22727a33c408d4c7961dcd1f630fc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 7 Jun 2011 19:07:23 +0200 Subject: set queue name to aciton name (useful for impstats!) so far untested, test follows --- action.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/action.c b/action.c index c5bd03cb..6a8bd2a3 100644 --- a/action.c +++ b/action.c @@ -290,7 +290,12 @@ actionConstructFinalize(action_t *pThis) ASSERT(pThis != NULL); /* find a name for our queue */ - snprintf((char*) pszQName, sizeof(pszQName)/sizeof(uchar), "action %d queue", iActionNbr); + if(pThis->pszName == NULL) { + snprintf((char*) pszQName, sizeof(pszQName)/sizeof(uchar), "action %d queue", iActionNbr); + } else { + strncpy(pszQName, pThis->pszName, sizeof(pszQName)); + pszQName[63] = '\0'; /* to be on the save side */ + } /* now check if we can run the action in "firehose mode" during stage one of * its processing (that is before messages are enqueued into the action q). -- cgit v1.2.3 From 517d3500a388699a957a92480b0537dc0510d9d1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 9 Jun 2011 00:52:22 +0200 Subject: preparing for 6.3.1 release --- ChangeLog | 6 +++--- configure.ac | 2 +- doc/manual.html | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 296c11d6..d95fd2ea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,8 @@ --------------------------------------------------------------------------- -Version 6.3.1 [DEVEL] (rgerhards), 2011-06-01 +Version 6.3.1 [DEVEL] (rgerhards), 2011-06-07 - added a first implementation of a DNS name cache - this still has a couple of weaknesses, like no expiration - of entries, suboptimal algorithms -- but it should perform better than + this still has a couple of weaknesses, like no expiration of entries, + suboptimal algorithms -- but it should perform much better than what we had previously. Implementation will be improved based on feedback during the next couple of releases --------------------------------------------------------------------------- diff --git a/configure.ac b/configure.ac index 3ca34c11..b659d291 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.0],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[6.3.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 9601f515..bf7c0bcd 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.3.0 (devel branch) of rsyslog. +

        This documentation is for version 6.3.1 (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 e1f7577b4881d9c72985be4001adfd2e58894abf Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 10 Jun 2011 01:14:15 +0200 Subject: bugfix: error state not correctly set for gone-away config directive --- tools/omfile.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/omfile.c b/tools/omfile.c index 7585ea8c..4e80e2f6 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -238,6 +238,7 @@ rsRetVal setDynaFileCacheSize(void __attribute__((unused)) *pVal, int iNewVal) rsRetVal goneAway(void __attribute__((unused)) *pVal, int iNewVal) { errmsg.LogError(0, RS_RET_ERR, "directive $omfileForceChown is no longer supported"); + return RS_RET_ERR; } -- cgit v1.2.3 From 8851decb0fbd82f3fd88fe2a0b7e662ef4479e71 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 10 Jun 2011 01:28:04 +0200 Subject: $ActionName is now also used for naming of queues in impstats... ...as well as in the debug output. This functionality has now been fully tested. --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 1150de9a..fb55044f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,8 @@ Version 5.9.0 [V5-DEVEL] (rgerhards), 2011-03-?? reference: http://kb.monitorware.com/post20791.html - added support to control KEEPALIVE settings in imptcp this has not yet been added to imtcp, but could be done on request. +- $ActionName is now also used for naming of queues in impstats + as well as in the debug output - bugfix: do not open files with full privileges, if privs will be dropped This make the privilege drop code more bulletproof, but breaks Ubuntu's work-around for log files created by external programs with the wrong -- cgit v1.2.3 From 49d7b4cd666429ece524ea4b3b2bd4041b5662e5 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 10 Jun 2011 03:39:40 +0200 Subject: preparing for 5.9.0 --- ChangeLog | 2 +- action.c | 2 +- configure.ac | 2 +- doc/manual.html | 2 +- tests/testsuites/imfile-basic.conf | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index fb55044f..855534d8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 5.9.0 [V5-DEVEL] (rgerhards), 2011-03-?? +Version 5.9.0 [V5-DEVEL] (rgerhards), 2011-06-08 - imfile: added $InputFileMaxLinesAtOnce directive - enhanced imfile to support input batching - added capability for imtcp and imptcp to activate keep-alive packets diff --git a/action.c b/action.c index 6a8bd2a3..b4762379 100644 --- a/action.c +++ b/action.c @@ -293,7 +293,7 @@ actionConstructFinalize(action_t *pThis) if(pThis->pszName == NULL) { snprintf((char*) pszQName, sizeof(pszQName)/sizeof(uchar), "action %d queue", iActionNbr); } else { - strncpy(pszQName, pThis->pszName, sizeof(pszQName)); + ustrncpy(pszQName, pThis->pszName, sizeof(pszQName)); pszQName[63] = '\0'; /* to be on the save side */ } diff --git a/configure.ac b/configure.ac index 1faaff89..49d8f2fa 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],[5.8.1],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.9.0],[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 5c656752..f6ae3000 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 5.8.1 (stable branch) of rsyslog. +

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

        If you like rsyslog, you might diff --git a/tests/testsuites/imfile-basic.conf b/tests/testsuites/imfile-basic.conf index 9fb9b5ca..59b109a6 100644 --- a/tests/testsuites/imfile-basic.conf +++ b/tests/testsuites/imfile-basic.conf @@ -6,6 +6,7 @@ $InputFileTag file: $InputFileStateFile stat-file1 $InputFileSeverity error $InputFileFacility local7 +$InputFileMaxLinesAtOnce 100000 $InputRunFileMonitor $template outfmt,"%msg:F,58:2%\n" -- cgit v1.2.3 From cca47caf92eaea4ae57cc9b016d9b458157447ce Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 10 Jun 2011 20:31:23 +0200 Subject: added some more tls-based tests to testbench --- tests/Makefile.am | 7 ++++++- tests/imtcp-tls-basic-vg.sh | 15 +++++++++++++++ tests/imtcp_conndrop_tls-vg.sh | 17 +++++++++++++++++ tests/imtcp_conndrop_tls.sh | 16 ++++++++++++++++ 4 files changed, 54 insertions(+), 1 deletion(-) create mode 100755 tests/imtcp-tls-basic-vg.sh create mode 100755 tests/imtcp_conndrop_tls-vg.sh create mode 100755 tests/imtcp_conndrop_tls.sh diff --git a/tests/Makefile.am b/tests/Makefile.am index 04afd761..3be4f296 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -103,7 +103,12 @@ if ENABLE_GNUTLS TESTS += \ sndrcv_tls_anon.sh \ sndrcv_tls_anon_rebind.sh \ - imtcp-tls-basic.sh + imtcp-tls-basic.sh \ + imtcp_conndrop_tls.sh +if HAVE_VALGRIND +TESTS += imtcp-tls-basic-vg.sh \ + imtcp_conndrop_tls-vg.sh +endif endif if ENABLE_OMUXSOCK diff --git a/tests/imtcp-tls-basic-vg.sh b/tests/imtcp-tls-basic-vg.sh new file mode 100755 index 00000000..960a14d1 --- /dev/null +++ b/tests/imtcp-tls-basic-vg.sh @@ -0,0 +1,15 @@ +# added 2011-02-28 by Rgerhards +# This file is part of the rsyslog project, released under GPLv3 +echo =============================================================================== +echo \[imtcp-tls-basic-vg.sh\]: testing imtcp in TLS mode - basic test +source $srcdir/diag.sh init +echo \$DefaultNetstreamDriverCAFile $srcdir/tls-certs/ca.pem >rsyslog.conf.tlscert +echo \$DefaultNetstreamDriverCertFile $srcdir/tls-certs/cert.pem >>rsyslog.conf.tlscert +echo \$DefaultNetstreamDriverKeyFile $srcdir/tls-certs/key.pem >>rsyslog.conf.tlscert +source $srcdir/diag.sh startup-vg imtcp-tls-basic.conf +source $srcdir/diag.sh tcpflood -p13514 -m50000 -Ttls -Z$srcdir/tls-certs/cert.pem -z$srcdir/tls-certs/key.pem +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown-vg +source $srcdir/diag.sh check-exit-vg +source $srcdir/diag.sh seq-check 0 49999 +source $srcdir/diag.sh exit diff --git a/tests/imtcp_conndrop_tls-vg.sh b/tests/imtcp_conndrop_tls-vg.sh new file mode 100755 index 00000000..21f6876c --- /dev/null +++ b/tests/imtcp_conndrop_tls-vg.sh @@ -0,0 +1,17 @@ +# Test imtcp/TLS with many dropping connections +# added 2011-06-09 by Rgerhards +# +# This file is part of the rsyslog project, released under GPLv3 +echo ==================================================================================== +echo TEST: \[imtcp_conndrop_tls-vg.sh\]: test imtcp/tls with random connection drops +cat rsyslog.action.1.include +source $srcdir/diag.sh init +source $srcdir/diag.sh startup-vg imtcp_conndrop.conf +# 100 byte messages to gain more practical data use +source $srcdir/diag.sh tcpflood -c20 -m50000 -r -d100 -P129 -D +sleep 10 # due to large messages, we need this time for the tcp receiver to settle... +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown-vg # and wait for it to terminate +source $srcdir/diag.sh check-exit-vg +source $srcdir/diag.sh seq-check 0 49999 -E +source $srcdir/diag.sh exit diff --git a/tests/imtcp_conndrop_tls.sh b/tests/imtcp_conndrop_tls.sh new file mode 100755 index 00000000..31a3477a --- /dev/null +++ b/tests/imtcp_conndrop_tls.sh @@ -0,0 +1,16 @@ +# Test imtcp/TLS with many dropping connections +# added 2011-06-09 by Rgerhards +# +# This file is part of the rsyslog project, released under GPLv3 +echo ==================================================================================== +echo TEST: \[imtcp_conndrop_tls.sh\]: test imtcp/tls with random connection drops +cat rsyslog.action.1.include +source $srcdir/diag.sh init +source $srcdir/diag.sh startup imtcp_conndrop.conf +# 100 byte messages to gain more practical data use +source $srcdir/diag.sh tcpflood -c20 -m50000 -r -d100 -P129 -D +sleep 10 # due to large messages, we need this time for the tcp receiver to settle... +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown # and wait for it to terminate +source $srcdir/diag.sh seq-check 0 49999 -E +source $srcdir/diag.sh exit -- cgit v1.2.3 From e1d21ca141706f730067e20958bbdd973672e019 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 10 Jun 2011 22:43:00 +0200 Subject: bugfix: memory leak in imtcp & subsystems under some circumstances This leak is tied to error conditions which lead to incorrect cleanup of some data structures. --- ChangeLog | 5 +++++ runtime/nsdsel_gtls.c | 1 + tcpsrv.c | 17 +++++++++++------ tests/Makefile.am | 3 +++ tests/manytcp-too-few-tls.sh | 13 +++++++++++++ tests/testsuites/manytcp-too-few-tls.conf | 22 ++++++++++++++++++++++ 6 files changed, 55 insertions(+), 6 deletions(-) create mode 100755 tests/manytcp-too-few-tls.sh create mode 100644 tests/testsuites/manytcp-too-few-tls.conf diff --git a/ChangeLog b/ChangeLog index d95fd2ea..78d48477 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,9 @@ --------------------------------------------------------------------------- +Version 6.3.2 [DEVEL] (rgerhards), 2011-06-07 +- bugfix: memory leak in imtcp & subsystems under some circumstances + This leak is tied to error conditions which lead to incorrect cleanup + of some data structures. +--------------------------------------------------------------------------- Version 6.3.1 [DEVEL] (rgerhards), 2011-06-07 - added a first implementation of a DNS name cache this still has a couple of weaknesses, like no expiration of entries, diff --git a/runtime/nsdsel_gtls.c b/runtime/nsdsel_gtls.c index 1a389a00..aff55af2 100644 --- a/runtime/nsdsel_gtls.c +++ b/runtime/nsdsel_gtls.c @@ -177,6 +177,7 @@ doRetry(nsd_gtls_t *pNsd) finalize_it: if(iRet != RS_RET_OK && iRet != RS_RET_CLOSED && iRet != RS_RET_RETRY) pNsd->bAbortConn = 1; /* request abort */ +dbgprintf("XXXXXX: doRetry: iRet %d, pNsd->bAbortConn %d\n", iRet, pNsd->bAbortConn); RETiRet; } diff --git a/tcpsrv.c b/tcpsrv.c index a8f69512..adb23e60 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -564,16 +564,18 @@ finalize_it: static inline rsRetVal processWorksetItem(tcpsrv_t *pThis, nspoll_t *pPoll, int idx, void *pUsr) { - tcps_sess_t *pNewSess; + tcps_sess_t *pNewSess = NULL; DEFiRet; - dbgprintf("tcpsrv: processing item %d, pUsr %p\n", idx, pUsr); + DBGPRINTF("tcpsrv: processing item %d, pUsr %p, bAbortConn\n", idx, pUsr); if(pUsr == pThis->ppLstn) { DBGPRINTF("New connect on NSD %p.\n", pThis->ppLstn[idx]); iRet = SessAccept(pThis, pThis->ppLstnPort[idx], &pNewSess, pThis->ppLstn[idx]); if(iRet == RS_RET_OK) { - if(pPoll != NULL) + 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); } else { DBGPRINTF("tcpsrv: error %d during accept\n", iRet); @@ -702,6 +704,7 @@ RunSelect(tcpsrv_t *pThis, nsd_epworkset_t workset[], size_t sizeWorkset) int iTCPSess; int bIsReady; nssel_t *pSel = NULL; + rsRetVal localRet; ISOBJ_TYPE_assert(pThis, tcpsrv); @@ -758,8 +761,8 @@ RunSelect(tcpsrv_t *pThis, nsd_epworkset_t workset[], size_t sizeWorkset) while(nfds && iTCPSess != -1) { if(glbl.GetGlobalInputTermState() == 1) ABORT_FINALIZE(RS_RET_FORCE_TERM); - CHKiRet(nssel.IsReady(pSel, pThis->pSessions[iTCPSess]->pStrm, NSDSEL_RD, &bIsReady, &nfds)); - if(bIsReady) { + localRet = nssel.IsReady(pSel, pThis->pSessions[iTCPSess]->pStrm, NSDSEL_RD, &bIsReady, &nfds); + if(bIsReady || localRet != RS_RET_OK) { workset[iWorkset].id = iTCPSess; workset[iWorkset].pUsr = (void*) pThis->pSessions[iTCPSess]; ++iWorkset; @@ -783,7 +786,9 @@ finalize_it: /* this is a very special case - this time only we do not exit the * crashed, which made sense (the rest of the engine was not prepared for * that) -- rgerhards, 2008-05-19 */ - /*EMPTY*/; + if(pSel != NULL) { /* cleanup missing? happens during err exit! */ + nssel.Destruct(&pSel); + } } /* note that this point is usually not reached */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 3be4f296..ed25c388 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -108,6 +108,7 @@ TESTS += \ if HAVE_VALGRIND TESTS += imtcp-tls-basic-vg.sh \ imtcp_conndrop_tls-vg.sh + manytcp-too-few-tls-vg.sh endif endif @@ -274,6 +275,8 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ testsuites/udp-msgreduc-orgmsg-vg.conf \ udp-msgreduc-vg.sh \ testsuites/udp-msgreduc-vg.conf \ + manytcp-too-few-tls.sh \ + testsuites/manytcp-too-few-tls.conf \ manytcp.sh \ testsuites/manytcp.conf \ manyptcp.sh \ diff --git a/tests/manytcp-too-few-tls.sh b/tests/manytcp-too-few-tls.sh new file mode 100755 index 00000000..d4da5f8b --- /dev/null +++ b/tests/manytcp-too-few-tls.sh @@ -0,0 +1,13 @@ +# test many concurrent tcp connections +echo \[manytcp-too-few-tls.sh\]: test concurrent tcp connections +source $srcdir/diag.sh init +source $srcdir/diag.sh startup-vg manytcp-too-few-tls.conf +# the config file specifies exactly 1100 connections +source $srcdir/diag.sh tcpflood -c1000 -m40000 +# the sleep below is needed to prevent too-early termination of the tcp listener +sleep 1 +source $srcdir/diag.sh shutdown-when-empty # shut down rsyslogd when done processing messages +source $srcdir/diag.sh wait-shutdown-vg # we need to wait until rsyslogd is finished! +source $srcdir/diag.sh check-exit-vg +source $srcdir/diag.sh seq-check 0 39999 +source $srcdir/diag.sh exit diff --git a/tests/testsuites/manytcp-too-few-tls.conf b/tests/testsuites/manytcp-too-few-tls.conf new file mode 100644 index 00000000..5269e73b --- /dev/null +++ b/tests/testsuites/manytcp-too-few-tls.conf @@ -0,0 +1,22 @@ +# Test for tcp "flood" testing +# rgerhards, 2009-04-08 +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/imtcp/.libs/imtcp +$MainMsgQueueTimeoutShutdown 10000 +$MaxOpenFiles 200 +$InputTCPMaxSessions 1100 +# certificates +$DefaultNetstreamDriverCAFile testsuites/x.509/ca.pem +$DefaultNetstreamDriverCertFile testsuites/x.509/client-cert.pem +$DefaultNetstreamDriverKeyFile testsuites/x.509/client-key.pem + +$DefaultNetstreamDriver gtls # use gtls netstream driver + +$InputTCPServerStreamDriverMode 1 +$InputTCPServerStreamDriverAuthMode anon +$InputTCPServerRun 13514 + +$template outfmt,"%msg:F,58:2%\n" +$template dynfile,"rsyslog.out.log" # trick to use relative path names! +:msg, contains, "msgnum:" ?dynfile;outfmt -- cgit v1.2.3 From 42d36fbf3a06bb10e966abe1bcd288d335c6ad18 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 14 Jun 2011 11:25:07 +0200 Subject: bugfix: TLS-mode memory leak was not completely fixed with previous commit --- runtime/nsd_gtls.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c index d0fd0e0f..cc8f78d1 100644 --- a/runtime/nsd_gtls.c +++ b/runtime/nsd_gtls.c @@ -1099,6 +1099,7 @@ gtlsEndSess(nsd_gtls_t *pThis) } } gnutls_deinit(pThis->sess); + pThis->bHaveSess = 0; } RETiRet; } @@ -1152,8 +1153,8 @@ CODESTARTobjDestruct(nsd_gtls) gnutls_x509_crt_deinit(pThis->ourCert); if(pThis->bOurKeyIsInit) gnutls_x509_privkey_deinit(pThis->ourKey); -#warning need more checks if the new gnutls_deinit() breaks things during normal operations -// gnutls_deinit(pThis->sess); /* see ln 600 pThis->bInSess as something to check? */ + if(pThis->bHaveSess) + gnutls_deinit(pThis->sess); ENDobjDestruct(nsd_gtls) -- cgit v1.2.3 From d5f78989d8fd2a3c11fd1e6ed1cd4d688b1e6728 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 20 Jun 2011 12:17:51 +0200 Subject: added support for obtaining timestamp from system for imuxsock This permits to read the time a message was submitted to the system log socket. Most importantly, this is provided in microsecond resolution. So we are able to obtain high precision timestampis even for messages that were - as is usual - not formatted with them. This also simplifies things in regard to local time calculation in chroot environments. Many thanks to Lennart Poettering for suggesting this feature, providing some guidance on implementing it and coordinating getting the necessary support into the Linux kernel. --- ChangeLog | 9 ++++++ configure.ac | 2 ++ doc/imuxsock.html | 12 ++++++- plugins/imuxsock/imuxsock.c | 74 ++++++++++++++++++++++++++++++++++++------- runtime/datetime.c | 77 +++++++++++++++++++++++++-------------------- runtime/datetime.h | 5 ++- 6 files changed, 132 insertions(+), 47 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6391ab99..c13cc142 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,14 @@ --------------------------------------------------------------------------- Version 5.9.1 [V5-DEVEL] (rgerhards), 2011-06-?? +- added support for obtaining timestamp from system for imuxsock + This permits to read the time a message was submitted to the system + log socket. Most importantly, this is provided in microsecond resolution. + So we are able to obtain high precision timestampis even for messages + that were - as is usual - not formatted with them. This also simplifies + things in regard to local time calculation in chroot environments. + Many thanks to Lennart Poettering for suggesting this feature, + providing some guidance on implementing it and coordinating getting the + necessary support into the Linux kernel. - bugfix: timestamp was incorrectly calculated for timezones with minute offset closes: http://bugzilla.adiscon.com/show_bug.cgi?id=271 diff --git a/configure.ac b/configure.ac index 49d8f2fa..41468f16 100644 --- a/configure.ac +++ b/configure.ac @@ -118,6 +118,8 @@ AC_CHECK_FUNCS([flock basename alarm clock_gettime gethostbyname gethostname get # let me know! -- rgerhards, 2010-10-06 AC_CHECK_DECL([SCM_CREDENTIALS], [AC_DEFINE(HAVE_SCM_CREDENTIALS, [1], [set define])], [], [#include #include ]) +AC_CHECK_DECL([SO_TIMESTAMP], [AC_DEFINE(HAVE_SO_TIMESTAMP, [1], [set define])], [], [#include +#include ]) # Check for MAXHOSTNAMELEN AC_MSG_CHECKING(for MAXHOSTNAMELEN) diff --git a/doc/imuxsock.html b/doc/imuxsock.html index ee5db22d..58b3ae54 100644 --- a/doc/imuxsock.html +++ b/doc/imuxsock.html @@ -68,9 +68,18 @@ messages that shall be rate-limited. 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 +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
      • +
      • $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.
      • @@ -87,6 +96,7 @@ 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 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 diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index af034b9f..da9eb993 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-2010 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -136,6 +136,7 @@ typedef struct lstn_s { sbool bCreatePath; /* auto-creation of socket directory? */ sbool bUseCreds; /* pull original creator credentials from socket */ sbool bWritePid; /* write original PID into tag */ + sbool bUseSysTimeStamp; /* use timestamp from system (instead of from message) */ } lstn_t; static lstn_t listeners[MAXFUNIX]; @@ -156,6 +157,8 @@ static int bUseFlowCtl = 0; /* use flow control or not (if yes, only LIGHT is u static int bIgnoreTimestamp = 1; /* ignore timestamps present in the incoming message? */ static int bWritePid = 0; /* use credentials from recvmsg() and fixup PID in TAG */ static int bWritePidSysSock = 0; /* use credentials from recvmsg() and fixup PID in TAG */ +static int bUseSysTimeStamp = 1; /* use timestamp from system (rather than from message) */ +static int bUseSysTimeStampSysSock = 1; /* same, for system log socket */ #define DFLT_bCreatePath 0 static int bCreatePath = DFLT_bCreatePath; /* auto-create socket path? */ #define DFLT_ratelimitInterval 5 @@ -302,6 +305,7 @@ addLstnSocketName(void __attribute__((unused)) *pVal, uchar *pNewVal) listeners[nfd].sockName = pNewVal; listeners[nfd].bUseCreds = (bWritePid || ratelimitInterval) ? 1 : 0; listeners[nfd].bWritePid = bWritePid; + listeners[nfd].bUseSysTimeStamp = bUseSysTimeStamp; nfd++; } else { errmsg.LogError(0, NO_ERRCODE, "Out of unix socket name descriptors, ignoring %s\n", @@ -415,6 +419,10 @@ openLogSocket(lstn_t *pLstn) errmsg.LogError(errno, NO_ERRCODE, "set SCM_CREDENTIALS failed on '%s'", pLstn->sockName); pLstn->bUseCreds = 0; } +// TODO: move to its own #if + if(setsockopt(pLstn->fd, SOL_SOCKET, SO_TIMESTAMP, &one, sizeof(one)) != 0) { + errmsg.LogError(errno, NO_ERRCODE, "set SO_TIMESTAMP failed on '%s'", pLstn->sockName); + } } # else /* HAVE_SCM_CREDENTIALS */ pLstn->bUseCreds = 0; @@ -505,7 +513,7 @@ fixPID(uchar *bufTAG, int *lenTag, struct ucred *cred) * can also mangle it if necessary. */ static inline rsRetVal -SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred) +SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred, struct timeval *ts) { msg_t *pMsg; int lenMsg; @@ -544,7 +552,13 @@ SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred) findRatelimiter(pLstn, cred, &ratelimiter); /* ignore error, better so than others... */ } - datetime.getCurrTime(&st, &tt); + if(ts == NULL) { + datetime.getCurrTime(&st, &tt); + } else { + datetime.timeval2syslogTime(ts, &st); + tt = ts->tv_sec; + } + if(ratelimiter != NULL && !withinRatelimit(ratelimiter, tt, cred->pid)) { STATSCOUNTER_INC(ctrLostRatelimit, mutCtrLostRatelimit); FINALIZE; @@ -564,8 +578,26 @@ SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred) parse++; lenMsg--; /* '>' */ - if(datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), &parse, &lenMsg) != RS_RET_OK) { - DBGPRINTF("we have a problem, invalid timestamp in msg!\n"); + if(ts == NULL) { + if(datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), &parse, &lenMsg) != RS_RET_OK) { + DBGPRINTF("we have a problem, invalid timestamp in msg!\n"); + } + } else { /* if we pulled the time from the system, we need to update the message text */ + if(lenMsg >= 16) { + /* RFC3164 timestamp is 16 bytes long, so assuming a valid stamp, + * we can fixup the message. If the part is smaller, the stamp can + * not be valid and we do not touch the message. Note that there may + * be some scenarios where the message is larg enough but the stamp is + * still invalid. In those cases we will destruct part of the message, + * but this case is considered extremely unlikely and thus not handled + * specifically. -- rgerhards, 2011-06-20 + */ + datetime.formatTimestamp3164(&st, (char*)parse, 0); + parse[15] = ' '; /* re-write \0 from fromatTimestamp3164 by SP */ + /* update "counters" to reflect processed timestamp */ + parse += 16; + lenMsg -= 16; + } } /* pull tag */ @@ -616,6 +648,7 @@ static rsRetVal readSocket(lstn_t *pLstn) struct cmsghdr *cm; # endif struct ucred *cred; + struct timeval *ts; uchar bufRcv[4096+1]; char aux[128]; uchar *pRcv = NULL; /* receive buffer */ @@ -654,21 +687,32 @@ static rsRetVal readSocket(lstn_t *pLstn) dbgprintf("Message from UNIX socket: #%d\n", pLstn->fd); if(iRcvd > 0) { cred = NULL; -# if HAVE_SCM_CREDENTIALS - if(pLstn->bUseCreds) { + ts = NULL; + if(pLstn->bUseCreds || pLstn->bUseSysTimeStamp) { dbgprintf("XXX: pre CM loop, length of control message %d\n", (int) msgh.msg_controllen); - for (cm = CMSG_FIRSTHDR(&msgh); cm; cm = CMSG_NXTHDR(&msgh, cm)) { + for(cm = CMSG_FIRSTHDR(&msgh); cm; cm = CMSG_NXTHDR(&msgh, cm)) { dbgprintf("XXX: in CM loop, %d, %d\n", cm->cmsg_level, cm->cmsg_type); - if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_CREDENTIALS) { +# if HAVE_SCM_CREDENTIALS + if( pLstn->bUseCreds + && cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_CREDENTIALS) { cred = (struct ucred*) CMSG_DATA(cm); dbgprintf("XXX: got credentials pid %d\n", (int) cred->pid); 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); + dbgprintf("XXX: got timestamp %ld.%ld\n", + (long) ts->tv_sec, (long) ts->tv_usec); + break; + } +# endif /* HAVE_SO_TIMESTAMP */ } dbgprintf("XXX: post CM loop\n"); } -# endif /* HAVE_SCM_CREDENTIALS */ - CHKiRet(SubmitMsg(pRcv, iRcvd, pLstn, cred)); + CHKiRet(SubmitMsg(pRcv, iRcvd, pLstn, cred, ts)); } else if(iRcvd < 0 && errno != EINTR) { char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); @@ -780,6 +824,7 @@ CODESTARTwillRun listeners[0].ratelimitSev = ratelimitSeveritySysSock; listeners[0].bUseCreds = (bWritePidSysSock || ratelimitIntervalSysSock) ? 1 : 0; listeners[0].bWritePid = bWritePidSysSock; + listeners[0].bUseSysTimeStamp = bUseSysTimeStampSysSock; sd_fds = sd_listen_fds(0); if (sd_fds < 0) { @@ -892,6 +937,8 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a bUseFlowCtl = 0; bWritePid = 0; bWritePidSysSock = 0; + bUseSysTimeStamp = 1; + bUseSysTimeStampSysSock = 1; bCreatePath = DFLT_bCreatePath; ratelimitInterval = DFLT_ratelimitInterval; ratelimitIntervalSysSock = DFLT_ratelimitInterval; @@ -927,6 +974,7 @@ CODEmodInit_QueryRegCFSLineHdlr listeners[0].bParseHost = 0; listeners[0].bUseCreds = 0; listeners[0].bCreatePath = 0; + listeners[0].bUseSysTimeStamp = 1; /* initialize socket names */ for(i = 1 ; i < MAXFUNIX ; ++i) { @@ -958,6 +1006,8 @@ CODEmodInit_QueryRegCFSLineHdlr NULL, &bCreatePath, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketusepidfromsystem", 0, eCmdHdlrBinary, NULL, &bWritePid, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketusesystimestamp", 0, eCmdHdlrBinary, + NULL, &bUseSysTimeStamp, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"addunixlistensocket", 0, eCmdHdlrGetWord, addLstnSocketName, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"imuxsockratelimitinterval", 0, eCmdHdlrInt, @@ -978,6 +1028,8 @@ CODEmodInit_QueryRegCFSLineHdlr 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, &bUseSysTimeStampSysSock, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogusepidfromsystem", 0, eCmdHdlrBinary, NULL, &bWritePidSysSock, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogratelimitinterval", 0, eCmdHdlrInt, diff --git a/runtime/datetime.c b/runtime/datetime.c index f81180ea..89452f1c 100644 --- a/runtime/datetime.c +++ b/runtime/datetime.c @@ -55,6 +55,47 @@ static const int tenPowers[6] = { 1, 10, 100, 1000, 10000, 100000 }; /* ------------------------------ methods ------------------------------ */ +/** + * Convert struct timeval to syslog_time + */ +void +timeval2syslogTime(struct timeval *tp, struct syslogTime *t) +{ + struct tm *tm; + struct tm tmBuf; + long lBias; + + tm = localtime_r((time_t*) &(tp->tv_sec), &tmBuf); + + t->year = tm->tm_year + 1900; + t->month = tm->tm_mon + 1; + t->day = tm->tm_mday; + t->hour = tm->tm_hour; + t->minute = tm->tm_min; + t->second = tm->tm_sec; + t->secfrac = tp->tv_usec; + t->secfracPrecision = 6; + +# if __sun + /* Solaris uses a different method of exporting the time zone. + * It is UTC - localtime, which is the opposite sign of mins east of GMT. + */ + lBias = -(daylight ? altzone : timezone); +# elif defined(__hpux) + lBias = tz.tz_dsttime ? - tz.tz_minuteswest : 0; +# else + lBias = tm->tm_gmtoff; +# endif + if(lBias < 0) { + t->OffsetMode = '-'; + lBias *= -1; + } else + t->OffsetMode = '+'; + t->OffsetHour = lBias / 3600; + t->OffsetMinute = (lBias % 3600) / 60; + t->timeType = TIME_TYPE_RFC5424; /* we have a high precision timestamp */ +} + /** * Get the current date/time in the best resolution the operating * system has to offer (well, actually at most down to the milli- @@ -74,9 +115,6 @@ static const int tenPowers[6] = { 1, 10, 100, 1000, 10000, 100000 }; static void getCurrTime(struct syslogTime *t, time_t *ttSeconds) { struct timeval tp; - struct tm *tm; - struct tm tmBuf; - long lBias; # if defined(__hpux) struct timezone tz; # endif @@ -93,37 +131,7 @@ static void getCurrTime(struct syslogTime *t, time_t *ttSeconds) if(ttSeconds != NULL) *ttSeconds = tp.tv_sec; - tm = localtime_r((time_t*) &(tp.tv_sec), &tmBuf); - - t->year = tm->tm_year + 1900; - t->month = tm->tm_mon + 1; - t->day = tm->tm_mday; - t->hour = tm->tm_hour; - t->minute = tm->tm_min; - t->second = tm->tm_sec; - t->secfrac = tp.tv_usec; - t->secfracPrecision = 6; - -# if __sun - /* Solaris uses a different method of exporting the time zone. - * It is UTC - localtime, which is the opposite sign of mins east of GMT. - */ - lBias = -(daylight ? altzone : timezone); -# elif defined(__hpux) - lBias = tz.tz_dsttime ? - tz.tz_minuteswest : 0; -# else - lBias = tm->tm_gmtoff; -# endif - if(lBias < 0) - { - t->OffsetMode = '-'; - lBias *= -1; - } - else - t->OffsetMode = '+'; - t->OffsetHour = lBias / 3600; - t->OffsetMinute = (lBias % 3600) / 60; - t->timeType = TIME_TYPE_RFC5424; /* we have a high precision timestamp */ + timeval2syslogTime(&tp, t); } @@ -861,6 +869,7 @@ CODESTARTobjQueryInterface(datetime) */ pIf->getCurrTime = getCurrTime; pIf->GetTime = getTime; + pIf->timeval2syslogTime = timeval2syslogTime; pIf->ParseTIMESTAMP3339 = ParseTIMESTAMP3339; pIf->ParseTIMESTAMP3164 = ParseTIMESTAMP3164; pIf->formatTimestampToMySQL = formatTimestampToMySQL; diff --git a/runtime/datetime.h b/runtime/datetime.h index 70bbf416..2175d6a1 100644 --- a/runtime/datetime.h +++ b/runtime/datetime.h @@ -44,8 +44,10 @@ BEGINinterface(datetime) /* name must also be changed in ENDinterface macro! */ int (*formatTimestampSecFrac)(struct syslogTime *ts, char* pBuf); /* v3, 2009-11-12 */ time_t (*GetTime)(time_t *ttSeconds); + /* v6, 2011-06-20 */ + void (*timeval2syslogTime)(struct timeval *tp, struct syslogTime *t); ENDinterface(datetime) -#define datetimeCURR_IF_VERSION 5 /* increment whenever you change the interface structure! */ +#define datetimeCURR_IF_VERSION 6 /* increment whenever you change the interface structure! */ /* interface changes: * 1 - initial version * 2 - not compatible to 1 - bugfix required ParseTIMESTAMP3164 to accept char ** as @@ -54,6 +56,7 @@ ENDinterface(datetime) * 3 - taken by v5 branch! * 4 - formatTimestamp3164 takes a third int parameter * 5 - merge of versions 3 + 4 (2010-03-09) + * 6 - see above */ /* prototypes */ -- cgit v1.2.3 From 47729f3b9362f7956c936088ac4bb703633cb33b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 24 Jun 2011 17:07:11 +0200 Subject: added support for obtaining timestamp for kernel message from message If the kernel time-stamps messages, time is now take from that timestamp instead of the system time when the message was read. This provides much better accuracy. Thanks to Lennart Poettering for suggesting this feature and his help during implementation. --- ChangeLog | 5 ++ plugins/imklog/bsd.c | 6 +-- plugins/imklog/imklog.c | 30 ++++++++---- plugins/imklog/imklog.h | 4 +- plugins/imklog/linux.c | 116 ++++++++++++++++++++++++++++++++++++++++------- plugins/imklog/solaris.c | 68 --------------------------- 6 files changed, 130 insertions(+), 99 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4c315819..3459f7d1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ --------------------------------------------------------------------------- Version 5.9.1 [V5-DEVEL] (rgerhards), 2011-06-?? +- added support for obtaining timestamp for kernel message from message + If the kernel time-stamps messages, time is now take from that + timestamp instead of the system time when the message was read. This + provides much better accuracy. Thanks to Lennart Poettering for + suggesting this feature and his help during implementation. - added support for obtaining timestamp from system for imuxsock This permits to read the time a message was submitted to the system log socket. Most importantly, this is provided in microsecond resolution. diff --git a/plugins/imklog/bsd.c b/plugins/imklog/bsd.c index 0a4c7cd4..930bbd11 100644 --- a/plugins/imklog/bsd.c +++ b/plugins/imklog/bsd.c @@ -155,18 +155,18 @@ readklog(void) for (p = (char*)pRcv; (q = strchr(p, '\n')) != NULL; p = q + 1) { *q = '\0'; - Syslog(LOG_INFO, (uchar*) p); + Syslog(LOG_INFO, (uchar*) p, NULL); } len = strlen(p); if (len >= iMaxLine - 1) { - Syslog(LOG_INFO, (uchar*)p); + Syslog(LOG_INFO, (uchar*)p, NULL); len = 0; } if (len > 0) memmove(pRcv, p, len + 1); } if (len > 0) - Syslog(LOG_INFO, pRcv); + Syslog(LOG_INFO, pRcv, NULL); if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) free(pRcv); diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c index c09fa4d8..cb28e68e 100644 --- a/plugins/imklog/imklog.c +++ b/plugins/imklog/imklog.c @@ -18,7 +18,10 @@ * Please note that this file replaces the klogd daemon that was * also present in pre-v3 versions of rsyslog. * - * Copyright (C) 2008, 2009 by Rainer Gerhards and Adiscon GmbH + * To test under Linux: + * echo test1 > /dev/kmsg + * + * Copyright (C) 2008-2011 by Rainer Gerhards and Adiscon GmbH * * This file is part of rsyslog. * @@ -93,15 +96,21 @@ static prop_t *pLocalHostIP = NULL; /* a pseudo-constant propterty for 127.0.0.1 * rgerhards, 2008-04-12 */ static rsRetVal -enqMsg(uchar *msg, uchar* pszTag, int iFacility, int iSeverity) +enqMsg(uchar *msg, uchar* pszTag, int iFacility, int iSeverity, struct timeval *tp) { - DEFiRet; + struct syslogTime st; msg_t *pMsg; + DEFiRet; assert(msg != NULL); assert(pszTag != NULL); - CHKiRet(msgConstruct(&pMsg)); + if(tp == NULL) { + CHKiRet(msgConstruct(&pMsg)); + } else { + datetime.timeval2syslogTime(tp, &st); + CHKiRet(msgConstructWithTime(&pMsg, &st, tp->tv_sec)); + } MsgSetFlowControlType(pMsg, eFLOWCTL_LIGHT_DELAY); MsgSetInputName(pMsg, pInputName); MsgSetRawMsgWOSize(pMsg, (char*)msg); @@ -174,22 +183,23 @@ rsRetVal imklogLogIntMsg(int priority, char *fmt, ...) va_end(ap); iRet = enqMsg((uchar*)pLogMsg, (uchar*) ((iFacilIntMsg == LOG_KERN) ? "kernel:" : "imklog:"), - iFacilIntMsg, LOG_PRI(priority)); + iFacilIntMsg, LOG_PRI(priority), NULL); RETiRet; } -/* log a kernel message +/* log a kernel message. If tp is non-NULL, it contains the message creation + * time to use. * rgerhards, 2008-04-14 */ -rsRetVal Syslog(int priority, uchar *pMsg) +rsRetVal Syslog(int priority, uchar *pMsg, struct timeval *tp) { - DEFiRet; int pri = -1; rsRetVal localRet; + DEFiRet; - /* first check if we have two PRIs. This can happen in case of systemd, + /* then check if we have two PRIs. This can happen in case of systemd, * in which case the second PRI is the rigth one. * TODO: added kernel timestamp support to this PoC. -- rgerhards, 2011-03-18 */ @@ -214,7 +224,7 @@ rsRetVal Syslog(int priority, uchar *pMsg) if(bPermitNonKernel == 0 && LOG_FAC(priority) != LOG_KERN) FINALIZE; /* silently ignore */ - iRet = enqMsg((uchar*)pMsg, (uchar*) "kernel:", LOG_FAC(priority), LOG_PRI(priority)); + iRet = enqMsg((uchar*)pMsg, (uchar*) "kernel:", LOG_FAC(priority), LOG_PRI(priority), tp); finalize_it: RETiRet; diff --git a/plugins/imklog/imklog.h b/plugins/imklog/imklog.h index c183026d..39bdeb5c 100644 --- a/plugins/imklog/imklog.h +++ b/plugins/imklog/imklog.h @@ -5,7 +5,7 @@ * Major change: 2008-04-09: switched to a driver interface for * several platforms * - * Copyright 2007-2008 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -56,7 +56,7 @@ extern uchar *pszPath; /* 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); +rsRetVal Syslog(int priority, uchar *msg, struct timeval *tp); /* prototypes */ extern int klog_getMaxLine(void); /* work-around for klog drivers to get configured max line size */ diff --git a/plugins/imklog/linux.c b/plugins/imklog/linux.c index 727708a5..8d9c8ad7 100644 --- a/plugins/imklog/linux.c +++ b/plugins/imklog/linux.c @@ -28,6 +28,8 @@ #include "rsyslog.h" #include #include +#include +#include #include #include #include @@ -181,6 +183,96 @@ static int copyin( uchar *line, int space, return(i); } + +/* submit a message to imklog Syslog() API. In this function, we check if + * a kernel timestamp is present and, if so, extract and strip it. + * Note: this is an extra processing step. We should revisit the whole + * idea in v6 and remove all that old stuff that we do not longer need + * (like symbol resolution). <-- TODO + * Special thanks to Lennart Poettering for suggesting on how to convert + * the kernel timestamp to a realtime timestamp. This method depends on + * the fact the the kernel timestamp is written using the monotonic clock. + * Shall that change (very unlikely), this code must be changed as well. Note + * that due to the way we generate the delta, we are unable to write the + * absolutely correc timestamp (system call overhead of the clock calls + * prevents us from doing so). However, the difference is very minor. + * rgerhards, 201106-24 + */ +static void +submitSyslog(int pri, uchar *buf) +{ + long secs; + long nsecs; + long secOffs; + long nsecOffs; + unsigned i; + unsigned bufsize; + struct timespec monotonic, realtime; + struct timeval tv; + struct timeval *tp = NULL; + + if(buf[3] != '[') + goto done; + DBGPRINTF("imklog: kernel timestamp detected, extracting it\n"); + + /* we now try to parse the timestamp. iff it parses, we assume + * it is a timestamp. Otherwise we know for sure it is no ts ;) + */ + i = 4; /* first digit after '[' */ + secs = 0; + while(buf[i] && isdigit(buf[i])) { + secs = secs * 10 + buf[i] - '0'; + ++i; + } + if(buf[i] != '.') { + DBGPRINTF("no dot --> no kernel timestamp\n"); + goto done; /* no TS! */ + } + + ++i; /* skip dot */ + nsecs = 0; + while(buf[i] && isdigit(buf[i])) { + nsecs = nsecs * 10 + buf[i] - '0'; + ++i; + } + if(buf[i] != ']') { + DBGPRINTF("no trailing ']' --> no kernel timestamp\n"); + goto done; /* no TS! */ + } + ++i; /* skip ']' */ + + /* we have a timestamp */ + DBGPRINTF("kernel timestamp is %ld %ld\n", secs, nsecs); + bufsize= strlen((char*)buf); + memcpy(buf+3, buf+i, bufsize - i + 1); + + clock_gettime(CLOCK_MONOTONIC, &monotonic); + clock_gettime(CLOCK_REALTIME, &realtime); + secOffs = realtime.tv_sec - monotonic.tv_sec; + nsecOffs = realtime.tv_nsec - monotonic.tv_nsec; + if(nsecOffs < 0) { + secOffs--; + nsecOffs += 1000000000l; + } + monotonic.tv_sec, monotonic.tv_nsec, + realtime.tv_sec, realtime.tv_nsec, + secOffs, nsecOffs); + + nsecs +=nsecOffs; + if(nsecs > 999999999l) { + secs++; + nsecs -= 1000000000l; + } + secs += secOffs; + tv.tv_sec = secs; + tv.tv_usec = nsecs / 1000; + tp = &tv; + +done: + Syslog(pri, buf, tp); +} + + /* * Messages are separated by "\n". Messages longer than * LOG_LINE_LENGTH are broken up. @@ -235,7 +327,7 @@ static void LogLine(char *ptr, int len) //dbgprintf("Line buffer full:\n"); //dbgprintf("\tLine: %s\n", line); - Syslog(LOG_INFO, line_buff); + submitSyslog(LOG_INFO, line_buff); line = line_buff; space = sizeof(line_buff)-1; parse_state = PARSING_TEXT; @@ -254,28 +346,24 @@ static void LogLine(char *ptr, int len) space -= delta; len -= delta; - if( space == 0 || len == 0 ) - { + if( space == 0 || len == 0 ) { break; /* full line_buff or end of input buffer */ } - if( *ptr == '\0' ) /* zero byte */ - { + if( *ptr == '\0' ) /* zero byte */ { ptr++; /* skip zero byte */ space -= 1; len -= 1; - break; } - if( *ptr == '\n' ) /* newline */ - { + if( *ptr == '\n' ) /* newline */ { ptr++; /* skip newline */ space -= 1; len -= 1; *line = 0; /* force null terminator */ - Syslog(LOG_INFO, line_buff); + submitSyslog(LOG_INFO, line_buff); line = line_buff; space = sizeof(line_buff)-1; if (symbols_twice) { @@ -285,9 +373,7 @@ static void LogLine(char *ptr, int len) skip_symbol_lookup = 1; ptr = save_ptr; len = save_len; - } - else - { + } else { skip_symbol_lookup = 0; save_ptr = ptr; save_len = len; @@ -295,8 +381,7 @@ static void LogLine(char *ptr, int len) } break; } - if( *ptr == '[' ) /* possible kernel symbol */ - { + if( *ptr == '[' ) /* possible kernel symbol */ { *line++ = *ptr++; space -= 1; len -= 1; @@ -310,8 +395,7 @@ static void LogLine(char *ptr, int len) break; case PARSING_SYMSTART: - if( *ptr != '<' ) - { + if( *ptr != '<' ) { parse_state = PARSING_TEXT; /* not a symbol */ break; } diff --git a/plugins/imklog/solaris.c b/plugins/imklog/solaris.c index 8a6d5af1..0a169cdd 100644 --- a/plugins/imklog/solaris.c +++ b/plugins/imklog/solaris.c @@ -80,74 +80,6 @@ klogWillRun(void) } -#if 0 -/* Read /dev/klog while data are available, split into lines. - * Contrary to standard BSD syslogd, we do a blocking read. We can - * afford this as imklog is running on its own threads. So if we have - * a single file, it really doesn't matter if we wait inside a 1-file - * select or the read() directly. - */ -static void -readklog(void) -{ - char *p, *q; - int len, i; - int iMaxLine; - uchar bufRcv[4096+1]; - uchar *pRcv = NULL; /* receive buffer */ - - iMaxLine = klog_getMaxLine(); - - /* we optimize performance: if iMaxLine is below 4K (which it is in almost all - * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory - * is used. We could use alloca() to achive a similar aspect, but there are so - * many issues with alloca() that I do not want to take that route. - * rgerhards, 2008-09-02 - */ - if((size_t) iMaxLine < sizeof(bufRcv) - 1) { - pRcv = bufRcv; - } else { - if((pRcv = (uchar*) malloc(sizeof(uchar) * (iMaxLine + 1))) == NULL) - iMaxLine = sizeof(bufRcv) - 1; /* better this than noting */ - } - - len = 0; - for (;;) { - dbgprintf("----------imklog(BSD) waiting for kernel log line\n"); - i = read(fklog, pRcv + len, iMaxLine - len); - if (i > 0) { - pRcv[i + len] = '\0'; - } else { - if (i < 0 && errno != EINTR && errno != EAGAIN) { - imklogLogIntMsg(LOG_ERR, - "imklog error %d reading kernel log - shutting down imklog", - errno); - fklog = -1; - } - break; - } - - for(p = pRcv; (q = strchr(p, '\n')) != NULL; p = q + 1) { - *q = '\0'; - Syslog(LOG_INFO, (uchar*) p); - } - len = strlen(p); - if (len >= iMaxLine - 1) { - Syslog(LOG_INFO, (uchar*)p); - len = 0; - } - if (len > 0) - memmove(pRcv, p, len + 1); - } - if (len > 0) - Syslog(LOG_INFO, pRcv); - - if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) - free(pRcv); -} -#endif - - /* to be called in the module's AfterRun entry point * rgerhards, 2008-04-09 */ -- cgit v1.2.3 From a924cfe6c2da54829f4729d6d56f8a1cc402475e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 27 Jun 2011 13:51:06 +0200 Subject: reduced sporadic failures during make check the imdiag implementation of "queue empty" was a bit racy, which sometimes lead to too-early termination of rsyslogd and thus some small memory leaks (which in turn showed up as problems during make check). The current architecture is not able to 100% guard against this, but the probleme probability has been reduced (and it showed to improve in practice). --- plugins/imdiag/imdiag.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c index 770b3437..b0025464 100644 --- a/plugins/imdiag/imdiag.c +++ b/plugins/imdiag/imdiag.c @@ -259,6 +259,8 @@ finalize_it: /* This function waits until the main queue is drained (size = 0) + * To make sure it really is drained, we check three times. Otherwise we + * may just see races. */ static rsRetVal waitMainQEmpty(tcps_sess_t *pSess) @@ -268,19 +270,22 @@ waitMainQEmpty(tcps_sess_t *pSess) DEFiRet; CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize)); - while(iMsgQueueSize > 0) { - /* DEV DEBUG ONLY if(iPrint++ % 500) - printf("imdiag: main msg queue size: %d\n", iMsgQueueSize); - */ - if(iPrint++ % 500 == 0) - dbgprintf("imdiag sleeping, wait mainq drain, curr size %d\n", iMsgQueueSize); - srSleep(0,2); /* wait a little bit */ - CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize)); + while(1) { if(iMsgQueueSize == 0) { /* verify that queue is still empty (else it could just be a race!) */ - srSleep(1,5); /* wait a little bit */ + srSleep(0,250000);/* wait a little bit */ CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize)); + if(iMsgQueueSize == 0) { + srSleep(0,500000);/* wait a little bit */ + CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize)); + } } + if(iMsgQueueSize == 0) + break; + if(iPrint++ % 500 == 0) + dbgprintf("imdiag sleeping, wait mainq drain, curr size %d\n", iMsgQueueSize); + srSleep(0,200000);/* wait a little bit */ + CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize)); } CHKiRet(sendResponse(pSess, "mainqueue empty\n")); -- cgit v1.2.3 From c7be4ad313c9220d80327339b11382db7ad125d5 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 30 Jun 2011 09:53:21 +0200 Subject: backported patch for testbench race reduction --- plugins/imdiag/imdiag.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c index ed6ef509..912c7bbf 100644 --- a/plugins/imdiag/imdiag.c +++ b/plugins/imdiag/imdiag.c @@ -255,6 +255,8 @@ finalize_it: /* This function waits until the main queue is drained (size = 0) + * To make sure it really is drained, we check three times. Otherwise we + * may just see races. */ static rsRetVal waitMainQEmpty(tcps_sess_t *pSess) @@ -264,19 +266,22 @@ waitMainQEmpty(tcps_sess_t *pSess) DEFiRet; CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize)); - while(iMsgQueueSize > 0) { - /* DEV DEBUG ONLY if(iPrint++ % 500) - printf("imdiag: main msg queue size: %d\n", iMsgQueueSize); - */ - if(iPrint++ % 500 == 0) - dbgprintf("imdiag sleeping, wait mainq drain, curr size %d\n", iMsgQueueSize); - srSleep(0,2); /* wait a little bit */ - CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize)); + while(1) { if(iMsgQueueSize == 0) { /* verify that queue is still empty (else it could just be a race!) */ - srSleep(1,5); /* wait a little bit */ + srSleep(0,250000);/* wait a little bit */ CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize)); + if(iMsgQueueSize == 0) { + srSleep(0,500000);/* wait a little bit */ + CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize)); + } } + if(iMsgQueueSize == 0) + break; + if(iPrint++ % 500 == 0) + dbgprintf("imdiag sleeping, wait mainq drain, curr size %d\n", iMsgQueueSize); + srSleep(0,200000);/* wait a little bit */ + CHKiRet(diagGetMainMsgQSize(&iMsgQueueSize)); } CHKiRet(sendResponse(pSess, "mainqueue empty\n")); -- cgit v1.2.3 From 6f7ce099df53a1fce7bced367d146a06a79871eb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 30 Jun 2011 10:02:47 +0200 Subject: cosmetic: reformatted some code so that more fits on a single screen --> useful for analysis --- runtime/conf.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/runtime/conf.c b/runtime/conf.c index 529142ed..cc8c205e 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -652,17 +652,14 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule for (bp=buf; *(bp+1); bp++) *bp=*(bp+1); *bp='\0'; - } - else { + } else { ignorepri = 0; } - if ( *buf == '=' ) - { + if ( *buf == '=' ) { singlpri = 1; pri = decodeSyslogName(&buf[1], syslogPriNames); } - else { - singlpri = 0; + else { singlpri = 0; pri = decodeSyslogName(buf, syslogPriNames); } @@ -690,17 +687,13 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule pRule->f_filterData.f_pmask[i] &= ~(1<f_filterData.f_pmask[i] |= (1<f_filterData.f_pmask[i] = TABLE_NOPRI; else pRule->f_filterData.f_pmask[i] = TABLE_ALLPRI; - } - else - { + } else { if ( ignorepri ) for (i2= 0; i2 <= pri; ++i2) pRule->f_filterData.f_pmask[i] &= ~(1< Date: Thu, 30 Jun 2011 10:09:03 +0200 Subject: preparing for 5.9.1 release --- ChangeLog | 2 +- configure.ac | 2 +- doc/manual.html | 2 +- plugins/imklog/linux.c | 3 --- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3459f7d1..a88b9e90 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 5.9.1 [V5-DEVEL] (rgerhards), 2011-06-?? +Version 5.9.1 [V5-DEVEL] (rgerhards), 2011-06-30 - added support for obtaining timestamp for kernel message from message If the kernel time-stamps messages, time is now take from that timestamp instead of the system time when the message was read. This diff --git a/configure.ac b/configure.ac index 41468f16..7656d9a7 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],[5.9.0],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.9.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 f6ae3000..ae58de47 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 5.9.0 (stable branch) of rsyslog. +

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

        If you like rsyslog, you might diff --git a/plugins/imklog/linux.c b/plugins/imklog/linux.c index 8d9c8ad7..b44619f5 100644 --- a/plugins/imklog/linux.c +++ b/plugins/imklog/linux.c @@ -254,9 +254,6 @@ submitSyslog(int pri, uchar *buf) secOffs--; nsecOffs += 1000000000l; } - monotonic.tv_sec, monotonic.tv_nsec, - realtime.tv_sec, realtime.tv_nsec, - secOffs, nsecOffs); nsecs +=nsecOffs; if(nsecs > 999999999l) { -- cgit v1.2.3 From 1eeeb6f603326234f1d17a16d3c55f8458f7177b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 30 Jun 2011 16:38:25 +0200 Subject: first try towards a flex/bison based config parser --- grammar/conf-fmt | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ grammar/makefile | 8 +++ grammar/rscript.l | 23 +++++++++ grammar/samp | 11 +++++ grammar/utils.c | 45 +++++++++++++++++ 5 files changed, 232 insertions(+) create mode 100644 grammar/conf-fmt create mode 100644 grammar/makefile create mode 100644 grammar/rscript.l create mode 100644 grammar/samp create mode 100644 grammar/utils.c diff --git a/grammar/conf-fmt b/grammar/conf-fmt new file mode 100644 index 00000000..e34ab784 --- /dev/null +++ b/grammar/conf-fmt @@ -0,0 +1,145 @@ +PRI filter: + +- facility and severity may be numeric (but discouraged) +- format: facility "." priority [";" next-selector] (no whitespace) +- facility: + * auth, authpriv, cron, daemon, kern, lpr, mail, mark, news, security + (same as auth), syslog, user, uucp and local0 through local7 + * multiple +- "priority" (actually severity): + * debug, info, notice, warning, warn (same as warning), + err, error (same as err), crit, alert, emerg, panic (same as + emerg). The keywords error, warn and panic are deprecated and + should not be used anymore. + * "=" in front of sev --> exactly this + * "!" in front of sev --> ignore this priority + * "=" and "!" can be combined +- * => all fac/severities +- a '\' at end of line means that the following line f is a + continuation line. If so, leading whitespace is stripped from + f and then f as appended to the end of the current line, replacing + the backslash and all whitespace following it. + This makes it somewhat easier to grab selectors from an old-style + config stream. + '\' [WHITESPACE]* LF + + +DEBIAN SAMPLE +This probably includes everything that is problematic... + +# /etc/rsyslog.conf Configuration file for rsyslog. +# +# For more information see +# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html + + +################# +#### MODULES #### +################# + +$ModLoad imuxsock # provides support for local system logging +$ModLoad imklog # provides kernel logging support (previously done by rklogd) +#$ModLoad immark # provides --MARK-- message capability + +# provides UDP syslog reception +#$ModLoad imudp +#$UDPServerRun 514 + +# provides TCP syslog reception +#$ModLoad imtcp +#$InputTCPServerRun 514 + + +########################### +#### GLOBAL DIRECTIVES #### +########################### + +# +# Use traditional timestamp format. +# To enable high precision timestamps, comment out the following line. +# +#$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat + +# +# Set the default permissions for all log files. +# +$FileOwner root +$FileGroup adm +$FileCreateMode 0640 +$DirCreateMode 0755 +$Umask 0022 + +# +# Include all config files in /etc/rsyslog.d/ +# +$IncludeConfig /etc/rsyslog.d/*.conf + + +############### +#### RULES #### +############### + +# +# First some standard log files. Log by facility. +# +auth,authpriv.* /var/log/auth.log +*.*;auth,authpriv.none -/var/log/syslog +#cron.* /var/log/cron.log +daemon.* -/var/log/daemon.log +kern.* -/var/log/kern.log +lpr.* -/var/log/lpr.log +mail.* -/var/log/mail.log +user.* -/var/log/user.log + +# +# Logging for the mail system. Split it up so that +# it is easy to write scripts to parse these files. +# +mail.info -/var/log/mail.info +mail.warn -/var/log/mail.warn +mail.err /var/log/mail.err + +# +# Logging for INN news system. +# +news.crit /var/log/news/news.crit +news.err /var/log/news/news.err +news.notice -/var/log/news/news.notice + +# +# Some "catch-all" log files. +# +*.=debug;\ + auth,authpriv.none;\ + news.none;mail.none -/var/log/debug +*.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -/var/log/messages + +# +# Emergencies are sent to everybody logged in. +# +*.emerg * + +# +# I like to have messages displayed on the console, but only on a virtual +# console I usually leave idle. +# +#daemon,mail.*;\ +# news.=crit;news.=err;news.=notice;\ +# *.=debug;*.=info;\ +# *.=notice;*.=warn /dev/tty8 + +# The named pipe /dev/xconsole is for the `xconsole' utility. To use it, +# you must invoke `xconsole' with the `-file' option: +# +# $ xconsole -file /dev/xconsole [...] +# +# NOTE: adjust the list below, or you'll go crazy if you have a reasonably +# busy site.. +# +daemon.*;mail.*;\ + news.err;\ + *.=debug;*.=info;\ + *.=notice;*.=warn |/dev/xconsole diff --git a/grammar/makefile b/grammar/makefile new file mode 100644 index 00000000..520d836b --- /dev/null +++ b/grammar/makefile @@ -0,0 +1,8 @@ +rscript: lex.yy.c utils.o + gcc -o rscript lex.yy.c utils.o -lestr -lfl + +lex.yy.c: rscript.l + flex rscript.l + +utils.o: utils.c + gcc -c utils.c diff --git a/grammar/rscript.l b/grammar/rscript.l new file mode 100644 index 00000000..eb2c23ad --- /dev/null +++ b/grammar/rscript.l @@ -0,0 +1,23 @@ +%{ +#include +%} + +%% + + +. { printf("%s", yytext); } + +%% +int +main(int argc, char *argv[]) +{ + es_str_t *str; + YY_BUFFER_STATE bp; + char ln[10240]; + + readConfFile(stdin, &str); + //printf("buffer: %s\n", es_getBufAddr(str)); + bp = yy_scan_buffer(es_getBufAddr(str), es_strlen(str)); + //yy_switch_to_buffer(bp); + yylex(); +} diff --git a/grammar/samp b/grammar/samp new file mode 100644 index 00000000..91d475b0 --- /dev/null +++ b/grammar/samp @@ -0,0 +1,11 @@ +daemon.*;mail.*;\ + news.err;\ + *.=debug;*.=info;\ + *.=notice;*.=warn |/dev/xconsole +*.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -/var/log/messages + +mail.info -/var/log/mail.info + diff --git a/grammar/utils.c b/grammar/utils.c new file mode 100644 index 00000000..f9c50bc9 --- /dev/null +++ b/grammar/utils.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include "libestr.h" + +void +readConfFile(FILE *fp, es_str_t **str) +{ + int c; + char ln[10240]; + int len, i; + int start; /* start index of to be submitted text */ + char *fgetsRet; + int bContLine = 0; + + *str = es_newStr(4096); + + while(fgets(ln, sizeof(ln), fp) != NULL) { + len = strlen(ln); + /* if we are continuation line, we need to drop leading WS */ + if(bContLine) { + for(start = 0 ; start < len && isspace(ln[start]) ; ++start) + /* JUST SCAN */; + } else { + start = 0; + } + for(i = len - 1 ; i >= start && isspace(ln[i]) ; --i) + /* JUST SCAN */; + if(i >= 0) { + if(ln[i] == '\\') { + --i; + bContLine = 1; + } else { + bContLine = 0; + } + /* add relevant data to buffer */ + es_addBuf(str, ln+start, i+1 - start); + if(!bContLine) + es_addChar(str, '\n'); + } + } + /* indicate end of buffer to flex */ + es_addChar(str, '\0'); + es_addChar(str, '\0'); +} -- cgit v1.2.3 From 0a1f27bba26c436b1c7042a2d3cc479dc1512e0a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 30 Jun 2011 17:55:48 +0200 Subject: worked on detecting old-style PRI filter --- grammar/debian.conf | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rscript.l | 1 + 2 files changed, 118 insertions(+) create mode 100644 grammar/debian.conf diff --git a/grammar/debian.conf b/grammar/debian.conf new file mode 100644 index 00000000..ad5d2217 --- /dev/null +++ b/grammar/debian.conf @@ -0,0 +1,117 @@ +# /etc/rsyslog.conf Configuration file for rsyslog. +# +# For more information see +# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html + + +################# +#### MODULES #### +################# + +$ModLoad imuxsock # provides support for local system logging +$ModLoad imklog # provides kernel logging support (previously done by rklogd) +#$ModLoad immark # provides --MARK-- message capability + +# provides UDP syslog reception +#$ModLoad imudp +#$UDPServerRun 514 + +# provides TCP syslog reception +#$ModLoad imtcp +#$InputTCPServerRun 514 + + +########################### +#### GLOBAL DIRECTIVES #### +########################### + +# +# Use traditional timestamp format. +# To enable high precision timestamps, comment out the following line. +# +#$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat + +# +# Set the default permissions for all log files. +# +$FileOwner root +$FileGroup adm +$FileCreateMode 0640 +$DirCreateMode 0755 +$Umask 0022 + +# +# Include all config files in /etc/rsyslog.d/ +# +$IncludeConfig /etc/rsyslog.d/*.conf + + +############### +#### RULES #### +############### + +# +# First some standard log files. Log by facility. +# +auth,authpriv.* /var/log/auth.log +*.*;auth,authpriv.none -/var/log/syslog +#cron.* /var/log/cron.log +daemon.* -/var/log/daemon.log +kern.* -/var/log/kern.log +lpr.* -/var/log/lpr.log +mail.* -/var/log/mail.log +user.* -/var/log/user.log + +# +# Logging for the mail system. Split it up so that +# it is easy to write scripts to parse these files. +# +mail.info -/var/log/mail.info +mail.warn -/var/log/mail.warn +mail.err /var/log/mail.err + +# +# Logging for INN news system. +# +news.crit /var/log/news/news.crit +news.err /var/log/news/news.err +news.notice -/var/log/news/news.notice + +# +# Some "catch-all" log files. +# +*.=debug;\ + auth,authpriv.none;\ + news.none;mail.none -/var/log/debug +*.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -/var/log/messages + +# +# Emergencies are sent to everybody logged in. +# +*.emerg * + +# +# I like to have messages displayed on the console, but only on a virtual +# console I usually leave idle. +# +#daemon,mail.*;\ +# news.=crit;news.=err;news.=notice;\ +# *.=debug;*.=info;\ +# *.=notice;*.=warn /dev/tty8 + +# The named pipe /dev/xconsole is for the `xconsole' utility. To use it, +# you must invoke `xconsole' with the `-file' option: +# +# $ xconsole -file /dev/xconsole [...] +# +# NOTE: adjust the list below, or you'll go crazy if you have a reasonably +# busy site.. +# +daemon.*;mail.*;\ + news.err;\ + *.=debug;*.=info;\ + *.=notice;*.=warn |/dev/xconsole + diff --git a/grammar/rscript.l b/grammar/rscript.l index eb2c23ad..18286d5e 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -5,6 +5,7 @@ %% +^[ \t]*[\*a-z]+.[!=;.\*a-z]+ { printf("PRI: '%s'\n", yytext); } . { printf("%s", yytext); } %% -- cgit v1.2.3 From 1f69bcb67fad8920867120b8ad310b5f60a7cc62 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 30 Jun 2011 19:03:48 +0200 Subject: milestone: first shot at rules to read old config file objects --- grammar/debian.conf | 2 ++ grammar/rscript.l | 33 +++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/grammar/debian.conf b/grammar/debian.conf index ad5d2217..e5e54fde 100644 --- a/grammar/debian.conf +++ b/grammar/debian.conf @@ -115,3 +115,5 @@ daemon.*;mail.*;\ *.=debug;*.=info;\ *.=notice;*.=warn |/dev/xconsole +# samples added to get full "flavor" of what we need to support... +:msg, contains, "error" /var/log/somelog diff --git a/grammar/rscript.l b/grammar/rscript.l index 18286d5e..dd86fbe9 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -1,3 +1,8 @@ +%option noyywrap nodefault case-insensitive + /*%option noyywrap nodefault case-insensitive */ + +%x OLDACT + /* old-style action expected -- need to parse differently */ %{ #include %} @@ -5,8 +10,32 @@ %% -^[ \t]*[\*a-z]+.[!=;.\*a-z]+ { printf("PRI: '%s'\n", yytext); } -. { printf("%s", yytext); } +\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); } + +^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { + printf("PROP-FILT: '%s'\n", yytext); + BEGIN OLDACT; + } + +^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("PRI-FILT: '%s'\n", yytext); + BEGIN OLDACT; + } + +#.*\n /* skip comments in input */ +.|\n { if(yytext[0] != '\n') printf("%s", yytext); } + +\* | +-\/[^ \t\n]+ | +\|[^ \t\n]+ | +\/[^ \t\n]+ { printf("old style action: '%s'\n", yytext); + BEGIN INITIAL; + } +[ \t\n] +.|\n { printf("invalid sequence in OLDACT mode: %s\n", + yytext); + } + + %% int -- cgit v1.2.3 From 8cd026b1cbb0f22f498963c862136c22d2920a15 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 1 Jul 2011 12:40:29 +0200 Subject: milestone: grammar contains rules for object blocks --- grammar/debian.new | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rscript.l | 60 +++++++++++++++++++++--------- 2 files changed, 149 insertions(+), 18 deletions(-) create mode 100644 grammar/debian.new diff --git a/grammar/debian.new b/grammar/debian.new new file mode 100644 index 00000000..a6574f62 --- /dev/null +++ b/grammar/debian.new @@ -0,0 +1,107 @@ +# /etc/rsyslog.conf Configuration file for rsyslog. +# +# For more information see +# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html + + +################# +#### MODULES #### +################# + +module( + name=imuxsock # provides support for local system logging + ) +$ModLoad imklog # provides kernel logging support (previously done by rklogd) +#$ModLoad immark # provides --MARK-- message capability + +# provides UDP syslog reception +#$ModLoad imudp +#$UDPServerRun 514 +module(name=imudp) +input(type=imudp port=514) + +# provides TCP syslog reception +#$ModLoad imtcp +#$InputTCPServerRun 514 + + +########################### +#### GLOBAL DIRECTIVES #### +########################### + +# +# Use traditional timestamp format. +# To enable high precision timestamps, comment out the following line. +# +#$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat + +# +# Set the default permissions for all log files. +# +$FileOwner root +$FileGroup adm +$FileCreateMode 0640 +$DirCreateMode 0755 +$Umask 0022 + +# +# Include all config files in /etc/rsyslog.d/ +# +$IncludeConfig /etc/rsyslog.d/*.conf + + +############### +#### RULES #### +############### + +# +# First some standard log files. Log by facility. +# +auth,authpriv.* /var/log/auth.log +*.*;auth,authpriv.none -/var/log/syslog +#cron.* /var/log/cron.log + +# +# Some "catch-all" log files. +# +*.=debug;\ + auth,authpriv.none;\ + news.none;mail.none -/var/log/debug +*.=info;*.=notice;*.=warn;\ + auth,authpriv.none;\ + cron,daemon.none;\ + mail,news.none -/var/log/messages + +# +# Emergencies are sent to everybody logged in. +# +*.emerg * + +# +# I like to have messages displayed on the console, but only on a virtual +# console I usually leave idle. +# +#daemon,mail.*;\ +# news.=crit;news.=err;news.=notice;\ +# *.=debug;*.=info;\ +# *.=notice;*.=warn /dev/tty8 + +# The named pipe /dev/xconsole is for the `xconsole' utility. To use it, +# you must invoke `xconsole' with the `-file' option: +# +# $ xconsole -file /dev/xconsole [...] +# +# NOTE: adjust the list below, or you'll go crazy if you have a reasonably +# busy site.. +# +daemon.*;mail.*;\ + news.err;\ + *.=debug;*.=info;\ + *.=notice;*.=warn |/dev/xconsole + +global (dnscache=yes arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") +# samples added to get full "flavor" of what we need to support... +:msg, contains, "error" /var/log/somelog +action(type=omfile target=/var/log/mail/log) +*.* * # test +*.info :ommysql:, tra, la , la # comment (comment to be part of old style line!) diff --git a/grammar/rscript.l b/grammar/rscript.l index dd86fbe9..b5d23d7a 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -1,41 +1,65 @@ %option noyywrap nodefault case-insensitive /*%option noyywrap nodefault case-insensitive */ -%x OLDACT - /* old-style action expected -- need to parse differently */ +%x INOBJ + /* INOBJ is selected if we are inside an object (name/value pairs!) */ %{ #include %} %% - -\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); } - +"global"[ \n\t]*"(" { printf("OBJ GLOBAL begin\n"); + BEGIN INOBJ; + } +"input"[ \n\t]*"(" { printf("OBJ INPUT begin\n"); + BEGIN INOBJ; + } +"module"[ \n\t]*"(" { printf("OBJ MODULE begin\n"); + BEGIN INOBJ; + } +"action"[ \n\t]*"(" { printf("OBJ ACTION begin\n"); + BEGIN INOBJ; + } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { printf("PROP-FILT: '%s'\n", yytext); - BEGIN OLDACT; + /*BEGIN OLDACT;*/ } ^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("PRI-FILT: '%s'\n", yytext); - BEGIN OLDACT; + /*BEGIN OLDACT;*/ } - -#.*\n /* skip comments in input */ -.|\n { if(yytext[0] != '\n') printf("%s", yytext); } -\* | --\/[^ \t\n]+ | -\|[^ \t\n]+ | -\/[^ \t\n]+ { printf("old style action: '%s'\n", yytext); - BEGIN INITIAL; +"*" | +[\|\.\/\-:][^\n]+ { printf("old style action: '%s'\n", yytext); + } + +")" { printf("OBJ end\n"); + BEGIN INITIAL; + } +[a-z][a-z0-9_]* { printf("INOBJ: name '%s'\n", yytext); + } +"=" { printf("INOBJ: equals\n"); } -[ \t\n] -.|\n { printf("invalid sequence in OLDACT mode: %s\n", - yytext); +[a-z0-9\.,_\+\-\/]* | +\"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { + printf("INOBJ: value '%s'\n", yytext); + BEGIN INOBJ; } +#.*\n /* skip comments in input */ +[ \n\t] +. { printf("INOBJ: invalid char '%s'\n", yytext); } + /* CFSYSLINE is valid in all modes */ +\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); } +\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); } + +\#.*\n /* skip comments in input */ +[\n\t ] /* drop whitespace */ +. { printf("invalid char: %s\n", yytext); + } + /*<> { printf("EOF reached\n"); }*/ %% int -- cgit v1.2.3 From 4ccdf6ea624c66024bce7cbede53049b5f218fb0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 1 Jul 2011 14:39:20 +0200 Subject: milestone: lexer now correctly identifies (almost) all constructs --- grammar/debian.new | 32 +++++++++++++++++++++- grammar/rscript.l | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/grammar/debian.new b/grammar/debian.new index a6574f62..4d55735c 100644 --- a/grammar/debian.new +++ b/grammar/debian.new @@ -103,5 +103,35 @@ global (dnscache=yes arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") # samples added to get full "flavor" of what we need to support... :msg, contains, "error" /var/log/somelog action(type=omfile target=/var/log/mail/log) -*.* * # test +*.* /* comment */ * # test *.info :ommysql:, tra, la , la # comment (comment to be part of old style line!) + +# from SUSE: +if ( \ + /* kernel up to warning except of firewall */ \ + ($syslogfacility-text == 'kern') and \ + ($syslogseverity <= 4 /* warning */ ) and not \ + ($msg contains 'IN=' and $msg contains 'OUT=') \ + ) or ( \ + /* up to errors except of facility authpriv */ \ + ($syslogseverity <= 3 /* errors */ ) and not \ + ($syslogfacility-text == 'authpriv') \ + ) \ +then /dev/tty10 +& |/dev/xconsole +# +# slightly modified to not use continuation lines +if ( /* kernel up to warning except of firewall */ + ($syslogfacility-text == 'kern') and + ($syslogseverity <= 4 /* warning */ ) and not + ($msg contains 'IN=' and $msg contains 'OUT=') + ) or ( + /* up to errors except of facility authpriv */ + ($syslogseverity <= 3 /* errors */ ) and not + ($syslogfacility-text == 'authpriv') + ) +then /dev/tty10 +& |/dev/xconsole + +*.* rger # write to user (ugly...) +ruleset name diff --git a/grammar/rscript.l b/grammar/rscript.l index b5d23d7a..10ce1748 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -1,14 +1,77 @@ + /* lex file for rsyslog config format v2. + * Please note: this file introduces the new config format, but maintains + * backward compatibility. In order to do so, the grammar is not 100% clean, + * but IMHO still sufficiently easy both to understand for programmers + * maitaining the code as well as users writing the config file. Users are, + * of course, encouraged to use new constructs only. But it needs to be noted + * that some of the legacy constructs (specifically the in-front-of-action + * PRI filter) are very hard to beat in ease of use, at least for simpler + * cases. So while we hope that cfsysline support can be dropped some time in + * the future, we will probably keep these useful constructs. + * + * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH + * Released under the GNU GPL v3. For details see LICENSE file. + */ + %option noyywrap nodefault case-insensitive /*%option noyywrap nodefault case-insensitive */ %x INOBJ /* INOBJ is selected if we are inside an object (name/value pairs!) */ +%x COMMENT + /* COMMENT is "the usual trick" to handle C-style comments */ +%x EXPR + /* EXPR is a bit ugly, but we need it to support pre v6-syntax. The problem + * is that cfsysline statement start with $..., the same like variables in + * an expression. However, cfsysline statements can never appear inside an + * expression. So we create a specific expr mode, which is turned on after + * we lexed a keyword that needs to be followed by an expression (using + * knowledge from the upper layer...). In expr mode, we strictly do + * expression-based parsing. Expr mode is stopped when we reach a token + * that can not be part of an expression (currently only "then"). As I + * wrote this ugly, but the price needed to pay in order to remain + * compatible to the previous format. + */ %{ #include +static int preCommentState; %} %% + /* keywords */ +"if" { printf("IF\n"); + BEGIN EXPR; + } +"then" { printf("THEN\n"); + BEGIN INITIAL; + } +"or" { printf("OR\n"); } +"and" { printf("AND\n"); } +"not" { printf("NOT\n"); } +"(" { printf("LPAREN\n"); } +")" { printf("RPAREN\n"); } +"==" { printf("==\n"); } +"<=" { printf("<=\n"); } +">=" { printf(">=\n"); } +"!=" | +"<>" { printf("!=\n"); } +"<" { printf("<\n"); } +">" { printf(">\n"); } +"contains" { printf("CONTAINS\n"); } +"contains_i" { printf("CONTAINS_I\n"); } +"startswith" { printf("STARTSWITH\n"); } +"startswith_i" { printf("STARTSWITH_I\n"); } +-?0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } +-?0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } +-?([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); } +\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); } +\'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); } +[ \t\n] +. { printf("invalid char in expr: %s\n", yytext); } +"&" { printf("AMPER\n"); } +"ruleset" { printf("RULESET\n"); } + "global"[ \n\t]*"(" { printf("OBJ GLOBAL begin\n"); BEGIN INOBJ; } @@ -23,17 +86,18 @@ } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { printf("PROP-FILT: '%s'\n", yytext); - /*BEGIN OLDACT;*/ } ^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("PRI-FILT: '%s'\n", yytext); - /*BEGIN OLDACT;*/ } "*" | -[\|\.\/\-:][^\n]+ { printf("old style action: '%s'\n", yytext); +\/[^*][^\n]* | +[\|\.\-:][^\n]+ { printf("old style action: '%s'\n", yytext); } +[a-z0-9_\-\+]+ { printf("name: '%s'\n", yytext); } + ")" { printf("OBJ end\n"); BEGIN INITIAL; } @@ -46,6 +110,15 @@ printf("INOBJ: value '%s'\n", yytext); BEGIN INOBJ; } +"/*" { preCommentState = YY_START; + BEGIN COMMENT; + } +"/*" { preCommentState = YY_START; + BEGIN COMMENT; + } +"*/" { BEGIN preCommentState; } +([^*]|\n)+|. + #.*\n /* skip comments in input */ [ \n\t] . { printf("INOBJ: invalid char '%s'\n", yytext); } -- cgit v1.2.3 From aff06b40a68eeb88fb37a0ef67ab7be1b4aaf701 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 1 Jul 2011 15:35:14 +0200 Subject: milestone: done some more twists to the lexer --- grammar/debian.new | 35 +++++++++++++++++++++++++++++++---- grammar/rscript.l | 3 +-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/grammar/debian.new b/grammar/debian.new index 4d55735c..e995a2e8 100644 --- a/grammar/debian.new +++ b/grammar/debian.new @@ -9,7 +9,7 @@ ################# module( - name=imuxsock # provides support for local system logging + name="imuxsock" # provides support for local system logging ) $ModLoad imklog # provides kernel logging support (previously done by rklogd) #$ModLoad immark # provides --MARK-- message capability @@ -17,8 +17,8 @@ $ModLoad imklog # provides kernel logging support (previously done by rklogd) # provides UDP syslog reception #$ModLoad imudp #$UDPServerRun 514 -module(name=imudp) -input(type=imudp port=514) +module(name="imudp") +input(type="imudp" port="514") # provides TCP syslog reception #$ModLoad imtcp @@ -99,7 +99,7 @@ daemon.*;mail.*;\ *.=debug;*.=info;\ *.=notice;*.=warn |/dev/xconsole -global (dnscache=yes arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") +global (dnscache="yes" arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") # samples added to get full "flavor" of what we need to support... :msg, contains, "error" /var/log/somelog action(type=omfile target=/var/log/mail/log) @@ -135,3 +135,30 @@ then /dev/tty10 *.* rger # write to user (ugly...) ruleset name + +# FEDORA, a bit more complex config +# ### begin forwarding rule ### +# The statement between the begin ... end define a SINGLE forwarding +# rule. They belong together, do NOT split them. If you create multiple +# forwarding rules, duplicate the whole block! +# Remote Logging (we use TCP for reliable delivery) +# +# An on-disk queue is created for this action. If the remote host is +# down, messages are spooled to disk and sent when it is up again. +#$WorkDirectory /var/spppl/rsyslog # where to place spool files +#$ActionQueueFileName fwdRule1 # unique name prefix for spool files +#$ActionQueueMaxDiskSpace 1g # 1gb space limit (use as much as possible) +#$ActionQueueSaveOnShutdown on # save messages to disk on shutdown +#$ActionQueueType LinkedList # run asynchronously +#$ActionResumeRetryCount -1 # infinite retries if host is down +# remote host is: name/ip:port, e.g. 192.168.0.1:514, port optional +#*.* @@remote-host:514 +# ### end of the forwarding rule ### +if $msg contains "error" then + action(type="omfwd" protocol="tcp" target="10.0.0.1:514" + action.retryCount="-1" + queue.type="linkedList" queue.fileName="fwdRule" queue.maxDiskSpace="1g" + queue.saveOnShutdown="on" + ) + & action(type="omfile" target="/var/log/somelog.log") + & action(type="omuser" target="all") diff --git a/grammar/rscript.l b/grammar/rscript.l index 10ce1748..f94ad43a 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -101,11 +101,10 @@ static int preCommentState; ")" { printf("OBJ end\n"); BEGIN INITIAL; } -[a-z][a-z0-9_]* { printf("INOBJ: name '%s'\n", yytext); +[a-z][a-z0-9_\.]* { printf("INOBJ: name '%s'\n", yytext); } "=" { printf("INOBJ: equals\n"); } -[a-z0-9\.,_\+\-\/]* | \"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { printf("INOBJ: value '%s'\n", yytext); BEGIN INOBJ; -- cgit v1.2.3 From 1ee14507b37bd7cb252341e7f6bdb6398407f1fd Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 2 Jul 2011 12:39:53 +0200 Subject: milestone: grammar for objects and cfsysline created --- grammar/makefile | 11 ++++--- grammar/rscript.l | 88 +++++++++++++++++++++++++++++++------------------------ grammar/rscript.y | 57 +++++++++++++++++++++++++++++++++++ grammar/utils.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++- grammar/utils.h | 52 ++++++++++++++++++++++++++++++++ 5 files changed, 242 insertions(+), 43 deletions(-) create mode 100644 grammar/rscript.y create mode 100644 grammar/utils.h diff --git a/grammar/makefile b/grammar/makefile index 520d836b..29aab217 100644 --- a/grammar/makefile +++ b/grammar/makefile @@ -1,8 +1,11 @@ -rscript: lex.yy.c utils.o - gcc -o rscript lex.yy.c utils.o -lestr -lfl +rscript: lex.yy.c utils.o rscript.tab.h utils.h + gcc -o rscript lex.yy.c rscript.tab.c utils.o -lestr -lex.yy.c: rscript.l +lex.yy.c: rscript.l rscript.tab.h flex rscript.l -utils.o: utils.c +rscript.tab.h: rscript.y + bison -d rscript.y + +utils.o: utils.c utils.h gcc -c utils.c diff --git a/grammar/rscript.l b/grammar/rscript.l index f94ad43a..73843692 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -33,7 +33,10 @@ * compatible to the previous format. */ %{ +#include #include +#include "utils.h" +#include "rscript.tab.h" static int preCommentState; %} @@ -72,68 +75,76 @@ static int preCommentState; "&" { printf("AMPER\n"); } "ruleset" { printf("RULESET\n"); } -"global"[ \n\t]*"(" { printf("OBJ GLOBAL begin\n"); - BEGIN INOBJ; - } -"input"[ \n\t]*"(" { printf("OBJ INPUT begin\n"); - BEGIN INOBJ; - } -"module"[ \n\t]*"(" { printf("OBJ MODULE begin\n"); - BEGIN INOBJ; - } -"action"[ \n\t]*"(" { printf("OBJ ACTION begin\n"); - BEGIN INOBJ; - } +"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; + BEGIN INOBJ; return BEGINOBJ; } +"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; + BEGIN INOBJ; return BEGINOBJ; } +"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; + BEGIN INOBJ; return BEGINOBJ; } +"action"[ \n\t]*"(" { yylval.objType = CNFOBJ_ACTION; + BEGIN INOBJ; return BEGINOBJ; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { printf("PROP-FILT: '%s'\n", yytext); } -^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("PRI-FILT: '%s'\n", yytext); - } +^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("PRI-FILT: '%s'\n", yytext); + } "*" | \/[^*][^\n]* | -[\|\.\-:][^\n]+ { printf("old style action: '%s'\n", yytext); - } +[\|\.\-:][^\n]+ { printf("old style action: '%s'\n", yytext); + } -[a-z0-9_\-\+]+ { printf("name: '%s'\n", yytext); } +[a-z0-9_\-\+]+ { printf("name: '%s'\n", yytext); } -")" { printf("OBJ end\n"); - BEGIN INITIAL; - } +")" { printf("OBJ end\n"); + BEGIN INITIAL; + return ENDOBJ; + } [a-z][a-z0-9_\.]* { printf("INOBJ: name '%s'\n", yytext); - } -"=" { printf("INOBJ: equals\n"); - } + yylval.estr = es_newStrFromCStr(yytext, yyleng); + return NAME; + } +"=" { printf("INOBJ: equals (%s)\n", yytext); + return(yytext[0]); + } \"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { - printf("INOBJ: value '%s'\n", yytext); - BEGIN INOBJ; - } -"/*" { preCommentState = YY_START; - BEGIN COMMENT; - } -"/*" { preCommentState = YY_START; - BEGIN COMMENT; - } -"*/" { BEGIN preCommentState; } + printf("INOBJ: value '%s'\n", yytext); + yylval.estr = es_newStrFromCStr(yytext+1, yyleng-2); + return VALUE; + } +"/*" { preCommentState = YY_START; + BEGIN COMMENT; + } +"/*" { preCommentState = YY_START; + BEGIN COMMENT; + } +"*/" { BEGIN preCommentState; } ([^*]|\n)+|. #.*\n /* skip comments in input */ [ \n\t] -. { printf("INOBJ: invalid char '%s'\n", yytext); } +. { printf("INOBJ: invalid char '%s'\n", yytext); } /* CFSYSLINE is valid in all modes */ -\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); } -\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); } +\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); + yylval.s = yytext; + return CFSYSLINE; + } +\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); + yylval.s = yytext; + return CFSYSLINE; + } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ -. { printf("invalid char: %s\n", yytext); - } +. { printf("invalid char: %s\n", yytext); + } /*<> { printf("EOF reached\n"); }*/ %% + /* int main(int argc, char *argv[]) { @@ -147,3 +158,4 @@ main(int argc, char *argv[]) //yy_switch_to_buffer(bp); yylex(); } +*/ diff --git a/grammar/rscript.y b/grammar/rscript.y new file mode 100644 index 00000000..6954d38d --- /dev/null +++ b/grammar/rscript.y @@ -0,0 +1,57 @@ + +%{ +#include +#include +#include "utils.h" +#define YYDEBUG 1 +%} + +%union { + char *s; + es_str_t *estr; + enum cnfobjType objType; + struct cnfobj *obj; + struct nvlst *nvlst; +} + +%token NAME +%token VALUE +%token BEGINOBJ +%token ENDOBJ +%token CFSYSLINE + +%type nv nvlst +%type obj + +%% + /* conf: | conf global | conf action*/ +conf: + | obj conf + | cfsysline conf + +obj: BEGINOBJ nvlst ENDOBJ { printf("XXXX: global processed\n"); + $$ = cnfobjNew($1, $2); + cnfobjPrint($$); + cnfobjDestruct($$); + } +cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1); + } +nvlst: { $$ = NULL; } + | nvlst nv { printf("XXXX: nvlst $1: %p, $2 %p\n", $1,$2); + $2->next = $1; + $$ = $2; + } +nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } + +%% +int yyerror(char *s) +{ + printf("yyerror called: %s\n", s); +} + +int main() +{ + yydebug = 0; + return yyparse(); +} + diff --git a/grammar/utils.c b/grammar/utils.c index f9c50bc9..ccc9fbc7 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -1,7 +1,9 @@ #include +#include #include #include -#include "libestr.h" +#include +#include "utils.h" void readConfFile(FILE *fp, es_str_t **str) @@ -43,3 +45,76 @@ readConfFile(FILE *fp, es_str_t **str) es_addChar(str, '\0'); es_addChar(str, '\0'); } + +struct nvlst* +nvlstNew(es_str_t *name, es_str_t *value) +{ + struct nvlst *lst; + + if((lst = malloc(sizeof(struct nvlst))) != NULL) { + lst->next = NULL; + lst->name = name; + lst->value = value; + } + + return lst; +} + +void +nvlstDestruct(struct nvlst *lst) +{ + struct nvlst *toDel; + + while(lst != NULL) { + toDel = lst; + lst = lst->next; + es_deleteStr(toDel->name); + es_deleteStr(toDel->value); + free(toDel); + } +} + + +void +nvlstPrint(struct nvlst *lst) +{ + char *name, *value; + printf("nvlst %p:\n", lst); + while(lst != NULL) { + name = es_str2cstr(lst->name, NULL); + value = es_str2cstr(lst->value, NULL); + printf("\tname: '%s', value '%s'\n", name, value); + free(name); + free(value); + lst = lst->next; + } +} + +struct cnfobj* +cnfobjNew(enum cnfobjType objType, struct nvlst *lst) +{ + struct cnfobj *o; + + if((o = malloc(sizeof(struct nvlst))) != NULL) { + o->objType = objType; + o->nvlst = lst; + } + + return o; +} + +void +cnfobjDestruct(struct cnfobj *o) +{ + if(o != NULL) { + nvlstDestruct(o->nvlst); + free(o); + } +} + +void +cnfobjPrint(struct cnfobj *o) +{ + printf("obj: '%s'\n", cnfobjType2str(o->objType)); + nvlstPrint(o->nvlst); +} diff --git a/grammar/utils.h b/grammar/utils.h new file mode 100644 index 00000000..45176a50 --- /dev/null +++ b/grammar/utils.h @@ -0,0 +1,52 @@ +#ifndef INC_UTILS_H +#define INC_UTILS_H +#include + +enum cnfobjType { + CNFOBJ_ACTION, + CNFOBJ_GLOBAL, + CNFOBJ_INPUT, + CNFOBJ_MODULE, + CNFOBJ_INVALID = 0 +}; + +static inline char* +cnfobjType2str(enum cnfobjType ot) +{ + switch(ot) { + case CNFOBJ_ACTION: + return "action"; + break; + case CNFOBJ_GLOBAL: + return "global"; + break; + case CNFOBJ_INPUT: + return "input"; + break; + case CNFOBJ_MODULE: + return "module"; + break; + default:return "error: invalid cnfobjType"; + } +} + +struct cnfobj { + enum cnfobjType objType; + struct nvlst *nvlst; +}; + +struct nvlst { + struct nvlst *next; + es_str_t *name; + es_str_t *value; +}; + + +void readConfFile(FILE *fp, es_str_t **str); +struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); +void nvlstDestruct(struct nvlst *lst); +void nvlstPrint(struct nvlst *lst); +struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst); +void cnfobjDestruct(struct cnfobj *o); +void cnfobjPrint(struct cnfobj *o); +#endif -- cgit v1.2.3 From 62e95c10ba84871fd5ad97fccd75664b07620013 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 2 Jul 2011 18:32:35 +0200 Subject: milestone: some support for rules in grammar --- grammar/rscript.l | 118 +++++++++++++++++++++--------------------------------- grammar/rscript.y | 33 +++++++++++---- grammar/utils.c | 12 ++++++ grammar/utils.h | 3 ++ 4 files changed, 85 insertions(+), 81 deletions(-) diff --git a/grammar/rscript.l b/grammar/rscript.l index 73843692..ccc39a2f 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -43,82 +43,60 @@ static int preCommentState; %% /* keywords */ -"if" { printf("IF\n"); - BEGIN EXPR; - } -"then" { printf("THEN\n"); - BEGIN INITIAL; - } -"or" { printf("OR\n"); } -"and" { printf("AND\n"); } -"not" { printf("NOT\n"); } -"(" { printf("LPAREN\n"); } -")" { printf("RPAREN\n"); } -"==" { printf("==\n"); } -"<=" { printf("<=\n"); } -">=" { printf(">=\n"); } +"if" { printf("IF\n"); BEGIN EXPR; } +"then" { printf("THEN\n"); BEGIN INITIAL; } +"or" { printf("OR\n"); } +"and" { printf("AND\n"); } +"not" { printf("NOT\n"); } +"(" { printf("LPAREN\n"); } +")" { printf("RPAREN\n"); } +"==" { printf("==\n"); } +"<=" { printf("<=\n"); } +">=" { printf(">=\n"); } "!=" | -"<>" { printf("!=\n"); } -"<" { printf("<\n"); } -">" { printf(">\n"); } -"contains" { printf("CONTAINS\n"); } -"contains_i" { printf("CONTAINS_I\n"); } -"startswith" { printf("STARTSWITH\n"); } -"startswith_i" { printf("STARTSWITH_I\n"); } --?0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } --?0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } --?([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); } -\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); } -\'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); } +"<>" { printf("!=\n"); } +"<" { printf("<\n"); } +">" { printf(">\n"); } +"contains" { printf("CONTAINS\n"); } +"contains_i" { printf("CONTAINS_I\n"); } +"startswith" { printf("STARTSWITH\n"); } +"startswith_i" { printf("STARTSWITH_I\n"); } +-?0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } +-?0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } +-?([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); } +\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); } +\'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); } [ \t\n] -. { printf("invalid char in expr: %s\n", yytext); } -"&" { printf("AMPER\n"); } -"ruleset" { printf("RULESET\n"); } +. { printf("invalid char in expr: %s\n", yytext); } +"&" { return '&'; } +"ruleset" { printf("RULESET\n"); } -"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; - BEGIN INOBJ; return BEGINOBJ; } -"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; - BEGIN INOBJ; return BEGINOBJ; } -"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; - BEGIN INOBJ; return BEGINOBJ; } -"action"[ \n\t]*"(" { yylval.objType = CNFOBJ_ACTION; - BEGIN INOBJ; return BEGINOBJ; } +"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; + BEGIN INOBJ; return BEGINOBJ; } +"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; + BEGIN INOBJ; return BEGINOBJ; } +"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; + BEGIN INOBJ; return BEGINOBJ; } +"action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { - printf("PROP-FILT: '%s'\n", yytext); - } - -^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("PRI-FILT: '%s'\n", yytext); + printf("PROP-FILT: '%s'\n", yytext); } +^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("token prifilt '%s'\n", yytext); yylval.s = strdup(yytext); return PRIFILT; } + "*" | \/[^*][^\n]* | -[\|\.\-:][^\n]+ { printf("old style action: '%s'\n", yytext); - } - +[\|\.\-:][^\n]+ { printf("toke legacy_action '%s'\n", yytext);yylval.s = strdup(yytext); return LEGACY_ACTION; } [a-z0-9_\-\+]+ { printf("name: '%s'\n", yytext); } - -")" { printf("OBJ end\n"); - BEGIN INITIAL; - return ENDOBJ; - } -[a-z][a-z0-9_\.]* { printf("INOBJ: name '%s'\n", yytext); - yylval.estr = es_newStrFromCStr(yytext, yyleng); - return NAME; - } -"=" { printf("INOBJ: equals (%s)\n", yytext); - return(yytext[0]); - } +")" { BEGIN INITIAL; return ENDOBJ; } +[a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); + return NAME; } +"=" { return(yytext[0]); } \"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { - printf("INOBJ: value '%s'\n", yytext); yylval.estr = es_newStrFromCStr(yytext+1, yyleng-2); - return VALUE; - } -"/*" { preCommentState = YY_START; - BEGIN COMMENT; - } -"/*" { preCommentState = YY_START; - BEGIN COMMENT; - } + return VALUE; } +"/*" { preCommentState = YY_START; BEGIN COMMENT; } +"/*" { preCommentState = YY_START; BEGIN COMMENT; } "*/" { BEGIN preCommentState; } ([^*]|\n)+|. @@ -127,14 +105,8 @@ static int preCommentState; . { printf("INOBJ: invalid char '%s'\n", yytext); } /* CFSYSLINE is valid in all modes */ -\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); - yylval.s = yytext; - return CFSYSLINE; - } -\$[a-z]+.*$ { printf("CFSYSLINE: '%s'\n", yytext); - yylval.s = yytext; - return CFSYSLINE; - } +\$[a-z]+.*$ { yylval.s = yytext; return CFSYSLINE; } +\$[a-z]+.*$ { yylval.s = yytext; return CFSYSLINE; } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ diff --git a/grammar/rscript.y b/grammar/rscript.y index 6954d38d..5bd8f0f9 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -19,30 +19,47 @@ %token BEGINOBJ %token ENDOBJ %token CFSYSLINE +%token BEGIN_ACTION +%token LEGACY_ACTION +%token PRIFILT +%token PROPFILT %type nv nvlst %type obj +%type actlst +%type act %% - /* conf: | conf global | conf action*/ -conf: +conf: /* empty (to end recursion) */ | obj conf | cfsysline conf + | rule conf -obj: BEGINOBJ nvlst ENDOBJ { printf("XXXX: global processed\n"); - $$ = cnfobjNew($1, $2); +obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); cnfobjPrint($$); cnfobjDestruct($$); } +obj: BEGIN_ACTION nvlst ENDOBJ { struct cnfobj *t = cnfobjNew(CNFOBJ_ACTION, $2); + cnfobjPrint(t); + cnfobjDestruct(t); + printf("XXXX: this is an new-style action!\n"); + } cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1); } nvlst: { $$ = NULL; } - | nvlst nv { printf("XXXX: nvlst $1: %p, $2 %p\n", $1,$2); - $2->next = $1; - $$ = $2; - } + | nvlst nv { $2->next = $1; $$ = $2; } nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } +rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); } + | PROPFILT actlst + +actlst: act { printf("action (end actlst) %s\n", $1);$$=$1; } + | actlst '&' act { printf("in actionlist %s\n", $3); } +act: BEGIN_ACTION nvlst ENDOBJ { $$ = "obj"; } + | LEGACY_ACTION { printf("legacy action: '%s'\n", $1); + /*free($1);*/ + $$ = $1;} + %% int yyerror(char *s) { diff --git a/grammar/utils.c b/grammar/utils.c index ccc9fbc7..a505704f 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -118,3 +118,15 @@ cnfobjPrint(struct cnfobj *o) printf("obj: '%s'\n", cnfobjType2str(o->objType)); nvlstPrint(o->nvlst); } + +/* debug helper */ +void +cstrPrint(char *text, es_str_t *estr) +{ + char *str; + printf("in cstrPrint, estr %p\n", estr); + str = es_str2cstr(estr, NULL); + printf("2: in cstrPrint, estr %p\n", estr); + printf("%s%s", text, str); + free(str); +} diff --git a/grammar/utils.h b/grammar/utils.h index 45176a50..66b05647 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -49,4 +49,7 @@ void nvlstPrint(struct nvlst *lst); struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst); void cnfobjDestruct(struct cnfobj *o); void cnfobjPrint(struct cnfobj *o); + +/* debug helper */ +void cstrPrint(char *text, es_str_t *estr); #endif -- cgit v1.2.3 From 1cdab4d2b548a0db54b5a2c5404f3f78e012113e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 3 Jul 2011 13:10:37 +0200 Subject: milestone: support for action list added to grammar --- grammar/rscript.l | 4 +- grammar/rscript.y | 33 +++++++++++---- grammar/utils.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- grammar/utils.h | 22 ++++++++++ 4 files changed, 163 insertions(+), 13 deletions(-) diff --git a/grammar/rscript.l b/grammar/rscript.l index ccc39a2f..750a3e81 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -105,8 +105,8 @@ static int preCommentState; . { printf("INOBJ: invalid char '%s'\n", yytext); } /* CFSYSLINE is valid in all modes */ -\$[a-z]+.*$ { yylval.s = yytext; return CFSYSLINE; } -\$[a-z]+.*$ { yylval.s = yytext; return CFSYSLINE; } +\$[a-z]+.*$ { yylval.s = strdup(yytext); return CFSYSLINE; } +\$[a-z]+.*$ { yylval.s = strdup(yytext); return CFSYSLINE; } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ diff --git a/grammar/rscript.y b/grammar/rscript.y index 5bd8f0f9..15348e4d 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -12,6 +12,7 @@ enum cnfobjType objType; struct cnfobj *obj; struct nvlst *nvlst; + struct cnfactlst *actlst; } %token NAME @@ -26,9 +27,20 @@ %type nv nvlst %type obj -%type actlst -%type act +%type actlst +%type act + +%expect 2 +/* two shift/reduce conflicts are created by the CFSYSLINE construct, which we + * unfortunately can not avoid. The problem is that CFSYSLINE can occur both in + * global context as well as within an action. It's not permitted somewhere else, + * but this is suficient for conflicts. The "dangling else" built-in resolution + * works well to solve this issue, so we accept it (it's a wonder that our + * old style grammar doesn't work at all, so we better do not complain...). + * Use "bison -v rscript.y" if more conflicts arise and check rscript.out for + * were exactly these conflicts exits. + */ %% conf: /* empty (to end recursion) */ | obj conf @@ -50,15 +62,20 @@ nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } -rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); } +rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); + $2 = cnfactlstReverse($2); + cnfactlstPrint($2); } | PROPFILT actlst -actlst: act { printf("action (end actlst) %s\n", $1);$$=$1; } - | actlst '&' act { printf("in actionlist %s\n", $3); } -act: BEGIN_ACTION nvlst ENDOBJ { $$ = "obj"; } +actlst: act { printf("action (end actlst)\n");$$=$1; } + | actlst '&' act { printf("in actionlist \n"); + $3->next = $1; $$ = $3; } + | actlst CFSYSLINE { printf("in actionlist/CFSYSLINE: %s\n", $2); + $$ = cnfactlstAddSysline($1, $2); } + +act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } | LEGACY_ACTION { printf("legacy action: '%s'\n", $1); - /*free($1);*/ - $$ = $1;} + $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } %% int yyerror(char *s) diff --git a/grammar/utils.c b/grammar/utils.c index a505704f..28e1a04a 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -74,7 +74,6 @@ nvlstDestruct(struct nvlst *lst) } } - void nvlstPrint(struct nvlst *lst) { @@ -119,14 +118,126 @@ cnfobjPrint(struct cnfobj *o) nvlstPrint(o->nvlst); } + +struct cnfactlst* +cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine) +{ + struct cnfactlst *actlst; + + if((actlst = malloc(sizeof(struct cnfactlst))) != NULL) { + actlst->next = NULL; + actlst->syslines = NULL; + actlst->actType = actType; + if(actType == CNFACT_V2) + actlst->data.lst = lst; + else + actlst->data.legActLine = actLine; + } + return actlst; +} + +struct cnfactlst* +cnfactlstAddSysline(struct cnfactlst* actlst, char *line) +{ + struct cnfcfsyslinelst *cflst; + + if((cflst = malloc(sizeof(struct cnfcfsyslinelst))) != NULL) { + cflst->next = NULL; + cflst->line = line; + if(actlst->syslines == NULL) { + actlst->syslines = cflst; + } else { + cflst->next = actlst->syslines; + actlst->syslines = cflst; + } + } + return actlst; +} + +void +cnfactlstDestruct(struct cnfactlst *actlst) +{ + struct cnfactlst *toDel; + + while(actlst != NULL) { + toDel = actlst; + actlst = actlst->next; + if(toDel->actType == CNFACT_V2) + nvlstDestruct(toDel->data.lst); + else + free(toDel->data.legActLine); + free(toDel); + } + +} + +static inline struct cnfcfsyslinelst* +cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) +{ + struct cnfcfsyslinelst *curr, *prev; + + if(lst == NULL) + return; + prev = lst; + lst = lst->next; + prev->next = NULL; + while(lst != NULL) { + curr = lst; + lst = lst->next; + curr->next = prev; + prev = curr; + } + return prev; +} + +struct cnfactlst* +cnfactlstReverse(struct cnfactlst *actlst) +{ + struct cnfactlst *curr, *prev; + + prev = actlst; + actlst = actlst->next; + prev->next = NULL; + while(actlst != NULL) { + curr = actlst; + actlst = actlst->next; + curr->syslines = cnfcfsyslinelstReverse(curr->syslines); + curr->next = prev; + prev = curr; + } + return prev; +} + +void +cnfactlstPrint(struct cnfactlst *actlst) +{ + struct cnfcfsyslinelst *cflst; + + printf("---------- cnfactlst %p:\n", actlst); + while(actlst != NULL) { + if(actlst->actType == CNFACT_V2) { + printf("V2 action type: "); + nvlstPrint(actlst->data.lst); + } else { + printf("legacy action line: '%s'\n", + actlst->data.legActLine); + } + for( cflst = actlst->syslines + ; cflst != NULL ; cflst = cflst->next) { + printf("cfsysline: '%s'\n", cflst->line); + } + actlst = actlst->next; + } + printf("----------\n"); +} + /* debug helper */ void cstrPrint(char *text, es_str_t *estr) { char *str; - printf("in cstrPrint, estr %p\n", estr); str = es_str2cstr(estr, NULL); - printf("2: in cstrPrint, estr %p\n", estr); printf("%s%s", text, str); free(str); } + diff --git a/grammar/utils.h b/grammar/utils.h index 66b05647..2a6ba10a 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -30,6 +30,8 @@ cnfobjType2str(enum cnfobjType ot) } } +enum cnfactType { CNFACT_V2, CNFACT_LEGACY }; + struct cnfobj { enum cnfobjType objType; struct nvlst *nvlst; @@ -41,6 +43,21 @@ struct nvlst { es_str_t *value; }; +struct cnfcfsyslinelst { + struct cnfcfsyslinelst *next; + char *line; +}; + +struct cnfactlst { + struct cnfactlst *next; + struct cnfcfsyslinelst *syslines; + enum cnfactType actType; + union { + struct nvlst *lst; + char *legActLine; + } data; +}; + void readConfFile(FILE *fp, es_str_t **str); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); @@ -49,6 +66,11 @@ void nvlstPrint(struct nvlst *lst); struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst); void cnfobjDestruct(struct cnfobj *o); void cnfobjPrint(struct cnfobj *o); +struct cnfactlst* cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine); +void cnfactlstDestruct(struct cnfactlst *actlst); +void cnfactlstPrint(struct cnfactlst *actlst); +struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); +struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); -- cgit v1.2.3 From 65076e28dfed0765e51c69be81a7842331aae1d2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 3 Jul 2011 17:09:09 +0200 Subject: milestone: grammar for basic if/then construct (no expr) --- grammar/mini.samp | 32 ++++++++++++++++++++++++++++++++ grammar/rscript.l | 13 +++++++------ grammar/rscript.y | 35 ++++++++++++++++++++++++++--------- 3 files changed, 65 insertions(+), 15 deletions(-) create mode 100644 grammar/mini.samp diff --git a/grammar/mini.samp b/grammar/mini.samp new file mode 100644 index 00000000..54efacec --- /dev/null +++ b/grammar/mini.samp @@ -0,0 +1,32 @@ +#global (dnscache="yes" arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") +action(type="omuser" target="all") +global (dnscache="no" b="2") +$FileOwner root +*.* * +$action somelog 1 +& /var/log/somelog +$action log2 1 +$action log2 2 +$action log2 3 +& action(type="fwd" target="10.1.1.2") +& /var/log/log2 + +if 1 then /var/log/log3 +/* sample bwlow is v7 +if 1 then { /var/log/log3 + if 2 then /var/log/log4 + *.* /var/log/log4b +} +*/ +*.* { /var/log/log5 + /var/log/log6 + $port 514 + @@fwd + rger + } +if 1/*pri("*.*")*/ then { + action(type="omfile" taget="/var/log/log5") + action(type="omfile" taget="/var/log/log6") + action(type="omfwd" taget="10.0.0.1" port="514") + action(type="omwusr" taget="rger") +} diff --git a/grammar/rscript.l b/grammar/rscript.l index 750a3e81..d6dab45b 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -43,8 +43,8 @@ static int preCommentState; %% /* keywords */ -"if" { printf("IF\n"); BEGIN EXPR; } -"then" { printf("THEN\n"); BEGIN INITIAL; } +"if" { BEGIN EXPR; return IF; } +"then" { BEGIN INITIAL; return THEN; } "or" { printf("OR\n"); } "and" { printf("AND\n"); } "not" { printf("NOT\n"); } @@ -63,12 +63,14 @@ static int preCommentState; "startswith_i" { printf("STARTSWITH_I\n"); } -?0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } -?0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } --?([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); } +-?([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); return NUMBER; } \$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); } \'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); } [ \t\n] . { printf("invalid char in expr: %s\n", yytext); } "&" { return '&'; } +"{" { return '{'; } +"}" { return '}'; } "ruleset" { printf("RULESET\n"); } "global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; @@ -86,8 +88,8 @@ static int preCommentState; "*" | \/[^*][^\n]* | -[\|\.\-:][^\n]+ { printf("toke legacy_action '%s'\n", yytext);yylval.s = strdup(yytext); return LEGACY_ACTION; } -[a-z0-9_\-\+]+ { printf("name: '%s'\n", yytext); } +[\|\.\-\@:~][^\n]+ | +[a-z0-9_\-\+]+ { yylval.s = strdup(yytext); return LEGACY_ACTION; } ")" { BEGIN INITIAL; return ENDOBJ; } [a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); return NAME; } @@ -106,7 +108,6 @@ static int preCommentState; /* CFSYSLINE is valid in all modes */ \$[a-z]+.*$ { yylval.s = strdup(yytext); return CFSYSLINE; } -\$[a-z]+.*$ { yylval.s = strdup(yytext); return CFSYSLINE; } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ diff --git a/grammar/rscript.y b/grammar/rscript.y index 15348e4d..7e9365c5 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -24,14 +24,18 @@ %token LEGACY_ACTION %token PRIFILT %token PROPFILT +%token IF +%token THEN +%token NUMBER %type nv nvlst %type obj %type actlst %type act +%type cfsysline +%type block - -%expect 2 +%expect 3 /* two shift/reduce conflicts are created by the CFSYSLINE construct, which we * unfortunately can not avoid. The problem is that CFSYSLINE can occur both in * global context as well as within an action. It's not permitted somewhere else, @@ -47,17 +51,17 @@ conf: /* empty (to end recursion) */ | cfsysline conf | rule conf -obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); +obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); cnfobjPrint($$); cnfobjDestruct($$); } -obj: BEGIN_ACTION nvlst ENDOBJ { struct cnfobj *t = cnfobjNew(CNFOBJ_ACTION, $2); + | BEGIN_ACTION nvlst ENDOBJ { struct cnfobj *t = cnfobjNew(CNFOBJ_ACTION, $2); cnfobjPrint(t); cnfobjDestruct(t); printf("XXXX: this is an new-style action!\n"); } -cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1); - } +cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1); } + nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } @@ -66,12 +70,25 @@ rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); $2 = cnfactlstReverse($2); cnfactlstPrint($2); } | PROPFILT actlst + | scriptfilt + +scriptfilt: IF NUMBER THEN actlst { printf("if filter detected\n"); } + +/* note: we can do some limited block-structuring with the v6 engine. In that case, + * we must not support additonal filters inside the blocks, so they must consist of + * "act", only. We can implement that via the "&" actlist logic. + */ +block: actlst + | block actlst + /* v7: | actlst + v7: | block rule */ -actlst: act { printf("action (end actlst)\n");$$=$1; } - | actlst '&' act { printf("in actionlist \n"); +actlst: act { printf("action (end actlst)\n");$$=$1; } + | actlst '&' act { printf("in actionlist \n"); $3->next = $1; $$ = $3; } - | actlst CFSYSLINE { printf("in actionlist/CFSYSLINE: %s\n", $2); + | actlst cfsysline { printf("in actionlist/CFSYSLINE: %s\n", $2); $$ = cnfactlstAddSysline($1, $2); } + | '{' block '}' { $$ = $2; } act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } | LEGACY_ACTION { printf("legacy action: '%s'\n", $1); -- cgit v1.2.3 From 719962c1f0f1ee1a6d5b5389417fb68adcde431b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 3 Jul 2011 18:13:23 +0200 Subject: milestone: added grammar for arithmetic expressions --- grammar/makefile | 7 ++++-- grammar/mini.samp | 2 +- grammar/rscript.l | 26 ++++++++++++-------- grammar/rscript.y | 28 +++++++++++++++++++-- grammar/utils.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- grammar/utils.h | 28 +++++++++++++++++++++ 6 files changed, 146 insertions(+), 18 deletions(-) diff --git a/grammar/makefile b/grammar/makefile index 29aab217..eb6c9522 100644 --- a/grammar/makefile +++ b/grammar/makefile @@ -1,5 +1,5 @@ rscript: lex.yy.c utils.o rscript.tab.h utils.h - gcc -o rscript lex.yy.c rscript.tab.c utils.o -lestr + gcc -g -o rscript lex.yy.c rscript.tab.c utils.o -lestr lex.yy.c: rscript.l rscript.tab.h flex rscript.l @@ -8,4 +8,7 @@ rscript.tab.h: rscript.y bison -d rscript.y utils.o: utils.c utils.h - gcc -c utils.c + gcc -g -Wall -c utils.c + +clean: + rm *.o diff --git a/grammar/mini.samp b/grammar/mini.samp index 54efacec..6aae758d 100644 --- a/grammar/mini.samp +++ b/grammar/mini.samp @@ -24,7 +24,7 @@ if 1 then { /var/log/log3 @@fwd rger } -if 1/*pri("*.*")*/ then { +if 2*4/5--(10-3)/*pri("*.*")*/ then { action(type="omfile" taget="/var/log/log5") action(type="omfile" taget="/var/log/log6") action(type="omfwd" taget="10.0.0.1" port="514") diff --git a/grammar/rscript.l b/grammar/rscript.l index d6dab45b..f7e51e25 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -45,11 +45,16 @@ static int preCommentState; /* keywords */ "if" { BEGIN EXPR; return IF; } "then" { BEGIN INITIAL; return THEN; } -"or" { printf("OR\n"); } -"and" { printf("AND\n"); } -"not" { printf("NOT\n"); } -"(" { printf("LPAREN\n"); } -")" { printf("RPAREN\n"); } +"or" { return OR; } +"and" { return AND; } +"not" { return NOT; } +"*" | +"/" | +"%" | +"+" | +"-" | +"(" | +")" { return yytext[0]; } "==" { printf("==\n"); } "<=" { printf("<=\n"); } ">=" { printf(">=\n"); } @@ -61,11 +66,12 @@ static int preCommentState; "contains_i" { printf("CONTAINS_I\n"); } "startswith" { printf("STARTSWITH\n"); } "startswith_i" { printf("STARTSWITH_I\n"); } --?0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } --?0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } --?([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); return NUMBER; } -\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); } -\'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); } +0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } +0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } +([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); + yylval.n = atoll(yytext); return NUMBER; } +\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); return VAR; } +\'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); return STRING; } [ \t\n] . { printf("invalid char in expr: %s\n", yytext); } "&" { return '&'; } diff --git a/grammar/rscript.y b/grammar/rscript.y index 7e9365c5..3b680990 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -8,11 +8,13 @@ %union { char *s; + long long n; es_str_t *estr; enum cnfobjType objType; struct cnfobj *obj; struct nvlst *nvlst; struct cnfactlst *actlst; + struct cnfexpr *expr; } %token NAME @@ -26,7 +28,12 @@ %token PROPFILT %token IF %token THEN -%token NUMBER +%token OR +%token AND +%token NOT +%token VAR +%token STRING +%token NUMBER %type nv nvlst %type obj @@ -34,6 +41,12 @@ %type act %type cfsysline %type block +%type expr + +%left AND OR +%left '+' '-' +%left '*' '/' '%' +%nonassoc UMINUS NOT %expect 3 /* two shift/reduce conflicts are created by the CFSYSLINE construct, which we @@ -72,7 +85,7 @@ rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); | PROPFILT actlst | scriptfilt -scriptfilt: IF NUMBER THEN actlst { printf("if filter detected\n"); } +scriptfilt: IF expr THEN actlst { printf("if filter detected, expr:\n"); cnfexprPrint($2,0); } /* note: we can do some limited block-structuring with the v6 engine. In that case, * we must not support additonal filters inside the blocks, so they must consist of @@ -94,6 +107,17 @@ act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } | LEGACY_ACTION { printf("legacy action: '%s'\n", $1); $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } +expr: expr '+' expr { $$ = cnfexprNew('+', $1, $3); } + | expr '-' expr { $$ = cnfexprNew('-', $1, $3); } + | expr '*' expr { $$ = cnfexprNew('*', $1, $3); } + | expr '/' expr { $$ = cnfexprNew('/', $1, $3); } + | expr '%' expr { $$ = cnfexprNew('%', $1, $3); } + | '(' expr ')' { $$ = $2; printf("( expr)\n"); } + | '-' expr %prec UMINUS { printf("uminus\n"); $$ = cnfexprNew('M', NULL, $2); } + | NUMBER { $$ = cnfnumvalNew($1); } + | STRING { $$ = cnfstringvalNew($1); } + | VAR { printf("variables not yet implemented!\n"); } + %% int yyerror(char *s) { diff --git a/grammar/utils.c b/grammar/utils.c index 28e1a04a..c26a856c 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -8,11 +8,9 @@ void readConfFile(FILE *fp, es_str_t **str) { - int c; char ln[10240]; int len, i; int start; /* start index of to be submitted text */ - char *fgetsRet; int bContLine = 0; *str = es_newStr(4096); @@ -177,7 +175,7 @@ cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) struct cnfcfsyslinelst *curr, *prev; if(lst == NULL) - return; + return NULL; prev = lst; lst = lst->next; prev->next = NULL; @@ -231,6 +229,75 @@ cnfactlstPrint(struct cnfactlst *actlst) printf("----------\n"); } +struct cnfexpr* +cnfexprNew(int nodetype, struct cnfexpr *l, struct cnfexpr *r) +{ + struct cnfexpr *expr; + if((expr = malloc(sizeof(struct cnfexpr))) != NULL) { + expr->nodetype = nodetype; + expr->l = l; + expr->r = r; + } + return expr; +} + + +inline static void +doIndent(indent) +{ + int i; + for(i = 0 ; i < indent ; ++i) + printf(" "); +} +void +cnfexprPrint(struct cnfexpr *expr, int indent) +{ + //printf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); + switch(expr->nodetype) { + case 'N': + doIndent(indent); + printf("%lld\n", ((struct cnfnumval*)expr)->val); + break; + case '+': + case '-': + case '*': + case '/': + case '%': + case 'M': + if(expr->l != NULL) + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("%c\n", (char) expr->nodetype); + cnfexprPrint(expr->r, indent+1); + break; + default: + printf("error: unknown nodetype\n"); + break; + } +} + +struct cnfnumval* +cnfnumvalNew(long long val) +{ + struct cnfnumval *numval; + if((numval = malloc(sizeof(struct cnfnumval))) != NULL) { + numval->nodetype = 'N'; + numval->val = val; + } + return numval; +} + +struct cnfstringval* +cnfstringvalNew(es_str_t *estr) +{ + struct cnfstringval *strval; + if((strval = malloc(sizeof(struct cnfstringval))) != NULL) { + strval->nodetype = 'S'; + strval->estr = estr; + } + return strval; +} + /* debug helper */ void cstrPrint(char *text, es_str_t *estr) diff --git a/grammar/utils.h b/grammar/utils.h index 2a6ba10a..a402d4b2 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -58,6 +58,30 @@ struct cnfactlst { } data; }; +/* the following structures support expressions, and may (very much later + * be the sole foundation for the AST. + */ +struct cnfexpr { + int nodetype; + struct cnfexpr *l; + struct cnfexpr *r; +}; + +struct cnfnumval { + int nodetype; + long long val; +}; + +struct cnfstringval { + int nodetype; + es_str_t *estr; +}; + +/* future extensions +struct x { + int nodetype; +}; +*/ void readConfFile(FILE *fp, es_str_t **str); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); @@ -71,6 +95,10 @@ void cnfactlstDestruct(struct cnfactlst *actlst); void cnfactlstPrint(struct cnfactlst *actlst); struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); +struct cnfexpr* cnfexprNew(int nodetype, struct cnfexpr *l, struct cnfexpr *r); +void cnfexprPrint(struct cnfexpr *expr, int indent); +struct cnfnumval* cnfnumvalNew(long long val); +struct cnfstringval* cnfstringvalNew(es_str_t *estr); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); -- cgit v1.2.3 From 849e4aa8e6437cbfb6efbc7379414fcf517e6db9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 3 Jul 2011 18:19:32 +0200 Subject: grammar: small optimization during expr creation --- grammar/mini.samp | 2 +- grammar/utils.c | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/grammar/mini.samp b/grammar/mini.samp index 6aae758d..9e00b7cf 100644 --- a/grammar/mini.samp +++ b/grammar/mini.samp @@ -24,7 +24,7 @@ if 1 then { /var/log/log3 @@fwd rger } -if 2*4/5--(10-3)/*pri("*.*")*/ then { +if 2*4/-5--(10-3)/*pri("*.*")*/ then { action(type="omfile" taget="/var/log/log5") action(type="omfile" taget="/var/log/log6") action(type="omfwd" taget="10.0.0.1" port="514") diff --git a/grammar/utils.c b/grammar/utils.c index c26a856c..bc300aaf 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -233,11 +233,20 @@ struct cnfexpr* cnfexprNew(int nodetype, struct cnfexpr *l, struct cnfexpr *r) { struct cnfexpr *expr; + + /* optimize some constructs during parsing */ + if(nodetype == 'M' && r->nodetype == 'N') { + ((struct cnfnumval*)r)->val *= -1; + expr = r; + goto done; + } + if((expr = malloc(sizeof(struct cnfexpr))) != NULL) { expr->nodetype = nodetype; expr->l = l; expr->r = r; } +done: return expr; } -- cgit v1.2.3 From 71003f146cc2dacfa8fc7c084404f3399812b64a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 08:34:13 +0200 Subject: milestone: added operations to expr, added evaluation --- grammar/mini.samp | 2 +- grammar/rscript.l | 19 +++--- grammar/rscript.y | 26 +++++++- grammar/utils.c | 187 +++++++++++++++++++++++++++++++++++++++++++++++++++++- grammar/utils.h | 19 ++++-- 5 files changed, 233 insertions(+), 20 deletions(-) diff --git a/grammar/mini.samp b/grammar/mini.samp index 9e00b7cf..8e00917f 100644 --- a/grammar/mini.samp +++ b/grammar/mini.samp @@ -24,7 +24,7 @@ if 1 then { /var/log/log3 @@fwd rger } -if 2*4/-5--(10-3)/*pri("*.*")*/ then { +if not 1==0 and 2*4/-5--(10-3)>7/*pri("*.*")*/ then { action(type="omfile" taget="/var/log/log5") action(type="omfile" taget="/var/log/log6") action(type="omfwd" taget="10.0.0.1" port="514") diff --git a/grammar/rscript.l b/grammar/rscript.l index f7e51e25..596becaf 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -55,21 +55,20 @@ static int preCommentState; "-" | "(" | ")" { return yytext[0]; } -"==" { printf("==\n"); } -"<=" { printf("<=\n"); } -">=" { printf(">=\n"); } +"==" { return CMP_EQ; } +"<=" { return CMP_LE; } +">=" { return CMP_GE; } "!=" | -"<>" { printf("!=\n"); } -"<" { printf("<\n"); } -">" { printf(">\n"); } +"<>" { return CMP_NE; } +"<" { return CMP_LT; } +">" { return CMP_GT; } "contains" { printf("CONTAINS\n"); } "contains_i" { printf("CONTAINS_I\n"); } "startswith" { printf("STARTSWITH\n"); } "startswith_i" { printf("STARTSWITH_I\n"); } -0[0-7]+ { printf("NUMBER (oct) %s\n", yytext); } -0x[0-7a-f] { printf("NUMBER (hex) %s\n", yytext); } -([1-9][0-9]*|0) { printf("NUMBER (dec) %s\n", yytext); - yylval.n = atoll(yytext); return NUMBER; } +0[0-7]+ | /* octal number */ +0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ +([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } \$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); return VAR; } \'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); return STRING; } [ \t\n] diff --git a/grammar/rscript.y b/grammar/rscript.y index 3b680990..3652eec2 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -34,6 +34,12 @@ %token VAR %token STRING %token NUMBER +%token CMP_EQ +%token CMP_NE +%token CMP_LE +%token CMP_GE +%token CMP_LT +%token CMP_GT %type nv nvlst %type obj @@ -44,12 +50,13 @@ %type expr %left AND OR +%left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT %left '+' '-' %left '*' '/' '%' %nonassoc UMINUS NOT %expect 3 -/* two shift/reduce conflicts are created by the CFSYSLINE construct, which we +/* these shift/reduce conflicts are created by the CFSYSLINE construct, which we * unfortunately can not avoid. The problem is that CFSYSLINE can occur both in * global context as well as within an action. It's not permitted somewhere else, * but this is suficient for conflicts. The "dangling else" built-in resolution @@ -85,7 +92,11 @@ rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); | PROPFILT actlst | scriptfilt -scriptfilt: IF expr THEN actlst { printf("if filter detected, expr:\n"); cnfexprPrint($2,0); } +scriptfilt: IF expr THEN actlst { printf("if filter detected, expr:\n"); cnfexprPrint($2,0); + struct exprret r; + cnfexprEval($2, &r); + printf("eval result: %lld\n", r.d.n); + } /* note: we can do some limited block-structuring with the v6 engine. In that case, * we must not support additonal filters inside the blocks, so they must consist of @@ -107,7 +118,16 @@ act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } | LEGACY_ACTION { printf("legacy action: '%s'\n", $1); $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } -expr: expr '+' expr { $$ = cnfexprNew('+', $1, $3); } +expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } + | expr OR expr { $$ = cnfexprNew(OR, $1, $3); } + | NOT expr { $$ = cnfexprNew(NOT, NULL, $2); } + | expr CMP_EQ expr { $$ = cnfexprNew(CMP_EQ, $1, $3); } + | expr CMP_NE expr { $$ = cnfexprNew(CMP_NE, $1, $3); } + | expr CMP_LE expr { $$ = cnfexprNew(CMP_LE, $1, $3); } + | expr CMP_GE expr { $$ = cnfexprNew(CMP_GE, $1, $3); } + | expr CMP_LT expr { $$ = cnfexprNew(CMP_LT, $1, $3); } + | expr CMP_GT expr { $$ = cnfexprNew(CMP_GT, $1, $3); } + | expr '+' expr { $$ = cnfexprNew('+', $1, $3); } | expr '-' expr { $$ = cnfexprNew('-', $1, $3); } | expr '*' expr { $$ = cnfexprNew('*', $1, $3); } | expr '/' expr { $$ = cnfexprNew('/', $1, $3); } diff --git a/grammar/utils.c b/grammar/utils.c index bc300aaf..4087bd81 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -4,6 +4,7 @@ #include #include #include "utils.h" +#include "rscript.tab.h" void readConfFile(FILE *fp, es_str_t **str) @@ -230,7 +231,7 @@ cnfactlstPrint(struct cnfactlst *actlst) } struct cnfexpr* -cnfexprNew(int nodetype, struct cnfexpr *l, struct cnfexpr *r) +cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r) { struct cnfexpr *expr; @@ -250,6 +251,134 @@ done: return expr; } +/* ensure that retval is a number; if string is no number, + * emit error message and set number to 0. + */ +static inline long long +exprret2Number(struct exprret *r) +{ + if(r->datatype == 'S') { + printf("toNumber CONVERSION MISSING\n"); abort(); + } + return r->d.n; +} + +/* ensure that retval is a string; if string is no number, + * emit error message and set number to 0. + */ +static inline es_str_t * +exprret2String(struct exprret *r) +{ + if(r->datatype == 'N') { + printf("toString CONVERSION MISSING\n"); abort(); + } + return r->d.estr; +} + +#define COMP_NUM_BINOP(x) \ + cnfexprEval(expr->l, &l); \ + cnfexprEval(expr->r, &r); \ + ret->datatype = 'N'; \ + ret->d.n = exprret2Number(&l) x exprret2Number(&r) + +/* evaluate an expression. + * Note that we try to avoid malloc whenever possible (because on + * the large overhead it has, especially on highly threaded programs). + * As such, the each caller level must provide buffer space for the + * result on its stack during recursion. This permits the callee to store + * the return value without malloc. As the value is a somewhat larger + * struct, we could otherwise not return it without malloc. + * Note that we implement boolean shortcut operations. For our needs, there + * simply is no case where full evaluation would make any sense at all. + */ +void +cnfexprEval(struct cnfexpr *expr, struct exprret *ret) +{ + struct exprret r, l; /* memory for subexpression results */ + + printf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + switch(expr->nodetype) { + case CMP_EQ: + COMP_NUM_BINOP(==); + break; + case CMP_NE: + COMP_NUM_BINOP(!=); + break; + case CMP_LE: + COMP_NUM_BINOP(<=); + break; + case CMP_GE: + COMP_NUM_BINOP(>=); + break; + case CMP_LT: + COMP_NUM_BINOP(<); + break; + case CMP_GT: + COMP_NUM_BINOP(>); + break; + case OR: + cnfexprEval(expr->l, &l); + ret->datatype = 'N'; + if(exprret2Number(&l)) { + ret->d.n = 1ll; + } else { + cnfexprEval(expr->r, &r); + if(exprret2Number(&r)) + ret->d.n = 1ll; + else + ret->d.n = 0ll; + } + break; + case AND: + cnfexprEval(expr->l, &l); + ret->datatype = 'N'; + if(exprret2Number(&l)) { + cnfexprEval(expr->r, &r); + if(exprret2Number(&r)) + ret->d.n = 1ll; + else + ret->d.n = 0ll; + } else { + ret->d.n = 0ll; + } + break; + case NOT: + cnfexprEval(expr->r, &r); + ret->datatype = 'N'; + ret->d.n = !exprret2Number(&l); + break; + case 'N': + ret->datatype = 'N'; + ret->d.n = ((struct cnfnumval*)expr)->val; + break; + case '+': + COMP_NUM_BINOP(+); + break; + case '-': + COMP_NUM_BINOP(-); + break; + case '*': + COMP_NUM_BINOP(*); + break; + case '/': + COMP_NUM_BINOP(/); + break; + case '%': + COMP_NUM_BINOP(%); + break; + case 'M': + cnfexprEval(expr->r, &r); + ret->datatype = 'N'; + ret->d.n = -exprret2Number(&r); + break; + default: + ret->datatype = 'N'; + ret->d.n = 0ll; + printf("eval error: unknown nodetype %u\n", + (unsigned) expr->nodetype); + break; + } +} inline static void doIndent(indent) @@ -263,6 +392,59 @@ cnfexprPrint(struct cnfexpr *expr, int indent) { //printf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); switch(expr->nodetype) { + case CMP_EQ: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("==\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_NE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("!=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_LE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("<=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_GE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf(">=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_LT: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("<\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_GT: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf(">\n"); + cnfexprPrint(expr->r, indent+1); + break; + case OR: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("OR\n"); + cnfexprPrint(expr->r, indent+1); + break; + case AND: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("AND\n"); + cnfexprPrint(expr->r, indent+1); + break; + case NOT: + doIndent(indent); + printf("NOT\n"); + cnfexprPrint(expr->r, indent+1); + break; case 'N': doIndent(indent); printf("%lld\n", ((struct cnfnumval*)expr)->val); @@ -280,7 +462,8 @@ cnfexprPrint(struct cnfexpr *expr, int indent) cnfexprPrint(expr->r, indent+1); break; default: - printf("error: unknown nodetype\n"); + printf("error: unknown nodetype %u\n", + (unsigned) expr->nodetype); break; } } diff --git a/grammar/utils.h b/grammar/utils.h index a402d4b2..f52bc1e0 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -62,18 +62,18 @@ struct cnfactlst { * be the sole foundation for the AST. */ struct cnfexpr { - int nodetype; + unsigned nodetype; struct cnfexpr *l; struct cnfexpr *r; }; struct cnfnumval { - int nodetype; + unsigned nodetype; long long val; }; struct cnfstringval { - int nodetype; + unsigned nodetype; es_str_t *estr; }; @@ -83,6 +83,16 @@ struct x { }; */ +/* the return value of an expresion evaluation */ +struct exprret { + union { + es_str_t *estr; + long long n; + } d; + char datatype; /* 'N' - number, 'S' - string */ +}; + + void readConfFile(FILE *fp, es_str_t **str); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); void nvlstDestruct(struct nvlst *lst); @@ -95,8 +105,9 @@ void cnfactlstDestruct(struct cnfactlst *actlst); void cnfactlstPrint(struct cnfactlst *actlst); struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); -struct cnfexpr* cnfexprNew(int nodetype, struct cnfexpr *l, struct cnfexpr *r); +struct cnfexpr* cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r); void cnfexprPrint(struct cnfexpr *expr, int indent); +void cnfexprEval(struct cnfexpr *expr, struct exprret *ret); struct cnfnumval* cnfnumvalNew(long long val); struct cnfstringval* cnfstringvalNew(es_str_t *estr); -- cgit v1.2.3 From 25cd9f59ad3a0daa2662e44b2e844116ad487450 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 09:36:12 +0200 Subject: milestone: added comparison ops, prepring for flex include processing --- grammar/mini.samp | 2 +- grammar/parserif.h | 6 ++++++ grammar/rscript.l | 38 ++++++++++++++++++++++++-------------- grammar/rscript.y | 16 +++++++++++++--- grammar/utils.c | 40 +++++++++++++++++++++++++++++++++++++++- 5 files changed, 83 insertions(+), 19 deletions(-) create mode 100644 grammar/parserif.h diff --git a/grammar/mini.samp b/grammar/mini.samp index 8e00917f..71cfbb69 100644 --- a/grammar/mini.samp +++ b/grammar/mini.samp @@ -24,7 +24,7 @@ if 1 then { /var/log/log3 @@fwd rger } -if not 1==0 and 2*4/-5--(10-3)>7/*pri("*.*")*/ then { +if not (1==0) and 2*4/-5--(10-3)>7/*pri("*.*")*/ then { action(type="omfile" taget="/var/log/log5") action(type="omfile" taget="/var/log/log6") action(type="omfwd" taget="10.0.0.1" port="514") diff --git a/grammar/parserif.h b/grammar/parserif.h new file mode 100644 index 00000000..e22b7d34 --- /dev/null +++ b/grammar/parserif.h @@ -0,0 +1,6 @@ +#ifndef PARSERIF_H_DEFINED +#define PARSERIF_H_DEFINED +extern int cnfSetLexFile(char*); +extern int yyparse(); +extern int yydebug; +#endif diff --git a/grammar/rscript.l b/grammar/rscript.l index 596becaf..b7c3e521 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -62,10 +62,10 @@ static int preCommentState; "<>" { return CMP_NE; } "<" { return CMP_LT; } ">" { return CMP_GT; } -"contains" { printf("CONTAINS\n"); } -"contains_i" { printf("CONTAINS_I\n"); } -"startswith" { printf("STARTSWITH\n"); } -"startswith_i" { printf("STARTSWITH_I\n"); } +"contains" { return CMP_CONTAINS; } +"contains_i" { return CMP_CONTAINSI; } +"startswith" { return CMP_STARTSWITH; } +"startswith_i" { return CMP_STARTSWITHI; } 0[0-7]+ | /* octal number */ 0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ ([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } @@ -100,7 +100,7 @@ static int preCommentState; return NAME; } "=" { return(yytext[0]); } \"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { - yylval.estr = es_newStrFromCStr(yytext+1, yyleng-2); + yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); return VALUE; } "/*" { preCommentState = YY_START; BEGIN COMMENT; } "/*" { preCommentState = YY_START; BEGIN COMMENT; } @@ -122,18 +122,28 @@ static int preCommentState; /*<> { printf("EOF reached\n"); }*/ %% - /* -int -main(int argc, char *argv[]) +/* set a new buffers. Returns 0 on success, something else otherwise. */ +int cnfSetLexFile(char *fname) { es_str_t *str; YY_BUFFER_STATE bp; - char ln[10240]; + FILE *fp; + int r = 0; - readConfFile(stdin, &str); - //printf("buffer: %s\n", es_getBufAddr(str)); + if(fname == NULL) { + fp = stdin; + } else { + if((fp = fopen(fname, "r")) == NULL) { + r = 1; + goto done; + } + } + readConfFile(fp, &str); + if(fp != stdin) + fclose(fp); bp = yy_scan_buffer(es_getBufAddr(str), es_strlen(str)); - //yy_switch_to_buffer(bp); - yylex(); + yylineno = 1; + +done: + return r; } -*/ diff --git a/grammar/rscript.y b/grammar/rscript.y index 3652eec2..8bf0e55a 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -40,6 +40,10 @@ %token CMP_GE %token CMP_LT %token CMP_GT +%token CMP_CONTAINS +%token CMP_CONTAINSI +%token CMP_STARTSWITH +%token CMP_STARTSWITHI %type nv nvlst %type obj @@ -50,7 +54,7 @@ %type expr %left AND OR -%left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT +%left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT CMP_CONTAINS CMP_CONTAINSI CMP_STARTSWITH CMP_STARTSWITHI %left '+' '-' %left '*' '/' '%' %nonassoc UMINUS NOT @@ -127,6 +131,10 @@ expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | expr CMP_GE expr { $$ = cnfexprNew(CMP_GE, $1, $3); } | expr CMP_LT expr { $$ = cnfexprNew(CMP_LT, $1, $3); } | expr CMP_GT expr { $$ = cnfexprNew(CMP_GT, $1, $3); } + | expr CMP_CONTAINS expr { $$ = cnfexprNew(CMP_CONTAINS, $1, $3); } + | expr CMP_CONTAINSI expr { $$ = cnfexprNew(CMP_CONTAINSI, $1, $3); } + | expr CMP_STARTSWITH expr { $$ = cnfexprNew(CMP_STARTSWITH, $1, $3); } + | expr CMP_STARTSWITHI expr { $$ = cnfexprNew(CMP_STARTSWITHI, $1, $3); } | expr '+' expr { $$ = cnfexprNew('+', $1, $3); } | expr '-' expr { $$ = cnfexprNew('-', $1, $3); } | expr '*' expr { $$ = cnfexprNew('*', $1, $3); } @@ -134,8 +142,8 @@ expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | expr '%' expr { $$ = cnfexprNew('%', $1, $3); } | '(' expr ')' { $$ = $2; printf("( expr)\n"); } | '-' expr %prec UMINUS { printf("uminus\n"); $$ = cnfexprNew('M', NULL, $2); } - | NUMBER { $$ = cnfnumvalNew($1); } - | STRING { $$ = cnfstringvalNew($1); } + | NUMBER { $$ = (struct cnfexpr*) cnfnumvalNew($1); } + | STRING { $$ = (struct cnfexpr*) cnfstringvalNew($1); } | VAR { printf("variables not yet implemented!\n"); } %% @@ -144,9 +152,11 @@ int yyerror(char *s) printf("yyerror called: %s\n", s); } +/* int main() { yydebug = 0; return yyparse(); } +*/ diff --git a/grammar/utils.c b/grammar/utils.c index 4087bd81..d09a34a9 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -4,6 +4,7 @@ #include #include #include "utils.h" +#include "parserif.h" #include "rscript.tab.h" void @@ -345,7 +346,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) case NOT: cnfexprEval(expr->r, &r); ret->datatype = 'N'; - ret->d.n = !exprret2Number(&l); + ret->d.n = !exprret2Number(&r); break; case 'N': ret->datatype = 'N'; @@ -428,6 +429,30 @@ cnfexprPrint(struct cnfexpr *expr, int indent) printf(">\n"); cnfexprPrint(expr->r, indent+1); break; + case CMP_CONTAINS: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("CONTAINS\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_CONTAINSI: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("CONTAINS_I\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_STARTSWITH: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("STARTSWITH\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_STARTSWITHI: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + printf("STARTSWITH_I\n"); + cnfexprPrint(expr->r, indent+1); + break; case OR: cnfexprPrint(expr->l, indent+1); doIndent(indent); @@ -500,3 +525,16 @@ cstrPrint(char *text, es_str_t *estr) free(str); } + +int +main(int argc, char *argv[]) +{ + int r; + + cnfSetLexFile(argc == 1 ? NULL : argv[1]); + yydebug = 0; + r = yyparse(); + printf("yyparse() returned %d\n", r); + return r; +} + -- cgit v1.2.3 From 4598557192c46e43edc5cc09b89c30045aacdb33 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 11:24:04 +0200 Subject: milestone: support for include files added support for directories will be added during rsyslog integration --- grammar/debian.conf | 2 +- grammar/rscript.l | 98 ++++++++++++++++++++++++++++++++++++++++++++++++----- grammar/rscript.y | 1 + grammar/utils.c | 16 +++++++-- 4 files changed, 106 insertions(+), 11 deletions(-) diff --git a/grammar/debian.conf b/grammar/debian.conf index e5e54fde..79c1f07d 100644 --- a/grammar/debian.conf +++ b/grammar/debian.conf @@ -43,7 +43,7 @@ $Umask 0022 # # Include all config files in /etc/rsyslog.d/ # -$IncludeConfig /etc/rsyslog.d/*.conf +#$IncludeConfig /etc/rsyslog.d/*.conf ############### diff --git a/grammar/rscript.l b/grammar/rscript.l index b7c3e521..7e7ab925 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -13,13 +13,17 @@ * Released under the GNU GPL v3. For details see LICENSE file. */ -%option noyywrap nodefault case-insensitive +%option noyywrap nodefault case-insensitive yylineno /*%option noyywrap nodefault case-insensitive */ %x INOBJ /* INOBJ is selected if we are inside an object (name/value pairs!) */ %x COMMENT /* COMMENT is "the usual trick" to handle C-style comments */ +%x INCL + /* INCL is in $IncludeConfig processing (skip to include file) */ +%x LINENO + /* LINENO: support for setting the linenumber */ %x EXPR /* EXPR is a bit ugly, but we need it to support pre v6-syntax. The problem * is that cfsysline statement start with $..., the same like variables in @@ -37,7 +41,16 @@ #include #include "utils.h" #include "rscript.tab.h" -static int preCommentState; +static int preCommentState; /* save for lex state before a comment */ + +struct bufstack { + struct bufstack *prev; + YY_BUFFER_STATE bs; + int lineno; + char *fn; +} *currbs = NULL; + +char *currfn; /* name of currently processed file */ %} %% @@ -77,6 +90,23 @@ static int preCommentState; "{" { return '{'; } "}" { return '}'; } "ruleset" { printf("RULESET\n"); } + /* line number support because the "preprocessor" combines lines and so needs + * to tell us the real source line. + */ +"preprocfilelinenumber(" { BEGIN LINENO; } +[0-9]+ { printf("linno was %d, set to %d\n", yylineno, atoi(yytext) -1); + yylineno = atoi(yytext) - 1; } +")" { BEGIN INITIAL; } +.|\n + /* $IncludeConfig must be detected as part of CFSYSLINE, because this is + * always the longest match :-( + */ +.|\n +[^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) + yyterminate(); + BEGIN INITIAL; + } + "global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; BEGIN INOBJ; return BEGINOBJ; } @@ -107,28 +137,36 @@ static int preCommentState; "*/" { BEGIN preCommentState; } ([^*]|\n)+|. -#.*\n /* skip comments in input */ +#.*$ /* skip comments in input */ [ \n\t] . { printf("INOBJ: invalid char '%s'\n", yytext); } /* CFSYSLINE is valid in all modes */ -\$[a-z]+.*$ { yylval.s = strdup(yytext); return CFSYSLINE; } +\$[a-z]+.*$ { /* see common on $IncludeConfig above */ + if(!strncasecmp(yytext, "$includeconfig ", 14)) { + yyless(14); + BEGIN INCL; + } else { + yylval.s = strdup(yytext); + return CFSYSLINE; + } + } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ . { printf("invalid char: %s\n", yytext); } - /*<> { printf("EOF reached\n"); }*/ +<> { if(popfile() != 0) yyterminate(); } %% /* set a new buffers. Returns 0 on success, something else otherwise. */ int cnfSetLexFile(char *fname) { - es_str_t *str; - YY_BUFFER_STATE bp; + es_str_t *str = NULL; FILE *fp; int r = 0; + struct bufstack *bs; if(fname == NULL) { fp = stdin; @@ -141,9 +179,53 @@ int cnfSetLexFile(char *fname) readConfFile(fp, &str); if(fp != stdin) fclose(fp); - bp = yy_scan_buffer(es_getBufAddr(str), es_strlen(str)); + + /* maintain stack */ + if((bs = malloc(sizeof(struct bufstack))) == NULL) { + r = 1; + goto done; + } + + if(currbs != NULL) + currbs->lineno = yylineno; + bs->prev = currbs; + bs->fn = strdup(fname); + bs->bs = yy_scan_buffer(es_getBufAddr(str), es_strlen(str)); + currbs = bs; + currfn = bs->fn; yylineno = 1; done: + if(r != 0) { + if(str != NULL) + es_deleteStr(str); + } return r; } + + +/* returns 0 on success, something else otherwise */ +int +popfile(void) +{ + struct bufstack *bs = currbs; + + if(bs == NULL) + return 1; + + /* delte current entry */ + yy_delete_buffer(bs->bs); + free(bs->fn); + + /* switch back to previous */ + currbs = bs->prev; + free(bs); + + if(currbs == NULL) + return 1; /* all processed */ + + yy_switch_to_buffer(currbs->bs); + yylineno = currbs->lineno; + currfn = currbs->fn; + return 0; +} diff --git a/grammar/rscript.y b/grammar/rscript.y index 8bf0e55a..440a5525 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -4,6 +4,7 @@ #include #include "utils.h" #define YYDEBUG 1 +extern int yylineno; %} %union { diff --git a/grammar/utils.c b/grammar/utils.c index d09a34a9..4e93c26c 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -11,13 +11,23 @@ void readConfFile(FILE *fp, es_str_t **str) { char ln[10240]; + char buf[512]; + int lenBuf; + int bWriteLineno = 0; int len, i; int start; /* start index of to be submitted text */ int bContLine = 0; + int lineno = 0; *str = es_newStr(4096); while(fgets(ln, sizeof(ln), fp) != NULL) { + ++lineno; + if(bWriteLineno) { + bWriteLineno = 0; + lenBuf = sprintf(buf, "PreprocFileLineNumber(%d)\n", lineno); + es_addBuf(str, buf, lenBuf); + } len = strlen(ln); /* if we are continuation line, we need to drop leading WS */ if(bContLine) { @@ -33,13 +43,15 @@ readConfFile(FILE *fp, es_str_t **str) --i; bContLine = 1; } else { + if(bContLine) /* write line number if we had cont line */ + bWriteLineno = 1; bContLine = 0; } /* add relevant data to buffer */ es_addBuf(str, ln+start, i+1 - start); - if(!bContLine) - es_addChar(str, '\n'); } + if(!bContLine) + es_addChar(str, '\n'); } /* indicate end of buffer to flex */ es_addChar(str, '\0'); -- cgit v1.2.3 From b966576f1e740966b35579d612050f4dfc09606c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 11:57:55 +0200 Subject: milestone: added BSD-style blocks --- grammar/debian.conf | 4 ++++ grammar/rscript.l | 8 ++++++-- grammar/rscript.y | 6 +++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/grammar/debian.conf b/grammar/debian.conf index 79c1f07d..91a67307 100644 --- a/grammar/debian.conf +++ b/grammar/debian.conf @@ -110,6 +110,10 @@ news.notice -/var/log/news/news.notice # NOTE: adjust the list below, or you'll go crazy if you have a reasonably # busy site.. # +!ThisTag ++host1 +-host2 ++* daemon.*;mail.*;\ news.err;\ *.=debug;*.=info;\ diff --git a/grammar/rscript.l b/grammar/rscript.l index 7e7ab925..a4c37c81 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -122,9 +122,10 @@ char *currfn; /* name of currently processed file */ ^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("token prifilt '%s'\n", yytext); yylval.s = strdup(yytext); return PRIFILT; } "*" | +\-\/[^*][^\n]* | \/[^*][^\n]* | [\|\.\-\@:~][^\n]+ | -[a-z0-9_\-\+]+ { yylval.s = strdup(yytext); return LEGACY_ACTION; } +[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); printf("LEGACY_ACT: '%s'\n", yytext);return LEGACY_ACTION; } ")" { BEGIN INITIAL; return ENDOBJ; } [a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); return NAME; } @@ -141,7 +142,6 @@ char *currfn; /* name of currently processed file */ [ \n\t] . { printf("INOBJ: invalid char '%s'\n", yytext); } - /* CFSYSLINE is valid in all modes */ \$[a-z]+.*$ { /* see common on $IncludeConfig above */ if(!strncasecmp(yytext, "$includeconfig ", 14)) { yyless(14); @@ -151,6 +151,10 @@ char *currfn; /* name of currently processed file */ return CFSYSLINE; } } +![^ \t\n]+[ \t]*$ { printf("BSD TAG '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } +[+-]\*[ \t\n]*#.*$ { printf("BSD HOST '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +[+-]\*[ \t\n]*$ { printf("BSD HOST '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { printf("BSD HOST '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ diff --git a/grammar/rscript.y b/grammar/rscript.y index 440a5525..186d0981 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -27,6 +27,8 @@ extern int yylineno; %token LEGACY_ACTION %token PRIFILT %token PROPFILT +%token BSD_TAG_SELECTOR +%token BSD_HOST_SELECTOR %token IF %token THEN %token OR @@ -73,8 +75,10 @@ extern int yylineno; %% conf: /* empty (to end recursion) */ | obj conf - | cfsysline conf | rule conf + | cfsysline conf + | BSD_TAG_SELECTOR conf + | BSD_HOST_SELECTOR conf obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); cnfobjPrint($$); -- cgit v1.2.3 From 3613f7e1bf0e5eb06d2049eaebb0f39afb71d153 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 12:22:48 +0200 Subject: milestone: PROPFILT added to grammar --- grammar/debian.conf | 1 - grammar/rscript.l | 14 ++++++++------ grammar/rscript.y | 14 ++++++++------ 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/grammar/debian.conf b/grammar/debian.conf index 91a67307..166cde52 100644 --- a/grammar/debian.conf +++ b/grammar/debian.conf @@ -118,6 +118,5 @@ daemon.*;mail.*;\ news.err;\ *.=debug;*.=info;\ *.=notice;*.=warn |/dev/xconsole - # samples added to get full "flavor" of what we need to support... :msg, contains, "error" /var/log/somelog diff --git a/grammar/rscript.l b/grammar/rscript.l index a4c37c81..6472ca13 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -117,6 +117,7 @@ char *currfn; /* name of currently processed file */ "action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { printf("PROP-FILT: '%s'\n", yytext); + return PROPFILT; } ^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("token prifilt '%s'\n", yytext); yylval.s = strdup(yytext); return PRIFILT; } @@ -124,8 +125,9 @@ char *currfn; /* name of currently processed file */ "*" | \-\/[^*][^\n]* | \/[^*][^\n]* | -[\|\.\-\@:~][^\n]+ | -[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); printf("LEGACY_ACT: '%s'\n", yytext);return LEGACY_ACTION; } +:[a-z0-9]+:[^\n]* | +[\|\.\-\@~][^\n]+ | +[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); printf("LEGA ACT: '%s'\n", yytext);return LEGACY_ACTION; } ")" { BEGIN INITIAL; return ENDOBJ; } [a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); return NAME; } @@ -151,10 +153,10 @@ char *currfn; /* name of currently processed file */ return CFSYSLINE; } } -![^ \t\n]+[ \t]*$ { printf("BSD TAG '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } -[+-]\*[ \t\n]*#.*$ { printf("BSD HOST '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -[+-]\*[ \t\n]*$ { printf("BSD HOST '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { printf("BSD HOST '%s'\n", yytext); yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +![^ \t\n]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } +[+-]\*[ \t\n]*#.*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +[+-]\*[ \t\n]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ diff --git a/grammar/rscript.y b/grammar/rscript.y index 186d0981..8dc00620 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -75,10 +75,10 @@ extern int yylineno; %% conf: /* empty (to end recursion) */ | obj conf - | rule conf - | cfsysline conf - | BSD_TAG_SELECTOR conf - | BSD_HOST_SELECTOR conf + | rule conf { printf("RULE processed, back in main\n"); } + | cfsysline conf { printf("cfsysline: %s\n", $1); } + | BSD_TAG_SELECTOR conf { printf("BSD tag '%s'\n", $1); } + | BSD_HOST_SELECTOR conf { printf("BSD host '%s'\n", $1); } obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); cnfobjPrint($$); @@ -89,7 +89,7 @@ obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); cnfobjDestruct(t); printf("XXXX: this is an new-style action!\n"); } -cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1); } +cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1);$$ = $1 } nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } @@ -98,7 +98,9 @@ nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); $2 = cnfactlstReverse($2); cnfactlstPrint($2); } - | PROPFILT actlst + | PROPFILT actlst { printf("PROPFILT: %s\n", $1); free($1); + $2 = cnfactlstReverse($2); + cnfactlstPrint($2); } | scriptfilt scriptfilt: IF expr THEN actlst { printf("if filter detected, expr:\n"); cnfexprPrint($2,0); -- cgit v1.2.3 From 11f50cfe836ec104b4167e7c6c5d207a4d8fe081 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 12:38:36 +0200 Subject: bugfix(new bug): cfsyslines were not properly reversed during parsing --- grammar/utils.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/grammar/utils.c b/grammar/utils.c index 4e93c26c..f25977d5 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -187,12 +187,10 @@ static inline struct cnfcfsyslinelst* cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) { struct cnfcfsyslinelst *curr, *prev; - +printf("syslinerevers on %p\n", lst); if(lst == NULL) return NULL; - prev = lst; - lst = lst->next; - prev->next = NULL; + prev = NULL; while(lst != NULL) { curr = lst; lst = lst->next; @@ -207,9 +205,7 @@ cnfactlstReverse(struct cnfactlst *actlst) { struct cnfactlst *curr, *prev; - prev = actlst; - actlst = actlst->next; - prev->next = NULL; + prev = NULL; while(actlst != NULL) { curr = actlst; actlst = actlst->next; -- cgit v1.2.3 From bffa39ab9539c0e26dbbfb450f42de93638292e1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 15:31:09 +0200 Subject: milstone: top-level grammer now ready for integration (but script detail still missing) --- grammar/debian.conf | 10 ++++++++ grammar/rscript.l | 13 +++++----- grammar/rscript.y | 73 +++++++++++++++++++++++++---------------------------- grammar/utils.c | 42 ++++++++++++++++++++++++++---- grammar/utils.h | 30 ++++++++++++++++++++++ 5 files changed, 118 insertions(+), 50 deletions(-) diff --git a/grammar/debian.conf b/grammar/debian.conf index 166cde52..ff7708c5 100644 --- a/grammar/debian.conf +++ b/grammar/debian.conf @@ -118,5 +118,15 @@ daemon.*;mail.*;\ news.err;\ *.=debug;*.=info;\ *.=notice;*.=warn |/dev/xconsole +$cfs 21 +$cfs 22 +$cfs 23 # samples added to get full "flavor" of what we need to support... :msg, contains, "error" /var/log/somelog +$cfs 11 +$cfs 12 +$cfs 13 +module() +$cfs 1 +$cfs 2 +$cfs 3 diff --git a/grammar/rscript.l b/grammar/rscript.l index 6472ca13..68f4d406 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -94,8 +94,7 @@ char *currfn; /* name of currently processed file */ * to tell us the real source line. */ "preprocfilelinenumber(" { BEGIN LINENO; } -[0-9]+ { printf("linno was %d, set to %d\n", yylineno, atoi(yytext) -1); - yylineno = atoi(yytext) - 1; } +[0-9]+ { yylineno = atoi(yytext) - 1; } ")" { BEGIN INITIAL; } .|\n /* $IncludeConfig must be detected as part of CFSYSLINE, because this is @@ -116,18 +115,18 @@ char *currfn; /* name of currently processed file */ BEGIN INOBJ; return BEGINOBJ; } "action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { - printf("PROP-FILT: '%s'\n", yytext); - return PROPFILT; - } + yylval.s = strdup(yytext); return PROPFILT; } -^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { printf("token prifilt '%s'\n", yytext); yylval.s = strdup(yytext); return PRIFILT; } +^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } "*" | \-\/[^*][^\n]* | \/[^*][^\n]* | :[a-z0-9]+:[^\n]* | [\|\.\-\@~][^\n]+ | -[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); printf("LEGA ACT: '%s'\n", yytext);return LEGACY_ACTION; } +[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); + // printf("lex: LEGA ACT: '%s'\n", yytext); + return LEGACY_ACTION; } ")" { BEGIN INITIAL; return ENDOBJ; } [a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); return NAME; } diff --git a/grammar/rscript.y b/grammar/rscript.y index 8dc00620..aaf133eb 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -16,6 +16,7 @@ extern int yylineno; struct nvlst *nvlst; struct cnfactlst *actlst; struct cnfexpr *expr; + struct cnfrule *rule; } %token NAME @@ -55,6 +56,8 @@ extern int yylineno; %type cfsysline %type block %type expr +%type rule +%type scriptfilt %left AND OR %left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT CMP_CONTAINS CMP_CONTAINSI CMP_STARTSWITH CMP_STARTSWITHI @@ -73,60 +76,54 @@ extern int yylineno; * were exactly these conflicts exits. */ %% +/* note: we use left recursion below, because that saves stack space AND + * offers the right sequence so that we can submit the top-layer objects + * one by one. + */ conf: /* empty (to end recursion) */ - | obj conf - | rule conf { printf("RULE processed, back in main\n"); } - | cfsysline conf { printf("cfsysline: %s\n", $1); } - | BSD_TAG_SELECTOR conf { printf("BSD tag '%s'\n", $1); } - | BSD_HOST_SELECTOR conf { printf("BSD host '%s'\n", $1); } - -obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); - cnfobjPrint($$); - cnfobjDestruct($$); - } - | BEGIN_ACTION nvlst ENDOBJ { struct cnfobj *t = cnfobjNew(CNFOBJ_ACTION, $2); - cnfobjPrint(t); - cnfobjDestruct(t); - printf("XXXX: this is an new-style action!\n"); - } -cfsysline: CFSYSLINE { printf("XXXX: processing CFSYSLINE: %s\n", $1);$$ = $1 } + | conf obj { printf("global:config: "); + cnfobjPrint($2); cnfobjDestruct($2); } + | conf rule { printf("global:rule processed\n"); + cnfrulePrint($2); } + | conf cfsysline { printf("global:cfsysline: %s\n", $2); } + | conf BSD_TAG_SELECTOR { printf("global:BSD tag '%s'\n", $2); } + | conf BSD_HOST_SELECTOR { printf("global:BSD host '%s'\n", $2); } + +obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } + | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } +cfsysline: CFSYSLINE { $$ = $1 } nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } -rule: PRIFILT actlst { printf("PRIFILT: %s\n", $1); free($1); - $2 = cnfactlstReverse($2); - cnfactlstPrint($2); } - | PROPFILT actlst { printf("PROPFILT: %s\n", $1); free($1); - $2 = cnfactlstReverse($2); - cnfactlstPrint($2); } - | scriptfilt - -scriptfilt: IF expr THEN actlst { printf("if filter detected, expr:\n"); cnfexprPrint($2,0); - struct exprret r; - cnfexprEval($2, &r); - printf("eval result: %lld\n", r.d.n); +rule: PRIFILT actlst { $$ = cnfruleNew(CNFFILT_PRI, $2); $$->filt.s = $1; } + | PROPFILT actlst { $$ = cnfruleNew(CNFFILT_PROP, $2); $$->filt.s = $1; } + | scriptfilt { $$ = $1; } + +scriptfilt: IF expr THEN actlst { $$ = cnfruleNew(CNFFILT_SCRIPT, $4); + $$->filt.expr = $2; + //struct exprret r; + //cnfexprEval($2, &r); + // printf("eval result: %lld\n", r.d.n); } /* note: we can do some limited block-structuring with the v6 engine. In that case, * we must not support additonal filters inside the blocks, so they must consist of * "act", only. We can implement that via the "&" actlist logic. */ -block: actlst - | block actlst +block: actlst { $$ = $1; } + | block actlst { $2->next = $1; $$ = $2; } /* v7: | actlst v7: | block rule */ -actlst: act { printf("action (end actlst)\n");$$=$1; } - | actlst '&' act { printf("in actionlist \n"); - $3->next = $1; $$ = $3; } - | actlst cfsysline { printf("in actionlist/CFSYSLINE: %s\n", $2); - $$ = cnfactlstAddSysline($1, $2); } +actlst: act { $$=$1; } + | actlst '&' act { $3->next = $1; $$ = $3; } + | actlst cfsysline { $$ = cnfactlstAddSysline($1, $2); } | '{' block '}' { $$ = $2; } act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } - | LEGACY_ACTION { printf("legacy action: '%s'\n", $1); + | LEGACY_ACTION { //printf("legacy action: '%s'\n", $1); $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } @@ -147,8 +144,8 @@ expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | expr '*' expr { $$ = cnfexprNew('*', $1, $3); } | expr '/' expr { $$ = cnfexprNew('/', $1, $3); } | expr '%' expr { $$ = cnfexprNew('%', $1, $3); } - | '(' expr ')' { $$ = $2; printf("( expr)\n"); } - | '-' expr %prec UMINUS { printf("uminus\n"); $$ = cnfexprNew('M', NULL, $2); } + | '(' expr ')' { $$ = $2; } + | '-' expr %prec UMINUS { $$ = cnfexprNew('M', NULL, $2); } | NUMBER { $$ = (struct cnfexpr*) cnfnumvalNew($1); } | STRING { $$ = (struct cnfexpr*) cnfstringvalNew($1); } | VAR { printf("variables not yet implemented!\n"); } diff --git a/grammar/utils.c b/grammar/utils.c index f25977d5..b04274c1 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -187,7 +187,6 @@ static inline struct cnfcfsyslinelst* cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) { struct cnfcfsyslinelst *curr, *prev; -printf("syslinerevers on %p\n", lst); if(lst == NULL) return NULL; prev = NULL; @@ -207,6 +206,7 @@ cnfactlstReverse(struct cnfactlst *actlst) prev = NULL; while(actlst != NULL) { + //printf("reversing: %s\n", actlst->data.legActLine); curr = actlst; actlst = actlst->next; curr->syslines = cnfcfsyslinelstReverse(curr->syslines); @@ -221,8 +221,8 @@ cnfactlstPrint(struct cnfactlst *actlst) { struct cnfcfsyslinelst *cflst; - printf("---------- cnfactlst %p:\n", actlst); while(actlst != NULL) { + printf("aclst %p: ", actlst); if(actlst->actType == CNFACT_V2) { printf("V2 action type: "); nvlstPrint(actlst->data.lst); @@ -232,11 +232,10 @@ cnfactlstPrint(struct cnfactlst *actlst) } for( cflst = actlst->syslines ; cflst != NULL ; cflst = cflst->next) { - printf("cfsysline: '%s'\n", cflst->line); + printf("action:cfsysline: '%s'\n", cflst->line); } actlst = actlst->next; } - printf("----------\n"); } struct cnfexpr* @@ -305,7 +304,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) { struct exprret r, l; /* memory for subexpression results */ - printf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + //printf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: COMP_NUM_BINOP(==); @@ -523,6 +522,39 @@ cnfstringvalNew(es_str_t *estr) return strval; } +struct cnfrule * +cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) +{ + struct cnfrule* cnfrule; + if((cnfrule = malloc(sizeof(struct cnfrule))) != NULL) { + cnfrule->nodetype = 'R'; + cnfrule->filttype = filttype; + cnfrule->actlst = cnfactlstReverse(actlst); + } + return cnfrule; +} + +void +cnfrulePrint(struct cnfrule *rule) +{ + printf("------ start rule %p:\n", rule); + printf("%s: ", cnfFiltType2str(rule->filttype)); + switch(rule->filttype) { + case CNFFILT_NONE: + break; + case CNFFILT_PRI: + case CNFFILT_PROP: + printf("%s\n", rule->filt.s); + break; + case CNFFILT_SCRIPT: + printf("\n"); + cnfexprPrint(rule->filt.expr, 0); + break; + } + cnfactlstPrint(rule->actlst); + printf("------ end rule %p\n", rule); +} + /* debug helper */ void cstrPrint(char *text, es_str_t *estr) diff --git a/grammar/utils.h b/grammar/utils.h index f52bc1e0..9dfac5b1 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -61,6 +61,34 @@ struct cnfactlst { /* the following structures support expressions, and may (very much later * be the sole foundation for the AST. */ +enum cnfFiltType { CNFFILT_NONE, CNFFILT_PRI, CNFFILT_PROP, CNFFILT_SCRIPT }; +static inline char* +cnfFiltType2str(enum cnfFiltType filttype) +{ + switch(filttype) { + case CNFFILT_NONE: + return("filter:none"); + case CNFFILT_PRI: + return("filter:pri"); + case CNFFILT_PROP: + return("filter:prop"); + case CNFFILT_SCRIPT: + return("filter:script"); + } + return("error:invalid_filter_type"); /* should never be reached */ +} + + +struct cnfrule { + unsigned nodetype; + enum cnfFiltType filttype; + union { + char *s; + struct cnfexpr *expr; + } filt; + struct cnfactlst *actlst; +}; + struct cnfexpr { unsigned nodetype; struct cnfexpr *l; @@ -110,6 +138,8 @@ void cnfexprPrint(struct cnfexpr *expr, int indent); void cnfexprEval(struct cnfexpr *expr, struct exprret *ret); struct cnfnumval* cnfnumvalNew(long long val); struct cnfstringval* cnfstringvalNew(es_str_t *estr); +struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst); +void cnfrulePrint(struct cnfrule *rule); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); -- cgit v1.2.3 From 460010068b1d46c23829e7106380ffb8527df949 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 16:00:26 +0200 Subject: milestone: strings and vars are now stored correctly in in-memory representation --- grammar/debian.new | 6 +++--- grammar/rscript.l | 7 +++++-- grammar/rscript.y | 15 +++------------ grammar/utils.c | 20 ++++++++++++++++++++ grammar/utils.h | 12 ++++++++++++ 5 files changed, 43 insertions(+), 17 deletions(-) diff --git a/grammar/debian.new b/grammar/debian.new index e995a2e8..6cf9b5e5 100644 --- a/grammar/debian.new +++ b/grammar/debian.new @@ -47,7 +47,7 @@ $Umask 0022 # # Include all config files in /etc/rsyslog.d/ # -$IncludeConfig /etc/rsyslog.d/*.conf +#$IncludeConfig /etc/rsyslog.d/*.conf ############### @@ -102,7 +102,7 @@ daemon.*;mail.*;\ global (dnscache="yes" arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") # samples added to get full "flavor" of what we need to support... :msg, contains, "error" /var/log/somelog -action(type=omfile target=/var/log/mail/log) +action(type="omfile" target="/var/log/mail/log") *.* /* comment */ * # test *.info :ommysql:, tra, la , la # comment (comment to be part of old style line!) @@ -134,7 +134,7 @@ then /dev/tty10 & |/dev/xconsole *.* rger # write to user (ugly...) -ruleset name +#ruleset name # FEDORA, a bit more complex config # ### begin forwarding rule ### diff --git a/grammar/rscript.l b/grammar/rscript.l index 68f4d406..37f08f66 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -82,8 +82,11 @@ char *currfn; /* name of currently processed file */ 0[0-7]+ | /* octal number */ 0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ ([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } -\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { printf("VARNAME: '%s'\n", yytext); return VAR; } -\'([^'\\]|\\['])*\' { printf("EXPR string: -%s-\n", yytext); return STRING; } +\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } +\'([^'\\]|\\['])*\' { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return STRING; } +\"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return STRING; } [ \t\n] . { printf("invalid char in expr: %s\n", yytext); } "&" { return '&'; } diff --git a/grammar/rscript.y b/grammar/rscript.y index aaf133eb..281a1775 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -35,7 +35,7 @@ extern int yylineno; %token OR %token AND %token NOT -%token VAR +%token VAR %token STRING %token NUMBER %token CMP_EQ @@ -148,19 +148,10 @@ expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | '-' expr %prec UMINUS { $$ = cnfexprNew('M', NULL, $2); } | NUMBER { $$ = (struct cnfexpr*) cnfnumvalNew($1); } | STRING { $$ = (struct cnfexpr*) cnfstringvalNew($1); } - | VAR { printf("variables not yet implemented!\n"); } + | VAR { $$ = (struct cnfexpr*) cnfvarNew($1); } %% int yyerror(char *s) { - printf("yyerror called: %s\n", s); + printf("parse failure on or before line %d: %s\n", yylineno, s); } - -/* -int main() -{ - yydebug = 0; - return yyparse(); -} - -*/ diff --git a/grammar/utils.c b/grammar/utils.c index b04274c1..791a8967 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -481,6 +481,15 @@ cnfexprPrint(struct cnfexpr *expr, int indent) doIndent(indent); printf("%lld\n", ((struct cnfnumval*)expr)->val); break; + case 'V': + doIndent(indent); + printf("var '%s'\n", ((struct cnfvar*)expr)->name); + break; + case 'S': + doIndent(indent); + cstrPrint("string '", ((struct cnfstringval*)expr)->estr); + printf("'\n"); + break; case '+': case '-': case '*': @@ -522,6 +531,17 @@ cnfstringvalNew(es_str_t *estr) return strval; } +struct cnfvar* +cnfvarNew(char *name) +{ + struct cnfvar *var; + if((var = malloc(sizeof(struct cnfvar))) != NULL) { + var->nodetype = 'V'; + var->name = name; + } + return var; +} + struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) { diff --git a/grammar/utils.h b/grammar/utils.h index 9dfac5b1..fb1462a3 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -60,6 +60,12 @@ struct cnfactlst { /* the following structures support expressions, and may (very much later * be the sole foundation for the AST. + * + * nodetypes (list not yet complete) + * S - string + * N - number + * V - var + * R - rule */ enum cnfFiltType { CNFFILT_NONE, CNFFILT_PRI, CNFFILT_PROP, CNFFILT_SCRIPT }; static inline char* @@ -105,6 +111,11 @@ struct cnfstringval { es_str_t *estr; }; +struct cnfvar { + unsigned nodetype; + char *name; +}; + /* future extensions struct x { int nodetype; @@ -140,6 +151,7 @@ struct cnfnumval* cnfnumvalNew(long long val); struct cnfstringval* cnfstringvalNew(es_str_t *estr); struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst); void cnfrulePrint(struct cnfrule *rule); +struct cnfvar* cnfvarNew(char *name); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); -- cgit v1.2.3 From 3d08f4e0f2dcc0f2216e11104ec43507eab22078 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 16:06:50 +0200 Subject: cleanup --- grammar/rscript.l | 13 ++----------- grammar/rscript.y | 37 ++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 30 deletions(-) diff --git a/grammar/rscript.l b/grammar/rscript.l index 37f08f66..a0ed3b0c 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -1,4 +1,4 @@ - /* lex file for rsyslog config format v2. + /* Lex file for rsyslog config format v2 (RainerScript). * Please note: this file introduces the new config format, but maintains * backward compatibility. In order to do so, the grammar is not 100% clean, * but IMHO still sufficiently easy both to understand for programmers @@ -106,10 +106,7 @@ char *currfn; /* name of currently processed file */ .|\n [^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) yyterminate(); - BEGIN INITIAL; - } - - + BEGIN INITIAL; } "global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; BEGIN INOBJ; return BEGINOBJ; } "input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; @@ -119,9 +116,7 @@ char *currfn; /* name of currently processed file */ "action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { yylval.s = strdup(yytext); return PROPFILT; } - ^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } - "*" | \-\/[^*][^\n]* | \/[^*][^\n]* | @@ -141,11 +136,9 @@ char *currfn; /* name of currently processed file */ "/*" { preCommentState = YY_START; BEGIN COMMENT; } "*/" { BEGIN preCommentState; } ([^*]|\n)+|. - #.*$ /* skip comments in input */ [ \n\t] . { printf("INOBJ: invalid char '%s'\n", yytext); } - \$[a-z]+.*$ { /* see common on $IncludeConfig above */ if(!strncasecmp(yytext, "$includeconfig ", 14)) { yyless(14); @@ -159,12 +152,10 @@ char *currfn; /* name of currently processed file */ [+-]\*[ \t\n]*#.*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } [+-]\*[ \t\n]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } ^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } - \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ . { printf("invalid char: %s\n", yytext); } - <> { if(popfile() != 0) yyterminate(); } %% diff --git a/grammar/rscript.y b/grammar/rscript.y index 281a1775..75fce49d 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -1,3 +1,17 @@ + /* Bison file for rsyslog config format v2 (RainerScript). + * Please note: this file introduces the new config format, but maintains + * backward compatibility. In order to do so, the grammar is not 100% clean, + * but IMHO still sufficiently easy both to understand for programmers + * maitaining the code as well as users writing the config file. Users are, + * of course, encouraged to use new constructs only. But it needs to be noted + * that some of the legacy constructs (specifically the in-front-of-action + * PRI filter) are very hard to beat in ease of use, at least for simpler + * cases. So while we hope that cfsysline support can be dropped some time in + * the future, we will probably keep these useful constructs. + * + * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH + * Released under the GNU GPL v3. For details see LICENSE file. + */ %{ #include @@ -92,40 +106,25 @@ conf: /* empty (to end recursion) */ obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } cfsysline: CFSYSLINE { $$ = $1 } - nvlst: { $$ = NULL; } | nvlst nv { $2->next = $1; $$ = $2; } -nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } - +nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } rule: PRIFILT actlst { $$ = cnfruleNew(CNFFILT_PRI, $2); $$->filt.s = $1; } | PROPFILT actlst { $$ = cnfruleNew(CNFFILT_PROP, $2); $$->filt.s = $1; } | scriptfilt { $$ = $1; } scriptfilt: IF expr THEN actlst { $$ = cnfruleNew(CNFFILT_SCRIPT, $4); - $$->filt.expr = $2; - //struct exprret r; - //cnfexprEval($2, &r); - // printf("eval result: %lld\n", r.d.n); - } - -/* note: we can do some limited block-structuring with the v6 engine. In that case, - * we must not support additonal filters inside the blocks, so they must consist of - * "act", only. We can implement that via the "&" actlist logic. - */ + $$->filt.expr = $2; } block: actlst { $$ = $1; } | block actlst { $2->next = $1; $$ = $2; } /* v7: | actlst - v7: | block rule */ - + v7: | block rule */ /* v7 extensions require new rule engine capabilities! */ actlst: act { $$=$1; } | actlst '&' act { $3->next = $1; $$ = $3; } | actlst cfsysline { $$ = cnfactlstAddSysline($1, $2); } | '{' block '}' { $$ = $2; } - act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } - | LEGACY_ACTION { //printf("legacy action: '%s'\n", $1); - $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } - + | LEGACY_ACTION { $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | expr OR expr { $$ = cnfexprNew(OR, $1, $3); } | NOT expr { $$ = cnfexprNew(NOT, NULL, $2); } -- cgit v1.2.3 From 183641a091a3d7b5eabe4419db4ebd2b6f84934e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 4 Jul 2011 18:25:17 +0200 Subject: milestone: added functions to grammar --- grammar/mini.samp | 1 + grammar/rscript.l | 3 +++ grammar/rscript.y | 8 ++++++++ grammar/utils.c | 39 +++++++++++++++++++++++++++++++++++++-- grammar/utils.h | 20 ++++++++++++++++++-- 5 files changed, 67 insertions(+), 4 deletions(-) diff --git a/grammar/mini.samp b/grammar/mini.samp index 71cfbb69..505ae67a 100644 --- a/grammar/mini.samp +++ b/grammar/mini.samp @@ -30,3 +30,4 @@ if not (1==0) and 2*4/-5--(10-3)>7/*pri("*.*")*/ then { action(type="omfwd" taget="10.0.0.1" port="514") action(type="omwusr" taget="rger") } +if getenv("user") == "test" then /var/log/testlog diff --git a/grammar/rscript.l b/grammar/rscript.l index a0ed3b0c..a7410b15 100644 --- a/grammar/rscript.l +++ b/grammar/rscript.l @@ -61,6 +61,7 @@ char *currfn; /* name of currently processed file */ "or" { return OR; } "and" { return AND; } "not" { return NOT; } +"," | "*" | "/" | "%" | @@ -88,6 +89,8 @@ char *currfn; /* name of currently processed file */ \"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); return STRING; } [ \t\n] +[a-z][a-z0-9_]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); + return FUNC; } . { printf("invalid char in expr: %s\n", yytext); } "&" { return '&'; } "{" { return '{'; } diff --git a/grammar/rscript.y b/grammar/rscript.y index 75fce49d..b24b7db7 100644 --- a/grammar/rscript.y +++ b/grammar/rscript.y @@ -31,10 +31,13 @@ extern int yylineno; struct cnfactlst *actlst; struct cnfexpr *expr; struct cnfrule *rule; + struct cnffunc *func; + struct cnffparamlst *fparams; } %token NAME %token VALUE +%token FUNC %token BEGINOBJ %token ENDOBJ %token CFSYSLINE @@ -72,6 +75,7 @@ extern int yylineno; %type expr %type rule %type scriptfilt +%type fparams %left AND OR %left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT CMP_CONTAINS CMP_CONTAINSI CMP_STARTSWITH CMP_STARTSWITHI @@ -145,9 +149,13 @@ expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } | expr '%' expr { $$ = cnfexprNew('%', $1, $3); } | '(' expr ')' { $$ = $2; } | '-' expr %prec UMINUS { $$ = cnfexprNew('M', NULL, $2); } + | FUNC '(' ')' { $$ = (struct cnfexpr*) cnffuncNew($1, NULL); } + | FUNC '(' fparams ')' { $$ = (struct cnfexpr*) cnffuncNew($1, $3); } | NUMBER { $$ = (struct cnfexpr*) cnfnumvalNew($1); } | STRING { $$ = (struct cnfexpr*) cnfstringvalNew($1); } | VAR { $$ = (struct cnfexpr*) cnfvarNew($1); } +fparams: expr { $$ = cnffparamlstNew($1, NULL); } + | expr ',' fparams { $$ = cnffparamlstNew($1, $3); } %% int yyerror(char *s) diff --git a/grammar/utils.c b/grammar/utils.c index 791a8967..16cad201 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -398,6 +398,7 @@ doIndent(indent) void cnfexprPrint(struct cnfexpr *expr, int indent) { + struct cnffparamlst *param; //printf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: @@ -477,6 +478,11 @@ cnfexprPrint(struct cnfexpr *expr, int indent) printf("NOT\n"); cnfexprPrint(expr->r, indent+1); break; + case 'S': + doIndent(indent); + cstrPrint("string '", ((struct cnfstringval*)expr)->estr); + printf("'\n"); + break; case 'N': doIndent(indent); printf("%lld\n", ((struct cnfnumval*)expr)->val); @@ -485,10 +491,15 @@ cnfexprPrint(struct cnfexpr *expr, int indent) doIndent(indent); printf("var '%s'\n", ((struct cnfvar*)expr)->name); break; - case 'S': + case 'F': doIndent(indent); - cstrPrint("string '", ((struct cnfstringval*)expr)->estr); + cstrPrint("function '", ((struct cnffunc*)expr)->fname); printf("'\n"); + for( param = ((struct cnffunc*)expr)->paramlst + ; param != NULL + ; param = param->next) { + cnfexprPrint(param->expr, indent+1); + } break; case '+': case '-': @@ -575,6 +586,30 @@ cnfrulePrint(struct cnfrule *rule) printf("------ end rule %p\n", rule); } +struct cnffparamlst * +cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) +{ + struct cnffparamlst* lst; + if((lst = malloc(sizeof(struct cnffparamlst))) != NULL) { + lst->nodetype = 'P'; + lst->expr = expr; + lst->next = next; + } + return lst; +} + +struct cnffunc * +cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) +{ + struct cnffunc* func; + if((func = malloc(sizeof(struct cnffunc))) != NULL) { + func->nodetype = 'F'; + func->fname = fname; + func->paramlst = paramlst; + } + return func; +} + /* debug helper */ void cstrPrint(char *text, es_str_t *estr) diff --git a/grammar/utils.h b/grammar/utils.h index fb1462a3..e75105da 100644 --- a/grammar/utils.h +++ b/grammar/utils.h @@ -62,10 +62,12 @@ struct cnfactlst { * be the sole foundation for the AST. * * nodetypes (list not yet complete) - * S - string + * F - function * N - number - * V - var + * P - fparamlst * R - rule + * S - string + * V - var */ enum cnfFiltType { CNFFILT_NONE, CNFFILT_PRI, CNFFILT_PROP, CNFFILT_SCRIPT }; static inline char* @@ -116,6 +118,18 @@ struct cnfvar { char *name; }; +struct cnffparamlst { + unsigned nodetype; /* P */ + struct cnffparamlst *next; + struct cnfexpr *expr; +}; + +struct cnffunc { + unsigned nodetype; + es_str_t *fname; + struct cnffparamlst *paramlst; +}; + /* future extensions struct x { int nodetype; @@ -152,6 +166,8 @@ struct cnfstringval* cnfstringvalNew(es_str_t *estr); struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst); void cnfrulePrint(struct cnfrule *rule); struct cnfvar* cnfvarNew(char *name); +struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst); +struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); -- cgit v1.2.3 From 641e383b8ad13ad6ee7fd9241214e24e6a983500 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 5 Jul 2011 08:21:04 +0200 Subject: milestone: grammar integrated in rsyslog build system --- Makefile.am | 2 +- configure.ac | 6 +- grammar/Makefile.am | 7 ++ grammar/makefile | 14 --- grammar/makefile.stand-alone | 14 +++ grammar/rscript-lex.l | 241 +++++++++++++++++++++++++++++++++++++++++++ grammar/rscript.l | 233 ----------------------------------------- grammar/utils.c | 4 +- tools/Makefile.am | 2 +- 9 files changed, 272 insertions(+), 251 deletions(-) create mode 100644 grammar/Makefile.am delete mode 100644 grammar/makefile create mode 100644 grammar/makefile.stand-alone create mode 100644 grammar/rscript-lex.l delete mode 100644 grammar/rscript.l diff --git a/Makefile.am b/Makefile.am index d689b9ee..7bf9dd0e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -66,7 +66,7 @@ EXTRA_DIST = \ contrib/gnutls/key.pem \ rsyslog.service.in -SUBDIRS = doc runtime . plugins/immark plugins/imuxsock plugins/imtcp plugins/imudp plugins/omtesting +SUBDIRS = doc runtime grammar . plugins/immark plugins/imuxsock plugins/imtcp plugins/imudp plugins/omtesting if ENABLE_RSYSLOGD SUBDIRS += tools diff --git a/configure.ac b/configure.ac index b0e71c20..1a239ca4 100644 --- a/configure.ac +++ b/configure.ac @@ -24,6 +24,8 @@ if test x"$HAVE_JAVAC" = x""; then fi # Checks for programs. +AC_PROG_LEX +AC_PROG_YACC AC_PROG_CC AM_PROG_CC_C_O if test "$GCC" = "yes" @@ -707,6 +709,7 @@ AC_ARG_ENABLE(rsyslogrt, if test "x$enable_rsyslogrt" = "xyes"; then RSRT_CFLAGS="-I\$(top_srcdir)/runtime -I\$(top_srcdir)" RSRT_LIBS="\$(top_builddir)/runtime/librsyslog.la" + CNF_LIBS="\$(top_builddir)/grammar/libgrammar.la" fi AM_CONDITIONAL(ENABLE_RSYSLOGRT, test x$enable_rsyslogrt = xyes) AC_SUBST(RSRT_CFLAGS) @@ -779,7 +782,7 @@ AM_CONDITIONAL(ENABLE_MAIL, test x$enable_mail = xyes) # would complicate things if we first needed to tell them how to enable imdiag. # rgerhards, 2008-07-25 AC_ARG_ENABLE(imdiag, - [AS_HELP_STRING([--enable-imdiag],[Enable imdiag @<:@default=yes@:>@])], + [AS_HELP_STRING([--enable-imdiag],[Enable imdiag @<:@default=no@:>@])], [case "${enableval}" in yes) enable_imdiag="yes" ;; no) enable_imdiag="no" ;; @@ -1224,6 +1227,7 @@ AM_CONDITIONAL(ENABLE_OMMONGODB, test x$enable_ommongodb = xyes) AC_CONFIG_FILES([Makefile \ runtime/Makefile \ + grammar/Makefile \ tools/Makefile \ doc/Makefile \ plugins/imudp/Makefile \ diff --git a/grammar/Makefile.am b/grammar/Makefile.am new file mode 100644 index 00000000..b2bd3430 --- /dev/null +++ b/grammar/Makefile.am @@ -0,0 +1,7 @@ +noinst_LTLIBRARIES = libgrammar.la + +libgrammar_la_SOURCES = \ + utils.c \ + utils.h \ + rscript-lex.l \ + rscript.y diff --git a/grammar/makefile b/grammar/makefile deleted file mode 100644 index eb6c9522..00000000 --- a/grammar/makefile +++ /dev/null @@ -1,14 +0,0 @@ -rscript: lex.yy.c utils.o rscript.tab.h utils.h - gcc -g -o rscript lex.yy.c rscript.tab.c utils.o -lestr - -lex.yy.c: rscript.l rscript.tab.h - flex rscript.l - -rscript.tab.h: rscript.y - bison -d rscript.y - -utils.o: utils.c utils.h - gcc -g -Wall -c utils.c - -clean: - rm *.o diff --git a/grammar/makefile.stand-alone b/grammar/makefile.stand-alone new file mode 100644 index 00000000..b998a39d --- /dev/null +++ b/grammar/makefile.stand-alone @@ -0,0 +1,14 @@ +rscript: lex.yy.c utils.o rscript.tab.h utils.h + gcc -DSTAND_ALONE -g -o rscript lex.yy.c rscript.tab.c utils.o -lestr + +lex.yy.c: rscript.l rscript.tab.h + flex rscript.l + +rscript.tab.h: rscript.y + bison -d rscript.y + +utils.o: utils.c utils.h + gcc -g -DSTAND_ALONE -Wall -c utils.c + +clean: + rm *.o diff --git a/grammar/rscript-lex.l b/grammar/rscript-lex.l new file mode 100644 index 00000000..1c7b963e --- /dev/null +++ b/grammar/rscript-lex.l @@ -0,0 +1,241 @@ + /* Lex file for rsyslog config format v2 (RainerScript). + * Please note: this file introduces the new config format, but maintains + * backward compatibility. In order to do so, the grammar is not 100% clean, + * but IMHO still sufficiently easy both to understand for programmers + * maitaining the code as well as users writing the config file. Users are, + * of course, encouraged to use new constructs only. But it needs to be noted + * that some of the legacy constructs (specifically the in-front-of-action + * PRI filter) are very hard to beat in ease of use, at least for simpler + * cases. So while we hope that cfsysline support can be dropped some time in + * the future, we will probably keep these useful constructs. + * + * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH + * Released under the GNU GPL v3. For details see LICENSE file. + */ + +%option noyywrap nodefault case-insensitive yylineno + /*%option noyywrap nodefault case-insensitive */ + +/* avoid compiler warning: `yyunput' defined but not used */ +%option nounput noinput + + +%x INOBJ + /* INOBJ is selected if we are inside an object (name/value pairs!) */ +%x COMMENT + /* COMMENT is "the usual trick" to handle C-style comments */ +%x INCL + /* INCL is in $IncludeConfig processing (skip to include file) */ +%x LINENO + /* LINENO: support for setting the linenumber */ +%x EXPR + /* EXPR is a bit ugly, but we need it to support pre v6-syntax. The problem + * is that cfsysline statement start with $..., the same like variables in + * an expression. However, cfsysline statements can never appear inside an + * expression. So we create a specific expr mode, which is turned on after + * we lexed a keyword that needs to be followed by an expression (using + * knowledge from the upper layer...). In expr mode, we strictly do + * expression-based parsing. Expr mode is stopped when we reach a token + * that can not be part of an expression (currently only "then"). As I + * wrote this ugly, but the price needed to pay in order to remain + * compatible to the previous format. + */ +%{ +#include +#include +#include "utils.h" +#include "rscript.tab.h" +static int preCommentState; /* save for lex state before a comment */ + +struct bufstack { + struct bufstack *prev; + YY_BUFFER_STATE bs; + int lineno; + char *fn; +} *currbs = NULL; + +char *currfn; /* name of currently processed file */ + +int popfile(void); +int cnfSetLexFile(char *fname); +%} + +%% + + /* keywords */ +"if" { BEGIN EXPR; return IF; } +"then" { BEGIN INITIAL; return THEN; } +"or" { return OR; } +"and" { return AND; } +"not" { return NOT; } +"," | +"*" | +"/" | +"%" | +"+" | +"-" | +"(" | +")" { return yytext[0]; } +"==" { return CMP_EQ; } +"<=" { return CMP_LE; } +">=" { return CMP_GE; } +"!=" | +"<>" { return CMP_NE; } +"<" { return CMP_LT; } +">" { return CMP_GT; } +"contains" { return CMP_CONTAINS; } +"contains_i" { return CMP_CONTAINSI; } +"startswith" { return CMP_STARTSWITH; } +"startswith_i" { return CMP_STARTSWITHI; } +0[0-7]+ | /* octal number */ +0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ +([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } +\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } +\'([^'\\]|\\['])*\' { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return STRING; } +\"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return STRING; } +[ \t\n] +[a-z][a-z0-9_]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); + return FUNC; } +. { printf("invalid char in expr: %s\n", yytext); } +"&" { return '&'; } +"{" { return '{'; } +"}" { return '}'; } +"ruleset" { printf("RULESET\n"); } + /* line number support because the "preprocessor" combines lines and so needs + * to tell us the real source line. + */ +"preprocfilelinenumber(" { BEGIN LINENO; } +[0-9]+ { yylineno = atoi(yytext) - 1; } +")" { BEGIN INITIAL; } +.|\n + /* $IncludeConfig must be detected as part of CFSYSLINE, because this is + * always the longest match :-( + */ +.|\n +[^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) + yyterminate(); + BEGIN INITIAL; } +"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; + BEGIN INOBJ; return BEGINOBJ; } +"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; + BEGIN INOBJ; return BEGINOBJ; } +"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; + BEGIN INOBJ; return BEGINOBJ; } +"action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } +^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { + yylval.s = strdup(yytext); return PROPFILT; } +^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } +"*" | +\-\/[^*][^\n]* | +\/[^*][^\n]* | +:[a-z0-9]+:[^\n]* | +[\|\.\-\@~][^\n]+ | +[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); + // printf("lex: LEGA ACT: '%s'\n", yytext); + return LEGACY_ACTION; } +")" { BEGIN INITIAL; return ENDOBJ; } +[a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); + return NAME; } +"=" { return(yytext[0]); } +\"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { + yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return VALUE; } +"/*" { preCommentState = YY_START; BEGIN COMMENT; } +"/*" { preCommentState = YY_START; BEGIN COMMENT; } +"*/" { BEGIN preCommentState; } +([^*]|\n)+|. +#.*$ /* skip comments in input */ +[ \n\t] +. { printf("INOBJ: invalid char '%s'\n", yytext); } +\$[a-z]+.*$ { /* see common on $IncludeConfig above */ + if(!strncasecmp(yytext, "$includeconfig ", 14)) { + yyless(14); + BEGIN INCL; + } else { + yylval.s = strdup(yytext); + return CFSYSLINE; + } + } +![^ \t\n]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } +[+-]\*[ \t\n]*#.*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +[+-]\*[ \t\n]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +\#.*\n /* skip comments in input */ +[\n\t ] /* drop whitespace */ +. { printf("invalid char: %s\n", yytext); + } +<> { if(popfile() != 0) yyterminate(); } + +%% +/* set a new buffers. Returns 0 on success, something else otherwise. */ +int +cnfSetLexFile(char *fname) +{ + es_str_t *str = NULL; + FILE *fp; + int r = 0; + struct bufstack *bs; + + if(fname == NULL) { + fp = stdin; + } else { + if((fp = fopen(fname, "r")) == NULL) { + r = 1; + goto done; + } + } + readConfFile(fp, &str); + if(fp != stdin) + fclose(fp); + + /* maintain stack */ + if((bs = malloc(sizeof(struct bufstack))) == NULL) { + r = 1; + goto done; + } + + if(currbs != NULL) + currbs->lineno = yylineno; + bs->prev = currbs; + bs->fn = strdup(fname); + bs->bs = yy_scan_buffer((char*)es_getBufAddr(str), es_strlen(str)); + currbs = bs; + currfn = bs->fn; + yylineno = 1; + +done: + if(r != 0) { + if(str != NULL) + es_deleteStr(str); + } + return r; +} + + +/* returns 0 on success, something else otherwise */ +int +popfile(void) +{ + struct bufstack *bs = currbs; + + if(bs == NULL) + return 1; + + /* delte current entry */ + yy_delete_buffer(bs->bs); + free(bs->fn); + + /* switch back to previous */ + currbs = bs->prev; + free(bs); + + if(currbs == NULL) + return 1; /* all processed */ + + yy_switch_to_buffer(currbs->bs); + yylineno = currbs->lineno; + currfn = currbs->fn; + return 0; +} diff --git a/grammar/rscript.l b/grammar/rscript.l deleted file mode 100644 index a7410b15..00000000 --- a/grammar/rscript.l +++ /dev/null @@ -1,233 +0,0 @@ - /* Lex file for rsyslog config format v2 (RainerScript). - * Please note: this file introduces the new config format, but maintains - * backward compatibility. In order to do so, the grammar is not 100% clean, - * but IMHO still sufficiently easy both to understand for programmers - * maitaining the code as well as users writing the config file. Users are, - * of course, encouraged to use new constructs only. But it needs to be noted - * that some of the legacy constructs (specifically the in-front-of-action - * PRI filter) are very hard to beat in ease of use, at least for simpler - * cases. So while we hope that cfsysline support can be dropped some time in - * the future, we will probably keep these useful constructs. - * - * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH - * Released under the GNU GPL v3. For details see LICENSE file. - */ - -%option noyywrap nodefault case-insensitive yylineno - /*%option noyywrap nodefault case-insensitive */ - -%x INOBJ - /* INOBJ is selected if we are inside an object (name/value pairs!) */ -%x COMMENT - /* COMMENT is "the usual trick" to handle C-style comments */ -%x INCL - /* INCL is in $IncludeConfig processing (skip to include file) */ -%x LINENO - /* LINENO: support for setting the linenumber */ -%x EXPR - /* EXPR is a bit ugly, but we need it to support pre v6-syntax. The problem - * is that cfsysline statement start with $..., the same like variables in - * an expression. However, cfsysline statements can never appear inside an - * expression. So we create a specific expr mode, which is turned on after - * we lexed a keyword that needs to be followed by an expression (using - * knowledge from the upper layer...). In expr mode, we strictly do - * expression-based parsing. Expr mode is stopped when we reach a token - * that can not be part of an expression (currently only "then"). As I - * wrote this ugly, but the price needed to pay in order to remain - * compatible to the previous format. - */ -%{ -#include -#include -#include "utils.h" -#include "rscript.tab.h" -static int preCommentState; /* save for lex state before a comment */ - -struct bufstack { - struct bufstack *prev; - YY_BUFFER_STATE bs; - int lineno; - char *fn; -} *currbs = NULL; - -char *currfn; /* name of currently processed file */ -%} - -%% - - /* keywords */ -"if" { BEGIN EXPR; return IF; } -"then" { BEGIN INITIAL; return THEN; } -"or" { return OR; } -"and" { return AND; } -"not" { return NOT; } -"," | -"*" | -"/" | -"%" | -"+" | -"-" | -"(" | -")" { return yytext[0]; } -"==" { return CMP_EQ; } -"<=" { return CMP_LE; } -">=" { return CMP_GE; } -"!=" | -"<>" { return CMP_NE; } -"<" { return CMP_LT; } -">" { return CMP_GT; } -"contains" { return CMP_CONTAINS; } -"contains_i" { return CMP_CONTAINSI; } -"startswith" { return CMP_STARTSWITH; } -"startswith_i" { return CMP_STARTSWITHI; } -0[0-7]+ | /* octal number */ -0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ -([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } -\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } -\'([^'\\]|\\['])*\' { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); - return STRING; } -\"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); - return STRING; } -[ \t\n] -[a-z][a-z0-9_]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); - return FUNC; } -. { printf("invalid char in expr: %s\n", yytext); } -"&" { return '&'; } -"{" { return '{'; } -"}" { return '}'; } -"ruleset" { printf("RULESET\n"); } - /* line number support because the "preprocessor" combines lines and so needs - * to tell us the real source line. - */ -"preprocfilelinenumber(" { BEGIN LINENO; } -[0-9]+ { yylineno = atoi(yytext) - 1; } -")" { BEGIN INITIAL; } -.|\n - /* $IncludeConfig must be detected as part of CFSYSLINE, because this is - * always the longest match :-( - */ -.|\n -[^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) - yyterminate(); - BEGIN INITIAL; } -"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; - BEGIN INOBJ; return BEGINOBJ; } -"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; - BEGIN INOBJ; return BEGINOBJ; } -"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; - BEGIN INOBJ; return BEGINOBJ; } -"action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } -^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { - yylval.s = strdup(yytext); return PROPFILT; } -^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } -"*" | -\-\/[^*][^\n]* | -\/[^*][^\n]* | -:[a-z0-9]+:[^\n]* | -[\|\.\-\@~][^\n]+ | -[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); - // printf("lex: LEGA ACT: '%s'\n", yytext); - return LEGACY_ACTION; } -")" { BEGIN INITIAL; return ENDOBJ; } -[a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); - return NAME; } -"=" { return(yytext[0]); } -\"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { - yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); - return VALUE; } -"/*" { preCommentState = YY_START; BEGIN COMMENT; } -"/*" { preCommentState = YY_START; BEGIN COMMENT; } -"*/" { BEGIN preCommentState; } -([^*]|\n)+|. -#.*$ /* skip comments in input */ -[ \n\t] -. { printf("INOBJ: invalid char '%s'\n", yytext); } -\$[a-z]+.*$ { /* see common on $IncludeConfig above */ - if(!strncasecmp(yytext, "$includeconfig ", 14)) { - yyless(14); - BEGIN INCL; - } else { - yylval.s = strdup(yytext); - return CFSYSLINE; - } - } -![^ \t\n]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } -[+-]\*[ \t\n]*#.*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -[+-]\*[ \t\n]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -\#.*\n /* skip comments in input */ -[\n\t ] /* drop whitespace */ -. { printf("invalid char: %s\n", yytext); - } -<> { if(popfile() != 0) yyterminate(); } - -%% -/* set a new buffers. Returns 0 on success, something else otherwise. */ -int cnfSetLexFile(char *fname) -{ - es_str_t *str = NULL; - FILE *fp; - int r = 0; - struct bufstack *bs; - - if(fname == NULL) { - fp = stdin; - } else { - if((fp = fopen(fname, "r")) == NULL) { - r = 1; - goto done; - } - } - readConfFile(fp, &str); - if(fp != stdin) - fclose(fp); - - /* maintain stack */ - if((bs = malloc(sizeof(struct bufstack))) == NULL) { - r = 1; - goto done; - } - - if(currbs != NULL) - currbs->lineno = yylineno; - bs->prev = currbs; - bs->fn = strdup(fname); - bs->bs = yy_scan_buffer(es_getBufAddr(str), es_strlen(str)); - currbs = bs; - currfn = bs->fn; - yylineno = 1; - -done: - if(r != 0) { - if(str != NULL) - es_deleteStr(str); - } - return r; -} - - -/* returns 0 on success, something else otherwise */ -int -popfile(void) -{ - struct bufstack *bs = currbs; - - if(bs == NULL) - return 1; - - /* delte current entry */ - yy_delete_buffer(bs->bs); - free(bs->fn); - - /* switch back to previous */ - currbs = bs->prev; - free(bs); - - if(currbs == NULL) - return 1; /* all processed */ - - yy_switch_to_buffer(currbs->bs); - yylineno = currbs->lineno; - currfn = currbs->fn; - return 0; -} diff --git a/grammar/utils.c b/grammar/utils.c index 16cad201..e488ebda 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -389,7 +389,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) } inline static void -doIndent(indent) +doIndent(int indent) { int i; for(i = 0 ; i < indent ; ++i) @@ -611,6 +611,7 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) } /* debug helper */ +#ifdef STAND_ALONE void cstrPrint(char *text, es_str_t *estr) { @@ -632,4 +633,5 @@ main(int argc, char *argv[]) printf("yyparse() returned %d\n", r); return r; } +#endif /* #ifdef STAND_ALONE */ diff --git a/tools/Makefile.am b/tools/Makefile.am index 5c3f7a40..f3b176f2 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -35,7 +35,7 @@ rsyslogd_SOURCES = \ pidfile.h \ \ ../dirty.h -rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) +rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) $(CNF_LIBS) rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) rsyslogd_LDFLAGS = -export-dynamic -- cgit v1.2.3 From 6175ce90b59d742976aa5a8b2603902761e540ae Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 5 Jul 2011 11:04:47 +0200 Subject: milestone: improved build system ... still had quite some glitches, as usual. This time it hopefully works under all circumstances (well, let's hope for "usual cir..." ;)). --- grammar/Makefile.am | 13 ++- grammar/grammar.y | 169 +++++++++++++++++++++++++++++++++ grammar/lexer.l | 251 ++++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rscript-lex.l | 241 ------------------------------------------------ grammar/rscript.y | 164 --------------------------------- grammar/testdriver.c | 50 ++++++++++ grammar/utils.c | 28 +----- 7 files changed, 482 insertions(+), 434 deletions(-) create mode 100644 grammar/grammar.y create mode 100644 grammar/lexer.l delete mode 100644 grammar/rscript-lex.l delete mode 100644 grammar/rscript.y create mode 100644 grammar/testdriver.c diff --git a/grammar/Makefile.am b/grammar/Makefile.am index b2bd3430..b482c99e 100644 --- a/grammar/Makefile.am +++ b/grammar/Makefile.am @@ -1,7 +1,16 @@ +BUILT_SOURCES = grammar.h +CLEANFILES = grammar.h grammar.c +AM_YFLAGS = -d noinst_LTLIBRARIES = libgrammar.la +bin_PROGRAMS = testdriver # TODO: make this conditional libgrammar_la_SOURCES = \ + grammar.y \ + lexer.l \ utils.c \ utils.h \ - rscript-lex.l \ - rscript.y + grammar.h + +testdriver_SOURCES = testdriver.c libgrammar.la +testdriver_LDADD = libgrammar.la +testdriver_LDFLAGS = -lestr diff --git a/grammar/grammar.y b/grammar/grammar.y new file mode 100644 index 00000000..76881fd1 --- /dev/null +++ b/grammar/grammar.y @@ -0,0 +1,169 @@ + /* Bison file for rsyslog config format v2 (RainerScript). + * Please note: this file introduces the new config format, but maintains + * backward compatibility. In order to do so, the grammar is not 100% clean, + * but IMHO still sufficiently easy both to understand for programmers + * maitaining the code as well as users writing the config file. Users are, + * of course, encouraged to use new constructs only. But it needs to be noted + * that some of the legacy constructs (specifically the in-front-of-action + * PRI filter) are very hard to beat in ease of use, at least for simpler + * cases. So while we hope that cfsysline support can be dropped some time in + * the future, we will probably keep these useful constructs. + * + * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH + * Released under the GNU GPL v3. For details see LICENSE file. + */ + +%{ +#include +#include +#include "utils.h" +#define YYDEBUG 1 +extern int yylineno; + +/* keep compile rule cleam of errors */ +extern int yylex(void); +extern int yyerror(char*); +%} + +%union { + char *s; + long long n; + es_str_t *estr; + enum cnfobjType objType; + struct cnfobj *obj; + struct nvlst *nvlst; + struct cnfactlst *actlst; + struct cnfexpr *expr; + struct cnfrule *rule; + struct cnffunc *func; + struct cnffparamlst *fparams; +} + +%token NAME +%token VALUE +%token FUNC +%token BEGINOBJ +%token ENDOBJ +%token CFSYSLINE +%token BEGIN_ACTION +%token LEGACY_ACTION +%token PRIFILT +%token PROPFILT +%token BSD_TAG_SELECTOR +%token BSD_HOST_SELECTOR +%token IF +%token THEN +%token OR +%token AND +%token NOT +%token VAR +%token STRING +%token NUMBER +%token CMP_EQ +%token CMP_NE +%token CMP_LE +%token CMP_GE +%token CMP_LT +%token CMP_GT +%token CMP_CONTAINS +%token CMP_CONTAINSI +%token CMP_STARTSWITH +%token CMP_STARTSWITHI + +%type nv nvlst +%type obj +%type actlst +%type act +%type cfsysline +%type block +%type expr +%type rule +%type scriptfilt +%type fparams + +%left AND OR +%left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT CMP_CONTAINS CMP_CONTAINSI CMP_STARTSWITH CMP_STARTSWITHI +%left '+' '-' +%left '*' '/' '%' +%nonassoc UMINUS NOT + +%expect 3 +/* these shift/reduce conflicts are created by the CFSYSLINE construct, which we + * unfortunately can not avoid. The problem is that CFSYSLINE can occur both in + * global context as well as within an action. It's not permitted somewhere else, + * but this is suficient for conflicts. The "dangling else" built-in resolution + * works well to solve this issue, so we accept it (it's a wonder that our + * old style grammar doesn't work at all, so we better do not complain...). + * Use "bison -v rscript.y" if more conflicts arise and check rscript.out for + * were exactly these conflicts exits. + */ +%% +/* note: we use left recursion below, because that saves stack space AND + * offers the right sequence so that we can submit the top-layer objects + * one by one. + */ +conf: /* empty (to end recursion) */ + | conf obj { printf("global:config: "); + cnfobjPrint($2); cnfobjDestruct($2); } + | conf rule { printf("global:rule processed\n"); + cnfrulePrint($2); } + | conf cfsysline { printf("global:cfsysline: %s\n", $2); } + | conf BSD_TAG_SELECTOR { printf("global:BSD tag '%s'\n", $2); } + | conf BSD_HOST_SELECTOR { printf("global:BSD host '%s'\n", $2); } + +obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } + | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } +cfsysline: CFSYSLINE { $$ = $1; } +nvlst: { $$ = NULL; } + | nvlst nv { $2->next = $1; $$ = $2; } +nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } +rule: PRIFILT actlst { $$ = cnfruleNew(CNFFILT_PRI, $2); $$->filt.s = $1; } + | PROPFILT actlst { $$ = cnfruleNew(CNFFILT_PROP, $2); $$->filt.s = $1; } + | scriptfilt { $$ = $1; } + +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); } + | '{' block '}' { $$ = $2; } +act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } + | LEGACY_ACTION { $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } +expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } + | expr OR expr { $$ = cnfexprNew(OR, $1, $3); } + | NOT expr { $$ = cnfexprNew(NOT, NULL, $2); } + | expr CMP_EQ expr { $$ = cnfexprNew(CMP_EQ, $1, $3); } + | expr CMP_NE expr { $$ = cnfexprNew(CMP_NE, $1, $3); } + | expr CMP_LE expr { $$ = cnfexprNew(CMP_LE, $1, $3); } + | expr CMP_GE expr { $$ = cnfexprNew(CMP_GE, $1, $3); } + | expr CMP_LT expr { $$ = cnfexprNew(CMP_LT, $1, $3); } + | expr CMP_GT expr { $$ = cnfexprNew(CMP_GT, $1, $3); } + | expr CMP_CONTAINS expr { $$ = cnfexprNew(CMP_CONTAINS, $1, $3); } + | expr CMP_CONTAINSI expr { $$ = cnfexprNew(CMP_CONTAINSI, $1, $3); } + | expr CMP_STARTSWITH expr { $$ = cnfexprNew(CMP_STARTSWITH, $1, $3); } + | expr CMP_STARTSWITHI expr { $$ = cnfexprNew(CMP_STARTSWITHI, $1, $3); } + | expr '+' expr { $$ = cnfexprNew('+', $1, $3); } + | expr '-' expr { $$ = cnfexprNew('-', $1, $3); } + | expr '*' expr { $$ = cnfexprNew('*', $1, $3); } + | expr '/' expr { $$ = cnfexprNew('/', $1, $3); } + | expr '%' expr { $$ = cnfexprNew('%', $1, $3); } + | '(' expr ')' { $$ = $2; } + | '-' expr %prec UMINUS { $$ = cnfexprNew('M', NULL, $2); } + | FUNC '(' ')' { $$ = (struct cnfexpr*) cnffuncNew($1, NULL); } + | FUNC '(' fparams ')' { $$ = (struct cnfexpr*) cnffuncNew($1, $3); } + | NUMBER { $$ = (struct cnfexpr*) cnfnumvalNew($1); } + | STRING { $$ = (struct cnfexpr*) cnfstringvalNew($1); } + | VAR { $$ = (struct cnfexpr*) cnfvarNew($1); } +fparams: expr { $$ = cnffparamlstNew($1, NULL); } + | expr ',' fparams { $$ = cnffparamlstNew($1, $3); } + +%% +int yyerror(char *s) +{ + printf("parse failure on or before line %d: %s\n", yylineno, s); + return 0; +} diff --git a/grammar/lexer.l b/grammar/lexer.l new file mode 100644 index 00000000..2411be6f --- /dev/null +++ b/grammar/lexer.l @@ -0,0 +1,251 @@ + /* Lex file for rsyslog config format v2 (RainerScript). + * Please note: this file introduces the new config format, but maintains + * backward compatibility. In order to do so, the grammar is not 100% clean, + * but IMHO still sufficiently easy both to understand for programmers + * maitaining the code as well as users writing the config file. Users are, + * of course, encouraged to use new constructs only. But it needs to be noted + * that some of the legacy constructs (specifically the in-front-of-action + * PRI filter) are very hard to beat in ease of use, at least for simpler + * cases. So while we hope that cfsysline support can be dropped some time in + * the future, we will probably keep these useful constructs. + * + * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH + * Released under the GNU GPL v3. For details see LICENSE file. + */ + +%option noyywrap nodefault case-insensitive yylineno + /*%option noyywrap nodefault case-insensitive */ + +/* avoid compiler warning: `yyunput' defined but not used */ +%option nounput noinput + + +%x INOBJ + /* INOBJ is selected if we are inside an object (name/value pairs!) */ +%x COMMENT + /* COMMENT is "the usual trick" to handle C-style comments */ +%x INCL + /* INCL is in $IncludeConfig processing (skip to include file) */ +%x LINENO + /* LINENO: support for setting the linenumber */ +%x EXPR + /* EXPR is a bit ugly, but we need it to support pre v6-syntax. The problem + * is that cfsysline statement start with $..., the same like variables in + * an expression. However, cfsysline statements can never appear inside an + * expression. So we create a specific expr mode, which is turned on after + * we lexed a keyword that needs to be followed by an expression (using + * knowledge from the upper layer...). In expr mode, we strictly do + * expression-based parsing. Expr mode is stopped when we reach a token + * that can not be part of an expression (currently only "then"). As I + * wrote this ugly, but the price needed to pay in order to remain + * compatible to the previous format. + */ +%{ +#include +#include +#include +#include +#include +#include "utils.h" +#include "grammar.h" +static int preCommentState; /* save for lex state before a comment */ + +struct bufstack { + struct bufstack *prev; + YY_BUFFER_STATE bs; + int lineno; + char *fn; +} *currbs = NULL; + +char *currfn; /* name of currently processed file */ + +int popfile(void); +int cnfSetLexFile(char *fname); + +/* somehow, I need these prototype even though the headers are + * included. I guess that's some autotools magic I don't understand... + */ +char *strdup(char*); +int fileno(FILE *stream); + +%} + +%% + + /* keywords */ +"if" { BEGIN EXPR; return IF; } +"then" { BEGIN INITIAL; return THEN; } +"or" { return OR; } +"and" { return AND; } +"not" { return NOT; } +"," | +"*" | +"/" | +"%" | +"+" | +"-" | +"(" | +")" { return yytext[0]; } +"==" { return CMP_EQ; } +"<=" { return CMP_LE; } +">=" { return CMP_GE; } +"!=" | +"<>" { return CMP_NE; } +"<" { return CMP_LT; } +">" { return CMP_GT; } +"contains" { return CMP_CONTAINS; } +"contains_i" { return CMP_CONTAINSI; } +"startswith" { return CMP_STARTSWITH; } +"startswith_i" { return CMP_STARTSWITHI; } +0[0-7]+ | /* octal number */ +0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ +([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } +\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } +\'([^'\\]|\\['])*\' { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return STRING; } +\"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return STRING; } +[ \t\n] +[a-z][a-z0-9_]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); + return FUNC; } +. { printf("invalid char in expr: %s\n", yytext); } +"&" { return '&'; } +"{" { return '{'; } +"}" { return '}'; } +"ruleset" { printf("RULESET\n"); } + /* line number support because the "preprocessor" combines lines and so needs + * to tell us the real source line. + */ +"preprocfilelinenumber(" { BEGIN LINENO; } +[0-9]+ { yylineno = atoi(yytext) - 1; } +")" { BEGIN INITIAL; } +.|\n + /* $IncludeConfig must be detected as part of CFSYSLINE, because this is + * always the longest match :-( + */ +.|\n +[^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) + yyterminate(); + BEGIN INITIAL; } +"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; + BEGIN INOBJ; return BEGINOBJ; } +"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; + BEGIN INOBJ; return BEGINOBJ; } +"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; + BEGIN INOBJ; return BEGINOBJ; } +"action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } +^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { + yylval.s = strdup(yytext); return PROPFILT; } +^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } +"*" | +\-\/[^*][^\n]* | +\/[^*][^\n]* | +:[a-z0-9]+:[^\n]* | +[\|\.\-\@~][^\n]+ | +[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); + // printf("lex: LEGA ACT: '%s'\n", yytext); + return LEGACY_ACTION; } +")" { BEGIN INITIAL; return ENDOBJ; } +[a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); + return NAME; } +"=" { return(yytext[0]); } +\"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { + yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); + return VALUE; } +"/*" { preCommentState = YY_START; BEGIN COMMENT; } +"/*" { preCommentState = YY_START; BEGIN COMMENT; } +"*/" { BEGIN preCommentState; } +([^*]|\n)+|. +#.*$ /* skip comments in input */ +[ \n\t] +. { printf("INOBJ: invalid char '%s'\n", yytext); } +\$[a-z]+.*$ { /* see common on $IncludeConfig above */ + if(!strncasecmp(yytext, "$includeconfig ", 14)) { + yyless(14); + BEGIN INCL; + } else { + yylval.s = strdup(yytext); + return CFSYSLINE; + } + } +![^ \t\n]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } +[+-]\*[ \t\n]*#.*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +[+-]\*[ \t\n]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } +\#.*\n /* skip comments in input */ +[\n\t ] /* drop whitespace */ +. { printf("invalid char: %s\n", yytext); + } +<> { if(popfile() != 0) yyterminate(); } + +%% +/* set a new buffers. Returns 0 on success, something else otherwise. */ +int +cnfSetLexFile(char *fname) +{ + es_str_t *str = NULL; + FILE *fp; + int r = 0; + struct bufstack *bs; + + if(fname == NULL) { + fp = stdin; + } else { + if((fp = fopen(fname, "r")) == NULL) { + r = 1; + goto done; + } + } + readConfFile(fp, &str); + if(fp != stdin) + fclose(fp); + + /* maintain stack */ + if((bs = malloc(sizeof(struct bufstack))) == NULL) { + r = 1; + goto done; + } + + if(currbs != NULL) + currbs->lineno = yylineno; + bs->prev = currbs; + bs->fn = strdup(fname); + bs->bs = yy_scan_buffer((char*)es_getBufAddr(str), es_strlen(str)); + currbs = bs; + currfn = bs->fn; + yylineno = 1; + +done: + if(r != 0) { + if(str != NULL) + es_deleteStr(str); + } + return r; +} + + +/* returns 0 on success, something else otherwise */ +int +popfile(void) +{ + struct bufstack *bs = currbs; + + if(bs == NULL) + return 1; + + /* delte current entry */ + yy_delete_buffer(bs->bs); + free(bs->fn); + + /* switch back to previous */ + currbs = bs->prev; + free(bs); + + if(currbs == NULL) + return 1; /* all processed */ + + yy_switch_to_buffer(currbs->bs); + yylineno = currbs->lineno; + currfn = currbs->fn; + return 0; +} diff --git a/grammar/rscript-lex.l b/grammar/rscript-lex.l deleted file mode 100644 index 1c7b963e..00000000 --- a/grammar/rscript-lex.l +++ /dev/null @@ -1,241 +0,0 @@ - /* Lex file for rsyslog config format v2 (RainerScript). - * Please note: this file introduces the new config format, but maintains - * backward compatibility. In order to do so, the grammar is not 100% clean, - * but IMHO still sufficiently easy both to understand for programmers - * maitaining the code as well as users writing the config file. Users are, - * of course, encouraged to use new constructs only. But it needs to be noted - * that some of the legacy constructs (specifically the in-front-of-action - * PRI filter) are very hard to beat in ease of use, at least for simpler - * cases. So while we hope that cfsysline support can be dropped some time in - * the future, we will probably keep these useful constructs. - * - * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH - * Released under the GNU GPL v3. For details see LICENSE file. - */ - -%option noyywrap nodefault case-insensitive yylineno - /*%option noyywrap nodefault case-insensitive */ - -/* avoid compiler warning: `yyunput' defined but not used */ -%option nounput noinput - - -%x INOBJ - /* INOBJ is selected if we are inside an object (name/value pairs!) */ -%x COMMENT - /* COMMENT is "the usual trick" to handle C-style comments */ -%x INCL - /* INCL is in $IncludeConfig processing (skip to include file) */ -%x LINENO - /* LINENO: support for setting the linenumber */ -%x EXPR - /* EXPR is a bit ugly, but we need it to support pre v6-syntax. The problem - * is that cfsysline statement start with $..., the same like variables in - * an expression. However, cfsysline statements can never appear inside an - * expression. So we create a specific expr mode, which is turned on after - * we lexed a keyword that needs to be followed by an expression (using - * knowledge from the upper layer...). In expr mode, we strictly do - * expression-based parsing. Expr mode is stopped when we reach a token - * that can not be part of an expression (currently only "then"). As I - * wrote this ugly, but the price needed to pay in order to remain - * compatible to the previous format. - */ -%{ -#include -#include -#include "utils.h" -#include "rscript.tab.h" -static int preCommentState; /* save for lex state before a comment */ - -struct bufstack { - struct bufstack *prev; - YY_BUFFER_STATE bs; - int lineno; - char *fn; -} *currbs = NULL; - -char *currfn; /* name of currently processed file */ - -int popfile(void); -int cnfSetLexFile(char *fname); -%} - -%% - - /* keywords */ -"if" { BEGIN EXPR; return IF; } -"then" { BEGIN INITIAL; return THEN; } -"or" { return OR; } -"and" { return AND; } -"not" { return NOT; } -"," | -"*" | -"/" | -"%" | -"+" | -"-" | -"(" | -")" { return yytext[0]; } -"==" { return CMP_EQ; } -"<=" { return CMP_LE; } -">=" { return CMP_GE; } -"!=" | -"<>" { return CMP_NE; } -"<" { return CMP_LT; } -">" { return CMP_GT; } -"contains" { return CMP_CONTAINS; } -"contains_i" { return CMP_CONTAINSI; } -"startswith" { return CMP_STARTSWITH; } -"startswith_i" { return CMP_STARTSWITHI; } -0[0-7]+ | /* octal number */ -0x[0-7a-f] | /* hex number, following rule is dec; strtoll handles all! */ -([1-9][0-9]*|0) { yylval.n = strtoll(yytext, NULL, 0); return NUMBER; } -\$[$!]{0,1}[a-z][a-z0-9\-_\.]* { yylval.s = strdup(yytext); return VAR; } -\'([^'\\]|\\['])*\' { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); - return STRING; } -\"([^"\\]|\\["])*\" { yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); - return STRING; } -[ \t\n] -[a-z][a-z0-9_]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); - return FUNC; } -. { printf("invalid char in expr: %s\n", yytext); } -"&" { return '&'; } -"{" { return '{'; } -"}" { return '}'; } -"ruleset" { printf("RULESET\n"); } - /* line number support because the "preprocessor" combines lines and so needs - * to tell us the real source line. - */ -"preprocfilelinenumber(" { BEGIN LINENO; } -[0-9]+ { yylineno = atoi(yytext) - 1; } -")" { BEGIN INITIAL; } -.|\n - /* $IncludeConfig must be detected as part of CFSYSLINE, because this is - * always the longest match :-( - */ -.|\n -[^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) - yyterminate(); - BEGIN INITIAL; } -"global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; - BEGIN INOBJ; return BEGINOBJ; } -"input"[ \n\t]*"(" { yylval.objType = CNFOBJ_INPUT; - BEGIN INOBJ; return BEGINOBJ; } -"module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; - BEGIN INOBJ; return BEGINOBJ; } -"action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } -^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { - yylval.s = strdup(yytext); return PROPFILT; } -^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } -"*" | -\-\/[^*][^\n]* | -\/[^*][^\n]* | -:[a-z0-9]+:[^\n]* | -[\|\.\-\@~][^\n]+ | -[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); - // printf("lex: LEGA ACT: '%s'\n", yytext); - return LEGACY_ACTION; } -")" { BEGIN INITIAL; return ENDOBJ; } -[a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); - return NAME; } -"=" { return(yytext[0]); } -\"([^"\\]|\\['"?\\abfnrtv]|\\[0-7]{1,3})*\" { - yylval.estr = es_newStrFromBuf(yytext+1, yyleng-2); - return VALUE; } -"/*" { preCommentState = YY_START; BEGIN COMMENT; } -"/*" { preCommentState = YY_START; BEGIN COMMENT; } -"*/" { BEGIN preCommentState; } -([^*]|\n)+|. -#.*$ /* skip comments in input */ -[ \n\t] -. { printf("INOBJ: invalid char '%s'\n", yytext); } -\$[a-z]+.*$ { /* see common on $IncludeConfig above */ - if(!strncasecmp(yytext, "$includeconfig ", 14)) { - yyless(14); - BEGIN INCL; - } else { - yylval.s = strdup(yytext); - return CFSYSLINE; - } - } -![^ \t\n]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_TAG_SELECTOR; } -[+-]\*[ \t\n]*#.*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -[+-]\*[ \t\n]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } -\#.*\n /* skip comments in input */ -[\n\t ] /* drop whitespace */ -. { printf("invalid char: %s\n", yytext); - } -<> { if(popfile() != 0) yyterminate(); } - -%% -/* set a new buffers. Returns 0 on success, something else otherwise. */ -int -cnfSetLexFile(char *fname) -{ - es_str_t *str = NULL; - FILE *fp; - int r = 0; - struct bufstack *bs; - - if(fname == NULL) { - fp = stdin; - } else { - if((fp = fopen(fname, "r")) == NULL) { - r = 1; - goto done; - } - } - readConfFile(fp, &str); - if(fp != stdin) - fclose(fp); - - /* maintain stack */ - if((bs = malloc(sizeof(struct bufstack))) == NULL) { - r = 1; - goto done; - } - - if(currbs != NULL) - currbs->lineno = yylineno; - bs->prev = currbs; - bs->fn = strdup(fname); - bs->bs = yy_scan_buffer((char*)es_getBufAddr(str), es_strlen(str)); - currbs = bs; - currfn = bs->fn; - yylineno = 1; - -done: - if(r != 0) { - if(str != NULL) - es_deleteStr(str); - } - return r; -} - - -/* returns 0 on success, something else otherwise */ -int -popfile(void) -{ - struct bufstack *bs = currbs; - - if(bs == NULL) - return 1; - - /* delte current entry */ - yy_delete_buffer(bs->bs); - free(bs->fn); - - /* switch back to previous */ - currbs = bs->prev; - free(bs); - - if(currbs == NULL) - return 1; /* all processed */ - - yy_switch_to_buffer(currbs->bs); - yylineno = currbs->lineno; - currfn = currbs->fn; - return 0; -} diff --git a/grammar/rscript.y b/grammar/rscript.y deleted file mode 100644 index b24b7db7..00000000 --- a/grammar/rscript.y +++ /dev/null @@ -1,164 +0,0 @@ - /* Bison file for rsyslog config format v2 (RainerScript). - * Please note: this file introduces the new config format, but maintains - * backward compatibility. In order to do so, the grammar is not 100% clean, - * but IMHO still sufficiently easy both to understand for programmers - * maitaining the code as well as users writing the config file. Users are, - * of course, encouraged to use new constructs only. But it needs to be noted - * that some of the legacy constructs (specifically the in-front-of-action - * PRI filter) are very hard to beat in ease of use, at least for simpler - * cases. So while we hope that cfsysline support can be dropped some time in - * the future, we will probably keep these useful constructs. - * - * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH - * Released under the GNU GPL v3. For details see LICENSE file. - */ - -%{ -#include -#include -#include "utils.h" -#define YYDEBUG 1 -extern int yylineno; -%} - -%union { - char *s; - long long n; - es_str_t *estr; - enum cnfobjType objType; - struct cnfobj *obj; - struct nvlst *nvlst; - struct cnfactlst *actlst; - struct cnfexpr *expr; - struct cnfrule *rule; - struct cnffunc *func; - struct cnffparamlst *fparams; -} - -%token NAME -%token VALUE -%token FUNC -%token BEGINOBJ -%token ENDOBJ -%token CFSYSLINE -%token BEGIN_ACTION -%token LEGACY_ACTION -%token PRIFILT -%token PROPFILT -%token BSD_TAG_SELECTOR -%token BSD_HOST_SELECTOR -%token IF -%token THEN -%token OR -%token AND -%token NOT -%token VAR -%token STRING -%token NUMBER -%token CMP_EQ -%token CMP_NE -%token CMP_LE -%token CMP_GE -%token CMP_LT -%token CMP_GT -%token CMP_CONTAINS -%token CMP_CONTAINSI -%token CMP_STARTSWITH -%token CMP_STARTSWITHI - -%type nv nvlst -%type obj -%type actlst -%type act -%type cfsysline -%type block -%type expr -%type rule -%type scriptfilt -%type fparams - -%left AND OR -%left CMP_EQ CMP_NE CMP_LE CMP_GE CMP_LT CMP_GT CMP_CONTAINS CMP_CONTAINSI CMP_STARTSWITH CMP_STARTSWITHI -%left '+' '-' -%left '*' '/' '%' -%nonassoc UMINUS NOT - -%expect 3 -/* these shift/reduce conflicts are created by the CFSYSLINE construct, which we - * unfortunately can not avoid. The problem is that CFSYSLINE can occur both in - * global context as well as within an action. It's not permitted somewhere else, - * but this is suficient for conflicts. The "dangling else" built-in resolution - * works well to solve this issue, so we accept it (it's a wonder that our - * old style grammar doesn't work at all, so we better do not complain...). - * Use "bison -v rscript.y" if more conflicts arise and check rscript.out for - * were exactly these conflicts exits. - */ -%% -/* note: we use left recursion below, because that saves stack space AND - * offers the right sequence so that we can submit the top-layer objects - * one by one. - */ -conf: /* empty (to end recursion) */ - | conf obj { printf("global:config: "); - cnfobjPrint($2); cnfobjDestruct($2); } - | conf rule { printf("global:rule processed\n"); - cnfrulePrint($2); } - | conf cfsysline { printf("global:cfsysline: %s\n", $2); } - | conf BSD_TAG_SELECTOR { printf("global:BSD tag '%s'\n", $2); } - | conf BSD_HOST_SELECTOR { printf("global:BSD host '%s'\n", $2); } - -obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } - | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } -cfsysline: CFSYSLINE { $$ = $1 } -nvlst: { $$ = NULL; } - | nvlst nv { $2->next = $1; $$ = $2; } -nv: NAME '=' VALUE { $$ = nvlstNew($1, $3); } -rule: PRIFILT actlst { $$ = cnfruleNew(CNFFILT_PRI, $2); $$->filt.s = $1; } - | PROPFILT actlst { $$ = cnfruleNew(CNFFILT_PROP, $2); $$->filt.s = $1; } - | scriptfilt { $$ = $1; } - -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); } - | '{' block '}' { $$ = $2; } -act: BEGIN_ACTION nvlst ENDOBJ { $$ = cnfactlstNew(CNFACT_V2, $2, NULL); } - | LEGACY_ACTION { $$ = cnfactlstNew(CNFACT_LEGACY, NULL, $1); } -expr: expr AND expr { $$ = cnfexprNew(AND, $1, $3); } - | expr OR expr { $$ = cnfexprNew(OR, $1, $3); } - | NOT expr { $$ = cnfexprNew(NOT, NULL, $2); } - | expr CMP_EQ expr { $$ = cnfexprNew(CMP_EQ, $1, $3); } - | expr CMP_NE expr { $$ = cnfexprNew(CMP_NE, $1, $3); } - | expr CMP_LE expr { $$ = cnfexprNew(CMP_LE, $1, $3); } - | expr CMP_GE expr { $$ = cnfexprNew(CMP_GE, $1, $3); } - | expr CMP_LT expr { $$ = cnfexprNew(CMP_LT, $1, $3); } - | expr CMP_GT expr { $$ = cnfexprNew(CMP_GT, $1, $3); } - | expr CMP_CONTAINS expr { $$ = cnfexprNew(CMP_CONTAINS, $1, $3); } - | expr CMP_CONTAINSI expr { $$ = cnfexprNew(CMP_CONTAINSI, $1, $3); } - | expr CMP_STARTSWITH expr { $$ = cnfexprNew(CMP_STARTSWITH, $1, $3); } - | expr CMP_STARTSWITHI expr { $$ = cnfexprNew(CMP_STARTSWITHI, $1, $3); } - | expr '+' expr { $$ = cnfexprNew('+', $1, $3); } - | expr '-' expr { $$ = cnfexprNew('-', $1, $3); } - | expr '*' expr { $$ = cnfexprNew('*', $1, $3); } - | expr '/' expr { $$ = cnfexprNew('/', $1, $3); } - | expr '%' expr { $$ = cnfexprNew('%', $1, $3); } - | '(' expr ')' { $$ = $2; } - | '-' expr %prec UMINUS { $$ = cnfexprNew('M', NULL, $2); } - | FUNC '(' ')' { $$ = (struct cnfexpr*) cnffuncNew($1, NULL); } - | FUNC '(' fparams ')' { $$ = (struct cnfexpr*) cnffuncNew($1, $3); } - | NUMBER { $$ = (struct cnfexpr*) cnfnumvalNew($1); } - | STRING { $$ = (struct cnfexpr*) cnfstringvalNew($1); } - | VAR { $$ = (struct cnfexpr*) cnfvarNew($1); } -fparams: expr { $$ = cnffparamlstNew($1, NULL); } - | expr ',' fparams { $$ = cnffparamlstNew($1, $3); } - -%% -int yyerror(char *s) -{ - printf("parse failure on or before line %d: %s\n", yylineno, s); -} diff --git a/grammar/testdriver.c b/grammar/testdriver.c new file mode 100644 index 00000000..e1623829 --- /dev/null +++ b/grammar/testdriver.c @@ -0,0 +1,50 @@ +/* This is a stand-alone test driver for grammar processing. We try to + * keep this separate as it simplyfies grammer development. + * + * Copyright 2011 by Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library 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. + * + * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ +#include "config.h" +#include +#include +#include +#include "parserif.h" + +void +cstrPrint(char *text, es_str_t *estr) +{ + char *str; + str = es_str2cstr(estr, NULL); + printf("%s%s", text, str); + free(str); +} + + +int +main(int argc, char *argv[]) +{ + int r; + + cnfSetLexFile(argc == 1 ? NULL : argv[1]); + yydebug = 0; + r = yyparse(); + printf("yyparse() returned %d\n", r); + return r; +} diff --git a/grammar/utils.c b/grammar/utils.c index e488ebda..d9bf67aa 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -5,7 +5,7 @@ #include #include "utils.h" #include "parserif.h" -#include "rscript.tab.h" +#include "grammar.h" void readConfFile(FILE *fp, es_str_t **str) @@ -609,29 +609,3 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) } return func; } - -/* debug helper */ -#ifdef STAND_ALONE -void -cstrPrint(char *text, es_str_t *estr) -{ - char *str; - str = es_str2cstr(estr, NULL); - printf("%s%s", text, str); - free(str); -} - - -int -main(int argc, char *argv[]) -{ - int r; - - cnfSetLexFile(argc == 1 ? NULL : argv[1]); - yydebug = 0; - r = yyparse(); - printf("yyparse() returned %d\n", r); - return r; -} -#endif /* #ifdef STAND_ALONE */ - -- cgit v1.2.3 From f8e7c7e3656085bee11b1667f32828dfb4e3df06 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 5 Jul 2011 12:33:48 +0200 Subject: milestone: some plumbing for rsyslog/stand alone parsing --- grammar/grammar.y | 13 +++++---- grammar/lexer.l | 4 +-- grammar/parserif.h | 8 +++--- grammar/testdriver.c | 30 +++++++++++++++++++++ grammar/utils.c | 76 ++++++++++++++++++++++++++-------------------------- 5 files changed, 83 insertions(+), 48 deletions(-) diff --git a/grammar/grammar.y b/grammar/grammar.y index 76881fd1..43e0289a 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -17,6 +17,7 @@ #include #include #include "utils.h" +#include "parserif.h" #define YYDEBUG 1 extern int yylineno; @@ -103,13 +104,13 @@ extern int yyerror(char*); * one by one. */ conf: /* empty (to end recursion) */ - | conf obj { printf("global:config: "); + | conf obj { dbgprintf("global:config: "); cnfobjPrint($2); cnfobjDestruct($2); } - | conf rule { printf("global:rule processed\n"); + | conf rule { dbgprintf("global:rule processed\n"); cnfrulePrint($2); } - | conf cfsysline { printf("global:cfsysline: %s\n", $2); } - | conf BSD_TAG_SELECTOR { printf("global:BSD tag '%s'\n", $2); } - | conf BSD_HOST_SELECTOR { printf("global:BSD host '%s'\n", $2); } + | conf cfsysline { dbgprintf("global:cfsysline: %s\n", $2); } + | conf BSD_TAG_SELECTOR { dbgprintf("global:BSD tag '%s'\n", $2); } + | conf BSD_HOST_SELECTOR { dbgprintf("global:BSD host '%s'\n", $2); } obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } @@ -162,8 +163,10 @@ fparams: expr { $$ = cnffparamlstNew($1, NULL); } | expr ',' fparams { $$ = cnffparamlstNew($1, $3); } %% +/* int yyerror(char *s) { printf("parse failure on or before line %d: %s\n", yylineno, s); return 0; } +*/ diff --git a/grammar/lexer.l b/grammar/lexer.l index 2411be6f..ba432b2e 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -65,7 +65,7 @@ int cnfSetLexFile(char *fname); /* somehow, I need these prototype even though the headers are * included. I guess that's some autotools magic I don't understand... */ -char *strdup(char*); +//char *strdup(char*); int fileno(FILE *stream); %} @@ -209,7 +209,7 @@ cnfSetLexFile(char *fname) if(currbs != NULL) currbs->lineno = yylineno; bs->prev = currbs; - bs->fn = strdup(fname); + bs->fn = strdup(fname == NULL ? "stdin" : fname); bs->bs = yy_scan_buffer((char*)es_getBufAddr(str), es_strlen(str)); currbs = bs; currfn = bs->fn; diff --git a/grammar/parserif.h b/grammar/parserif.h index e22b7d34..b6986dd8 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -1,6 +1,8 @@ #ifndef PARSERIF_H_DEFINED #define PARSERIF_H_DEFINED -extern int cnfSetLexFile(char*); -extern int yyparse(); -extern int yydebug; +int cnfSetLexFile(char*); +int yyparse(); +int yydebug; +void dbgprintf(char *fmt, ...) __attribute__((format(printf, 1, 2))); +void parser_errmsg(char *fmt, ...) __attribute__((format(printf, 1, 2))); #endif diff --git a/grammar/testdriver.c b/grammar/testdriver.c index e1623829..915b5942 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -24,9 +24,39 @@ #include "config.h" #include #include +#include #include #include "parserif.h" +extern int yylineno; + +void +parser_errmsg(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + printf("error on or before line %d: ", yylineno); + vprintf(fmt, ap); + printf("\n"); + va_end(ap); +} + +int +yyerror(char *s) +{ + parser_errmsg("%s", s); + return 0; +} + +void +dbgprintf(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); + va_end(ap); +} + void cstrPrint(char *text, es_str_t *estr) { diff --git a/grammar/utils.c b/grammar/utils.c index d9bf67aa..0812fa6b 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -90,11 +90,11 @@ void nvlstPrint(struct nvlst *lst) { char *name, *value; - printf("nvlst %p:\n", lst); + dbgprintf("nvlst %p:\n", lst); while(lst != NULL) { name = es_str2cstr(lst->name, NULL); value = es_str2cstr(lst->value, NULL); - printf("\tname: '%s', value '%s'\n", name, value); + dbgprintf("\tname: '%s', value '%s'\n", name, value); free(name); free(value); lst = lst->next; @@ -126,7 +126,7 @@ cnfobjDestruct(struct cnfobj *o) void cnfobjPrint(struct cnfobj *o) { - printf("obj: '%s'\n", cnfobjType2str(o->objType)); + dbgprintf("obj: '%s'\n", cnfobjType2str(o->objType)); nvlstPrint(o->nvlst); } @@ -206,7 +206,7 @@ cnfactlstReverse(struct cnfactlst *actlst) prev = NULL; while(actlst != NULL) { - //printf("reversing: %s\n", actlst->data.legActLine); + //dbgprintf("reversing: %s\n", actlst->data.legActLine); curr = actlst; actlst = actlst->next; curr->syslines = cnfcfsyslinelstReverse(curr->syslines); @@ -222,17 +222,17 @@ cnfactlstPrint(struct cnfactlst *actlst) struct cnfcfsyslinelst *cflst; while(actlst != NULL) { - printf("aclst %p: ", actlst); + dbgprintf("aclst %p: ", actlst); if(actlst->actType == CNFACT_V2) { - printf("V2 action type: "); + dbgprintf("V2 action type: "); nvlstPrint(actlst->data.lst); } else { - printf("legacy action line: '%s'\n", + dbgprintf("legacy action line: '%s'\n", actlst->data.legActLine); } for( cflst = actlst->syslines ; cflst != NULL ; cflst = cflst->next) { - printf("action:cfsysline: '%s'\n", cflst->line); + dbgprintf("action:cfsysline: '%s'\n", cflst->line); } actlst = actlst->next; } @@ -266,7 +266,7 @@ static inline long long exprret2Number(struct exprret *r) { if(r->datatype == 'S') { - printf("toNumber CONVERSION MISSING\n"); abort(); + dbgprintf("toNumber CONVERSION MISSING\n"); abort(); } return r->d.n; } @@ -278,7 +278,7 @@ static inline es_str_t * exprret2String(struct exprret *r) { if(r->datatype == 'N') { - printf("toString CONVERSION MISSING\n"); abort(); + dbgprintf("toString CONVERSION MISSING\n"); abort(); } return r->d.estr; } @@ -304,7 +304,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) { struct exprret r, l; /* memory for subexpression results */ - //printf("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) { case CMP_EQ: COMP_NUM_BINOP(==); @@ -382,7 +382,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) default: ret->datatype = 'N'; ret->d.n = 0ll; - printf("eval error: unknown nodetype %u\n", + dbgprintf("eval error: unknown nodetype %u\n", (unsigned) expr->nodetype); break; } @@ -393,108 +393,108 @@ doIndent(int indent) { int i; for(i = 0 ; i < indent ; ++i) - printf(" "); + dbgprintf(" "); } void cnfexprPrint(struct cnfexpr *expr, int indent) { struct cnffparamlst *param; - //printf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); + //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("==\n"); + dbgprintf("==\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_NE: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("!=\n"); + dbgprintf("!=\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_LE: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("<=\n"); + dbgprintf("<=\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_GE: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf(">=\n"); + dbgprintf(">=\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_LT: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("<\n"); + dbgprintf("<\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_GT: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf(">\n"); + dbgprintf(">\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_CONTAINS: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("CONTAINS\n"); + dbgprintf("CONTAINS\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_CONTAINSI: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("CONTAINS_I\n"); + dbgprintf("CONTAINS_I\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_STARTSWITH: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("STARTSWITH\n"); + dbgprintf("STARTSWITH\n"); cnfexprPrint(expr->r, indent+1); break; case CMP_STARTSWITHI: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("STARTSWITH_I\n"); + dbgprintf("STARTSWITH_I\n"); cnfexprPrint(expr->r, indent+1); break; case OR: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("OR\n"); + dbgprintf("OR\n"); cnfexprPrint(expr->r, indent+1); break; case AND: cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("AND\n"); + dbgprintf("AND\n"); cnfexprPrint(expr->r, indent+1); break; case NOT: doIndent(indent); - printf("NOT\n"); + dbgprintf("NOT\n"); cnfexprPrint(expr->r, indent+1); break; case 'S': doIndent(indent); cstrPrint("string '", ((struct cnfstringval*)expr)->estr); - printf("'\n"); + dbgprintf("'\n"); break; case 'N': doIndent(indent); - printf("%lld\n", ((struct cnfnumval*)expr)->val); + dbgprintf("%lld\n", ((struct cnfnumval*)expr)->val); break; case 'V': doIndent(indent); - printf("var '%s'\n", ((struct cnfvar*)expr)->name); + dbgprintf("var '%s'\n", ((struct cnfvar*)expr)->name); break; case 'F': doIndent(indent); cstrPrint("function '", ((struct cnffunc*)expr)->fname); - printf("'\n"); + dbgprintf("'\n"); for( param = ((struct cnffunc*)expr)->paramlst ; param != NULL ; param = param->next) { @@ -510,11 +510,11 @@ cnfexprPrint(struct cnfexpr *expr, int indent) if(expr->l != NULL) cnfexprPrint(expr->l, indent+1); doIndent(indent); - printf("%c\n", (char) expr->nodetype); + dbgprintf("%c\n", (char) expr->nodetype); cnfexprPrint(expr->r, indent+1); break; default: - printf("error: unknown nodetype %u\n", + dbgprintf("error: unknown nodetype %u\n", (unsigned) expr->nodetype); break; } @@ -568,22 +568,22 @@ cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) void cnfrulePrint(struct cnfrule *rule) { - printf("------ start rule %p:\n", rule); - printf("%s: ", cnfFiltType2str(rule->filttype)); + dbgprintf("------ start rule %p:\n", rule); + dbgprintf("%s: ", cnfFiltType2str(rule->filttype)); switch(rule->filttype) { case CNFFILT_NONE: break; case CNFFILT_PRI: case CNFFILT_PROP: - printf("%s\n", rule->filt.s); + dbgprintf("%s\n", rule->filt.s); break; case CNFFILT_SCRIPT: - printf("\n"); + dbgprintf("\n"); cnfexprPrint(rule->filt.expr, 0); break; } cnfactlstPrint(rule->actlst); - printf("------ end rule %p\n", rule); + dbgprintf("------ end rule %p\n", rule); } struct cnffparamlst * -- cgit v1.2.3 From 88fdb0c5ef6a34d28b358c9a50a6b172e25c4ee4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 6 Jul 2011 08:32:07 +0200 Subject: issue a warning if old omusrmsg action syntax is used --- runtime/rsyslog.h | 1 + tools/omusrmsg.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 613a3e7a..d20cd5bb 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -344,6 +344,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_ERR_WRKDIR = -2181, /**< problems with the rsyslog working directory */ RS_RET_WRN_WRKDIR = -2182, /**< correctable problems with the rsyslog working directory */ RS_RET_ERR_QUEUE_EMERGENCY = -2183, /**< some fatal error caused queue to switch to emergency mode */ + RS_RET_OUTDATED_STMT = -2184, /**< some outdated statement/functionality is being used in conf file */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/tools/omusrmsg.c b/tools/omusrmsg.c index c737454f..6d46813e 100644 --- a/tools/omusrmsg.c +++ b/tools/omusrmsg.c @@ -281,9 +281,17 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) */ if(!strncmp((char*) p, ":omusrmsg:", sizeof(":omusrmsg:") - 1)) { p += sizeof(":omusrmsg:") - 1; /* eat indicator sequence (-1 because of '\0'!) */ - } else if(!*p || !((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') - || (*p >= '0' && *p <= '9') || *p == '_' || *p == '.' || *p == '*')) + } else { + if(!*p || !((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') + || (*p >= '0' && *p <= '9') || *p == '_' || *p == '.' || *p == '*')) { ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); + } else { + errmsg.LogError(0, RS_RET_OUTDATED_STMT, + "action '%s' treated as ':omusrmsg:%s' - please " + "change syntax, '%s' will not be supported in the future", + p, p, p); + } + } CHKiRet(createInstance(&pData)); -- cgit v1.2.3 From b035298e30a5caebbf9dbb7b57ad4e17497b2abf Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 6 Jul 2011 09:43:42 +0200 Subject: preparing for 6.3.2 --- ChangeLog | 2 +- configure.ac | 2 +- doc/manual.html | 10 +--------- tests/Makefile.am | 23 +++++++++++++++-------- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 43222443..29da56a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 6.3.2 [DEVEL] (rgerhards), 2011-06-?? +Version 6.3.2 [DEVEL] (rgerhards), 2011-07-06 - added support for the ":omusrmsg:" syntax in configuring user messages - systemd support: set stdout/stderr to null - thx to Lennart for the patch - added support for obtaining timestamp for kernel message from message diff --git a/configure.ac b/configure.ac index 5cda2f75..ef77ec45 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.1],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[6.3.2],[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 1131fb7a..19dcadb5 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -19,15 +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.

        -<<<<<<< HEAD -

        This documentation is for version 6.3.1 (devel branch) of rsyslog. -======= -<<<<<<< HEAD -

        This documentation is for version 6.1.10 (beta branch) of rsyslog. -======= -

        This documentation is for version 5.8.2 (v5-stable branch) of rsyslog. ->>>>>>> 68a01594000b788e530ee8f716545dafccf85982 ->>>>>>> 8cd429f7eeee548ff3d5a4d44daa22c2e5a1cf3a +

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

        If you like rsyslog, you might diff --git a/tests/Makefile.am b/tests/Makefile.am index 3a514aa0..a53840ac 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -267,6 +267,7 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ diskqueue-fsync.sh \ testsuites/diskqueue-fsync.conf \ imtcp-tls-basic.sh \ + imtcp-tls-basic-vg.sh \ testsuites/imtcp-tls-basic.conf \ tls-certs/ca-key.pem \ tls-certs/ca.pem \ @@ -292,6 +293,9 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ testsuites/imptcp_conndrop.conf \ imtcp_conndrop.sh \ testsuites/imtcp_conndrop.conf \ + imtcp_conndrop_tls.sh \ + imtcp_conndrop_tls-vg.sh \ + testsuites/imtcp_conndrop.conf \ imtcp_addtlframedelim.sh \ testsuites/imtcp_addtlframedelim.conf \ tcp-msgreduc-vg.sh \ @@ -501,12 +505,15 @@ inputfilegen_LDADD = $(SOL_LIBS) nettester_SOURCES = nettester.c getline.c nettester_LDADD = $(SOL_LIBS) -rt_init_SOURCES = rt-init.c $(test_files) -rt_init_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) -rt_init_LDADD = $(RSRT_LIBS) $(ZLIB_LIBS) $(PTHREADS_LIBS) $(SOL_LIBS) -rt_init_LDFLAGS = -export-dynamic +# rtinit tests disabled for the moment - also questionable if they +# really provide value (after all, everything fails if rtinit fails...) +#rt_init_SOURCES = rt-init.c $(test_files) +#rt_init_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) +#rt_init_LDADD = $(RSRT_LIBS) $(ZLIB_LIBS) $(PTHREADS_LIBS) $(SOL_LIBS) +#rt_init_LDFLAGS = -export-dynamic -rscript_SOURCES = rscript.c getline.c $(test_files) -rscript_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) -rscript_LDADD = $(RSRT_LIBS) $(ZLIB_LIBS) $(PTHREADS_LIBS) $(SOL_LIBS) -rscript_LDFLAGS = -export-dynamic +# same for basic rscript tests +#rscript_SOURCES = rscript.c getline.c $(test_files) +#rscript_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) +#rscript_LDADD = $(RSRT_LIBS) $(ZLIB_LIBS) $(PTHREADS_LIBS) $(SOL_LIBS) +#rscript_LDFLAGS = -export-dynamic -- cgit v1.2.3 From 2081c264a3b3219ed4756e548ec9b122fae9328c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 6 Jul 2011 10:05:29 +0200 Subject: milestone: abstracted parser interface ... so that both testdriver and other callers (rsyslog!) can use it without changing the parser (this simplifies development). --- grammar/grammar.y | 13 +++++-------- grammar/parserif.h | 10 ++++++++++ grammar/testdriver.c | 30 +++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/grammar/grammar.y b/grammar/grammar.y index 43e0289a..428011c5 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -104,14 +104,11 @@ extern int yyerror(char*); * one by one. */ conf: /* empty (to end recursion) */ - | conf obj { dbgprintf("global:config: "); - cnfobjPrint($2); cnfobjDestruct($2); } - | conf rule { dbgprintf("global:rule processed\n"); - cnfrulePrint($2); } - | conf cfsysline { dbgprintf("global:cfsysline: %s\n", $2); } - | conf BSD_TAG_SELECTOR { dbgprintf("global:BSD tag '%s'\n", $2); } - | conf BSD_HOST_SELECTOR { dbgprintf("global:BSD host '%s'\n", $2); } - + | conf obj { cnfDoObj($2); } + | conf rule { cnfDoRule($2); } + | conf cfsysline { cnfDoCfsysline($2); } + | conf BSD_TAG_SELECTOR { cnfDoBSDTag($2); } + | conf BSD_HOST_SELECTOR { cnfDoBSDHost($2); } obj: BEGINOBJ nvlst ENDOBJ { $$ = cnfobjNew($1, $2); } | BEGIN_ACTION nvlst ENDOBJ { $$ = cnfobjNew(CNFOBJ_ACTION, $2); } cfsysline: CFSYSLINE { $$ = $1; } diff --git a/grammar/parserif.h b/grammar/parserif.h index b6986dd8..c88114c9 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -5,4 +5,14 @@ int yyparse(); int yydebug; void dbgprintf(char *fmt, ...) __attribute__((format(printf, 1, 2))); void parser_errmsg(char *fmt, ...) __attribute__((format(printf, 1, 2))); + +/* entry points to be called after the parser has processed the + * element in question. Actual processing must than be done inside + * these functions. + */ +void cnfDoObj(struct cnfobj *o); +void cnfDoRule(struct cnfrule *rule); +void cnfDoCfsysline(char *ln); +void cnfDoBSDTag(char *ln); +void cnfDoBSDHost(char *ln); #endif diff --git a/grammar/testdriver.c b/grammar/testdriver.c index 915b5942..9899dbd1 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -26,6 +26,7 @@ #include #include #include +#include "utils.h" #include "parserif.h" extern int yylineno; @@ -57,6 +58,34 @@ dbgprintf(char *fmt, ...) va_end(ap); } +void cnfDoObj(struct cnfobj *o) +{ + dbgprintf("global:obj: "); + cnfobjPrint(o); + cnfobjDestruct(o); +} + +void cnfDoRule(struct cnfrule *rule) +{ + dbgprintf("global:rule processed\n"); + cnfrulePrint(rule); +} + +void cnfDoCfsysline(char *ln) +{ + dbgprintf("global:cfsysline: %s\n", ln); +} + +void cnfDoBSDTag(char *ln) +{ + dbgprintf("global:BSD tag: %s\n", ln); +} + +void cnfDoBSDHost(char *ln) +{ + dbgprintf("global:BSD host: %s\n", ln); +} + void cstrPrint(char *text, es_str_t *estr) { @@ -66,7 +95,6 @@ cstrPrint(char *text, es_str_t *estr) free(str); } - int main(int argc, char *argv[]) { -- cgit v1.2.3 From 4fcfea31e3c46d27c5a54a8d1d9925e59550f82c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 6 Jul 2011 11:32:54 +0200 Subject: milestone/[NONWORKING]: first integration of new parser, rules are not yet handled --- configure.ac | 4 +- grammar/parserif.h | 1 + grammar/testdriver.c | 9 ----- grammar/utils.c | 9 +++++ runtime/Makefile.am | 2 +- runtime/rsconf.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++ tools/Makefile.am | 2 +- 7 files changed, 120 insertions(+), 13 deletions(-) diff --git a/configure.ac b/configure.ac index 1a239ca4..4f9113bd 100644 --- a/configure.ac +++ b/configure.ac @@ -707,9 +707,9 @@ AC_ARG_ENABLE(rsyslogrt, [enable_rsyslogrt=yes] ) if test "x$enable_rsyslogrt" = "xyes"; then - RSRT_CFLAGS="-I\$(top_srcdir)/runtime -I\$(top_srcdir)" + RSRT_CFLAGS="-I\$(top_srcdir)/runtime -I\$(top_srcdir) -I\$(top_srcdir)/grammar" RSRT_LIBS="\$(top_builddir)/runtime/librsyslog.la" - CNF_LIBS="\$(top_builddir)/grammar/libgrammar.la" + #??CNF_LIBS="\$(top_builddir)/grammar/libgrammar.la" fi AM_CONDITIONAL(ENABLE_RSYSLOGRT, test x$enable_rsyslogrt = xyes) AC_SUBST(RSRT_CFLAGS) diff --git a/grammar/parserif.h b/grammar/parserif.h index c88114c9..0a6434d3 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -1,5 +1,6 @@ #ifndef PARSERIF_H_DEFINED #define PARSERIF_H_DEFINED +#include "utils.h" int cnfSetLexFile(char*); int yyparse(); int yydebug; diff --git a/grammar/testdriver.c b/grammar/testdriver.c index 9899dbd1..43f3bd3f 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -86,15 +86,6 @@ void cnfDoBSDHost(char *ln) dbgprintf("global:BSD host: %s\n", ln); } -void -cstrPrint(char *text, es_str_t *estr) -{ - char *str; - str = es_str2cstr(estr, NULL); - printf("%s%s", text, str); - free(str); -} - int main(int argc, char *argv[]) { diff --git a/grammar/utils.c b/grammar/utils.c index 0812fa6b..f49af9b0 100644 --- a/grammar/utils.c +++ b/grammar/utils.c @@ -609,3 +609,12 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) } return func; } + +void +cstrPrint(char *text, es_str_t *estr) +{ + char *str; + str = es_str2cstr(estr, NULL); + dbgprintf("%s%s", text, str); + free(str); +} diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 232d8f03..7c3d18ef 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -117,7 +117,7 @@ librsyslog_la_SOURCES = \ if WITH_MODDIRS librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/:$(moddirs)\" $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools else -librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools +librsyslog_la_CPPFLAGS = -DSD_EXPORT_SYMBOLS -D_PATH_MODDIR=\"$(pkglibdir)/\" -I$(top_srcdir) $(PTHREADS_CFLAGS) $(LIBEE_CFLAGS) -I\$(top_srcdir)/tools -I\$(top_srcdir)/grammar endif #librsyslog_la_LDFLAGS = -module -avoid-version librsyslog_la_LIBADD = $(DL_LIBS) $(RT_LIBS) $(LIBEE_LIBS) diff --git a/runtime/rsconf.c b/runtime/rsconf.c index cb76e6da..446a9c8b 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +64,7 @@ #include "parser.h" #include "outchannel.h" #include "threads.h" +#include "parserif.h" #include "dirty.h" /* static data */ @@ -92,6 +94,7 @@ static uchar template_StdPgSQLFmt[] = "\"insert into SystemEvents (Message, Faci static uchar template_spoofadr[] = "\"%fromhost-ip%\""; /* end templates */ +void cnfDoCfsysline(char *ln); /* Standard-Constructor */ @@ -212,6 +215,102 @@ CODESTARTobjDebugPrint(rsconf) ENDobjDebugPrint(rsconf) +rsRetVal +cnfDoActlst(struct cnfactlst *actlst) +{ + struct cnfcfsyslinelst *cflst; + rsRetVal localRet; + DEFiRet; + + while(actlst != NULL) { + dbgprintf("aclst %p: ", actlst); + if(actlst->actType == CNFACT_V2) { + dbgprintf("V2 action type not yet handled\n"); + } else { + dbgprintf("legacy action line not yet handled:%s\n", + actlst->data.legActLine); + } + for( cflst = actlst->syslines + ; cflst != NULL ; cflst = cflst->next) { + cnfDoCfsysline(cflst->line); + } + actlst = actlst->next; + } + RETiRet; +} + + +/*------------------------------ interface to flex/bison parser ------------------------------*/ +extern int yylineno; + +void +parser_errmsg(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + // TODO: create useful code ;) 2011-07-06 + dbgprintf("error on or before line %d: ", yylineno); + vprintf(fmt, ap); + printf("\n"); + va_end(ap); +} + +int +yyerror(char *s) +{ + parser_errmsg("%s", s); + return 0; +} +void cnfDoObj(struct cnfobj *o) +{ + dbgprintf("cnf:global:obj: "); + cnfobjPrint(o); + cnfobjDestruct(o); +} + +void cnfDoRule(struct cnfrule *rule) +{ + dbgprintf("cnf:global:rule\n"); + cnfrulePrint(rule); + + switch(rule->filttype) { + case CNFFILT_NONE: + break; + case CNFFILT_PRI: + case CNFFILT_PROP: + dbgprintf("%s\n", rule->filt.s); + break; + case CNFFILT_SCRIPT: + dbgprintf("\n"); + cnfexprPrint(rule->filt.expr, 0); + break; + } + cnfDoActlst(rule->actlst); +} + +void cnfDoCfsysline(char *ln) +{ + dbgprintf("cnf:global:cfsysline: %s\n", ln); + /* the legacy system needs the "$" stripped */ + conf.cfsysline(loadConf, (uchar*) ln+1); + dbgprintf("cnf:cfsysline call done\n"); +} + +void cnfDoBSDTag(char *ln) +{ + dbgprintf("cnf:global:BSD tag: %s\n", ln); + cflineProcessTagSelector(conf, &line); +} + +void cnfDoBSDHost(char *ln) +{ + dbgprintf("cnf:global:BSD host: %s\n", ln); + cflineProcessHostSelector(conf, &line); +} +/*------------------------------ end interface to flex/bison parser ------------------------------*/ + + + /* drop to specified group * if something goes wrong, the function never returns * Note that such an abort can cause damage to on-disk structures, so we should @@ -994,6 +1093,7 @@ load(rsconf_t **cnf, uchar *confFile) int iNbrActions; int bHadConfigErr = 0; char cbuf[BUFSIZ]; + int r; DEFiRet; CHKiRet(rsconfConstruct(&loadConf)); @@ -1003,6 +1103,12 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! CHKiRet(initLegacyConf()); /* open the configuration file */ + dbgprintf("ZZZZZ: calling cnfSetLexFile(%s)\n", confFile); + r = cnfSetLexFile((char*)confFile); + dbgprintf("ZZZZZ: cnfSetLexFile returns %d, calling yyparse()\n", r); + r = yyparse(); + dbgprintf("ZZZZZ: yyparse returns %d\n", r); + exit(1); localRet = conf.processConfFile(loadConf, confFile); CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions)); diff --git a/tools/Makefile.am b/tools/Makefile.am index f3b176f2..1bed5ae8 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -36,7 +36,7 @@ rsyslogd_SOURCES = \ \ ../dirty.h rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) $(CNF_LIBS) -rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) +rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) $(CNF_LIBS) ../grammar/libgrammar.la rsyslogd_LDFLAGS = -export-dynamic if ENABLE_DIAGTOOLS -- cgit v1.2.3 From 30f2b5b094d282af6f601aa4e8fa88c1baf187f4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 6 Jul 2011 12:26:52 +0200 Subject: milestone:/[PARTWORK]: config is processed using new parser, except... ... for "if" filters (more work to come, probably lots of more work... ;)) --- runtime/conf.c | 31 ++++++++++++------------- runtime/conf.h | 13 +++++++++-- runtime/rsconf.c | 70 ++++++++++++++++++++++++++++++++++++++++++++------------ tools/syslogd.c | 2 +- 4 files changed, 82 insertions(+), 34 deletions(-) diff --git a/runtime/conf.c b/runtime/conf.c index 6a2e57fa..5eb1aae2 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -354,7 +354,7 @@ finalize_it: * 2004-11-17 rgerhards */ rsRetVal -cfsysline(rsconf_t *conf, uchar *p) +cfsysline(uchar *p) { DEFiRet; uchar szCmd[64]; @@ -602,7 +602,7 @@ cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int * rgerhards 2005-09-15 */ /* GPLv3 - stems back to sysklogd */ -static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) +rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) { uchar *p; register uchar *q; @@ -619,7 +619,7 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule ASSERT(*pline != NULL); ISOBJ_TYPE_assert(pRule, rule); - dbgprintf(" - traditional PRI filter\n"); + dbgprintf(" - traditional PRI filter '%s'\n", *pline); errno = 0; /* keep strerror_r() stuff out of logerror messages */ pRule->f_filter_type = FILTER_PRI; @@ -632,7 +632,6 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule /* scan through the list of selectors */ for (p = *pline; *p && *p != '\t' && *p != ' ';) { - /* find the end of this facility name list */ for (q = p; *q && *q != '\t' && *q++ != '.'; ) continue; @@ -643,8 +642,10 @@ static rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule *bp = '\0'; /* skip cruft */ - while (strchr(",;", *q)) - q++; + if(*q) { + while (strchr(",;", *q)) + q++; + } /* decode priority name */ if ( *buf == '!' ) { @@ -836,7 +837,7 @@ finalize_it: * of the action part. A pointer to that beginnig is passed back to the caller. * rgerhards 2005-09-15 */ -static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) +rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) { rsParsObj *pPars; cstr_t *pCSCompOp; @@ -848,7 +849,7 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) ASSERT(*pline != NULL); ASSERT(f != NULL); - dbgprintf(" - property-based filter\n"); + dbgprintf(" - property-based filter '%s'\n", *pline); errno = 0; /* keep strerror_r() stuff out of logerror messages */ f->f_filter_type = FILTER_PROP; @@ -908,7 +909,6 @@ static rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) iOffset = 0; } -dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSCompOp)); if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "contains", 8)) { f->f_filterData.prop.operation = FIOP_CONTAINS; } else if(!rsCStrOffsetSzStrCmp(pCSCompOp, iOffset, (uchar*) "isequal", 7)) { @@ -927,7 +927,6 @@ dbgprintf("XXX: offset is %d, string '%s'\n", iOffset, rsCStrGetSzStrNoNULL(pCSC } rsCStrDestruct(&pCSCompOp); /* no longer needed */ -dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); if(f->f_filterData.prop.operation != FIOP_ISEMPTY) { /* read compare value */ iRet = parsQuotedCStr(pPars, &f->f_filterData.prop.pCSCompValue); @@ -958,7 +957,7 @@ dbgprintf("XXX: fiop is %u\n", (unsigned) f->f_filterData.prop.operation); * from the config file ("+/-hostname"). It stores it for further reference. * rgerhards 2005-10-19 */ -static rsRetVal cflineProcessHostSelector(rsconf_t *conf, uchar **pline) +rsRetVal cflineProcessHostSelector(uchar **pline) { DEFiRet; @@ -1008,7 +1007,7 @@ finalize_it: * from the config file ("!tagname"). It stores it for further reference. * rgerhards 2005-10-18 */ -static rsRetVal cflineProcessTagSelector(rsconf_t *conf, uchar **pline) +rsRetVal cflineProcessTagSelector(uchar **pline) { DEFiRet; @@ -1093,7 +1092,7 @@ finalize_it: /* process the action part of a selector line * rgerhards, 2007-08-01 */ -static rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) +rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) { modInfo_t *pMod; cfgmodules_etry_t *node; @@ -1214,15 +1213,15 @@ cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr) /* check type of line and call respective processing */ switch(*line) { case '!': - iRet = cflineProcessTagSelector(conf, &line); + iRet = cflineProcessTagSelector(&line); break; case '+': case '-': - iRet = cflineProcessHostSelector(conf, &line); + iRet = cflineProcessHostSelector(&line); break; case '$': ++line; /* eat '$' */ - iRet = cfsysline(conf, line); + iRet = cfsysline(line); break; default: iRet = cflineClassic(conf, line, pfCurr); diff --git a/runtime/conf.h b/runtime/conf.h index 096af630..28ccdde1 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -21,6 +21,7 @@ */ #ifndef INCLUDED_CONF_H #define INCLUDED_CONF_H +#include "action.h" /* definitions used for doNameLine to differentiate between different command types * (with otherwise identical code). This is a left-over from the previous config @@ -34,7 +35,7 @@ extern int bConfStrictScoping; /* force strict scoping during config processing? /* interfaces */ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ rsRetVal (*doNameLine)(uchar **pp, void* pVal); - rsRetVal (*cfsysline)(rsconf_t *conf, uchar *p); + rsRetVal (*cfsysline)(uchar *p); rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); rsRetVal (*doIncludeLine)(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal); rsRetVal (*cfline)(rsconf_t *conf, uchar *line, rule_t **pfCurr); @@ -48,8 +49,10 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ */ /* version 5 -- 2011-04-19 rgerhards */ /* complete revamp, we now use the rsconf object */ + /* version 6 -- 2011-07-06 rgerhards */ + /* again a complete revamp, using flex/bison based parser now */ ENDinterface(conf) -#define confCURR_IF_VERSION 5 /* increment whenever you change the interface structure! */ +#define confCURR_IF_VERSION 6 /* increment whenever you change the interface structure! */ /* in Version 3, entry point "ReInitConf()" was removed, as we do not longer need * to support restart-type HUP -- rgerhards, 2009-07-15 */ @@ -63,5 +66,11 @@ PROTOTYPEObj(conf); rsRetVal cflineParseTemplateName(uchar** pp, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *dfltTplName); rsRetVal cflineParseFileName(uchar* p, uchar *pFileName, omodStringRequest_t *pOMSR, int iEntry, int iTplOpts, uchar *pszTpl); +/* more dirt to cover the new config interface (will go away...) */ +rsRetVal cflineProcessTagSelector(uchar **pline); +rsRetVal cflineProcessHostSelector(uchar **pline); +rsRetVal cflineProcessTradPRIFilter(uchar **pline, rule_t *pRule); +rsRetVal cflineProcessPropFilter(uchar **pline, rule_t *f); +rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction); #endif /* #ifndef INCLUDED_CONF_H */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 446a9c8b..17332464 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -39,6 +39,7 @@ #include "rsyslog.h" #include "obj.h" #include "srUtils.h" +#include "rule.h" #include "ruleset.h" #include "modules.h" #include "conf.h" @@ -69,6 +70,7 @@ /* static data */ DEFobjStaticHelpers +DEFobjCurrIf(rule) DEFobjCurrIf(ruleset) DEFobjCurrIf(module) DEFobjCurrIf(conf) @@ -216,10 +218,12 @@ ENDobjDebugPrint(rsconf) rsRetVal -cnfDoActlst(struct cnfactlst *actlst) +cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) { struct cnfcfsyslinelst *cflst; + action_t *pAction; rsRetVal localRet; + uchar *str; DEFiRet; while(actlst != NULL) { @@ -227,8 +231,10 @@ cnfDoActlst(struct cnfactlst *actlst) if(actlst->actType == CNFACT_V2) { dbgprintf("V2 action type not yet handled\n"); } else { - dbgprintf("legacy action line not yet handled:%s\n", - actlst->data.legActLine); + dbgprintf("legacy action line:%s\n", actlst->data.legActLine); + str = (uchar*) actlst->data.legActLine; + iRet = cflineDoAction(loadConf, &str, &pAction); + iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction); } for( cflst = actlst->syslines ; cflst != NULL ; cflst = cflst->next) { @@ -268,44 +274,77 @@ void cnfDoObj(struct cnfobj *o) cnfobjDestruct(o); } -void cnfDoRule(struct cnfrule *rule) +void cnfDoRule(struct cnfrule *cnfrule) { + rule_t *pRule; + uchar *str; + DEFiRet; + dbgprintf("cnf:global:rule\n"); - cnfrulePrint(rule); + cnfrulePrint(cnfrule); - switch(rule->filttype) { + CHKiRet(rule.Construct(&pRule)); /* create "fresh" selector */ + CHKiRet(rule.SetAssRuleset(pRule, ruleset.GetCurrent(loadConf))); /* create "fresh" selector */ + CHKiRet(rule.ConstructFinalize(pRule)); /* create "fresh" selector */ + + switch(cnfrule->filttype) { case CNFFILT_NONE: break; case CNFFILT_PRI: + str = (uchar*) cnfrule->filt.s; + iRet = cflineProcessTradPRIFilter(&str, pRule); + break; case CNFFILT_PROP: - dbgprintf("%s\n", rule->filt.s); + dbgprintf("%s\n", cnfrule->filt.s); + str = (uchar*) cnfrule->filt.s; + iRet = cflineProcessPropFilter(&str, pRule); break; case CNFFILT_SCRIPT: - dbgprintf("\n"); - cnfexprPrint(rule->filt.expr, 0); + dbgprintf("TODO: script filter implementation missing\n"); + cnfexprPrint(cnfrule->filt.expr, 0); break; } - cnfDoActlst(rule->actlst); + /* we now check if there are some global (BSD-style) filter conditions + * and, if so, we copy them over. rgerhards, 2005-10-18 + */ +#if 0 // TODO: add LATER! + if(pDfltProgNameCmp != NULL) { + CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp)); + } + + if(eDfltHostnameCmpMode != HN_NO_COMP) { + f->eHostnameCmpMode = eDfltHostnameCmpMode; + CHKiRet(rsCStrConstructFromCStr(&(f->pCSHostnameComp), pDfltHostnameCmp)); + } +#endif + + cnfDoActlst(cnfrule->actlst, pRule); + + CHKiRet(ruleset.AddRule(loadConf, rule.GetAssRuleset(pRule), &pRule)); + +finalize_it: + //TODO: do something with error states + ; } void cnfDoCfsysline(char *ln) { dbgprintf("cnf:global:cfsysline: %s\n", ln); /* the legacy system needs the "$" stripped */ - conf.cfsysline(loadConf, (uchar*) ln+1); + conf.cfsysline((uchar*) ln+1); dbgprintf("cnf:cfsysline call done\n"); } void cnfDoBSDTag(char *ln) { dbgprintf("cnf:global:BSD tag: %s\n", ln); - cflineProcessTagSelector(conf, &line); + cflineProcessTagSelector((uchar**)&ln); } void cnfDoBSDHost(char *ln) { dbgprintf("cnf:global:BSD host: %s\n", ln); - cflineProcessHostSelector(conf, &line); + cflineProcessHostSelector((uchar**)&ln); } /*------------------------------ end interface to flex/bison parser ------------------------------*/ @@ -1108,8 +1147,7 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! dbgprintf("ZZZZZ: cnfSetLexFile returns %d, calling yyparse()\n", r); r = yyparse(); dbgprintf("ZZZZZ: yyparse returns %d\n", r); - exit(1); - localRet = conf.processConfFile(loadConf, confFile); + //localRet = conf.processConfFile(loadConf, confFile); CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions)); if(localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) { @@ -1208,6 +1246,7 @@ ENDobjQueryInterface(rsconf) BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ CHKiRet(objUse(ruleset, CORE_COMPONENT)); + CHKiRet(objUse(rule, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); CHKiRet(objUse(conf, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); @@ -1223,6 +1262,7 @@ ENDObjClassInit(rsconf) /* De-initialize the rsconf class. */ BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */ + objRelease(rule, CORE_COMPONENT); objRelease(ruleset, CORE_COMPONENT); objRelease(module, CORE_COMPONENT); objRelease(conf, CORE_COMPONENT); diff --git a/tools/syslogd.c b/tools/syslogd.c index 6dbd4be5..79bf0c8a 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -802,7 +802,7 @@ void legacyOptsHook(void) errno = 0; errmsg.LogError(0, NO_ERRCODE, "Warning: backward compatibility layer added to following " "directive to rsyslog.conf: %s", pThis->line); - conf.cfsysline(ourConf, pThis->line); + conf.cfsysline(pThis->line); } pThis = pThis->next; } -- cgit v1.2.3 From 5710b413963d2fde9d062127ed72672b8a58a07e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 7 Jul 2011 08:22:40 +0200 Subject: milestone/[PARTWORK]: integrted script filter, but var access is missing --- grammar/Makefile.am | 4 +- grammar/grammar.y | 24 +- grammar/lexer.l | 23 +- grammar/parserif.h | 2 +- grammar/rainerscript.c | 658 +++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rainerscript.h | 176 +++++++++++++ grammar/testdriver.c | 2 +- grammar/utils.c | 620 ---------------------------------------------- grammar/utils.h | 174 ------------- runtime/conf.c | 10 +- runtime/conf.h | 3 + runtime/rsconf.c | 20 +- runtime/rule.c | 8 +- runtime/rule.h | 6 +- 14 files changed, 909 insertions(+), 821 deletions(-) create mode 100644 grammar/rainerscript.c create mode 100644 grammar/rainerscript.h delete mode 100644 grammar/utils.c delete mode 100644 grammar/utils.h diff --git a/grammar/Makefile.am b/grammar/Makefile.am index b482c99e..2b149abe 100644 --- a/grammar/Makefile.am +++ b/grammar/Makefile.am @@ -7,8 +7,8 @@ bin_PROGRAMS = testdriver # TODO: make this conditional libgrammar_la_SOURCES = \ grammar.y \ lexer.l \ - utils.c \ - utils.h \ + rainerscript.c \ + rainerscript.h \ grammar.h testdriver_SOURCES = testdriver.c libgrammar.la diff --git a/grammar/grammar.y b/grammar/grammar.y index 428011c5..b8790411 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -9,14 +9,30 @@ * cases. So while we hope that cfsysline support can be dropped some time in * the future, we will probably keep these useful constructs. * - * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH - * Released under the GNU GPL v3. For details see LICENSE file. + * Copyright 2011 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library 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. + * + * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. */ - %{ #include #include -#include "utils.h" +#include "rainerscript.h" #include "parserif.h" #define YYDEBUG 1 extern int yylineno; diff --git a/grammar/lexer.l b/grammar/lexer.l index ba432b2e..d761003a 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -9,8 +9,25 @@ * cases. So while we hope that cfsysline support can be dropped some time in * the future, we will probably keep these useful constructs. * - * Copyright (C) 2011 by Rainer Gerhards and Adiscon GmbH - * Released under the GNU GPL v3. For details see LICENSE file. + * Copyright 2011 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library 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. + * + * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. */ %option noyywrap nodefault case-insensitive yylineno @@ -46,7 +63,7 @@ #include #include #include -#include "utils.h" +#include "rainerscript.h" #include "grammar.h" static int preCommentState; /* save for lex state before a comment */ diff --git a/grammar/parserif.h b/grammar/parserif.h index 0a6434d3..a04abb0c 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -1,6 +1,6 @@ #ifndef PARSERIF_H_DEFINED #define PARSERIF_H_DEFINED -#include "utils.h" +#include "rainerscript.h" int cnfSetLexFile(char*); int yyparse(); int yydebug; diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c new file mode 100644 index 00000000..801a52b2 --- /dev/null +++ b/grammar/rainerscript.c @@ -0,0 +1,658 @@ +/* rainerscript.c - routines to support RainerScript config language + * + * Module begun 2011-07-01 by Rainer Gerhards + * + * Copyright 2011 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library 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. + * + * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include "rainerscript.h" +#include "parserif.h" +#include "grammar.h" + +void +readConfFile(FILE *fp, es_str_t **str) +{ + char ln[10240]; + char buf[512]; + int lenBuf; + int bWriteLineno = 0; + int len, i; + int start; /* start index of to be submitted text */ + int bContLine = 0; + int lineno = 0; + + *str = es_newStr(4096); + + while(fgets(ln, sizeof(ln), fp) != NULL) { + ++lineno; + if(bWriteLineno) { + bWriteLineno = 0; + lenBuf = sprintf(buf, "PreprocFileLineNumber(%d)\n", lineno); + es_addBuf(str, buf, lenBuf); + } + len = strlen(ln); + /* if we are continuation line, we need to drop leading WS */ + if(bContLine) { + for(start = 0 ; start < len && isspace(ln[start]) ; ++start) + /* JUST SCAN */; + } else { + start = 0; + } + for(i = len - 1 ; i >= start && isspace(ln[i]) ; --i) + /* JUST SCAN */; + if(i >= 0) { + if(ln[i] == '\\') { + --i; + bContLine = 1; + } else { + if(bContLine) /* write line number if we had cont line */ + bWriteLineno = 1; + bContLine = 0; + } + /* add relevant data to buffer */ + es_addBuf(str, ln+start, i+1 - start); + } + if(!bContLine) + es_addChar(str, '\n'); + } + /* indicate end of buffer to flex */ + es_addChar(str, '\0'); + es_addChar(str, '\0'); +} + +struct nvlst* +nvlstNew(es_str_t *name, es_str_t *value) +{ + struct nvlst *lst; + + if((lst = malloc(sizeof(struct nvlst))) != NULL) { + lst->next = NULL; + lst->name = name; + lst->value = value; + } + + return lst; +} + +void +nvlstDestruct(struct nvlst *lst) +{ + struct nvlst *toDel; + + while(lst != NULL) { + toDel = lst; + lst = lst->next; + es_deleteStr(toDel->name); + es_deleteStr(toDel->value); + free(toDel); + } +} + +void +nvlstPrint(struct nvlst *lst) +{ + char *name, *value; + dbgprintf("nvlst %p:\n", lst); + while(lst != NULL) { + name = es_str2cstr(lst->name, NULL); + value = es_str2cstr(lst->value, NULL); + dbgprintf("\tname: '%s', value '%s'\n", name, value); + free(name); + free(value); + lst = lst->next; + } +} + +struct cnfobj* +cnfobjNew(enum cnfobjType objType, struct nvlst *lst) +{ + struct cnfobj *o; + + if((o = malloc(sizeof(struct nvlst))) != NULL) { + o->objType = objType; + o->nvlst = lst; + } + + return o; +} + +void +cnfobjDestruct(struct cnfobj *o) +{ + if(o != NULL) { + nvlstDestruct(o->nvlst); + free(o); + } +} + +void +cnfobjPrint(struct cnfobj *o) +{ + dbgprintf("obj: '%s'\n", cnfobjType2str(o->objType)); + nvlstPrint(o->nvlst); +} + + +struct cnfactlst* +cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine) +{ + struct cnfactlst *actlst; + + if((actlst = malloc(sizeof(struct cnfactlst))) != NULL) { + actlst->next = NULL; + actlst->syslines = NULL; + actlst->actType = actType; + if(actType == CNFACT_V2) + actlst->data.lst = lst; + else + actlst->data.legActLine = actLine; + } + return actlst; +} + +struct cnfactlst* +cnfactlstAddSysline(struct cnfactlst* actlst, char *line) +{ + struct cnfcfsyslinelst *cflst; + + if((cflst = malloc(sizeof(struct cnfcfsyslinelst))) != NULL) { + cflst->next = NULL; + cflst->line = line; + if(actlst->syslines == NULL) { + actlst->syslines = cflst; + } else { + cflst->next = actlst->syslines; + actlst->syslines = cflst; + } + } + return actlst; +} + +void +cnfactlstDestruct(struct cnfactlst *actlst) +{ + struct cnfactlst *toDel; + + while(actlst != NULL) { + toDel = actlst; + actlst = actlst->next; + if(toDel->actType == CNFACT_V2) + nvlstDestruct(toDel->data.lst); + else + free(toDel->data.legActLine); + free(toDel); + } + +} + +static inline struct cnfcfsyslinelst* +cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) +{ + struct cnfcfsyslinelst *curr, *prev; + if(lst == NULL) + return NULL; + prev = NULL; + while(lst != NULL) { + curr = lst; + lst = lst->next; + curr->next = prev; + prev = curr; + } + return prev; +} + +struct cnfactlst* +cnfactlstReverse(struct cnfactlst *actlst) +{ + struct cnfactlst *curr, *prev; + + prev = NULL; + while(actlst != NULL) { + //dbgprintf("reversing: %s\n", actlst->data.legActLine); + curr = actlst; + actlst = actlst->next; + curr->syslines = cnfcfsyslinelstReverse(curr->syslines); + curr->next = prev; + prev = curr; + } + return prev; +} + +void +cnfactlstPrint(struct cnfactlst *actlst) +{ + struct cnfcfsyslinelst *cflst; + + while(actlst != NULL) { + dbgprintf("aclst %p: ", actlst); + if(actlst->actType == CNFACT_V2) { + dbgprintf("V2 action type: "); + nvlstPrint(actlst->data.lst); + } else { + dbgprintf("legacy action line: '%s'\n", + actlst->data.legActLine); + } + for( cflst = actlst->syslines + ; cflst != NULL ; cflst = cflst->next) { + dbgprintf("action:cfsysline: '%s'\n", cflst->line); + } + actlst = actlst->next; + } +} + +struct cnfexpr* +cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r) +{ + struct cnfexpr *expr; + + /* optimize some constructs during parsing */ + if(nodetype == 'M' && r->nodetype == 'N') { + ((struct cnfnumval*)r)->val *= -1; + expr = r; + goto done; + } + + if((expr = malloc(sizeof(struct cnfexpr))) != NULL) { + expr->nodetype = nodetype; + expr->l = l; + expr->r = r; + } +done: + return expr; +} + +/* ensure that retval is a number; if string is no number, + * emit error message and set number to 0. + */ +static inline long long +exprret2Number(struct exprret *r) +{ + if(r->datatype == 'S') { + dbgprintf("toNumber CONVERSION MISSING\n"); abort(); + } + return r->d.n; +} + +/* ensure that retval is a string; if string is no number, + * emit error message and set number to 0. + */ +static inline es_str_t * +exprret2String(struct exprret *r) +{ + if(r->datatype == 'N') { + dbgprintf("toString CONVERSION MISSING\n"); abort(); + } + return r->d.estr; +} + +#define COMP_NUM_BINOP(x) \ + cnfexprEval(expr->l, &l); \ + cnfexprEval(expr->r, &r); \ + ret->datatype = 'N'; \ + ret->d.n = exprret2Number(&l) x exprret2Number(&r) + +/* evaluate an expression. + * Note that we try to avoid malloc whenever possible (because on + * the large overhead it has, especially on highly threaded programs). + * As such, the each caller level must provide buffer space for the + * result on its stack during recursion. This permits the callee to store + * the return value without malloc. As the value is a somewhat larger + * struct, we could otherwise not return it without malloc. + * Note that we implement boolean shortcut operations. For our needs, there + * simply is no case where full evaluation would make any sense at all. + */ +void +cnfexprEval(struct cnfexpr *expr, struct exprret *ret) +{ + struct exprret r, l; /* memory for subexpression results */ + + //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + switch(expr->nodetype) { + case CMP_EQ: + COMP_NUM_BINOP(==); + break; + case CMP_NE: + COMP_NUM_BINOP(!=); + break; + case CMP_LE: + COMP_NUM_BINOP(<=); + break; + case CMP_GE: + COMP_NUM_BINOP(>=); + break; + case CMP_LT: + COMP_NUM_BINOP(<); + break; + case CMP_GT: + COMP_NUM_BINOP(>); + break; + case OR: + cnfexprEval(expr->l, &l); + ret->datatype = 'N'; + if(exprret2Number(&l)) { + ret->d.n = 1ll; + } else { + cnfexprEval(expr->r, &r); + if(exprret2Number(&r)) + ret->d.n = 1ll; + else + ret->d.n = 0ll; + } + break; + case AND: + cnfexprEval(expr->l, &l); + ret->datatype = 'N'; + if(exprret2Number(&l)) { + cnfexprEval(expr->r, &r); + if(exprret2Number(&r)) + ret->d.n = 1ll; + else + ret->d.n = 0ll; + } else { + ret->d.n = 0ll; + } + break; + case NOT: + cnfexprEval(expr->r, &r); + ret->datatype = 'N'; + ret->d.n = !exprret2Number(&r); + break; + case 'N': + ret->datatype = 'N'; + ret->d.n = ((struct cnfnumval*)expr)->val; + break; + case '+': + COMP_NUM_BINOP(+); + break; + case '-': + COMP_NUM_BINOP(-); + break; + case '*': + COMP_NUM_BINOP(*); + break; + case '/': + COMP_NUM_BINOP(/); + break; + case '%': + COMP_NUM_BINOP(%); + break; + case 'M': + cnfexprEval(expr->r, &r); + ret->datatype = 'N'; + ret->d.n = -exprret2Number(&r); + break; + default: + ret->datatype = 'N'; + ret->d.n = 0ll; + dbgprintf("eval error: unknown nodetype %u\n", + (unsigned) expr->nodetype); + break; + } +} + +/* 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. + */ +int +cnfexprEvalBool(struct cnfexpr *expr) +{ + struct exprret ret; + cnfexprEval(expr, &ret); + return exprret2Number(&ret); +} + +inline static void +doIndent(int indent) +{ + int i; + for(i = 0 ; i < indent ; ++i) + dbgprintf(" "); +} +void +cnfexprPrint(struct cnfexpr *expr, int indent) +{ + struct cnffparamlst *param; + //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); + switch(expr->nodetype) { + case CMP_EQ: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("==\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_NE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("!=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_LE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("<=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_GE: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf(">=\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_LT: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("<\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_GT: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf(">\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_CONTAINS: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("CONTAINS\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_CONTAINSI: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("CONTAINS_I\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_STARTSWITH: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("STARTSWITH\n"); + cnfexprPrint(expr->r, indent+1); + break; + case CMP_STARTSWITHI: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("STARTSWITH_I\n"); + cnfexprPrint(expr->r, indent+1); + break; + case OR: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("OR\n"); + cnfexprPrint(expr->r, indent+1); + break; + case AND: + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("AND\n"); + cnfexprPrint(expr->r, indent+1); + break; + case NOT: + doIndent(indent); + dbgprintf("NOT\n"); + cnfexprPrint(expr->r, indent+1); + break; + case 'S': + doIndent(indent); + cstrPrint("string '", ((struct cnfstringval*)expr)->estr); + dbgprintf("'\n"); + break; + case 'N': + doIndent(indent); + dbgprintf("%lld\n", ((struct cnfnumval*)expr)->val); + break; + case 'V': + doIndent(indent); + dbgprintf("var '%s'\n", ((struct cnfvar*)expr)->name); + break; + case 'F': + doIndent(indent); + cstrPrint("function '", ((struct cnffunc*)expr)->fname); + dbgprintf("'\n"); + for( param = ((struct cnffunc*)expr)->paramlst + ; param != NULL + ; param = param->next) { + cnfexprPrint(param->expr, indent+1); + } + break; + case '+': + case '-': + case '*': + case '/': + case '%': + case 'M': + if(expr->l != NULL) + cnfexprPrint(expr->l, indent+1); + doIndent(indent); + dbgprintf("%c\n", (char) expr->nodetype); + cnfexprPrint(expr->r, indent+1); + break; + default: + dbgprintf("error: unknown nodetype %u\n", + (unsigned) expr->nodetype); + break; + } +} + +struct cnfnumval* +cnfnumvalNew(long long val) +{ + struct cnfnumval *numval; + if((numval = malloc(sizeof(struct cnfnumval))) != NULL) { + numval->nodetype = 'N'; + numval->val = val; + } + return numval; +} + +struct cnfstringval* +cnfstringvalNew(es_str_t *estr) +{ + struct cnfstringval *strval; + if((strval = malloc(sizeof(struct cnfstringval))) != NULL) { + strval->nodetype = 'S'; + strval->estr = estr; + } + return strval; +} + +struct cnfvar* +cnfvarNew(char *name) +{ + struct cnfvar *var; + if((var = malloc(sizeof(struct cnfvar))) != NULL) { + var->nodetype = 'V'; + var->name = name; + } + return var; +} + +struct cnfrule * +cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) +{ + struct cnfrule* cnfrule; + if((cnfrule = malloc(sizeof(struct cnfrule))) != NULL) { + cnfrule->nodetype = 'R'; + cnfrule->filttype = filttype; + cnfrule->actlst = cnfactlstReverse(actlst); + } + return cnfrule; +} + +void +cnfrulePrint(struct cnfrule *rule) +{ + dbgprintf("------ start rule %p:\n", rule); + dbgprintf("%s: ", cnfFiltType2str(rule->filttype)); + switch(rule->filttype) { + case CNFFILT_NONE: + break; + case CNFFILT_PRI: + case CNFFILT_PROP: + dbgprintf("%s\n", rule->filt.s); + break; + case CNFFILT_SCRIPT: + dbgprintf("\n"); + cnfexprPrint(rule->filt.expr, 0); + break; + } + cnfactlstPrint(rule->actlst); + dbgprintf("------ end rule %p\n", rule); +} + +struct cnffparamlst * +cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) +{ + struct cnffparamlst* lst; + if((lst = malloc(sizeof(struct cnffparamlst))) != NULL) { + lst->nodetype = 'P'; + lst->expr = expr; + lst->next = next; + } + return lst; +} + +struct cnffunc * +cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) +{ + struct cnffunc* func; + if((func = malloc(sizeof(struct cnffunc))) != NULL) { + func->nodetype = 'F'; + func->fname = fname; + func->paramlst = paramlst; + } + return func; +} + +void +cstrPrint(char *text, es_str_t *estr) +{ + char *str; + str = es_str2cstr(estr, NULL); + dbgprintf("%s%s", text, str); + free(str); +} diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h new file mode 100644 index 00000000..bab7e602 --- /dev/null +++ b/grammar/rainerscript.h @@ -0,0 +1,176 @@ +#ifndef INC_UTILS_H +#define INC_UTILS_H +#include +#include + +enum cnfobjType { + CNFOBJ_ACTION, + CNFOBJ_GLOBAL, + CNFOBJ_INPUT, + CNFOBJ_MODULE, + CNFOBJ_INVALID = 0 +}; + +static inline char* +cnfobjType2str(enum cnfobjType ot) +{ + switch(ot) { + case CNFOBJ_ACTION: + return "action"; + break; + case CNFOBJ_GLOBAL: + return "global"; + break; + case CNFOBJ_INPUT: + return "input"; + break; + case CNFOBJ_MODULE: + return "module"; + break; + default:return "error: invalid cnfobjType"; + } +} + +enum cnfactType { CNFACT_V2, CNFACT_LEGACY }; + +struct cnfobj { + enum cnfobjType objType; + struct nvlst *nvlst; +}; + +struct nvlst { + struct nvlst *next; + es_str_t *name; + es_str_t *value; +}; + +struct cnfcfsyslinelst { + struct cnfcfsyslinelst *next; + char *line; +}; + +struct cnfactlst { + struct cnfactlst *next; + struct cnfcfsyslinelst *syslines; + enum cnfactType actType; + union { + struct nvlst *lst; + char *legActLine; + } data; +}; + +/* the following structures support expressions, and may (very much later + * be the sole foundation for the AST. + * + * nodetypes (list not yet complete) + * F - function + * N - number + * P - fparamlst + * R - rule + * S - string + * V - var + */ +enum cnfFiltType { CNFFILT_NONE, CNFFILT_PRI, CNFFILT_PROP, CNFFILT_SCRIPT }; +static inline char* +cnfFiltType2str(enum cnfFiltType filttype) +{ + switch(filttype) { + case CNFFILT_NONE: + return("filter:none"); + case CNFFILT_PRI: + return("filter:pri"); + case CNFFILT_PROP: + return("filter:prop"); + case CNFFILT_SCRIPT: + return("filter:script"); + } + return("error:invalid_filter_type"); /* should never be reached */ +} + + +struct cnfrule { + unsigned nodetype; + enum cnfFiltType filttype; + union { + char *s; + struct cnfexpr *expr; + } filt; + struct cnfactlst *actlst; +}; + +struct cnfexpr { + unsigned nodetype; + struct cnfexpr *l; + struct cnfexpr *r; +}; + +struct cnfnumval { + unsigned nodetype; + long long val; +}; + +struct cnfstringval { + unsigned nodetype; + es_str_t *estr; +}; + +struct cnfvar { + unsigned nodetype; + char *name; +}; + +struct cnffparamlst { + unsigned nodetype; /* P */ + struct cnffparamlst *next; + struct cnfexpr *expr; +}; + +struct cnffunc { + unsigned nodetype; + es_str_t *fname; + struct cnffparamlst *paramlst; +}; + +/* future extensions +struct x { + int nodetype; +}; +*/ + +/* the return value of an expresion evaluation */ +struct exprret { + union { + es_str_t *estr; + long long n; + } d; + char datatype; /* 'N' - number, 'S' - string */ +}; + + +void readConfFile(FILE *fp, es_str_t **str); +struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); +void nvlstDestruct(struct nvlst *lst); +void nvlstPrint(struct nvlst *lst); +struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst); +void cnfobjDestruct(struct cnfobj *o); +void cnfobjPrint(struct cnfobj *o); +struct cnfactlst* cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine); +void cnfactlstDestruct(struct cnfactlst *actlst); +void cnfactlstPrint(struct cnfactlst *actlst); +struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); +struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); +struct cnfexpr* cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r); +void cnfexprPrint(struct cnfexpr *expr, int indent); +void cnfexprEval(struct cnfexpr *expr, struct exprret *ret); +int cnfexprEvalBool(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); +void cnfrulePrint(struct cnfrule *rule); +struct cnfvar* cnfvarNew(char *name); +struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst); +struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next); + +/* debug helper */ +void cstrPrint(char *text, es_str_t *estr); +#endif diff --git a/grammar/testdriver.c b/grammar/testdriver.c index 43f3bd3f..52d2d0c7 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -26,7 +26,7 @@ #include #include #include -#include "utils.h" +#include "rainerscript.h" #include "parserif.h" extern int yylineno; diff --git a/grammar/utils.c b/grammar/utils.c deleted file mode 100644 index f49af9b0..00000000 --- a/grammar/utils.c +++ /dev/null @@ -1,620 +0,0 @@ -#include -#include -#include -#include -#include -#include "utils.h" -#include "parserif.h" -#include "grammar.h" - -void -readConfFile(FILE *fp, es_str_t **str) -{ - char ln[10240]; - char buf[512]; - int lenBuf; - int bWriteLineno = 0; - int len, i; - int start; /* start index of to be submitted text */ - int bContLine = 0; - int lineno = 0; - - *str = es_newStr(4096); - - while(fgets(ln, sizeof(ln), fp) != NULL) { - ++lineno; - if(bWriteLineno) { - bWriteLineno = 0; - lenBuf = sprintf(buf, "PreprocFileLineNumber(%d)\n", lineno); - es_addBuf(str, buf, lenBuf); - } - len = strlen(ln); - /* if we are continuation line, we need to drop leading WS */ - if(bContLine) { - for(start = 0 ; start < len && isspace(ln[start]) ; ++start) - /* JUST SCAN */; - } else { - start = 0; - } - for(i = len - 1 ; i >= start && isspace(ln[i]) ; --i) - /* JUST SCAN */; - if(i >= 0) { - if(ln[i] == '\\') { - --i; - bContLine = 1; - } else { - if(bContLine) /* write line number if we had cont line */ - bWriteLineno = 1; - bContLine = 0; - } - /* add relevant data to buffer */ - es_addBuf(str, ln+start, i+1 - start); - } - if(!bContLine) - es_addChar(str, '\n'); - } - /* indicate end of buffer to flex */ - es_addChar(str, '\0'); - es_addChar(str, '\0'); -} - -struct nvlst* -nvlstNew(es_str_t *name, es_str_t *value) -{ - struct nvlst *lst; - - if((lst = malloc(sizeof(struct nvlst))) != NULL) { - lst->next = NULL; - lst->name = name; - lst->value = value; - } - - return lst; -} - -void -nvlstDestruct(struct nvlst *lst) -{ - struct nvlst *toDel; - - while(lst != NULL) { - toDel = lst; - lst = lst->next; - es_deleteStr(toDel->name); - es_deleteStr(toDel->value); - free(toDel); - } -} - -void -nvlstPrint(struct nvlst *lst) -{ - char *name, *value; - dbgprintf("nvlst %p:\n", lst); - while(lst != NULL) { - name = es_str2cstr(lst->name, NULL); - value = es_str2cstr(lst->value, NULL); - dbgprintf("\tname: '%s', value '%s'\n", name, value); - free(name); - free(value); - lst = lst->next; - } -} - -struct cnfobj* -cnfobjNew(enum cnfobjType objType, struct nvlst *lst) -{ - struct cnfobj *o; - - if((o = malloc(sizeof(struct nvlst))) != NULL) { - o->objType = objType; - o->nvlst = lst; - } - - return o; -} - -void -cnfobjDestruct(struct cnfobj *o) -{ - if(o != NULL) { - nvlstDestruct(o->nvlst); - free(o); - } -} - -void -cnfobjPrint(struct cnfobj *o) -{ - dbgprintf("obj: '%s'\n", cnfobjType2str(o->objType)); - nvlstPrint(o->nvlst); -} - - -struct cnfactlst* -cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine) -{ - struct cnfactlst *actlst; - - if((actlst = malloc(sizeof(struct cnfactlst))) != NULL) { - actlst->next = NULL; - actlst->syslines = NULL; - actlst->actType = actType; - if(actType == CNFACT_V2) - actlst->data.lst = lst; - else - actlst->data.legActLine = actLine; - } - return actlst; -} - -struct cnfactlst* -cnfactlstAddSysline(struct cnfactlst* actlst, char *line) -{ - struct cnfcfsyslinelst *cflst; - - if((cflst = malloc(sizeof(struct cnfcfsyslinelst))) != NULL) { - cflst->next = NULL; - cflst->line = line; - if(actlst->syslines == NULL) { - actlst->syslines = cflst; - } else { - cflst->next = actlst->syslines; - actlst->syslines = cflst; - } - } - return actlst; -} - -void -cnfactlstDestruct(struct cnfactlst *actlst) -{ - struct cnfactlst *toDel; - - while(actlst != NULL) { - toDel = actlst; - actlst = actlst->next; - if(toDel->actType == CNFACT_V2) - nvlstDestruct(toDel->data.lst); - else - free(toDel->data.legActLine); - free(toDel); - } - -} - -static inline struct cnfcfsyslinelst* -cnfcfsyslinelstReverse(struct cnfcfsyslinelst *lst) -{ - struct cnfcfsyslinelst *curr, *prev; - if(lst == NULL) - return NULL; - prev = NULL; - while(lst != NULL) { - curr = lst; - lst = lst->next; - curr->next = prev; - prev = curr; - } - return prev; -} - -struct cnfactlst* -cnfactlstReverse(struct cnfactlst *actlst) -{ - struct cnfactlst *curr, *prev; - - prev = NULL; - while(actlst != NULL) { - //dbgprintf("reversing: %s\n", actlst->data.legActLine); - curr = actlst; - actlst = actlst->next; - curr->syslines = cnfcfsyslinelstReverse(curr->syslines); - curr->next = prev; - prev = curr; - } - return prev; -} - -void -cnfactlstPrint(struct cnfactlst *actlst) -{ - struct cnfcfsyslinelst *cflst; - - while(actlst != NULL) { - dbgprintf("aclst %p: ", actlst); - if(actlst->actType == CNFACT_V2) { - dbgprintf("V2 action type: "); - nvlstPrint(actlst->data.lst); - } else { - dbgprintf("legacy action line: '%s'\n", - actlst->data.legActLine); - } - for( cflst = actlst->syslines - ; cflst != NULL ; cflst = cflst->next) { - dbgprintf("action:cfsysline: '%s'\n", cflst->line); - } - actlst = actlst->next; - } -} - -struct cnfexpr* -cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r) -{ - struct cnfexpr *expr; - - /* optimize some constructs during parsing */ - if(nodetype == 'M' && r->nodetype == 'N') { - ((struct cnfnumval*)r)->val *= -1; - expr = r; - goto done; - } - - if((expr = malloc(sizeof(struct cnfexpr))) != NULL) { - expr->nodetype = nodetype; - expr->l = l; - expr->r = r; - } -done: - return expr; -} - -/* ensure that retval is a number; if string is no number, - * emit error message and set number to 0. - */ -static inline long long -exprret2Number(struct exprret *r) -{ - if(r->datatype == 'S') { - dbgprintf("toNumber CONVERSION MISSING\n"); abort(); - } - return r->d.n; -} - -/* ensure that retval is a string; if string is no number, - * emit error message and set number to 0. - */ -static inline es_str_t * -exprret2String(struct exprret *r) -{ - if(r->datatype == 'N') { - dbgprintf("toString CONVERSION MISSING\n"); abort(); - } - return r->d.estr; -} - -#define COMP_NUM_BINOP(x) \ - cnfexprEval(expr->l, &l); \ - cnfexprEval(expr->r, &r); \ - ret->datatype = 'N'; \ - ret->d.n = exprret2Number(&l) x exprret2Number(&r) - -/* evaluate an expression. - * Note that we try to avoid malloc whenever possible (because on - * the large overhead it has, especially on highly threaded programs). - * As such, the each caller level must provide buffer space for the - * result on its stack during recursion. This permits the callee to store - * the return value without malloc. As the value is a somewhat larger - * struct, we could otherwise not return it without malloc. - * Note that we implement boolean shortcut operations. For our needs, there - * simply is no case where full evaluation would make any sense at all. - */ -void -cnfexprEval(struct cnfexpr *expr, struct exprret *ret) -{ - struct exprret r, l; /* memory for subexpression results */ - - //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); - switch(expr->nodetype) { - case CMP_EQ: - COMP_NUM_BINOP(==); - break; - case CMP_NE: - COMP_NUM_BINOP(!=); - break; - case CMP_LE: - COMP_NUM_BINOP(<=); - break; - case CMP_GE: - COMP_NUM_BINOP(>=); - break; - case CMP_LT: - COMP_NUM_BINOP(<); - break; - case CMP_GT: - COMP_NUM_BINOP(>); - break; - case OR: - cnfexprEval(expr->l, &l); - ret->datatype = 'N'; - if(exprret2Number(&l)) { - ret->d.n = 1ll; - } else { - cnfexprEval(expr->r, &r); - if(exprret2Number(&r)) - ret->d.n = 1ll; - else - ret->d.n = 0ll; - } - break; - case AND: - cnfexprEval(expr->l, &l); - ret->datatype = 'N'; - if(exprret2Number(&l)) { - cnfexprEval(expr->r, &r); - if(exprret2Number(&r)) - ret->d.n = 1ll; - else - ret->d.n = 0ll; - } else { - ret->d.n = 0ll; - } - break; - case NOT: - cnfexprEval(expr->r, &r); - ret->datatype = 'N'; - ret->d.n = !exprret2Number(&r); - break; - case 'N': - ret->datatype = 'N'; - ret->d.n = ((struct cnfnumval*)expr)->val; - break; - case '+': - COMP_NUM_BINOP(+); - break; - case '-': - COMP_NUM_BINOP(-); - break; - case '*': - COMP_NUM_BINOP(*); - break; - case '/': - COMP_NUM_BINOP(/); - break; - case '%': - COMP_NUM_BINOP(%); - break; - case 'M': - cnfexprEval(expr->r, &r); - ret->datatype = 'N'; - ret->d.n = -exprret2Number(&r); - break; - default: - ret->datatype = 'N'; - ret->d.n = 0ll; - dbgprintf("eval error: unknown nodetype %u\n", - (unsigned) expr->nodetype); - break; - } -} - -inline static void -doIndent(int indent) -{ - int i; - for(i = 0 ; i < indent ; ++i) - dbgprintf(" "); -} -void -cnfexprPrint(struct cnfexpr *expr, int indent) -{ - struct cnffparamlst *param; - //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); - switch(expr->nodetype) { - case CMP_EQ: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("==\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_NE: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("!=\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_LE: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("<=\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_GE: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf(">=\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_LT: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("<\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_GT: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf(">\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_CONTAINS: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("CONTAINS\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_CONTAINSI: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("CONTAINS_I\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_STARTSWITH: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("STARTSWITH\n"); - cnfexprPrint(expr->r, indent+1); - break; - case CMP_STARTSWITHI: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("STARTSWITH_I\n"); - cnfexprPrint(expr->r, indent+1); - break; - case OR: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("OR\n"); - cnfexprPrint(expr->r, indent+1); - break; - case AND: - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("AND\n"); - cnfexprPrint(expr->r, indent+1); - break; - case NOT: - doIndent(indent); - dbgprintf("NOT\n"); - cnfexprPrint(expr->r, indent+1); - break; - case 'S': - doIndent(indent); - cstrPrint("string '", ((struct cnfstringval*)expr)->estr); - dbgprintf("'\n"); - break; - case 'N': - doIndent(indent); - dbgprintf("%lld\n", ((struct cnfnumval*)expr)->val); - break; - case 'V': - doIndent(indent); - dbgprintf("var '%s'\n", ((struct cnfvar*)expr)->name); - break; - case 'F': - doIndent(indent); - cstrPrint("function '", ((struct cnffunc*)expr)->fname); - dbgprintf("'\n"); - for( param = ((struct cnffunc*)expr)->paramlst - ; param != NULL - ; param = param->next) { - cnfexprPrint(param->expr, indent+1); - } - break; - case '+': - case '-': - case '*': - case '/': - case '%': - case 'M': - if(expr->l != NULL) - cnfexprPrint(expr->l, indent+1); - doIndent(indent); - dbgprintf("%c\n", (char) expr->nodetype); - cnfexprPrint(expr->r, indent+1); - break; - default: - dbgprintf("error: unknown nodetype %u\n", - (unsigned) expr->nodetype); - break; - } -} - -struct cnfnumval* -cnfnumvalNew(long long val) -{ - struct cnfnumval *numval; - if((numval = malloc(sizeof(struct cnfnumval))) != NULL) { - numval->nodetype = 'N'; - numval->val = val; - } - return numval; -} - -struct cnfstringval* -cnfstringvalNew(es_str_t *estr) -{ - struct cnfstringval *strval; - if((strval = malloc(sizeof(struct cnfstringval))) != NULL) { - strval->nodetype = 'S'; - strval->estr = estr; - } - return strval; -} - -struct cnfvar* -cnfvarNew(char *name) -{ - struct cnfvar *var; - if((var = malloc(sizeof(struct cnfvar))) != NULL) { - var->nodetype = 'V'; - var->name = name; - } - return var; -} - -struct cnfrule * -cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst) -{ - struct cnfrule* cnfrule; - if((cnfrule = malloc(sizeof(struct cnfrule))) != NULL) { - cnfrule->nodetype = 'R'; - cnfrule->filttype = filttype; - cnfrule->actlst = cnfactlstReverse(actlst); - } - return cnfrule; -} - -void -cnfrulePrint(struct cnfrule *rule) -{ - dbgprintf("------ start rule %p:\n", rule); - dbgprintf("%s: ", cnfFiltType2str(rule->filttype)); - switch(rule->filttype) { - case CNFFILT_NONE: - break; - case CNFFILT_PRI: - case CNFFILT_PROP: - dbgprintf("%s\n", rule->filt.s); - break; - case CNFFILT_SCRIPT: - dbgprintf("\n"); - cnfexprPrint(rule->filt.expr, 0); - break; - } - cnfactlstPrint(rule->actlst); - dbgprintf("------ end rule %p\n", rule); -} - -struct cnffparamlst * -cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) -{ - struct cnffparamlst* lst; - if((lst = malloc(sizeof(struct cnffparamlst))) != NULL) { - lst->nodetype = 'P'; - lst->expr = expr; - lst->next = next; - } - return lst; -} - -struct cnffunc * -cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) -{ - struct cnffunc* func; - if((func = malloc(sizeof(struct cnffunc))) != NULL) { - func->nodetype = 'F'; - func->fname = fname; - func->paramlst = paramlst; - } - return func; -} - -void -cstrPrint(char *text, es_str_t *estr) -{ - char *str; - str = es_str2cstr(estr, NULL); - dbgprintf("%s%s", text, str); - free(str); -} diff --git a/grammar/utils.h b/grammar/utils.h deleted file mode 100644 index e75105da..00000000 --- a/grammar/utils.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef INC_UTILS_H -#define INC_UTILS_H -#include - -enum cnfobjType { - CNFOBJ_ACTION, - CNFOBJ_GLOBAL, - CNFOBJ_INPUT, - CNFOBJ_MODULE, - CNFOBJ_INVALID = 0 -}; - -static inline char* -cnfobjType2str(enum cnfobjType ot) -{ - switch(ot) { - case CNFOBJ_ACTION: - return "action"; - break; - case CNFOBJ_GLOBAL: - return "global"; - break; - case CNFOBJ_INPUT: - return "input"; - break; - case CNFOBJ_MODULE: - return "module"; - break; - default:return "error: invalid cnfobjType"; - } -} - -enum cnfactType { CNFACT_V2, CNFACT_LEGACY }; - -struct cnfobj { - enum cnfobjType objType; - struct nvlst *nvlst; -}; - -struct nvlst { - struct nvlst *next; - es_str_t *name; - es_str_t *value; -}; - -struct cnfcfsyslinelst { - struct cnfcfsyslinelst *next; - char *line; -}; - -struct cnfactlst { - struct cnfactlst *next; - struct cnfcfsyslinelst *syslines; - enum cnfactType actType; - union { - struct nvlst *lst; - char *legActLine; - } data; -}; - -/* the following structures support expressions, and may (very much later - * be the sole foundation for the AST. - * - * nodetypes (list not yet complete) - * F - function - * N - number - * P - fparamlst - * R - rule - * S - string - * V - var - */ -enum cnfFiltType { CNFFILT_NONE, CNFFILT_PRI, CNFFILT_PROP, CNFFILT_SCRIPT }; -static inline char* -cnfFiltType2str(enum cnfFiltType filttype) -{ - switch(filttype) { - case CNFFILT_NONE: - return("filter:none"); - case CNFFILT_PRI: - return("filter:pri"); - case CNFFILT_PROP: - return("filter:prop"); - case CNFFILT_SCRIPT: - return("filter:script"); - } - return("error:invalid_filter_type"); /* should never be reached */ -} - - -struct cnfrule { - unsigned nodetype; - enum cnfFiltType filttype; - union { - char *s; - struct cnfexpr *expr; - } filt; - struct cnfactlst *actlst; -}; - -struct cnfexpr { - unsigned nodetype; - struct cnfexpr *l; - struct cnfexpr *r; -}; - -struct cnfnumval { - unsigned nodetype; - long long val; -}; - -struct cnfstringval { - unsigned nodetype; - es_str_t *estr; -}; - -struct cnfvar { - unsigned nodetype; - char *name; -}; - -struct cnffparamlst { - unsigned nodetype; /* P */ - struct cnffparamlst *next; - struct cnfexpr *expr; -}; - -struct cnffunc { - unsigned nodetype; - es_str_t *fname; - struct cnffparamlst *paramlst; -}; - -/* future extensions -struct x { - int nodetype; -}; -*/ - -/* the return value of an expresion evaluation */ -struct exprret { - union { - es_str_t *estr; - long long n; - } d; - char datatype; /* 'N' - number, 'S' - string */ -}; - - -void readConfFile(FILE *fp, es_str_t **str); -struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); -void nvlstDestruct(struct nvlst *lst); -void nvlstPrint(struct nvlst *lst); -struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst); -void cnfobjDestruct(struct cnfobj *o); -void cnfobjPrint(struct cnfobj *o); -struct cnfactlst* cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine); -void cnfactlstDestruct(struct cnfactlst *actlst); -void cnfactlstPrint(struct cnfactlst *actlst); -struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); -struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); -struct cnfexpr* cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r); -void cnfexprPrint(struct cnfexpr *expr, int indent); -void cnfexprEval(struct cnfexpr *expr, struct exprret *ret); -struct cnfnumval* cnfnumvalNew(long long val); -struct cnfstringval* cnfstringvalNew(es_str_t *estr); -struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst); -void cnfrulePrint(struct cnfrule *rule); -struct cnfvar* cnfvarNew(char *name); -struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst); -struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next); - -/* debug helper */ -void cstrPrint(char *text, es_str_t *estr); -#endif diff --git a/runtime/conf.c b/runtime/conf.c index 5eb1aae2..51cf39e1 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -104,9 +104,9 @@ int bConfStrictScoping = 0; /* force strict scoping during config processing? */ * be run in a single thread anyways. So there can be no race conditions. * rgerhards 2005-10-18 */ -static EHostnameCmpMode eDfltHostnameCmpMode = HN_NO_COMP; -static cstr_t *pDfltHostnameCmp = NULL; -static cstr_t *pDfltProgNameCmp = NULL; +EHostnameCmpMode eDfltHostnameCmpMode = HN_NO_COMP; +cstr_t *pDfltHostnameCmp = NULL; +cstr_t *pDfltProgNameCmp = NULL; /* process a directory and include all of its files into @@ -763,6 +763,7 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) } +#if 0 /* Helper to cfline(). This function processes an "if" type of filter, * what essentially means it parses an expression. As usual, * It processes the line up to the beginning of the action part. @@ -830,6 +831,7 @@ finalize_it: RETiRet; } +#endif /* Helper to cfline(). This function takes the filter part of a property @@ -1061,12 +1063,14 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) case ':': CHKiRet(cflineProcessPropFilter(pp, f)); break; +#if 0 case 'i': /* "if" filter? */ if(*(*pp+1) && (*(*pp+1) == 'f') && isspace(*(*pp+2))) { CHKiRet(cflineProcessIfFilter(pp, f)); break; } /*FALLTHROUGH*/ +#endif default: CHKiRet(cflineProcessTradPRIFilter(pp, f)); break; diff --git a/runtime/conf.h b/runtime/conf.h index 28ccdde1..aa57c8fc 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -72,5 +72,8 @@ rsRetVal cflineProcessHostSelector(uchar **pline); rsRetVal cflineProcessTradPRIFilter(uchar **pline, rule_t *pRule); rsRetVal cflineProcessPropFilter(uchar **pline, rule_t *f); rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction); +extern EHostnameCmpMode eDfltHostnameCmpMode; +extern cstr_t *pDfltHostnameCmp; +extern cstr_t *pDfltProgNameCmp; #endif /* #ifndef INCLUDED_CONF_H */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 17332464..cb8eac50 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -255,7 +255,9 @@ parser_errmsg(char *fmt, ...) va_list ap; va_start(ap, fmt); // TODO: create useful code ;) 2011-07-06 - dbgprintf("error on or before line %d: ", yylineno); + errmsg.LogError(0, NO_ERRCODE, "error during parsing on or before line %d", + yylineno); +dbgprintf("error on or before line %d: ", yylineno); vprintf(fmt, ap); printf("\n"); va_end(ap); @@ -284,8 +286,8 @@ void cnfDoRule(struct cnfrule *cnfrule) cnfrulePrint(cnfrule); CHKiRet(rule.Construct(&pRule)); /* create "fresh" selector */ - CHKiRet(rule.SetAssRuleset(pRule, ruleset.GetCurrent(loadConf))); /* create "fresh" selector */ - CHKiRet(rule.ConstructFinalize(pRule)); /* create "fresh" selector */ + CHKiRet(rule.SetAssRuleset(pRule, ruleset.GetCurrent(loadConf))); + CHKiRet(rule.ConstructFinalize(pRule)); switch(cnfrule->filttype) { case CNFFILT_NONE: @@ -300,23 +302,21 @@ void cnfDoRule(struct cnfrule *cnfrule) iRet = cflineProcessPropFilter(&str, pRule); break; case CNFFILT_SCRIPT: - dbgprintf("TODO: script filter implementation missing\n"); - cnfexprPrint(cnfrule->filt.expr, 0); + pRule->f_filter_type = FILTER_EXPR; + pRule->f_filterData.f_expr = cnfrule->filt.expr; break; } /* we now check if there are some global (BSD-style) filter conditions * and, if so, we copy them over. rgerhards, 2005-10-18 */ -#if 0 // TODO: add LATER! if(pDfltProgNameCmp != NULL) { - CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp)); + CHKiRet(rsCStrConstructFromCStr(&(pRule->pCSProgNameComp), pDfltProgNameCmp)); } if(eDfltHostnameCmpMode != HN_NO_COMP) { - f->eHostnameCmpMode = eDfltHostnameCmpMode; - CHKiRet(rsCStrConstructFromCStr(&(f->pCSHostnameComp), pDfltHostnameCmp)); + pRule->eHostnameCmpMode = eDfltHostnameCmpMode; + CHKiRet(rsCStrConstructFromCStr(&(pRule->pCSHostnameComp), pDfltHostnameCmp)); } -#endif cnfDoActlst(cnfrule->actlst, pRule); diff --git a/runtime/rule.c b/runtime/rule.c index 3dcee877..8976c898 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -40,6 +40,7 @@ #include "var.h" #include "srUtils.h" #include "batch.h" +#include "parserif.h" #include "unicode-helper.h" /* static data */ @@ -186,14 +187,17 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) else bRet = 1; } else if(pRule->f_filter_type == FILTER_EXPR) { +#if 0 CHKiRet(vm.Construct(&pVM)); CHKiRet(vm.ConstructFinalize(pVM)); CHKiRet(vm.SetMsg(pVM, pMsg)); CHKiRet(vm.ExecProg(pVM, pRule->f_filterData.f_expr->pVmprg)); CHKiRet(vm.PopBoolFromStack(pVM, &pResult)); - dbgprintf("result of rainerscript filter evaluation: %lld\n", pResult->val.num); /* VM is destructed on function exit */ bRet = (pResult->val.num) ? 1 : 0; +#endif + bRet = cnfexprEvalBool(pRule->f_filterData.expr); + 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, @@ -356,9 +360,11 @@ CODESTARTobjDestruct(rule) rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache); if(pThis->f_filterData.prop.propName != NULL) es_deleteStr(pThis->f_filterData.prop.propName); +#if 0 } else if(pThis->f_filter_type == FILTER_EXPR) { if(pThis->f_filterData.f_expr != NULL) expr.Destruct(&pThis->f_filterData.f_expr); +#endif } llDestroy(&pThis->llActList); diff --git a/runtime/rule.h b/runtime/rule.h index 3b34e11a..f346c764 100644 --- a/runtime/rule.h +++ b/runtime/rule.h @@ -2,7 +2,7 @@ * * This implements rules within rsyslog. * - * Copyright 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2009-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -28,7 +28,8 @@ #include "libestr.h" #include "linkedlist.h" #include "regexp.h" -#include "expr.h" +#include "expr.h" // TODO: remove #if 0 +#include "rainerscript.h" /* the rule object */ struct rule_s { @@ -52,6 +53,7 @@ struct rule_s { propid_t propID; /* ID of the requested property */ es_str_t *propName; /* name of property for CEE-based filters */ } prop; + struct cnfexpr *expr; /* expression object */ expr_t *f_expr; /* expression object */ } f_filterData; -- cgit v1.2.3 From 8a9e0cc68e3314b02065dcd3424201f25f176dfb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 7 Jul 2011 16:35:51 +0200 Subject: milestone/[PARTWORK]: obtaining msg vars integrated, "==" works for strings --- configure.ac | 2 +- grammar/parserif.h | 1 + grammar/rainerscript.c | 68 +++++++++++++++++++++++++++++++++++++------------- grammar/rainerscript.h | 4 +-- grammar/testdriver.c | 8 ++++++ runtime/msg.c | 55 ++++++++++++++++++++++++++++++++++------ runtime/msg.h | 1 + runtime/rsconf.c | 14 +++++++++-- runtime/rule.c | 2 +- 9 files changed, 124 insertions(+), 31 deletions(-) diff --git a/configure.ac b/configure.ac index 4f9113bd..5612b1b2 100644 --- a/configure.ac +++ b/configure.ac @@ -38,7 +38,7 @@ AC_CANONICAL_HOST PKG_PROG_PKG_CONFIG # modules we require -PKG_CHECK_MODULES(LIBESTR, libestr >= 0.1.0) +PKG_CHECK_MODULES(LIBESTR, libestr >= 0.1.1) PKG_CHECK_MODULES(LIBEE, libee >= 0.3.1) case "${host}" in diff --git a/grammar/parserif.h b/grammar/parserif.h index a04abb0c..bebb1dfb 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -16,4 +16,5 @@ void cnfDoRule(struct cnfrule *rule); void cnfDoCfsysline(char *ln); void cnfDoBSDTag(char *ln); void cnfDoBSDHost(char *ln); +es_str_t *cnfGetVar(char *name, void *usrptr); #endif diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 801a52b2..ea23dc1a 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -291,8 +291,9 @@ done: static inline long long exprret2Number(struct exprret *r) { + long long n; if(r->datatype == 'S') { - dbgprintf("toNumber CONVERSION MISSING\n"); abort(); + n = es_str2num(r->d.estr); } return r->d.n; } @@ -301,22 +302,24 @@ exprret2Number(struct exprret *r) * emit error message and set number to 0. */ static inline es_str_t * -exprret2String(struct exprret *r) +exprret2String(struct exprret *r, int *bMustFree) { if(r->datatype == 'N') { - dbgprintf("toString CONVERSION MISSING\n"); abort(); + *bMustFree = 1; + return es_newStrFromNumber(r->d.n); } + *bMustFree = 0; return r->d.estr; } #define COMP_NUM_BINOP(x) \ - cnfexprEval(expr->l, &l); \ - cnfexprEval(expr->r, &r); \ + cnfexprEval(expr->l, &l, usrptr); \ + cnfexprEval(expr->r, &r, usrptr); \ ret->datatype = 'N'; \ ret->d.n = exprret2Number(&l) x exprret2Number(&r) /* evaluate an expression. - * Note that we try to avoid malloc whenever possible (because on + * Note that we try to avoid malloc whenever possible (because of * the large overhead it has, especially on highly threaded programs). * As such, the each caller level must provide buffer space for the * result on its stack during recursion. This permits the callee to store @@ -326,14 +329,35 @@ exprret2String(struct exprret *r) * simply is no case where full evaluation would make any sense at all. */ void -cnfexprEval(struct cnfexpr *expr, struct exprret *ret) +cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) { struct exprret r, l; /* memory for subexpression results */ + es_str_t *estr; + int bMustFree; //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: - COMP_NUM_BINOP(==); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = !es_strcmp(l.d.estr, r.d.estr); + } else { + estr = exprret2String(&r, &bMustFree); + ret->d.n = !es_strcmp(l.d.estr, estr); + if(bMustFree) es_deleteStr(estr); + } + } else { + if(r.datatype == 'S') { + estr = exprret2String(&l, &bMustFree); + ret->d.n = !es_strcmp(r.d.estr, estr); + if(bMustFree) es_deleteStr(estr); + } else { + ret->d.n = (l.d.n == r.d.n); + } + } break; case CMP_NE: COMP_NUM_BINOP(!=); @@ -351,12 +375,12 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) COMP_NUM_BINOP(>); break; case OR: - cnfexprEval(expr->l, &l); + cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; if(exprret2Number(&l)) { ret->d.n = 1ll; } else { - cnfexprEval(expr->r, &r); + cnfexprEval(expr->r, &r, usrptr); if(exprret2Number(&r)) ret->d.n = 1ll; else @@ -364,10 +388,10 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) } break; case AND: - cnfexprEval(expr->l, &l); + cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; if(exprret2Number(&l)) { - cnfexprEval(expr->r, &r); + cnfexprEval(expr->r, &r, usrptr); if(exprret2Number(&r)) ret->d.n = 1ll; else @@ -377,7 +401,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) } break; case NOT: - cnfexprEval(expr->r, &r); + cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; ret->d.n = !exprret2Number(&r); break; @@ -385,6 +409,14 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) ret->datatype = 'N'; ret->d.n = ((struct cnfnumval*)expr)->val; break; + case 'S': + ret->datatype = 'S'; + ret->d.estr = es_strdup(((struct cnfstringval*)expr)->estr); + break; + case 'V': + ret->datatype = 'S'; + ret->d.estr = cnfGetVar(((struct cnfvar*)expr)->name, usrptr); + break; case '+': COMP_NUM_BINOP(+); break; @@ -401,15 +433,15 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) COMP_NUM_BINOP(%); break; case 'M': - cnfexprEval(expr->r, &r); + cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; ret->d.n = -exprret2Number(&r); break; default: ret->datatype = 'N'; ret->d.n = 0ll; - dbgprintf("eval error: unknown nodetype %u\n", - (unsigned) expr->nodetype); + dbgprintf("eval error: unknown nodetype %u['%c']\n", + (unsigned) expr->nodetype, (char) expr->nodetype); break; } } @@ -419,10 +451,10 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret) * important. */ int -cnfexprEvalBool(struct cnfexpr *expr) +cnfexprEvalBool(struct cnfexpr *expr, void *usrptr) { struct exprret ret; - cnfexprEval(expr, &ret); + cnfexprEval(expr, &ret, usrptr); return exprret2Number(&ret); } diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index bab7e602..8b5c36de 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -161,8 +161,8 @@ struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); struct cnfexpr* cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r); void cnfexprPrint(struct cnfexpr *expr, int indent); -void cnfexprEval(struct cnfexpr *expr, struct exprret *ret); -int cnfexprEvalBool(struct cnfexpr *expr); +void cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void *pusr); +int cnfexprEvalBool(struct cnfexpr *expr, void *usrptr); 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/grammar/testdriver.c b/grammar/testdriver.c index 52d2d0c7..3e161d38 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -86,6 +86,14 @@ void cnfDoBSDHost(char *ln) dbgprintf("global:BSD host: %s\n", ln); } +es_str_t* +cnfGetVar(char *name, void *usrptr) +{ + es_str_t *estr; + estr = es_newStrFromCStr("", 1); + return estr; +} + int main(int argc, char *argv[]) { diff --git a/runtime/msg.c b/runtime/msg.c index c5cbb5c8..96fe1b2c 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #if HAVE_MALLOC_H # include @@ -480,16 +481,13 @@ getRcvFromIP(msg_t *pM) } - -/* map a property name (string) to a property ID */ -rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID) +/* map a property name (C string) to a property ID */ +rsRetVal +propNameStrToID(uchar *pName, propid_t *pPropID) { - uchar *pName; DEFiRet; - assert(pCSPropName != NULL); - assert(pPropID != NULL); - pName = rsCStrGetSzStrNoNULL(pCSPropName); + assert(pName != NULL); /* sometimes there are aliases to the original MonitoWare * property names. These come after || in the ifs below. */ @@ -577,6 +575,21 @@ rsRetVal propNameToID(cstr_t *pCSPropName, propid_t *pPropID) } +/* map a property name (string) to a property ID */ +rsRetVal +propNameToID(cstr_t *pCSPropName, propid_t *pPropID) +{ + uchar *pName; + DEFiRet; + + assert(pCSPropName != NULL); + assert(pPropID != NULL); + pName = rsCStrGetSzStrNoNULL(pCSPropName); + iRet = propNameStrToID(pName, pPropID); + RETiRet; +} + + /* map a property ID to a name string (useful for displaying) */ uchar *propIDToName(propid_t propID) { @@ -3190,6 +3203,34 @@ finalize_it: } + +/* Return an es_str_t for given message property. + */ +es_str_t* +msgGetMsgVarNew(msg_t *pThis, uchar *name) +{ + size_t propLen; + uchar *pszProp = NULL; + propid_t propid; + unsigned short bMustBeFreed = 0; + es_str_t *estr; + + ISOBJ_TYPE_assert(pThis, msg); + + /* always call MsgGetProp() without a template specifier */ + /* TODO: optimize propNameToID() call -- rgerhards, 2009-06-26 */ + propNameStrToID(name, &propid); + pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, NULL, &propLen, &bMustBeFreed); + +dbgprintf("ZZZZ: var %s returns '%s'\n", name, pszProp); + estr = es_newStrFromCStr((char*)pszProp, propLen); + if(bMustBeFreed) + free(pszProp); + + return estr; +} + + /* This function can be used as a generic way to set properties. * We have to handle a lot of legacy, so our return value is not always * 100% correct (called functions do not always provide one, should diff --git a/runtime/msg.h b/runtime/msg.h index 01a1e059..19debb03 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -170,6 +170,7 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, size_t *pPropLen, unsigned short *pbMustBeFreed); char *textpri(char *pRes, size_t pResLen, int pri); rsRetVal msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar); +es_str_t* msgGetMsgVarNew(msg_t *pThis, uchar *name); rsRetVal MsgEnableThreadSafety(void); uchar *getRcvFrom(msg_t *pM); void getTAG(msg_t *pM, uchar **ppBuf, int *piLen); diff --git a/runtime/rsconf.c b/runtime/rsconf.c index cb8eac50..459c9a17 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -222,7 +222,6 @@ cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) { struct cnfcfsyslinelst *cflst; action_t *pAction; - rsRetVal localRet; uchar *str; DEFiRet; @@ -280,7 +279,7 @@ void cnfDoRule(struct cnfrule *cnfrule) { rule_t *pRule; uchar *str; - DEFiRet; + rsRetVal iRet = RS_RET_OK; //DEFiRet; dbgprintf("cnf:global:rule\n"); cnfrulePrint(cnfrule); @@ -346,6 +345,17 @@ void cnfDoBSDHost(char *ln) dbgprintf("cnf:global:BSD host: %s\n", ln); cflineProcessHostSelector((uchar**)&ln); } + +es_str_t* +cnfGetVar(char *name, void *usrptr) +{ + es_str_t *estr; + dbgprintf("ZZZZ: var '%s' requested", name); + if(name[0] == '$') { + estr = msgGetMsgVarNew((msg_t*) usrptr, (uchar*)name+1); + } + return estr; +} /*------------------------------ end interface to flex/bison parser ------------------------------*/ diff --git a/runtime/rule.c b/runtime/rule.c index 8976c898..67ef8650 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -196,7 +196,7 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) /* VM is destructed on function exit */ bRet = (pResult->val.num) ? 1 : 0; #endif - bRet = cnfexprEvalBool(pRule->f_filterData.expr); + bRet = cnfexprEvalBool(pRule->f_filterData.expr, pMsg); dbgprintf("result of rainerscript filter evaluation: %d\n", bRet); } else { assert(pRule->f_filter_type == FILTER_PROP); /* assert() just in case... */ -- cgit v1.2.3 From 834fe024b4e53f65d9622a176116f232e212e326 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 07:13:56 +0200 Subject: milestone/[PARTWORK]: implemented "CONTAINS" --- grammar/rainerscript.c | 26 +++++++++++++++++++------- runtime/rsconf.c | 2 +- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index ea23dc1a..bcc73af0 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -332,8 +332,9 @@ void cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) { struct exprret r, l; /* memory for subexpression results */ - es_str_t *estr; + es_str_t *estr_r, *estr_l; int bMustFree; + int bMustFree2; //dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); switch(expr->nodetype) { @@ -345,15 +346,15 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = !es_strcmp(l.d.estr, r.d.estr); } else { - estr = exprret2String(&r, &bMustFree); - ret->d.n = !es_strcmp(l.d.estr, estr); - if(bMustFree) es_deleteStr(estr); + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = !es_strcmp(l.d.estr, estr_r); + if(bMustFree) es_deleteStr(estr_r); } } else { if(r.datatype == 'S') { - estr = exprret2String(&l, &bMustFree); - ret->d.n = !es_strcmp(r.d.estr, estr); - if(bMustFree) es_deleteStr(estr); + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = !es_strcmp(r.d.estr, estr_l); + if(bMustFree) es_deleteStr(estr_l); } else { ret->d.n = (l.d.n == r.d.n); } @@ -374,6 +375,17 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) case CMP_GT: COMP_NUM_BINOP(>); break; + case CMP_CONTAINS: + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + estr_r = exprret2String(&r, &bMustFree); + estr_l = exprret2String(&l, &bMustFree2); + ret->datatype = 'N'; +dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); + ret->d.n = es_strContains(estr_l, estr_r) != -1; + if(bMustFree) es_deleteStr(estr_r); + if(bMustFree2) es_deleteStr(estr_l); + break; case OR: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 459c9a17..0d3c940a 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -350,7 +350,7 @@ es_str_t* cnfGetVar(char *name, void *usrptr) { es_str_t *estr; - dbgprintf("ZZZZ: var '%s' requested", name); + dbgprintf("ZZZZ: var '%s' requested\n", name); if(name[0] == '$') { estr = msgGetMsgVarNew((msg_t*) usrptr, (uchar*)name+1); } -- cgit v1.2.3 From d9ea755214ab75afa039a4df89f828d4b8b30ef0 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 09:13:39 +0200 Subject: milestone/[PARTWORK]: implemented comparison operations --- grammar/lexer.l | 3 + grammar/rainerscript.c | 252 ++++++++++++++++++++++++++++++++++++++++++------- runtime/Makefile.am | 20 ++-- runtime/rsconf.c | 3 - runtime/rsyslog.c | 4 + runtime/rule.c | 11 --- tools/syslogd.c | 1 - 7 files changed, 236 insertions(+), 58 deletions(-) diff --git a/grammar/lexer.l b/grammar/lexer.l index d761003a..347a2a7a 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -72,6 +72,7 @@ struct bufstack { YY_BUFFER_STATE bs; int lineno; char *fn; + es_str_t *estr; } *currbs = NULL; char *currfn; /* name of currently processed file */ @@ -228,6 +229,7 @@ cnfSetLexFile(char *fname) bs->prev = currbs; bs->fn = strdup(fname == NULL ? "stdin" : fname); bs->bs = yy_scan_buffer((char*)es_getBufAddr(str), es_strlen(str)); + bs->estr = str; /* needed so we can free it later */ currbs = bs; currfn = bs->fn; yylineno = 1; @@ -253,6 +255,7 @@ popfile(void) /* delte current entry */ yy_delete_buffer(bs->bs); free(bs->fn); + free(bs->estr); /* switch back to previous */ currbs = bs->prev; diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index bcc73af0..0def9653 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -286,14 +286,17 @@ done: } /* ensure that retval is a number; if string is no number, - * emit error message and set number to 0. + * try to convert it to one. The semantics from es_str2num() + * are used (bSuccess tells if the conversion went well or not). */ static inline long long -exprret2Number(struct exprret *r) +exprret2Number(struct exprret *r, int *bSuccess) { long long n; if(r->datatype == 'S') { - n = es_str2num(r->d.estr); + n = es_str2num(r->d.estr, bSuccess); + } else { + *bSuccess = 1; } return r->d.n; } @@ -316,7 +319,17 @@ exprret2String(struct exprret *r, int *bMustFree) cnfexprEval(expr->l, &l, usrptr); \ cnfexprEval(expr->r, &r, usrptr); \ ret->datatype = 'N'; \ - ret->d.n = exprret2Number(&l) x exprret2Number(&r) + ret->d.n = exprret2Number(&l, &convok_l) x exprret2Number(&r, &convok_r) + +#define PREP_TWO_STRINGS \ + cnfexprEval(expr->l, &l, usrptr); \ + cnfexprEval(expr->r, &r, usrptr); \ + estr_r = exprret2String(&r, &bMustFree); \ + estr_l = exprret2String(&l, &bMustFree2) + +#define FREE_TWO_STRINGS \ + if(bMustFree) es_deleteStr(estr_r); \ + if(bMustFree2) es_deleteStr(estr_l) /* evaluate an expression. * Note that we try to avoid malloc whenever possible (because of @@ -333,67 +346,239 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) { struct exprret r, l; /* memory for subexpression results */ es_str_t *estr_r, *estr_l; - int bMustFree; - int bMustFree2; + int convok_r, convok_l; + int bMustFree, bMustFree2; + long long n_r, n_l; //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. + */ case CMP_EQ: cnfexprEval(expr->l, &l, usrptr); cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; if(l.datatype == 'S') { if(r.datatype == 'S') { - ret->d.n = !es_strcmp(l.d.estr, r.d.estr); + ret->d.n = !es_strcmp(l.d.estr, r.d.estr); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); - ret->d.n = !es_strcmp(l.d.estr, estr_r); - if(bMustFree) es_deleteStr(estr_r); + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l == r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = !es_strcmp(l.d.estr, estr_r); /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } } } else { if(r.datatype == 'S') { - estr_l = exprret2String(&l, &bMustFree); - ret->d.n = !es_strcmp(r.d.estr, estr_l); - if(bMustFree) es_deleteStr(estr_l); + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n == n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = !es_strcmp(r.d.estr, estr_l); /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } } else { - ret->d.n = (l.d.n == r.d.n); + ret->d.n = (l.d.n == r.d.n); /*CMP*/ } } break; case CMP_NE: - COMP_NUM_BINOP(!=); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr); /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l != r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r); /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n != n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l); /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n != r.d.n); /*CMP*/ + } + } break; case CMP_LE: - COMP_NUM_BINOP(<=); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr) <= 0; /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l <= r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r) <= 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n <= n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l) <= 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n <= r.d.n); /*CMP*/ + } + } break; case CMP_GE: - COMP_NUM_BINOP(>=); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr) >= 0; /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l >= r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r) >= 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n >= n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l) >= 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n >= r.d.n); /*CMP*/ + } + } break; case CMP_LT: - COMP_NUM_BINOP(<); + cnfexprEval(expr->l, &l, usrptr); + cnfexprEval(expr->r, &r, usrptr); + ret->datatype = 'N'; + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr) < 0; /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l < r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r) < 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n < n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l) < 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n < r.d.n); /*CMP*/ + } + } break; case CMP_GT: - COMP_NUM_BINOP(>); - break; - case CMP_CONTAINS: cnfexprEval(expr->l, &l, usrptr); cnfexprEval(expr->r, &r, usrptr); - estr_r = exprret2String(&r, &bMustFree); - estr_l = exprret2String(&l, &bMustFree2); ret->datatype = 'N'; -dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); + if(l.datatype == 'S') { + if(r.datatype == 'S') { + ret->d.n = es_strcmp(l.d.estr, r.d.estr) > 0; /*CMP*/ + } else { + n_l = exprret2Number(&l, &convok_l); + if(convok_l) { + ret->d.n = (n_l > r.d.n); /*CMP*/ + } else { + estr_r = exprret2String(&r, &bMustFree); + ret->d.n = es_strcmp(l.d.estr, estr_r) > 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_r); + } + } + } else { + if(r.datatype == 'S') { + n_r = exprret2Number(&r, &convok_r); + if(convok_r) { + ret->d.n = (l.d.n > n_r); /*CMP*/ + } else { + estr_l = exprret2String(&l, &bMustFree); + ret->d.n = es_strcmp(r.d.estr, estr_l) > 0; /*CMP*/ + if(bMustFree) es_deleteStr(estr_l); + } + } else { + ret->d.n = (l.d.n > r.d.n); /*CMP*/ + } + } + break; + case CMP_STARTSWITH: + PREP_TWO_STRINGS; + ret->datatype = 'N'; + ret->d.n = es_strncmp(estr_l, estr_r, estr_r->lenStr) == 0; + FREE_TWO_STRINGS; + break; + case CMP_STARTSWITHI: + PREP_TWO_STRINGS; + ret->datatype = 'N'; + ret->d.n = es_strncasecmp(estr_l, estr_r, estr_r->lenStr) == 0; + FREE_TWO_STRINGS; + break; + case CMP_CONTAINS: + PREP_TWO_STRINGS; + ret->datatype = 'N'; ret->d.n = es_strContains(estr_l, estr_r) != -1; - if(bMustFree) es_deleteStr(estr_r); - if(bMustFree2) es_deleteStr(estr_l); + FREE_TWO_STRINGS; + break; + case CMP_CONTAINSI: + PREP_TWO_STRINGS; + ret->datatype = 'N'; + ret->d.n = es_strCaseContains(estr_l, estr_r) != -1; + FREE_TWO_STRINGS; break; case OR: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; - if(exprret2Number(&l)) { + if(exprret2Number(&l, &convok_l)) { ret->d.n = 1ll; } else { cnfexprEval(expr->r, &r, usrptr); - if(exprret2Number(&r)) + if(exprret2Number(&r, &convok_r)) ret->d.n = 1ll; else ret->d.n = 0ll; @@ -402,9 +587,9 @@ dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); case AND: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; - if(exprret2Number(&l)) { + if(exprret2Number(&l, &convok_l)) { cnfexprEval(expr->r, &r, usrptr); - if(exprret2Number(&r)) + if(exprret2Number(&r, &convok_r)) ret->d.n = 1ll; else ret->d.n = 0ll; @@ -415,7 +600,7 @@ dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); case NOT: cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; - ret->d.n = !exprret2Number(&r); + ret->d.n = !exprret2Number(&r, &convok_r); break; case 'N': ret->datatype = 'N'; @@ -447,7 +632,7 @@ dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); case 'M': cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; - ret->d.n = -exprret2Number(&r); + ret->d.n = -exprret2Number(&r, &convok_r); break; default: ret->datatype = 'N'; @@ -465,9 +650,10 @@ dbgprintf("ZZZZ: contains ret %d\n", es_strContains(estr_l, estr_r)); int cnfexprEvalBool(struct cnfexpr *expr, void *usrptr) { + int convok; struct exprret ret; cnfexprEval(expr, &ret, usrptr); - return exprret2Number(&ret); + return exprret2Number(&ret, &convok); } inline static void diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 7c3d18ef..c6c860ea 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -5,6 +5,16 @@ pkglib_LTLIBRARIES = #pkglib_LTLIBRARIES = librsyslog.la librsyslog_la_SOURCES = \ + expr.c \ + expr.h \ + vm.c \ + vm.h \ + vmstk.c \ + vmstk.h \ + vmprg.c \ + vmprg.h \ + vmop.c \ + vmop.h \ rsyslog.c \ rsyslog.h \ typedefs.h \ @@ -55,8 +65,6 @@ librsyslog_la_SOURCES = \ statsobj.h \ sync.c \ sync.h \ - expr.c \ - expr.h \ ctok.c \ ctok.h \ ctok_token.c \ @@ -71,14 +79,6 @@ librsyslog_la_SOURCES = \ wti.h \ sysvar.c \ sysvar.h \ - vm.c \ - vm.h \ - vmstk.c \ - vmstk.h \ - vmprg.c \ - vmprg.h \ - vmop.c \ - vmop.h \ queue.c \ queue.h \ ruleset.c \ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 0d3c940a..c1bc3b72 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -1152,11 +1152,8 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! CHKiRet(initLegacyConf()); /* open the configuration file */ - dbgprintf("ZZZZZ: calling cnfSetLexFile(%s)\n", confFile); r = cnfSetLexFile((char*)confFile); - dbgprintf("ZZZZZ: cnfSetLexFile returns %d, calling yyparse()\n", r); r = yyparse(); - dbgprintf("ZZZZZ: yyparse returns %d\n", r); //localRet = conf.processConfFile(loadConf, confFile); CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions)); diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index 2b8f2b64..d71fe88a 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -182,10 +182,13 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(ctok_tokenClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "ctok"; CHKiRet(ctokClassInit(NULL)); +#if 1 if(ppErrObj != NULL) *ppErrObj = "vmstk"; CHKiRet(vmstkClassInit(NULL)); +#endif if(ppErrObj != NULL) *ppErrObj = "sysvar"; CHKiRet(sysvarClassInit(NULL)); +#if 1 if(ppErrObj != NULL) *ppErrObj = "vm"; CHKiRet(vmClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "vmop"; @@ -194,6 +197,7 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(vmprgClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "expr"; CHKiRet(exprClassInit(NULL)); +#endif if(ppErrObj != NULL) *ppErrObj = "rule"; CHKiRet(ruleClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "ruleset"; diff --git a/runtime/rule.c b/runtime/rule.c index 67ef8650..0b4b48a2 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -36,7 +36,6 @@ #include "action.h" #include "rule.h" #include "errmsg.h" -#include "vm.h" #include "var.h" #include "srUtils.h" #include "batch.h" @@ -46,9 +45,7 @@ /* static data */ DEFobjStaticHelpers DEFobjCurrIf(errmsg) -DEFobjCurrIf(expr) DEFobjCurrIf(var) -DEFobjCurrIf(vm) /* support for simple textual representation of FIOP names @@ -124,7 +121,6 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) uchar *pszPropVal; int bRet = 0; size_t propLen; - vm_t *pVM = NULL; var_t *pResult = NULL; ISOBJ_TYPE_assert(pRule, rule); @@ -276,9 +272,6 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) finalize_it: /* destruct in any case, not just on error, but it makes error handling much easier */ - if(pVM != NULL) - vm.Destruct(&pVM); - if(pResult != NULL) var.Destruct(&pResult); @@ -482,9 +475,7 @@ ENDobjQueryInterface(rule) */ BEGINObjClassExit(rule, OBJ_IS_CORE_MODULE) /* class, version */ objRelease(errmsg, CORE_COMPONENT); - objRelease(expr, CORE_COMPONENT); objRelease(var, CORE_COMPONENT); - objRelease(vm, CORE_COMPONENT); ENDObjClassExit(rule) @@ -495,9 +486,7 @@ ENDObjClassExit(rule) BEGINObjClassInit(rule, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ CHKiRet(objUse(errmsg, CORE_COMPONENT)); - CHKiRet(objUse(expr, CORE_COMPONENT)); CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(vm, CORE_COMPONENT)); /* set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, ruleDebugPrint); diff --git a/tools/syslogd.c b/tools/syslogd.c index 79bf0c8a..f623b398 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -1602,7 +1602,6 @@ GlobalClassExit(void) objRelease(ruleset, CORE_COMPONENT); objRelease(rule, CORE_COMPONENT); objRelease(expr, CORE_COMPONENT); - vmClassExit(); /* this is hack, currently core_modules do not get this automatically called */ parserClassExit(); /* this is hack, currently core_modules do not get this automatically called */ rsconfClassExit(); /* this is hack, currently core_modules do not get this automatically called */ objRelease(datetime, CORE_COMPONENT); -- cgit v1.2.3 From 379bd30a5481056c2e5e71443149fb6b3b2295fc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 14:50:35 +0200 Subject: milestone/[PARTWORK]: integrated all variable types (msg/sys/cee) --- grammar/rainerscript.c | 24 ++++++++++-- runtime/msg.c | 42 +++++++++++++++++++++ runtime/msg.h | 1 + runtime/rsconf.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 161 insertions(+), 5 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 0def9653..91e71e97 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -285,6 +285,7 @@ done: return expr; } + /* ensure that retval is a number; if string is no number, * try to convert it to one. The semantics from es_str2num() * are used (bSuccess tells if the conversion went well or not). @@ -315,21 +316,28 @@ exprret2String(struct exprret *r, int *bMustFree) return r->d.estr; } +#define FREE_BOTH_RET \ + if(r.datatype == 'S') es_deleteStr(r.d.estr); \ + if(l.datatype == 'S') es_deleteStr(l.d.estr) + #define COMP_NUM_BINOP(x) \ cnfexprEval(expr->l, &l, usrptr); \ cnfexprEval(expr->r, &r, usrptr); \ ret->datatype = 'N'; \ - ret->d.n = exprret2Number(&l, &convok_l) x exprret2Number(&r, &convok_r) + ret->d.n = exprret2Number(&l, &convok_l) x exprret2Number(&r, &convok_r); \ + FREE_BOTH_RET #define PREP_TWO_STRINGS \ cnfexprEval(expr->l, &l, usrptr); \ cnfexprEval(expr->r, &r, usrptr); \ estr_r = exprret2String(&r, &bMustFree); \ - estr_l = exprret2String(&l, &bMustFree2) + estr_l = exprret2String(&l, &bMustFree2); \ + FREE_BOTH_RET #define FREE_TWO_STRINGS \ if(bMustFree) es_deleteStr(estr_r); \ - if(bMustFree2) es_deleteStr(estr_l) + if(bMustFree2) es_deleteStr(estr_l); \ + FREE_BOTH_RET /* evaluate an expression. * Note that we try to avoid malloc whenever possible (because of @@ -386,6 +394,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n == r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_NE: cnfexprEval(expr->l, &l, usrptr); @@ -418,6 +427,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n != r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_LE: cnfexprEval(expr->l, &l, usrptr); @@ -450,6 +460,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n <= r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_GE: cnfexprEval(expr->l, &l, usrptr); @@ -482,6 +493,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n >= r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_LT: cnfexprEval(expr->l, &l, usrptr); @@ -514,6 +526,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n < r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_GT: cnfexprEval(expr->l, &l, usrptr); @@ -546,6 +559,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = (l.d.n > r.d.n); /*CMP*/ } } + FREE_BOTH_RET; break; case CMP_STARTSWITH: PREP_TWO_STRINGS; @@ -583,6 +597,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) else ret->d.n = 0ll; } + FREE_BOTH_RET; break; case AND: cnfexprEval(expr->l, &l, usrptr); @@ -596,11 +611,13 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) } else { ret->d.n = 0ll; } + FREE_BOTH_RET; break; case NOT: cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; ret->d.n = !exprret2Number(&r, &convok_r); + if(r.datatype == 'S') es_deleteStr(r.d.estr); break; case 'N': ret->datatype = 'N'; @@ -633,6 +650,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; ret->d.n = -exprret2Number(&r, &convok_r); + if(r.datatype == 'S') es_deleteStr(r.d.estr); break; default: ret->datatype = 'N'; diff --git a/runtime/msg.c b/runtime/msg.c index 96fe1b2c..4e96a02f 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -3116,9 +3116,51 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, * to rewrite the script engine as well! * rgerhards, 2010-12-03 */ +es_str_t* +msgGetCEEVarNew(msg_t *pMsg, char *name) +{ + es_str_t *estr = NULL; + es_str_t *epropName = NULL; + struct ee_field *field; + + ISOBJ_TYPE_assert(pMsg, msg); + + if(pMsg->event == NULL) { + estr = es_newStr(1); + goto done; + } + + epropName = es_newStrFromCStr(name, strlen(name)); // TODO: optimize (in grammar!) +dbgprintf("ZZZZ: pmsg->event %p\n", pMsg->event); + field = ee_getEventField(pMsg->event, epropName); + if(field != NULL) { + estr = ee_getFieldValueAsStr(field, 0); + } + if(estr == NULL) { + DBGPRINTF("msgGetCEEVar: error obtaining var (field=%p, var='%s')\n", + field, name); + estr = es_newStrFromCStr("*ERROR*", sizeof("*ERROR*") - 1); + } + es_deleteStr(epropName); + +done: + return estr; +} + + +/* The function returns a cee variable suitable for use with RainerScript. Most importantly, this means + * that the value is returned in a var_t object. The var_t is constructed inside this function and + * MUST be freed by the caller. + * Note that we need to do a lot of conversions between es_str_t and cstr -- this will go away once + * we have moved larger parts of rsyslog to es_str_t. Acceptable for the moment, especially as we intend + * to rewrite the script engine as well! + * rgerhards, 2010-12-03 + * + */ rsRetVal msgGetCEEVar(msg_t *pMsg, cstr_t *propName, var_t **ppVar) { +#warning remove as part of cleanup DEFiRet; var_t *pVar; cstr_t *pstrProp; diff --git a/runtime/msg.h b/runtime/msg.h index 19debb03..55d2dfc0 100644 --- a/runtime/msg.h +++ b/runtime/msg.h @@ -178,6 +178,7 @@ char *getTimeReported(msg_t *pM, enum tplFormatTypes eFmt); char *getPRI(msg_t *pMsg); 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) */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index c1bc3b72..d12a258b 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -65,6 +65,7 @@ #include "parser.h" #include "outchannel.h" #include "threads.h" +#include "datetime.h" #include "parserif.h" #include "dirty.h" @@ -77,6 +78,7 @@ DEFobjCurrIf(conf) DEFobjCurrIf(errmsg) DEFobjCurrIf(glbl) DEFobjCurrIf(parser) +DEFobjCurrIf(datetime) /* exported static data */ rsconf_t *runConf = NULL;/* the currently running config */ @@ -244,6 +246,87 @@ cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) RETiRet; } +/* This function returns the current date in different + * variants. It is used to construct the $NOW series of + * system properties. The returned buffer must be freed + * by the caller when no longer needed. If the function + * can not allocate memory, it returns a NULL pointer. + * TODO: this was taken from msg.c and we should consolidate it with the code + * there. This is especially important when we increase the number of system + * variables (what we definitely want to do). + */ +typedef enum ENOWType { NOW_NOW, NOW_YEAR, NOW_MONTH, NOW_DAY, NOW_HOUR, NOW_MINUTE } eNOWType; +static rsRetVal +getNOW(eNOWType eNow, es_str_t **estr) +{ + DEFiRet; + uchar szBuf[16]; + struct syslogTime t; + es_size_t len; + + datetime.getCurrTime(&t, NULL); + switch(eNow) { + case NOW_NOW: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), + "%4.4d-%2.2d-%2.2d", t.year, t.month, t.day); + break; + case NOW_YEAR: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%4.4d", t.year); + break; + case NOW_MONTH: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.month); + break; + case NOW_DAY: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.day); + break; + case NOW_HOUR: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.hour); + break; + case NOW_MINUTE: + len = snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.minute); + break; + } + + /* now create a string object out of it and hand that over to the var */ + *estr = es_newStrFromCStr((char*)szBuf, len); + + RETiRet; +} + + + +static inline es_str_t * +getSysVar(char *name) +{ + es_str_t *estr = NULL; + rsRetVal iRet = RS_RET_OK; + + if(!strcmp(name, "now")) { + CHKiRet(getNOW(NOW_NOW, &estr)); + } else if(!strcmp(name, "year")) { + CHKiRet(getNOW(NOW_YEAR, &estr)); + } else if(!strcmp(name, "month")) { + CHKiRet(getNOW(NOW_MONTH, &estr)); + } else if(!strcmp(name, "day")) { + CHKiRet(getNOW(NOW_DAY, &estr)); + } else if(!strcmp(name, "hour")) { + CHKiRet(getNOW(NOW_HOUR, &estr)); + } else if(!strcmp(name, "minute")) { + CHKiRet(getNOW(NOW_MINUTE, &estr)); + } else if(!strcmp(name, "myhostname")) { + char *hn = (char*)glbl.GetLocalHostName(); + estr = es_newStrFromCStr(hn, strlen(hn)); + } else { + ABORT_FINALIZE(RS_RET_SYSVAR_NOT_FOUND); + } +finalize_it: + if(iRet != RS_RET_OK) { + dbgprintf("getSysVar error iRet %d\n", iRet); + if(estr == NULL) + estr = es_newStrFromCStr("*ERROR*", sizeof("*ERROR*") - 1); + } + return estr; +} /*------------------------------ interface to flex/bison parser ------------------------------*/ extern int yylineno; @@ -350,9 +433,19 @@ es_str_t* cnfGetVar(char *name, void *usrptr) { es_str_t *estr; - dbgprintf("ZZZZ: var '%s' requested\n", name); if(name[0] == '$') { - estr = msgGetMsgVarNew((msg_t*) usrptr, (uchar*)name+1); + if(name[1] == '$') + estr = getSysVar(name+2); + else if(name[1] == '!') + estr = msgGetCEEVarNew((msg_t*) usrptr, name+2); + else + estr = msgGetMsgVarNew((msg_t*) usrptr, (uchar*)name+1); + } + if(Debug) { + char *s; + s = es_str2cstr(estr, NULL); + dbgprintf("rainerscript: var '%s': '%s'\n", name, s); + free(s); } return estr; } @@ -1258,6 +1351,7 @@ BEGINObjClassInit(rsconf, 1, OBJ_IS_CORE_MODULE) /* class, version */ CHKiRet(objUse(conf, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(parser, CORE_COMPONENT)); /* now set our own handlers */ @@ -1275,6 +1369,7 @@ BEGINObjClassExit(rsconf, OBJ_IS_CORE_MODULE) /* class, version */ objRelease(conf, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); + objRelease(datetime, CORE_COMPONENT); objRelease(parser, CORE_COMPONENT); ENDObjClassExit(rsconf) -- cgit v1.2.3 From d649820ee508a9de3bcf37a9e3b71ff11ca3a8ea Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 14:59:42 +0200 Subject: cosmetic updates --- runtime/msg.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/runtime/msg.c b/runtime/msg.c index 4e96a02f..0de805a7 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -3108,9 +3108,8 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, } -/* The function returns a cee variable suitable for use with RainerScript. Most importantly, this means - * that the value is returned in a var_t object. The var_t is constructed inside this function and - * MUST be freed by the caller. +/* The function returns a cee variable suitable for use with RainerScript. + * Note: caller must free the returned string. * Note that we need to do a lot of conversions between es_str_t and cstr -- this will go away once * we have moved larger parts of rsyslog to es_str_t. Acceptable for the moment, especially as we intend * to rewrite the script engine as well! @@ -3131,7 +3130,6 @@ msgGetCEEVarNew(msg_t *pMsg, char *name) } epropName = es_newStrFromCStr(name, strlen(name)); // TODO: optimize (in grammar!) -dbgprintf("ZZZZ: pmsg->event %p\n", pMsg->event); field = ee_getEventField(pMsg->event, epropName); if(field != NULL) { estr = ee_getFieldValueAsStr(field, 0); -- cgit v1.2.3 From f2ef6cd10699ab9f91b9e3e53726512cd290ea68 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 8 Jul 2011 19:00:23 +0200 Subject: optimized function representation --- grammar/rainerscript.c | 36 ++++++++++++++++++++++++++++-------- grammar/rainerscript.h | 4 +++- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 91e71e97..de15d5f3 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -685,6 +685,9 @@ void cnfexprPrint(struct cnfexpr *expr, int indent) { struct cnffparamlst *param; + struct cnffunc *func; + int i; + //dbgprintf("expr %p, indent %d, type '%c'\n", expr, indent, expr->nodetype); switch(expr->nodetype) { case CMP_EQ: @@ -779,12 +782,11 @@ cnfexprPrint(struct cnfexpr *expr, int indent) break; case 'F': doIndent(indent); - cstrPrint("function '", ((struct cnffunc*)expr)->fname); - dbgprintf("'\n"); - for( param = ((struct cnffunc*)expr)->paramlst - ; param != NULL - ; param = param->next) { - cnfexprPrint(param->expr, indent+1); + func = (struct cnffunc*) expr; + cstrPrint("function '", func->fname); + dbgprintf("' (%u params)\n", (unsigned) func->nParams); + for(i = 0 ; i < func->nParams ; ++i) { + cnfexprPrint(func->expr[i], indent+1); } break; case '+': @@ -888,10 +890,28 @@ struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) { struct cnffunc* func; - if((func = malloc(sizeof(struct cnffunc))) != NULL) { + struct cnffparamlst *param, *toDel; + unsigned short i; + unsigned short nParams; + + /* we first need to find out how many params we have */ + nParams = 0; + for(param = paramlst ; param != NULL ; param = param->next) + ++nParams; + if((func = malloc(sizeof(struct cnffunc) + (nParams * sizeof(struct cnfexp*)))) + != NULL) { func->nodetype = 'F'; func->fname = fname; - func->paramlst = paramlst; + func->nParams = nParams; + func->fID = 0; /* use name */ + /* shuffle params over to array (access speed!) */ + param = paramlst; + for(i = 0 ; i < nParams ; ++i) { + func->expr[i] = param->expr; + toDel = param; + param = param->next; + free(toDel); + } } return func; } diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 8b5c36de..b7abf153 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -128,7 +128,9 @@ struct cnffparamlst { struct cnffunc { unsigned nodetype; es_str_t *fname; - struct cnffparamlst *paramlst; + unsigned short nParams; + unsigned short *fID; /* function ID for built-ins, 0 means use name */ + struct cnfexpr *expr[]; }; /* future extensions -- cgit v1.2.3 From f5e0bbe2d9d1d9594a01fc869392374d1a44afbe Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 09:30:17 +0200 Subject: milestone/[PARTWORK]: implemented RainerScript functions --- grammar/rainerscript.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++--- grammar/rainerscript.h | 19 +++++++- grammar/testdriver.c | 1 + 3 files changed, 129 insertions(+), 7 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index de15d5f3..41107de5 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -316,6 +316,91 @@ exprret2String(struct exprret *r, int *bMustFree) return r->d.estr; } +/* Perform a function call. This has been moved out of cnfExprEval in order + * to keep the code small and easier to maintain. + */ +static inline void +doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) +{ + char *fname; + char *envvar; + int bMustFree; + es_str_t *estr; + char *str; + struct exprret r[CNFFUNC_MAX_ARGS]; + + dbgprintf("rainerscript: executing function id %d\n", func->fID); + switch(func->fID) { + case CNFFUNC_STRLEN: + if(func->expr[0]->nodetype == 'S') { + /* if we already have a string, we do not need to + * do one more recursive call. + */ + ret->d.n = es_strlen(((struct cnfstringval*) func->expr[0])->estr); + } else { + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = exprret2String(&r[0], &bMustFree); + ret->d.n = es_strlen(estr); + if(bMustFree) es_deleteStr(estr); + } + ret->datatype = 'N'; + break; + case CNFFUNC_GETENV: + /* note: the optimizer shall have replaced calls to getenv() + * with a constant argument to a single string (once obtained via + * getenv()). So we do NOT need to check if there is just a + * string following. + */ + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = exprret2String(&r[0], &bMustFree); + str = (char*) es_str2cstr(estr, NULL); + envvar = getenv(str); + ret->datatype = 'S'; + ret->d.estr = es_newStrFromCStr(envvar, strlen(envvar)); + if(bMustFree) es_deleteStr(estr); + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); + free(str); + break; + case CNFFUNC_TOLOWER: + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = exprret2String(&r[0], &bMustFree); + if(!bMustFree) /* let caller handle that M) */ + estr = es_strdup(estr); + es_tolower(estr); + ret->datatype = 'S'; + ret->d.estr = estr; + break; + case CNFFUNC_CSTR: + cnfexprEval(func->expr[0], &r[0], usrptr); + estr = exprret2String(&r[0], &bMustFree); + if(!bMustFree) /* let caller handle that M) */ + estr = es_strdup(estr); + ret->datatype = 'S'; + ret->d.estr = estr; + break; + case CNFFUNC_CNUM: + if(func->expr[0]->nodetype == 'N') { + ret->d.n = ((struct cnfnumval*)func->expr[0])->val; + } else if(func->expr[0]->nodetype == 'S') { + ret->d.n = es_str2num(((struct cnfstringval*) func->expr[0])->estr, + NULL); + } else { + cnfexprEval(func->expr[0], &r[0], usrptr); + ret->d.n = exprret2Number(&r[0], NULL); + if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); + } + ret->datatype = 'N'; + break; + default: + if(Debug) { + fname = es_str2cstr(func->fname, NULL); + dbgprintf("rainerscript: invalid function id %u (name '%s')\n", + (unsigned) func->fID, fname); + free(fname); + } + } +} + #define FREE_BOTH_RET \ if(r.datatype == 'S') es_deleteStr(r.d.estr); \ if(l.datatype == 'S') es_deleteStr(l.d.estr) @@ -329,10 +414,9 @@ exprret2String(struct exprret *r, int *bMustFree) #define PREP_TWO_STRINGS \ cnfexprEval(expr->l, &l, usrptr); \ - cnfexprEval(expr->r, &r, usrptr); \ - estr_r = exprret2String(&r, &bMustFree); \ estr_l = exprret2String(&l, &bMustFree2); \ - FREE_BOTH_RET + cnfexprEval(expr->r, &r, usrptr); \ + estr_r = exprret2String(&r, &bMustFree) #define FREE_TWO_STRINGS \ if(bMustFree) es_deleteStr(estr_r); \ @@ -652,6 +736,9 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) ret->d.n = -exprret2Number(&r, &convok_r); if(r.datatype == 'S') es_deleteStr(r.d.estr); break; + case 'F': + doFuncCall((struct cnffunc*) expr, ret, usrptr); + break; default: ret->datatype = 'N'; ret->d.n = 0ll; @@ -684,7 +771,6 @@ doIndent(int indent) void cnfexprPrint(struct cnfexpr *expr, int indent) { - struct cnffparamlst *param; struct cnffunc *func; int i; @@ -784,7 +870,7 @@ cnfexprPrint(struct cnfexpr *expr, int indent) doIndent(indent); func = (struct cnffunc*) expr; cstrPrint("function '", func->fname); - dbgprintf("' (%u params)\n", (unsigned) func->nParams); + dbgprintf("' (id:%d, params:%hu)\n", func->fID, func->nParams); for(i = 0 ; i < func->nParams ; ++i) { cnfexprPrint(func->expr[i], indent+1); } @@ -886,6 +972,24 @@ cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) return lst; } +static inline enum cnffuncid +funcName2ID(es_str_t *fname) +{ + if(!es_strbufcmp(fname, (unsigned char*)"strlen", sizeof("strlen") - 1)) { + return CNFFUNC_STRLEN; + } else if(!es_strbufcmp(fname, (unsigned char*)"getenv", sizeof("getenv") - 1)) { + return CNFFUNC_GETENV; + } else if(!es_strbufcmp(fname, (unsigned char*)"tolower", sizeof("tolower") - 1)) { + return CNFFUNC_TOLOWER; + } else if(!es_strbufcmp(fname, (unsigned char*)"cstr", sizeof("cstr") - 1)) { + return CNFFUNC_CSTR; + } else if(!es_strbufcmp(fname, (unsigned char*)"cnum", sizeof("cnum") - 1)) { + return CNFFUNC_CNUM; + } else { + return CNFFUNC_INVALID; + } +} + struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) { @@ -903,7 +1007,7 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) func->nodetype = 'F'; func->fname = fname; func->nParams = nParams; - func->fID = 0; /* use name */ + func->fID = funcName2ID(fname); /* shuffle params over to array (access speed!) */ param = paramlst; for(i = 0 ; i < nParams ; ++i) { diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index b7abf153..5d9eff7f 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -3,6 +3,13 @@ #include #include +#define CNFFUNC_MAX_ARGS 32 + /**< maximum number of arguments that any function can have (among + * others, this is used to size data structures). + */ + +extern int Debug; /* 1 if in debug mode, 0 otherwise -- to be enhanced */ + enum cnfobjType { CNFOBJ_ACTION, CNFOBJ_GLOBAL, @@ -125,11 +132,21 @@ struct cnffparamlst { struct cnfexpr *expr; }; +enum cnffuncid { + CNFFUNC_INVALID = 0, /**< defunct entry, do not use (should normally not be present) */ + CNFFUNC_NAME = 1, /**< use name to call function (for future use) */ + CNFFUNC_STRLEN, + CNFFUNC_GETENV, + CNFFUNC_TOLOWER, + CNFFUNC_CSTR, + CNFFUNC_CNUM +}; + struct cnffunc { unsigned nodetype; es_str_t *fname; unsigned short nParams; - unsigned short *fID; /* function ID for built-ins, 0 means use name */ + enum cnffuncid fID; /* function ID for built-ins, 0 means use name */ struct cnfexpr *expr[]; }; diff --git a/grammar/testdriver.c b/grammar/testdriver.c index 3e161d38..784e286e 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -30,6 +30,7 @@ #include "parserif.h" extern int yylineno; +int Debug = 1; void parser_errmsg(char *fmt, ...) -- cgit v1.2.3 From 59f8ebdba75d693f7b462f51b7b50136b590dea7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 09:43:06 +0200 Subject: checking number of parameters provided to function --- grammar/rainerscript.c | 34 ++++++++++++++++++++++++++++++++-- 1 file changed, 32 insertions(+), 2 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 41107de5..f8809e13 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -398,6 +398,8 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) (unsigned) func->fID, fname); free(fname); } + ret->datatype = 'N'; + ret->d.n = 0; } } @@ -972,18 +974,46 @@ cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) return lst; } +/* Obtain function id from name AND number of params. Issues the + * relevant error messages if errors are detected. + */ static inline enum cnffuncid -funcName2ID(es_str_t *fname) +funcName2ID(es_str_t *fname, unsigned short nParams) { if(!es_strbufcmp(fname, (unsigned char*)"strlen", sizeof("strlen") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for strlen() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_STRLEN; } else if(!es_strbufcmp(fname, (unsigned char*)"getenv", sizeof("getenv") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for getenv() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_GETENV; } else if(!es_strbufcmp(fname, (unsigned char*)"tolower", sizeof("tolower") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for tolower() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_TOLOWER; } else if(!es_strbufcmp(fname, (unsigned char*)"cstr", sizeof("cstr") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for cstr() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_CSTR; } else if(!es_strbufcmp(fname, (unsigned char*)"cnum", sizeof("cnum") - 1)) { + if(nParams != 1) { + parser_errmsg("number of parameters for cnum() must be one " + "but is %d.", nParams); + return CNFFUNC_INVALID; + } return CNFFUNC_CNUM; } else { return CNFFUNC_INVALID; @@ -1007,7 +1037,7 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) func->nodetype = 'F'; func->fname = fname; func->nParams = nParams; - func->fID = funcName2ID(fname); + func->fID = funcName2ID(fname, nParams); /* shuffle params over to array (access speed!) */ param = paramlst; for(i = 0 ; i < nParams ; ++i) { -- cgit v1.2.3 From da6489743cd31a7896f17f5500dbfd18e0560260 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 17:33:12 +0200 Subject: milestone/[PARTWORK]: made sure all legacy selectors work ... except for the not guaranteed $outchannel construct, which we could not fix without syntax change. Shouldn't hurt too many. --- doc/log_rotation_fix_size.html | 2 +- doc/rsyslog_conf_output.html | 2 +- grammar/grammar.y | 1 + grammar/lexer.l | 3 ++- tools/omfile.c | 8 ++++++++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/doc/log_rotation_fix_size.html b/doc/log_rotation_fix_size.html index 190b24cb..51edf033 100644 --- a/doc/log_rotation_fix_size.html +++ b/doc/log_rotation_fix_size.html @@ -34,7 +34,7 @@ Channels to achieve this. Putting the following directive

        # outchannel definiation $outchannel log_rotation,/var/log/log_rotation.log, 52428800,/home/me/./log_rotation_script # activate the channel and log everything to it -*.* $log_rotation +*.* :omfile:$log_rotation # end log rotation via outchannel

        diff --git a/doc/rsyslog_conf_output.html b/doc/rsyslog_conf_output.html index c52aaa5e..426f2f27 100644 --- a/doc/rsyslog_conf_output.html +++ b/doc/rsyslog_conf_output.html @@ -49,7 +49,7 @@ does not activate it. To do so, you must use a selector line (see below). That selector line includes the channel name plus an $ sign in front of it. A sample might be:

        -*.* $mychannel
        +*.* :omfile:$mychannel

        In its current form, output channels primarily provide the ability to size-limit an output file. To do so, specify a maximum size. When this diff --git a/grammar/grammar.y b/grammar/grammar.y index b8790411..402b1a57 100644 --- a/grammar/grammar.y +++ b/grammar/grammar.y @@ -63,6 +63,7 @@ extern int yyerror(char*); %token ENDOBJ %token CFSYSLINE %token BEGIN_ACTION +%token STOP %token LEGACY_ACTION %token PRIFILT %token PROPFILT diff --git a/grammar/lexer.l b/grammar/lexer.l index 347a2a7a..802b2d89 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -134,6 +134,7 @@ int fileno(FILE *stream); /* line number support because the "preprocessor" combines lines and so needs * to tell us the real source line. */ +"stop" { dbgprintf("STOP\n"); return STOP; } "preprocfilelinenumber(" { BEGIN LINENO; } [0-9]+ { yylineno = atoi(yytext) - 1; } ")" { BEGIN INITIAL; } @@ -159,7 +160,7 @@ int fileno(FILE *stream); \-\/[^*][^\n]* | \/[^*][^\n]* | :[a-z0-9]+:[^\n]* | -[\|\.\-\@~][^\n]+ | +[\|\.\-\@\^?~>][^\n]+ | [a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); // printf("lex: LEGA ACT: '%s'\n", yytext); return LEGACY_ACTION; } diff --git a/tools/omfile.c b/tools/omfile.c index b50a36ab..8ecfc302 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -712,6 +712,14 @@ ENDdoAction BEGINparseSelectorAct CODESTARTparseSelectorAct + /* Note: the indicator sequence permits us to use '$' to signify + * outchannel, what otherwise is not possible due to truely + * unresolvable grammar conflicts (*this time no way around*). + * rgerhards, 2011-07-09 + */ + if(!strncmp((char*) p, ":omfile:", sizeof(":omfile:") - 1)) { + p += sizeof(":omfile:") - 1; + } if(!(*p == '$' || *p == '?' || *p == '/' || *p == '.' || *p == '-')) ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); -- cgit v1.2.3 From 6ebf9ada253ffd8c88cbe84a46fd5aa3bfd58367 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 18:00:29 +0200 Subject: milestone/[WORKS AGAIN!]: looks like the new conf format is integrated finally completed $IncludeConfig processing. --- grammar/lexer.l | 2 +- grammar/rainerscript.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rainerscript.h | 1 + 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/grammar/lexer.l b/grammar/lexer.l index 802b2d89..316b2a65 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -143,7 +143,7 @@ int fileno(FILE *stream); * always the longest match :-( */ .|\n -[^ \t\n]+ { if(cnfSetLexFile(yytext) != 0) +[^ \t\n]+ { if(cnfDoInclude(yytext) != 0) yyterminate(); BEGIN INITIAL; } "global"[ \n\t]*"(" { yylval.objType = CNFOBJ_GLOBAL; diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index f8809e13..680f8775 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include #include "rainerscript.h" #include "parserif.h" @@ -1050,6 +1053,55 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) return func; } +int +cnfDoInclude(char *name) +{ + char *cfgFile; + unsigned i; + int result; + glob_t cfgFiles; + struct stat fileInfo; + + /* Use GLOB_MARK to append a trailing slash for directories. + * Required by doIncludeDirectory(). + */ + result = glob(name, GLOB_MARK, NULL, &cfgFiles); + if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { +#if 0 + char errStr[1024]; + rs_strerror_r(errno, errStr, sizeof(errStr)); + errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s", + pattern, errStr); + ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND); +#endif + dbgprintf("includeconfig glob error %d\n", errno); + return 1; + } + + for(i = 0; i < cfgFiles.gl_pathc; i++) { + cfgFile = cfgFiles.gl_pathv[i]; + + if(stat(cfgFile, &fileInfo) != 0) + continue; /* continue with the next file if we can't stat() the file */ + + if(S_ISREG(fileInfo.st_mode)) { /* config file */ + dbgprintf("requested to include config file '%s'\n", cfgFile); + cnfSetLexFile(cfgFile); + } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */ + if(strcmp(name, cfgFile)) { + /* do not include ourselves! */ + dbgprintf("requested to include directory '%s'\n", cfgFile); + cnfDoInclude(cfgFile); + } + } else { + dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile); + } + } + + globfree(&cfgFiles); + return 0; +} + void cstrPrint(char *text, es_str_t *estr) { diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 5d9eff7f..75bb782d 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -189,6 +189,7 @@ void cnfrulePrint(struct cnfrule *rule); struct cnfvar* cnfvarNew(char *name); struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst); struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next); +int cnfDoInclude(char *name); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); -- cgit v1.2.3 From 5e2b03a31c312e6cd6a7f4cb0bca1f062668dc52 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 9 Jul 2011 18:31:50 +0200 Subject: cleaup & emergency config system reactivated --- grammar/lexer.l | 23 +++++ grammar/rainerscript.h | 1 + runtime/conf.c | 257 ------------------------------------------------- runtime/conf.h | 2 - runtime/rsconf.c | 56 ++++------- runtime/rule.c | 9 -- runtime/rule.h | 1 - tests/Makefile.am | 3 +- 8 files changed, 44 insertions(+), 308 deletions(-) diff --git a/grammar/lexer.l b/grammar/lexer.l index 316b2a65..64a804fa 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -198,6 +198,29 @@ int fileno(FILE *stream); <> { if(popfile() != 0) yyterminate(); } %% +int +cnfParseBuffer(char *buf, unsigned lenBuf) +{ + struct bufstack *bs; + int r = 0; + /* maintain stack */ + if((bs = malloc(sizeof(struct bufstack))) == NULL) { + r = 1; + goto done; + } + + if(currbs != NULL) + currbs->lineno = yylineno; + bs->prev = currbs; + bs->fn = strdup("*buffer*"); + bs->bs = yy_scan_buffer(buf, lenBuf); + bs->estr = NULL; + currbs = bs; + currfn = bs->fn; + yylineno = 1; +done: return r; +} + /* set a new buffers. Returns 0 on success, something else otherwise. */ int cnfSetLexFile(char *fname) diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 75bb782d..62c2aa50 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -166,6 +166,7 @@ struct exprret { }; +int cnfParseBuffer(char *buf, unsigned lenBuf); void readConfFile(FILE *fp, es_str_t **str); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); void nvlstDestruct(struct nvlst *lst); diff --git a/runtime/conf.c b/runtime/conf.c index 51cf39e1..4c8f2285 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -79,7 +79,6 @@ /* forward definitions */ static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); -static rsRetVal processConfFile(rsconf_t *conf, uchar *pConfFile); /* static data */ @@ -109,146 +108,6 @@ cstr_t *pDfltHostnameCmp = NULL; cstr_t *pDfltProgNameCmp = NULL; -/* process a directory and include all of its files into - * the current config file. There is no specific order of inclusion, - * files are included in the order they are read from the directory. - * The caller must have make sure that the provided parameter is - * indeed a directory. - * rgerhards, 2007-08-01 - */ -static rsRetVal doIncludeDirectory(rsconf_t *conf, uchar *pDirName) -{ - DEFiRet; - int iEntriesDone = 0; - DIR *pDir; - union { - struct dirent d; - char b[offsetof(struct dirent, d_name) + NAME_MAX + 1]; - } u; - struct dirent *res; - size_t iDirNameLen; - size_t iFileNameLen; - uchar szFullFileName[MAXFNAME]; - - ASSERT(pDirName != NULL); - - if((pDir = opendir((char*) pDirName)) == NULL) { - errmsg.LogError(errno, RS_RET_FOPEN_FAILURE, "error opening include directory"); - ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); - } - - /* prepare file name buffer */ - iDirNameLen = strlen((char*) pDirName); - memcpy(szFullFileName, pDirName, iDirNameLen); - - /* now read the directory */ - iEntriesDone = 0; - while(readdir_r(pDir, &u.d, &res) == 0) { - if(res == NULL) - break; /* this also indicates end of directory */ -# ifdef DT_REG - /* TODO: find an alternate way to checking for special files if this is - * not defined. This is currently a known problem on HP UX, but the work- - * around is simple: do not create special files in that directory. So - * fixing this is actually not the most important thing on earth... - * rgerhards, 2008-03-04 - */ - if(res->d_type != DT_REG) - continue; /* we are not interested in special files */ -# endif - if(res->d_name[0] == '.') - continue; /* these files we are also not interested in */ - ++iEntriesDone; - /* construct filename */ - iFileNameLen = strlen(res->d_name); - if (iFileNameLen > NAME_MAX) - iFileNameLen = NAME_MAX; - memcpy(szFullFileName + iDirNameLen, res->d_name, iFileNameLen); - *(szFullFileName + iDirNameLen + iFileNameLen) = '\0'; - dbgprintf("including file '%s'\n", szFullFileName); - processConfFile(conf, szFullFileName); - /* we deliberately ignore the iRet of processConfFile() - this is because - * failure to process one file does not mean all files will fail. By ignoring, - * we retry with the next file, which is the best thing we can do. -- rgerhards, 2007-08-01 - */ - } - - if(iEntriesDone == 0) { - /* I just make it a debug output, because I can think of a lot of cases where it - * makes sense not to have any files. E.g. a system maintainer may place a $Include - * into the config file just in case, when additional modules be installed. When none - * are installed, the directory will be empty, which is fine. -- rgerhards 2007-08-01 - */ - dbgprintf("warning: the include directory contained no files - this may be ok.\n"); - } - -finalize_it: - if(pDir != NULL) - closedir(pDir); - - RETiRet; -} - - -/* process a $include config line. That type of line requires - * inclusion of another file. - * rgerhards, 2007-08-01 - */ -rsRetVal -doIncludeLine(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal) -{ - DEFiRet; - char pattern[MAXFNAME]; - uchar *cfgFile; - glob_t cfgFiles; - int result; - size_t i = 0; - struct stat fileInfo; - - ASSERT(pp != NULL); - ASSERT(*pp != NULL); - - if(getSubString(pp, (char*) pattern, sizeof(pattern) / sizeof(char), ' ') != 0) { - errmsg.LogError(0, RS_RET_NOT_FOUND, "could not parse config file name"); - ABORT_FINALIZE(RS_RET_NOT_FOUND); - } - - /* Use GLOB_MARK to append a trailing slash for directories. - * Required by doIncludeDirectory(). - */ - result = glob(pattern, GLOB_MARK, NULL, &cfgFiles); - if(result == GLOB_NOSPACE || result == GLOB_ABORTED) { - char errStr[1024]; - rs_strerror_r(errno, errStr, sizeof(errStr)); - errmsg.LogError(0, RS_RET_FILE_NOT_FOUND, "error accessing config file or directory '%s': %s", - pattern, errStr); - ABORT_FINALIZE(RS_RET_FILE_NOT_FOUND); - } - - for(i = 0; i < cfgFiles.gl_pathc; i++) { - cfgFile = (uchar*) cfgFiles.gl_pathv[i]; - - if(stat((char*) cfgFile, &fileInfo) != 0) - continue; /* continue with the next file if we can't stat() the file */ - - if(S_ISREG(fileInfo.st_mode)) { /* config file */ - dbgprintf("requested to include config file '%s'\n", cfgFile); - iRet = processConfFile(conf, cfgFile); - } else if(S_ISDIR(fileInfo.st_mode)) { /* config directory */ - dbgprintf("requested to include directory '%s'\n", cfgFile); - iRet = doIncludeDirectory(conf, cfgFile); - } else { /* TODO: shall we handle symlinks or not? */ - dbgprintf("warning: unable to process IncludeConfig directive '%s'\n", cfgFile); - } - } - - globfree(&cfgFiles); - -finalize_it: - RETiRet; -} - - /* process a $ModLoad config line. */ rsRetVal doModLoad(uchar **pp, __attribute__((unused)) void* pVal) @@ -389,120 +248,6 @@ finalize_it: } - - -/* process a configuration file - * started with code from init() by rgerhards on 2007-07-31 - */ -static rsRetVal -processConfFile(rsconf_t *conf, uchar *pConfFile) -{ - int iLnNbr = 0; - FILE *cf; - rule_t *pCurrRule = NULL; - uchar *p; - uchar cbuf[CFGLNSIZ]; - uchar *cline; - int i; - int bHadAnError = 0; - uchar *pszOrgLine = NULL; - size_t lenLine; - DEFiRet; - ASSERT(pConfFile != NULL); - - if((cf = fopen((char*)pConfFile, "r")) == NULL) { - ABORT_FINALIZE(RS_RET_FOPEN_FAILURE); - } - - /* Now process the file. - */ - cline = cbuf; - while (fgets((char*)cline, sizeof(cbuf) - (cline - cbuf), cf) != NULL) { - ++iLnNbr; - /* drop LF - TODO: make it better, replace fgets(), but its clean as it is */ - lenLine = ustrlen(cline); - if(cline[lenLine-1] == '\n') { - cline[lenLine-1] = '\0'; - } - free(pszOrgLine); - pszOrgLine = ustrdup(cline); /* save if needed for errmsg, NULL ptr is OK */ - /* check for end-of-section, comments, strip off trailing - * spaces and newline character. - */ - p = cline; - skipWhiteSpace(&p); - if (*p == '\0' || *p == '#') - continue; - - /* we now need to copy the characters to the begin of line. As this overlaps, - * we can not use strcpy(). -- rgerhards, 2008-03-20 - * TODO: review the code at whole - this is highly suspect (but will go away - * once we do the rest of RainerScript). - */ - for( i = 0 ; p[i] != '\0' ; ++i) { - cline[i] = p[i]; - } - cline[i] = '\0'; - - for (p = (uchar*) strchr((char*)cline, '\0'); isspace((int) *--p);) - /*EMPTY*/; - if (*p == '\\') { - if ((p - cbuf) > CFGLNSIZ - 30) { - /* Oops the buffer is full - what now? */ - cline = cbuf; - } else { - *p = 0; - cline = p; - continue; - } - } else - cline = cbuf; - *++p = '\0'; /* TODO: check this */ - - /* we now have the complete line, and are positioned at the first non-whitespace - * character. So let's process it - */ - if(cfline(conf, cbuf, &pCurrRule) != RS_RET_OK) { - /* we log a message, but otherwise ignore the error. After all, the next - * line can be correct. -- rgerhards, 2007-08-02 - */ - uchar szErrLoc[MAXFNAME + 64]; - dbgprintf("config line NOT successfully processed\n"); - snprintf((char*)szErrLoc, sizeof(szErrLoc) / sizeof(uchar), - "%s, line %d", pConfFile, iLnNbr); - errmsg.LogError(0, NO_ERRCODE, "the last error occured in %s:\"%s\"", (char*)szErrLoc, (char*)pszOrgLine); - bHadAnError = 1; - } - } - - /* we probably have one selector left to be added - so let's do that now */ - if(pCurrRule != NULL) { - CHKiRet(ruleset.AddRule(conf, rule.GetAssRuleset(pCurrRule), &pCurrRule)); - } - - /* close the configuration file */ - fclose(cf); - -finalize_it: - if(iRet != RS_RET_OK) { - char errStr[1024]; - if(pCurrRule != NULL) - rule.Destruct(&pCurrRule); - - rs_strerror_r(errno, errStr, sizeof(errStr)); - dbgprintf("error %d processing config file '%s'; os error (if any): %s\n", - iRet, pConfFile, errStr); - } - - free(pszOrgLine); - - if(bHadAnError && (iRet == RS_RET_OK)) { /* a bit dirty, enhance in future releases */ - iRet = RS_RET_NONFATAL_CONFIG_ERR; - } - RETiRet; -} - - /* Helper to cfline() and its helpers. Parses a template name * from an "action" line. Must be called with the Line pointer * pointing to the first character after the semicolon. @@ -1266,9 +1011,7 @@ CODESTARTobjQueryInterface(conf) pIf->doNameLine = doNameLine; pIf->cfsysline = cfsysline; pIf->doModLoad = doModLoad; - pIf->doIncludeLine = doIncludeLine; pIf->cfline = cfline; - pIf->processConfFile = processConfFile; pIf->GetNbrActActions = GetNbrActActions; finalize_it: diff --git a/runtime/conf.h b/runtime/conf.h index aa57c8fc..a74b99c5 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -37,9 +37,7 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ rsRetVal (*doNameLine)(uchar **pp, void* pVal); rsRetVal (*cfsysline)(uchar *p); rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); - rsRetVal (*doIncludeLine)(rsconf_t *conf, uchar **pp, __attribute__((unused)) void* pVal); rsRetVal (*cfline)(rsconf_t *conf, uchar *line, rule_t **pfCurr); - rsRetVal (*processConfFile)(rsconf_t *conf, uchar *pConfFile); rsRetVal (*GetNbrActActions)(rsconf_t *conf, int *); /* version 4 -- 2010-07-23 rgerhards */ /* "just" added global variables diff --git a/runtime/rsconf.c b/runtime/rsconf.c index d12a258b..ac969286 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -385,7 +385,7 @@ void cnfDoRule(struct cnfrule *cnfrule) break; case CNFFILT_SCRIPT: pRule->f_filter_type = FILTER_EXPR; - pRule->f_filterData.f_expr = cnfrule->filt.expr; + pRule->f_filterData.expr = cnfrule->filt.expr; break; } /* we now check if there are some global (BSD-style) filter conditions @@ -790,19 +790,6 @@ static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int } -/* this method is needed to shuffle the current conf object down to the - * IncludeConfig handler. - */ -static rsRetVal -doIncludeLine(void *pVal, uchar *pNewVal) -{ - DEFiRet; - iRet = conf.doIncludeLine(ourConf, pVal, pNewVal); - free(pNewVal); - RETiRet; -} - - /* set the maximum message size */ static rsRetVal setMaxMsgSize(void __attribute__((unused)) *pVal, long iNewVal) { @@ -1081,8 +1068,6 @@ initLegacyConf(void) setActionResumeInterval, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, conf.doModLoad, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"includeconfig", 0, eCmdHdlrCustomHandler, - doIncludeLine, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, setMaxMsgSize, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, @@ -1236,6 +1221,7 @@ load(rsconf_t **cnf, uchar *confFile) int bHadConfigErr = 0; char cbuf[BUFSIZ]; int r; + char *emergConf; DEFiRet; CHKiRet(rsconfConstruct(&loadConf)); @@ -1246,11 +1232,12 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! /* open the configuration file */ r = cnfSetLexFile((char*)confFile); - r = yyparse(); - //localRet = conf.processConfFile(loadConf, confFile); - CHKiRet(conf.GetNbrActActions(loadConf, &iNbrActions)); + if(r == 0) { + r = yyparse(); + conf.GetNbrActActions(loadConf, &iNbrActions); + } - if(localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) { + if(r == 1) { errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", confFile); bHadConfigErr = 1; } else if(iNbrActions == 0) { @@ -1259,8 +1246,7 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! bHadConfigErr = 1; } - if((localRet != RS_RET_OK && localRet != RS_RET_NONFATAL_CONFIG_ERR) || iNbrActions == 0) { - + if(r == 1 || iNbrActions == 0) { /* rgerhards: this code is executed to set defaults when the * config file could not be opened. We might think about * abandoning the run in this case - but this, too, is not @@ -1268,23 +1254,17 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! * We ignore any errors while doing this - we would be lost anyhow... */ errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!"); - - /* note: we previously used _POSIY_TTY_NAME_MAX+1, but this turned out to be - * too low on linux... :-S -- rgerhards, 2008-07-28 - */ - char szTTYNameBuf[128]; - rule_t *pRule = NULL; /* initialization to NULL is *vitally* important! */ - conf.cfline(loadConf, UCHAR_CONSTANT("*.ERR\t" _PATH_CONSOLE), &pRule); - conf.cfline(loadConf, UCHAR_CONSTANT("syslog.*\t" _PATH_CONSOLE), &pRule); - conf.cfline(loadConf, UCHAR_CONSTANT("*.PANIC\t*"), &pRule); - conf.cfline(loadConf, UCHAR_CONSTANT("syslog.*\troot"), &pRule); - if(ttyname_r(0, szTTYNameBuf, sizeof(szTTYNameBuf)) == 0) { - snprintf(cbuf,sizeof(cbuf), "*.*\t%s", szTTYNameBuf); - conf.cfline(loadConf, (uchar*)cbuf, &pRule); - } else { - DBGPRINTF("error %d obtaining controlling terminal, not using that emergency rule\n", errno); + emergConf = + "*.err " _PATH_CONSOLE "\n" + "syslog.*" _PATH_CONSOLE "\n" + "*.panic :omusrmsg:*" "\n" + "syslog.* :omusrmsg:root" "\n"; + cnfParseBuffer(emergConf, strlen(emergConf)); + r = yyparse(); + if(r != 0) { + fprintf(stderr, "rsyslogd: could not even activate emergency conf - terminating\n"); + exit(1); } - ruleset.AddRule(loadConf, ruleset.GetCurrent(loadConf), &pRule); } CHKiRet(validateConf()); diff --git a/runtime/rule.c b/runtime/rule.c index 0b4b48a2..e7f3522e 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -183,15 +183,6 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) else bRet = 1; } else if(pRule->f_filter_type == FILTER_EXPR) { -#if 0 - CHKiRet(vm.Construct(&pVM)); - CHKiRet(vm.ConstructFinalize(pVM)); - CHKiRet(vm.SetMsg(pVM, pMsg)); - CHKiRet(vm.ExecProg(pVM, pRule->f_filterData.f_expr->pVmprg)); - CHKiRet(vm.PopBoolFromStack(pVM, &pResult)); - /* VM is destructed on function exit */ - bRet = (pResult->val.num) ? 1 : 0; -#endif bRet = cnfexprEvalBool(pRule->f_filterData.expr, pMsg); dbgprintf("result of rainerscript filter evaluation: %d\n", bRet); } else { diff --git a/runtime/rule.h b/runtime/rule.h index f346c764..8c2f72c9 100644 --- a/runtime/rule.h +++ b/runtime/rule.h @@ -54,7 +54,6 @@ struct rule_s { es_str_t *propName; /* name of property for CEE-based filters */ } prop; struct cnfexpr *expr; /* expression object */ - expr_t *f_expr; /* expression object */ } f_filterData; ruleset_t *pRuleset; /* associated ruleset */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 3a514aa0..86e845cb 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,7 +1,8 @@ if ENABLE_TESTBENCH # TODO: reenable TESTRUNS = rt_init rscript check_PROGRAMS = $(TESTRUNS) ourtail nettester tcpflood chkseq msleep randomgen diagtalker uxsockrcvr syslog_caller syslog_inject inputfilegen -TESTS = $(TESTRUNS) cfg.sh +TESTS = $(TESTRUNS) +#TESTS = $(TESTRUNS) cfg.sh if ENABLE_IMDIAG TESTS += \ -- cgit v1.2.3 From 4e11040e04c7147f9787e2a496591f7ada190480 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 10:56:09 +0200 Subject: preparing for 5.9.2 --- ChangeLog | 2 +- configure.ac | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1bb08bca..078b2eb8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 5.9.2 [V5-DEVEL] (rgerhards), 2011-06-?? +Version 5.9.2 [V5-DEVEL] (rgerhards), 2011-07-11 - systemd support: set stdout/stderr to null - thx to Lennart for the patch - added support for the ":omusrmsg:" syntax in configuring user messages - added support for the ":omfile:" syntax in configuring user messages diff --git a/configure.ac b/configure.ac index b1650394..1dd876ac 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],[5.9.1],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.9.2],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -- cgit v1.2.3 From 84f217e87d6cd912a81564acc341d00515571f96 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 15:07:56 +0200 Subject: cleanup, removing now unused code --- runtime/Makefile.am | 10 - runtime/conf.c | 83 ----- runtime/expr.c | 482 ----------------------------- runtime/expr.h | 57 ---- runtime/rsyslog.c | 19 -- runtime/rule.c | 5 - runtime/rule.h | 1 - runtime/vm.c | 869 ---------------------------------------------------- runtime/vm.h | 68 ---- runtime/vmop.c | 307 ------------------- runtime/vmop.h | 129 -------- runtime/vmprg.c | 236 -------------- runtime/vmprg.h | 69 ----- runtime/vmstk.c | 234 -------------- runtime/vmstk.h | 56 ---- tools/syslogd.c | 5 - tools/syslogd.h | 1 - 17 files changed, 2631 deletions(-) delete mode 100644 runtime/expr.c delete mode 100644 runtime/expr.h delete mode 100644 runtime/vm.c delete mode 100644 runtime/vm.h delete mode 100644 runtime/vmop.c delete mode 100644 runtime/vmop.h delete mode 100644 runtime/vmprg.c delete mode 100644 runtime/vmprg.h delete mode 100644 runtime/vmstk.c delete mode 100644 runtime/vmstk.h diff --git a/runtime/Makefile.am b/runtime/Makefile.am index c6c860ea..7f7e55fd 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -5,16 +5,6 @@ pkglib_LTLIBRARIES = #pkglib_LTLIBRARIES = librsyslog.la librsyslog_la_SOURCES = \ - expr.c \ - expr.h \ - vm.c \ - vm.h \ - vmstk.c \ - vmstk.h \ - vmprg.c \ - vmprg.h \ - vmop.c \ - vmop.h \ rsyslog.c \ rsyslog.h \ typedefs.h \ diff --git a/runtime/conf.c b/runtime/conf.c index 4c8f2285..413d02bb 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -65,7 +65,6 @@ #include "srUtils.h" #include "errmsg.h" #include "net.h" -#include "expr.h" #include "ctok.h" #include "ctok_token.h" #include "rule.h" @@ -83,7 +82,6 @@ static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); /* static data */ DEFobjStaticHelpers -DEFobjCurrIf(expr) DEFobjCurrIf(ctok) DEFobjCurrIf(ctok_token) DEFobjCurrIf(module) @@ -508,77 +506,6 @@ rsRetVal cflineProcessTradPRIFilter(uchar **pline, register rule_t *pRule) } -#if 0 -/* Helper to cfline(). This function processes an "if" type of filter, - * what essentially means it parses an expression. As usual, - * It processes the line up to the beginning of the action part. - * A pointer to that beginnig is passed back to the caller. - * rgerhards 2008-01-19 - */ -static rsRetVal cflineProcessIfFilter(uchar **pline, register rule_t *f) -{ - DEFiRet; - ctok_t *tok; - ctok_token_t *pToken; - - ASSERT(pline != NULL); - ASSERT(*pline != NULL); - ASSERT(f != NULL); - - dbgprintf(" - general expression-based filter\n"); - errno = 0; /* keep strerror_r() stuff out of logerror messages */ - - f->f_filter_type = FILTER_EXPR; - - /* if we come to over here, pline starts with "if ". We just skip that part. */ - (*pline) += 3; - - /* we first need a tokenizer... */ - CHKiRet(ctok.Construct(&tok)); - CHKiRet(ctok.Setpp(tok, *pline)); - CHKiRet(ctok.ConstructFinalize(tok)); - - /* now construct our expression */ - CHKiRet(expr.Construct(&f->f_filterData.f_expr)); - CHKiRet(expr.ConstructFinalize(f->f_filterData.f_expr)); - - /* ready to go... */ - CHKiRet(expr.Parse(f->f_filterData.f_expr, tok)); - - /* we now need to parse off the "then" - and note an error if it is - * missing... - */ - CHKiRet(ctok.GetToken(tok, &pToken)); - if(pToken->tok != ctok_THEN) { - ctok_token.Destruct(&pToken); - ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); - } - - ctok_token.Destruct(&pToken); /* no longer needed */ - - /* we are done, so we now need to restore things */ - CHKiRet(ctok.Getpp(tok, pline)); - CHKiRet(ctok.Destruct(&tok)); - - /* debug support - print vmprg after construction (uncomment to use) */ - /* vmprgDebugPrint(f->f_filterData.f_expr->pVmprg); */ - - /* we now need to skip whitespace to the action part, else we confuse - * the legacy rsyslog conf parser. -- rgerhards, 2008-02-25 - */ - while(isspace(**pline)) - ++(*pline); - -finalize_it: - if(iRet == RS_RET_SYNTAX_ERROR) { - errmsg.LogError(0, RS_RET_SYNTAX_ERROR, "syntax error in expression"); - } - - RETiRet; -} -#endif - - /* Helper to cfline(). This function takes the filter part of a property * based filter and decodes it. It processes the line up to the beginning * of the action part. A pointer to that beginnig is passed back to the caller. @@ -808,14 +735,6 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) case ':': CHKiRet(cflineProcessPropFilter(pp, f)); break; -#if 0 - case 'i': /* "if" filter? */ - if(*(*pp+1) && (*(*pp+1) == 'f') && isspace(*(*pp+2))) { - CHKiRet(cflineProcessIfFilter(pp, f)); - break; - } - /*FALLTHROUGH*/ -#endif default: CHKiRet(cflineProcessTradPRIFilter(pp, f)); break; @@ -1163,7 +1082,6 @@ CODESTARTObjClassExit(conf) } /* release objects we no longer need */ - objRelease(expr, CORE_COMPONENT); objRelease(ctok, CORE_COMPONENT); objRelease(ctok_token, CORE_COMPONENT); objRelease(module, CORE_COMPONENT); @@ -1180,7 +1098,6 @@ ENDObjClassExit(conf) */ BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */ /* request objects we use */ - CHKiRet(objUse(expr, CORE_COMPONENT)); CHKiRet(objUse(ctok, CORE_COMPONENT)); CHKiRet(objUse(ctok_token, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); diff --git a/runtime/expr.c b/runtime/expr.c deleted file mode 100644 index 01431474..00000000 --- a/runtime/expr.c +++ /dev/null @@ -1,482 +0,0 @@ -/* expr.c - an expression class. - * This module contains all code needed to represent expressions. Most - * importantly, that means code to parse and execute them. Expressions - * heavily depend on (loadable) functions, so it works in conjunction - * with the function manager. - * - * Module begun 2007-11-30 by Rainer Gerhards - * - * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include - -#include "rsyslog.h" -#include "template.h" -#include "expr.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(vmprg) -DEFobjCurrIf(var) -DEFobjCurrIf(ctok_token) -DEFobjCurrIf(ctok) - - -/* ------------------------------ parser functions ------------------------------ */ -/* the following functions implement the parser. They are all static. For - * simplicity, the function names match their ABNF definition. The ABNF is defined - * in the doc set. See file expression.html for details. I do *not* reproduce it - * here in an effort to keep both files in sync. - * - * All functions receive the current expression object as parameter as well as the - * current tokenizer. - * - * rgerhards, 2008-02-19 - */ - -/* forward definition - thanks to recursive ABNF, we can not avoid at least one ;) */ -static rsRetVal expr(expr_t *pThis, ctok_t *tok); - - -static rsRetVal -function(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken = NULL; - int iNumArgs = 0; - var_t *pVar; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(ctok.GetToken(tok, &pToken)); - /* note: pToken is destructed in finalize_it */ - - if(pToken->tok == ctok_LPAREN) { - CHKiRet(ctok_token.Destruct(&pToken)); /* token processed, "eat" it */ - CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one */ - } else - ABORT_FINALIZE(RS_RET_FUNC_NO_LPAREN); - - /* we first push all the params on the stack. Then we call the function */ - while(pToken->tok != ctok_RPAREN) { - ++iNumArgs; - CHKiRet(ctok.UngetToken(tok, pToken)); /* not for us, so let others process it */ - CHKiRet(expr(pThis, tok)); - CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one, needed for while() check */ - if(pToken->tok == ctok_COMMA) { - CHKiRet(ctok_token.Destruct(&pToken)); /* token processed, "eat" it */ - CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one */ - if(pToken->tok == ctok_RPAREN) { - ABORT_FINALIZE(RS_RET_FUNC_MISSING_EXPR); - } - } - } - - - /* now push number of arguments - this must be on top of the stack */ - CHKiRet(var.Construct(&pVar)); - CHKiRet(var.ConstructFinalize(pVar)); - CHKiRet(var.SetNumber(pVar, iNumArgs)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, pVar)); /* add to program */ - - -finalize_it: - if(pToken != NULL) { - ctok_token.Destruct(&pToken); /* "eat" processed token */ - } - - RETiRet; -} - - -static rsRetVal -terminal(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken = NULL; - var_t *pVar; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(ctok.GetToken(tok, &pToken)); - /* note: pToken is destructed in finalize_it */ - - switch(pToken->tok) { - case ctok_SIMPSTR: - dbgoprint((obj_t*) pThis, "simpstr\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, pVar)); /* add to program */ - break; - case ctok_NUMBER: - dbgoprint((obj_t*) pThis, "number\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCONSTANT, pVar)); /* add to program */ - break; - case ctok_FUNCTION: - dbgoprint((obj_t*) pThis, "function\n"); - CHKiRet(function(pThis, tok)); /* this creates the stack call frame */ - /* ... but we place the call instruction onto the stack ourselfs (because - * we have all relevant information) - */ - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(var.ConvToString(pVar)); /* make sure we have a string */ - CHKiRet(vmprg.AddCallOperation(pThis->pVmprg, pVar->val.pStr)); /* add to program */ - CHKiRet(var.Destruct(&pVar)); - break; - case ctok_MSGVAR: - dbgoprint((obj_t*) pThis, "MSGVAR\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHMSGVAR, pVar)); /* add to program */ - break; - case ctok_CEEVAR: - dbgoprint((obj_t*) pThis, "SYSVAR\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHCEEVAR, pVar)); /* add to program */ - break; - case ctok_SYSVAR: - dbgoprint((obj_t*) pThis, "SYSVAR\n"); - CHKiRet(ctok_token.UnlinkVar(pToken, &pVar)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_PUSHSYSVAR, pVar)); /* add to program */ - break; - case ctok_LPAREN: - dbgoprint((obj_t*) pThis, "expr\n"); - CHKiRet(ctok_token.Destruct(&pToken)); /* "eat" processed token */ - CHKiRet(expr(pThis, tok)); - CHKiRet(ctok.GetToken(tok, &pToken)); /* get next one */ - if(pToken->tok != ctok_RPAREN) - ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); - break; - default: - dbgoprint((obj_t*) pThis, "invalid token %d\n", pToken->tok); - ABORT_FINALIZE(RS_RET_SYNTAX_ERROR); - break; - } - -finalize_it: - if(pToken != NULL) { - ctok_token.Destruct(&pToken); /* "eat" processed token */ - } - - RETiRet; -} - -static rsRetVal -factor(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - int bWasNot; - int bWasUnaryMinus; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(ctok.GetToken(tok, &pToken)); - if(pToken->tok == ctok_NOT) { - dbgprintf("not\n"); - bWasNot = 1; - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); /* get new one for next check */ - } else { - bWasNot = 0; - } - - if(pToken->tok == ctok_MINUS) { - dbgprintf("unary minus\n"); - bWasUnaryMinus = 1; - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - } else { - bWasUnaryMinus = 0; - /* we could not process the token, so push it back */ - CHKiRet(ctok.UngetToken(tok, pToken)); - } - - CHKiRet(terminal(pThis, tok)); - - /* warning: the order if the two following ifs is important. Do not change them, this - * would change the semantics of the expression! - */ - if(bWasUnaryMinus) { - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_UNARY_MINUS, NULL)); /* add to program */ - } - - if(bWasNot == 1) { - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_NOT, NULL)); /* add to program */ - } - -finalize_it: - RETiRet; -} - - -static rsRetVal -term(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(factor(pThis, tok)); - - /* *(("*" / "/" / "%") factor) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - while(pToken->tok == ctok_TIMES || pToken->tok == ctok_DIV || pToken->tok == ctok_MOD) { - dbgoprint((obj_t*) pThis, "/,*,%%\n"); - CHKiRet(factor(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, (opcode_t) pToken->tok, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); - } - - /* unget the token that made us exit the loop - it's obviously not one - * we can process. - */ - CHKiRet(ctok.UngetToken(tok, pToken)); - -finalize_it: - RETiRet; -} - -static rsRetVal -val(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(term(pThis, tok)); - - /* *(("+" / "-") term) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - while(pToken->tok == ctok_PLUS || pToken->tok == ctok_MINUS || pToken->tok == ctok_STRADD) { - dbgoprint((obj_t*) pThis, "+/-/&\n"); - CHKiRet(term(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, (opcode_t) pToken->tok, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); - } - - /* unget the token that made us exit the loop - it's obviously not one - * we can process. - */ - CHKiRet(ctok.UngetToken(tok, pToken)); - -finalize_it: - RETiRet; -} - - -static rsRetVal -e_cmp(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(val(pThis, tok)); - - /* 0*1(cmp_op val) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - if(ctok_token.IsCmpOp(pToken)) { - dbgoprint((obj_t*) pThis, "cmp\n"); - CHKiRet(val(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, (opcode_t) pToken->tok, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - } else { - /* we could not process the token, so push it back */ - CHKiRet(ctok.UngetToken(tok, pToken)); - } - - -finalize_it: - RETiRet; -} - - -static rsRetVal -e_and(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(e_cmp(pThis, tok)); - - /* *("and" e_cmp) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - while(pToken->tok == ctok_AND) { - dbgoprint((obj_t*) pThis, "and\n"); - CHKiRet(e_cmp(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_AND, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); - } - - /* unget the token that made us exit the loop - it's obviously not one - * we can process. - */ - CHKiRet(ctok.UngetToken(tok, pToken)); - -finalize_it: - RETiRet; -} - - -static rsRetVal -expr(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - ctok_token_t *pToken; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - CHKiRet(e_and(pThis, tok)); - - /* *("or" e_and) part */ - CHKiRet(ctok.GetToken(tok, &pToken)); - while(pToken->tok == ctok_OR) { - dbgoprint((obj_t*) pThis, "found OR\n"); - CHKiRet(e_and(pThis, tok)); - CHKiRet(vmprg.AddVarOperation(pThis->pVmprg, opcode_OR, NULL)); /* add to program */ - CHKiRet(ctok_token.Destruct(&pToken)); /* no longer needed */ - CHKiRet(ctok.GetToken(tok, &pToken)); - } - - /* unget the token that made us exit the loop - it's obviously not one - * we can process. - */ - CHKiRet(ctok.UngetToken(tok, pToken)); - -finalize_it: - RETiRet; -} - - -/* ------------------------------ end parser functions ------------------------------ */ - - -/* ------------------------------ actual expr object functions ------------------------------ */ - -/* Standard-Constructor - * rgerhards, 2008-02-09 (a rainy Tenerife return flight day ;)) - */ -BEGINobjConstruct(expr) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(expr) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -rsRetVal exprConstructFinalize(expr_t __attribute__((unused)) *pThis) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, expr); - - RETiRet; -} - - -/* destructor for the expr object */ -BEGINobjDestruct(expr) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(expr) - if(pThis->pVmprg != NULL) - vmprg.Destruct(&pThis->pVmprg); -ENDobjDestruct(expr) - - -/* parse an expression object based on a given tokenizer - * rgerhards, 2008-02-19 - */ -rsRetVal -exprParse(expr_t *pThis, ctok_t *tok) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, expr); - ISOBJ_TYPE_assert(tok, ctok); - - /* first, we need to make sure we have a program where we can add to what we parse... */ - CHKiRet(vmprg.Construct(&pThis->pVmprg)); - CHKiRet(vmprg.ConstructFinalize(pThis->pVmprg)); - - /* happy parsing... */ - CHKiRet(expr(pThis, tok)); - dbgoprint((obj_t*) pThis, "successfully parsed/created expression\n"); - -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(expr) -CODESTARTobjQueryInterface(expr) - if(pIf->ifVersion != exprCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = exprConstruct; - pIf->ConstructFinalize = exprConstructFinalize; - pIf->Destruct = exprDestruct; - pIf->Parse = exprParse; -finalize_it: -ENDobjQueryInterface(expr) - - -/* Initialize the expr class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(expr, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(vmprg, CORE_COMPONENT)); - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(ctok_token, CORE_COMPONENT)); - CHKiRet(objUse(ctok, CORE_COMPONENT)); - - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, exprConstructFinalize); -ENDObjClassInit(expr) - -/* vi:set ai: - */ diff --git a/runtime/expr.h b/runtime/expr.h deleted file mode 100644 index 1afe1a1f..00000000 --- a/runtime/expr.h +++ /dev/null @@ -1,57 +0,0 @@ -/* The expr object. - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_EXPR_H -#define INCLUDED_EXPR_H - -#include "obj.h" -#include "ctok.h" -#include "vmprg.h" -#include "stringbuf.h" - -/* a node inside an expression tree */ -typedef struct exprNode_s { - char dummy; -} exprNode_t; - - -/* the expression object */ -typedef struct expr_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - vmprg_t *pVmprg; /* the expression in vmprg format - ready to execute */ -} expr_t; - - -/* interfaces */ -BEGINinterface(expr) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(expr); - rsRetVal (*Construct)(expr_t **ppThis); - rsRetVal (*ConstructFinalize)(expr_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(expr_t **ppThis); - rsRetVal (*Parse)(expr_t *pThis, ctok_t *ctok); -ENDinterface(expr) -#define exprCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - -/* prototypes */ -PROTOTYPEObj(expr); - -#endif /* #ifndef INCLUDED_EXPR_H */ diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index d71fe88a..c5abcb2a 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -62,16 +62,11 @@ #include "rsyslog.h" #include "obj.h" -#include "vm.h" #include "sysvar.h" #include "stringbuf.h" #include "wti.h" #include "wtp.h" -#include "expr.h" #include "ctok.h" -#include "vmop.h" -#include "vmstk.h" -#include "vmprg.h" #include "datetime.h" #include "queue.h" #include "conf.h" @@ -182,22 +177,8 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(ctok_tokenClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "ctok"; CHKiRet(ctokClassInit(NULL)); -#if 1 - if(ppErrObj != NULL) *ppErrObj = "vmstk"; - CHKiRet(vmstkClassInit(NULL)); -#endif if(ppErrObj != NULL) *ppErrObj = "sysvar"; CHKiRet(sysvarClassInit(NULL)); -#if 1 - if(ppErrObj != NULL) *ppErrObj = "vm"; - CHKiRet(vmClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "vmop"; - CHKiRet(vmopClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "vmprg"; - CHKiRet(vmprgClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "expr"; - CHKiRet(exprClassInit(NULL)); -#endif if(ppErrObj != NULL) *ppErrObj = "rule"; CHKiRet(ruleClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "ruleset"; diff --git a/runtime/rule.c b/runtime/rule.c index e7f3522e..1a430577 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -344,11 +344,6 @@ CODESTARTobjDestruct(rule) rsCStrRegexDestruct(&pThis->f_filterData.prop.regex_cache); if(pThis->f_filterData.prop.propName != NULL) es_deleteStr(pThis->f_filterData.prop.propName); -#if 0 - } else if(pThis->f_filter_type == FILTER_EXPR) { - if(pThis->f_filterData.f_expr != NULL) - expr.Destruct(&pThis->f_filterData.f_expr); -#endif } llDestroy(&pThis->llActList); diff --git a/runtime/rule.h b/runtime/rule.h index 8c2f72c9..76ed5f0b 100644 --- a/runtime/rule.h +++ b/runtime/rule.h @@ -28,7 +28,6 @@ #include "libestr.h" #include "linkedlist.h" #include "regexp.h" -#include "expr.h" // TODO: remove #if 0 #include "rainerscript.h" /* the rule object */ diff --git a/runtime/vm.c b/runtime/vm.c deleted file mode 100644 index bbc8d346..00000000 --- a/runtime/vm.c +++ /dev/null @@ -1,869 +0,0 @@ -/* vm.c - the arithmetic stack of a virtual machine. - * - * Module begun 2008-02-22 by Rainer Gerhards - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include -#include - -#include "rsyslog.h" -#include "obj.h" -#include "vm.h" -#include "sysvar.h" -#include "stringbuf.h" -#include "unicode-helper.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(vmstk) -DEFobjCurrIf(var) -DEFobjCurrIf(sysvar) - -static pthread_mutex_t mutGetenv; /* we need to make this global because otherwise we can not guarantee proper init! */ - -/* ------------------------------ function registry code and structures ------------------------------ */ - -/* we maintain a registry of known functions */ -/* currently, this is a singly-linked list, this shall become a binary - * tree when we add the real call interface. So far, entries are added - * at the root, only. - */ -typedef struct s_rsf_entry { - cstr_t *pName; /* function name */ - prsf_t rsf; /* pointer to function code */ - struct s_rsf_entry *pNext; /* Pointer to next element or NULL */ -} rsf_entry_t; -rsf_entry_t *funcRegRoot = NULL; - - -/* add a function to the function registry. - * The handed-over cstr_t* object must no longer be used by the caller. - * A duplicate function name is an error. - * rgerhards, 2009-04-06 - */ -static rsRetVal -rsfrAddFunction(uchar *szName, prsf_t rsf) -{ - rsf_entry_t *pEntry; - size_t lenName; - DEFiRet; - - assert(szName != NULL); - assert(rsf != NULL); - - /* first check if we have a duplicate name, with the current approach this means - * we need to go through the whole list. - */ - lenName = strlen((char*)szName); - for(pEntry = funcRegRoot ; pEntry != NULL ; pEntry = pEntry->pNext) - if(!rsCStrSzStrCmp(pEntry->pName, szName, lenName)) - ABORT_FINALIZE(RS_RET_DUP_FUNC_NAME); - - /* unique name, so add to head of list */ - CHKmalloc(pEntry = calloc(1, sizeof(rsf_entry_t))); - CHKiRet(rsCStrConstructFromszStr(&pEntry->pName, szName)); - CHKiRet(cstrFinalize(pEntry->pName)); - pEntry->rsf = rsf; - pEntry->pNext = funcRegRoot; - funcRegRoot = pEntry; - -finalize_it: - if(iRet != RS_RET_OK && iRet != RS_RET_DUP_FUNC_NAME) - free(pEntry); - - RETiRet; -} - - -/* find a function inside the function registry - * The caller provides a cstr_t with the function name and receives - * a function pointer back. If no function is found, an RS_RET_UNKNW_FUNC - * error is returned. So if the function returns with RS_RET_OK, the caller - * can savely assume the function pointer is valid. - * rgerhards, 2009-04-06 - */ -static rsRetVal -findRSFunction(cstr_t *pcsName, prsf_t *prsf) -{ - rsf_entry_t *pEntry; - rsf_entry_t *pFound; - DEFiRet; - - assert(prsf != NULL); - - /* find function by list walkthrough. */ - pFound = NULL; - for(pEntry = funcRegRoot ; pEntry != NULL && pFound == NULL ; pEntry = pEntry->pNext) - if(!rsCStrCStrCmp(pEntry->pName, pcsName)) - pFound = pEntry; - - if(pFound == NULL) - ABORT_FINALIZE(RS_RET_UNKNW_FUNC); - - *prsf = pFound->rsf; - -finalize_it: - RETiRet; -} - - -/* find the name of a RainerScript function whom's function pointer - * is known. This function returns the cstr_t object, which MUST NOT - * be modified by the caller. - * rgerhards, 2009-04-06 - */ -static rsRetVal -findRSFunctionName(prsf_t rsf, cstr_t **ppcsName) -{ - rsf_entry_t *pEntry; - rsf_entry_t *pFound; - DEFiRet; - - assert(rsf != NULL); - assert(ppcsName != NULL); - - /* find function by list walkthrough. */ - pFound = NULL; - for(pEntry = funcRegRoot ; pEntry != NULL && pFound == NULL ; pEntry = pEntry->pNext) - if(pEntry->rsf == rsf) - pFound = pEntry; - - if(pFound == NULL) - ABORT_FINALIZE(RS_RET_UNKNW_FUNC); - - *ppcsName = pFound->pName; - -finalize_it: - RETiRet; -} - - -/* free the whole function registry - */ -static void -rsfrRemoveAll(void) -{ - rsf_entry_t *pEntry; - rsf_entry_t *pEntryDel; - - BEGINfunc - pEntry = funcRegRoot; - while(pEntry != NULL) { - pEntryDel = pEntry; - pEntry = pEntry->pNext; - cstrDestruct(&pEntryDel->pName); - free(pEntryDel); - } - funcRegRoot = NULL; - ENDfunc -} - - -/* ------------------------------ end function registry code and structures ------------------------------ */ - - -/* ------------------------------ instruction set implementation ------------------------------ * - * The following functions implement the VM's instruction set. - */ -#define BEGINop(instruction) \ - static rsRetVal op##instruction(vm_t *pThis, __attribute__((unused)) vmop_t *pOp) \ - { \ - DEFiRet; - -#define CODESTARTop(instruction) \ - ISOBJ_TYPE_assert(pThis, vm); - -#define PUSHRESULTop(operand, res) \ - /* we have a result, so let's push it */ \ - var.SetNumber(operand, res); \ - vmstk.Push(pThis->pStk, operand); /* result */ - -#define ENDop(instruction) \ - RETiRet; \ - } - -/* code generator for boolean operations */ -#define BOOLOP(name, OPERATION) \ -BEGINop(name) /* remember to set the instruction also in the ENDop macro! */ \ - var_t *operand1; \ - var_t *operand2; \ -CODESTARTop(name) \ - vmstk.PopBool(pThis->pStk, &operand1); \ - vmstk.PopBool(pThis->pStk, &operand2); \ - if(operand1->val.num OPERATION operand2->val.num) { \ - CHKiRet(var.SetNumber(operand1, 1)); \ - } else { \ - CHKiRet(var.SetNumber(operand1, 0)); \ - } \ - vmstk.Push(pThis->pStk, operand1); /* result */ \ - var.Destruct(&operand2); /* no longer needed */ \ -finalize_it: \ -ENDop(name) -BOOLOP(OR, ||) -BOOLOP(AND, &&) -#undef BOOLOP - - -/* code generator for numerical operations */ -#define NUMOP(name, OPERATION) \ -BEGINop(name) /* remember to set the instruction also in the ENDop macro! */ \ - var_t *operand1; \ - var_t *operand2; \ -CODESTARTop(name) \ - vmstk.PopNumber(pThis->pStk, &operand1); \ - vmstk.PopNumber(pThis->pStk, &operand2); \ - operand1->val.num = operand1->val.num OPERATION operand2->val.num; \ - vmstk.Push(pThis->pStk, operand1); /* result */ \ - var.Destruct(&operand2); /* no longer needed */ \ -ENDop(name) -NUMOP(PLUS, +) -NUMOP(MINUS, -) -NUMOP(TIMES, *) -NUMOP(DIV, /) -NUMOP(MOD, %) -#undef BOOLOP - - -/* code generator for compare operations */ -#define BEGINCMPOP(name) \ -BEGINop(name) \ - var_t *operand1; \ - var_t *operand2; \ - number_t bRes; \ -CODESTARTop(name) \ - CHKiRet(vmstk.Pop2CommOp(pThis->pStk, &operand1, &operand2)); \ - /* data types are equal (so we look only at operand1), but we must \ - * check which type we have to deal with... \ - */ \ - switch(operand1->varType) { -#define ENDCMPOP(name) \ - default: \ - bRes = 0; /* we do not abort just so that we have a value. TODO: reconsider */ \ - break; \ - } \ - \ - /* we have a result, so let's push it */ \ - var.SetNumber(operand1, bRes); \ - vmstk.Push(pThis->pStk, operand1); /* result */ \ - var.Destruct(&operand2); /* no longer needed */ \ -finalize_it: \ -ENDop(name) - -BEGINCMPOP(CMP_EQ) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num == operand2->val.num; - break; - case VARTYPE_STR: - bRes = !rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr); - break; -ENDCMPOP(CMP_EQ) - -BEGINCMPOP(CMP_NEQ) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num != operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr); - break; -ENDCMPOP(CMP_NEQ) - -BEGINCMPOP(CMP_LT) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num < operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr) < 0; - break; -ENDCMPOP(CMP_LT) - -BEGINCMPOP(CMP_GT) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num > operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr) > 0; - break; -ENDCMPOP(CMP_GT) - -BEGINCMPOP(CMP_LTEQ) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num <= operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr) <= 0; - break; -ENDCMPOP(CMP_LTEQ) - -BEGINCMPOP(CMP_GTEQ) /* remember to change the name also in the END macro! */ - case VARTYPE_NUMBER: - bRes = operand1->val.num >= operand2->val.num; - break; - case VARTYPE_STR: - bRes = rsCStrCStrCmp(operand1->val.pStr, operand2->val.pStr) >= 0; - break; -ENDCMPOP(CMP_GTEQ) - -#undef BEGINCMPOP -#undef ENDCMPOP -/* end regular compare operations */ - -/* comare operations that work on strings, only */ -BEGINop(CMP_CONTAINS) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; - number_t bRes; -CODESTARTop(CMP_CONTAINS) - /* operand2 is on top of stack, so needs to be popped first */ - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); - /* TODO: extend cstr class so that it supports location of cstr inside cstr */ - bRes = (rsCStrLocateInSzStr(operand2->val.pStr, rsCStrGetSzStr(operand1->val.pStr)) == -1) ? 0 : 1; - - /* we have a result, so let's push it */ - PUSHRESULTop(operand1, bRes); - var.Destruct(&operand2); /* no longer needed */ -ENDop(CMP_CONTAINS) - - -BEGINop(CMP_CONTAINSI) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; - number_t bRes; -CODESTARTop(CMP_CONTAINSI) - /* operand2 is on top of stack, so needs to be popped first */ - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); -var.DebugPrint(operand1); \ -var.DebugPrint(operand2); \ - /* TODO: extend cstr class so that it supports location of cstr inside cstr */ - bRes = (rsCStrCaseInsensitiveLocateInSzStr(operand2->val.pStr, rsCStrGetSzStr(operand1->val.pStr)) == -1) ? 0 : 1; - - /* we have a result, so let's push it */ - PUSHRESULTop(operand1, bRes); - var.Destruct(&operand2); /* no longer needed */ -ENDop(CMP_CONTAINSI) - - -BEGINop(CMP_STARTSWITH) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; - number_t bRes; -CODESTARTop(CMP_STARTSWITH) - /* operand2 is on top of stack, so needs to be popped first */ - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); - /* TODO: extend cstr class so that it supports location of cstr inside cstr */ - bRes = (rsCStrStartsWithSzStr(operand1->val.pStr, rsCStrGetSzStr(operand2->val.pStr), - rsCStrLen(operand2->val.pStr)) == 0) ? 1 : 0; - - /* we have a result, so let's push it */ - PUSHRESULTop(operand1, bRes); - var.Destruct(&operand2); /* no longer needed */ -ENDop(CMP_STARTSWITH) - - -BEGINop(CMP_STARTSWITHI) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; - number_t bRes; -CODESTARTop(CMP_STARTSWITHI) - /* operand2 is on top of stack, so needs to be popped first */ - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); - /* TODO: extend cstr class so that it supports location of cstr inside cstr */ - bRes = (rsCStrCaseInsensitveStartsWithSzStr(operand1->val.pStr, rsCStrGetSzStr(operand2->val.pStr), - rsCStrLen(operand2->val.pStr)) == 0) ? 1 : 0; - - /* we have a result, so let's push it */ - PUSHRESULTop(operand1, bRes); - var.Destruct(&operand2); /* no longer needed */ -ENDop(CMP_STARTSWITHI) - -/* end comare operations that work on strings, only */ - -BEGINop(STRADD) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand1; - var_t *operand2; -CODESTARTop(STRADD) - vmstk.PopString(pThis->pStk, &operand2); - vmstk.PopString(pThis->pStk, &operand1); - - CHKiRet(rsCStrAppendCStr(operand1->val.pStr, operand2->val.pStr)); - CHKiRet(cstrFinalize(operand1->val.pStr)); - - /* we have a result, so let's push it */ - vmstk.Push(pThis->pStk, operand1); - var.Destruct(&operand2); /* no longer needed */ -finalize_it: -ENDop(STRADD) - -BEGINop(NOT) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand; -CODESTARTop(NOT) - vmstk.PopBool(pThis->pStk, &operand); - PUSHRESULTop(operand, !operand->val.num); -ENDop(NOT) - -BEGINop(UNARY_MINUS) /* remember to set the instruction also in the ENDop macro! */ - var_t *operand; -CODESTARTop(UNARY_MINUS) - vmstk.PopNumber(pThis->pStk, &operand); - PUSHRESULTop(operand, -operand->val.num); -ENDop(UNARY_MINUS) - - -BEGINop(PUSHCONSTANT) /* remember to set the instruction also in the ENDop macro! */ - var_t *pVarDup; /* we need to duplicate the var, as we need to hand it over */ -CODESTARTop(PUSHCONSTANT) - CHKiRet(var.Duplicate(pOp->operand.pVar, &pVarDup)); - vmstk.Push(pThis->pStk, pVarDup); -finalize_it: -ENDop(PUSHCONSTANT) - - -BEGINop(PUSHMSGVAR) /* remember to set the instruction also in the ENDop macro! */ - var_t *pVal; /* the value to push */ - cstr_t *pstrVal; -CODESTARTop(PUSHMSGVAR) -dbgprintf("XXX: pushMSGVAR, var '%s'\n", rsCStrGetSzStr(pOp->operand.pVar->val.pStr)); - if(pThis->pMsg == NULL) { - /* TODO: flag an error message! As a work-around, we permit - * execution to continue here with an empty string - */ - /* TODO: create a method in var to create a string var? */ - CHKiRet(var.Construct(&pVal)); - CHKiRet(var.ConstructFinalize(pVal)); - CHKiRet(rsCStrConstructFromszStr(&pstrVal, (uchar*)"")); - CHKiRet(var.SetString(pVal, pstrVal)); - } else { - /* we have a message, so pull value from there */ - CHKiRet(msgGetMsgVar(pThis->pMsg, pOp->operand.pVar->val.pStr, &pVal)); - } - - /* if we reach this point, we have a valid pVal and can push it */ - vmstk.Push(pThis->pStk, pVal); -finalize_it: -ENDop(PUSHMSGVAR) - - -BEGINop(PUSHCEEVAR) /* remember to set the instruction also in the ENDop macro! */ - var_t *pVal; /* the value to push */ - cstr_t *pstrVal; -CODESTARTop(PUSHCEEVAR) -dbgprintf("XXX: pushCEEVAR, var '%s'\n", rsCStrGetSzStr(pOp->operand.pVar->val.pStr)); - if(pThis->pMsg == NULL) { - /* TODO: flag an error message! As a work-around, we permit - * execution to continue here with an empty string - */ - CHKiRet(var.Construct(&pVal)); - CHKiRet(var.ConstructFinalize(pVal)); - CHKiRet(rsCStrConstructFromszStr(&pstrVal, (uchar*)"")); - CHKiRet(var.SetString(pVal, pstrVal)); - } else { - /* we have a message, so pull value from there */ - CHKiRet(msgGetCEEVar(pThis->pMsg, pOp->operand.pVar->val.pStr, &pVal)); - } - - /* if we reach this point, we have a valid pVal and can push it */ - vmstk.Push(pThis->pStk, pVal); -dbgprintf("XXX: pushCEEVAR, result '%s'\n", rsCStrGetSzStr(pVal->val.pStr)); -finalize_it: -ENDop(PUSHCEEVAR) - - -BEGINop(PUSHSYSVAR) /* remember to set the instruction also in the ENDop macro! */ - var_t *pVal; /* the value to push */ -CODESTARTop(PUSHSYSVAR) - CHKiRet(sysvar.GetVar(pOp->operand.pVar->val.pStr, &pVal)); - vmstk.Push(pThis->pStk, pVal); -finalize_it: - if(Debug && iRet != RS_RET_OK) { - if(iRet == RS_RET_SYSVAR_NOT_FOUND) { - DBGPRINTF("rainerscript: sysvar '%s' not found\n", - rsCStrGetSzStrNoNULL(pOp->operand.pVar->val.pStr)); - } else { - DBGPRINTF("rainerscript: error %d trying to obtain sysvar '%s'\n", - iRet, rsCStrGetSzStrNoNULL(pOp->operand.pVar->val.pStr)); - } - } -ENDop(PUSHSYSVAR) - -/* The function call operation is only very roughly implemented. While the plumbing - * to reach this instruction is fine, the instruction itself currently supports only - * functions with a single argument AND with a name that we know. - * TODO: later, we can add here the real logic, that involves looking up function - * names, loading them dynamically ... and all that... - * implementation begun 2009-03-10 by rgerhards - */ -BEGINop(FUNC_CALL) /* remember to set the instruction also in the ENDop macro! */ - var_t *numOperands; -CODESTARTop(FUNC_CALL) - vmstk.PopNumber(pThis->pStk, &numOperands); - CHKiRet((*pOp->operand.rsf)(pThis->pStk, numOperands->val.num)); - var.Destruct(&numOperands); /* no longer needed */ -finalize_it: -ENDop(FUNC_CALL) - - -/* ------------------------------ end instruction set implementation ------------------------------ */ - - -/* ------------------------------ begin built-in function implementation ------------------------------ */ -/* note: this shall probably be moved to a separate module, but for the time being we do it directly - * in here. This is on our way to get from a dirty to a clean solution via baby steps that are - * a bit less dirty each time... - * - * The advantage of doing it here is that we do not yet need to think about how to handle the - * exit case, where we must not unload function modules which functions are still referenced. - * - * CALLING INTERFACE: - * The function must pop its parameters off the stack and pop its result onto - * the stack when it is finished. The number of parameters the function was - * called with is provided to it. If the argument count is less then what the function - * expected, it may handle the situation with defaults (or return an error). If the - * argument count is greater than expected, returnung an error is highly - * recommended (use RS_RET_INVLD_NBR_ARGUMENTS for these cases). - * - * All function names are prefixed with "rsf_" (RainerScript Function) to have - * a separate "name space". - * - * rgerhards, 2009-04-06 - */ - - -/* The strlen function, also probably a prototype of how all functions should be - * implemented. - * rgerhards, 2009-04-06 - */ -static rsRetVal -rsf_strlen(vmstk_t *pStk, int numOperands) -{ - DEFiRet; - var_t *operand1; - int iStrlen; - - if(numOperands != 1) - ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS); - - /* pop args and do operaton (trivial case here...) */ - vmstk.PopString(pStk, &operand1); - iStrlen = strlen((char*) rsCStrGetSzStr(operand1->val.pStr)); - - /* Store result and cleanup */ - var.SetNumber(operand1, iStrlen); - vmstk.Push(pStk, operand1); -finalize_it: - RETiRet; -} - - -/* The getenv function. Note that we guard the OS call by a mutex, as that - * function is not guaranteed to be thread-safe. This implementation here is far from - * being optimal, at least we should cache the result. This is left TODO for - * a later revision. - * rgerhards, 2009-11-03 - */ -static rsRetVal -rsf_getenv(vmstk_t *pStk, int numOperands) -{ - DEFiRet; - var_t *operand1; - char *envResult; - cstr_t *pCstr; - - if(numOperands != 1) - ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS); - - /* pop args and do operaton (trivial case here...) */ - vmstk.PopString(pStk, &operand1); - d_pthread_mutex_lock(&mutGetenv); - envResult = getenv((char*) rsCStrGetSzStr(operand1->val.pStr)); - DBGPRINTF("rsf_getenv(): envvar '%s', return '%s'\n", rsCStrGetSzStr(operand1->val.pStr), - envResult == NULL ? "(NULL)" : envResult); - iRet = rsCStrConstructFromszStr(&pCstr, (envResult == NULL) ? UCHAR_CONSTANT("") : (uchar*)envResult); - d_pthread_mutex_unlock(&mutGetenv); - if(iRet != RS_RET_OK) - FINALIZE; /* need to do this after mutex is unlocked! */ - - /* Store result and cleanup */ - var.SetString(operand1, pCstr); - vmstk.Push(pStk, operand1); -finalize_it: - RETiRet; -} - - -/* The "tolower" function, which converts its sole argument to lower case. - * Quite honestly, currently this is primarily a test driver for me... - * rgerhards, 2009-04-06 - */ -static rsRetVal -rsf_tolower(vmstk_t *pStk, int numOperands) -{ - DEFiRet; - var_t *operand1; - uchar *pSrc; - cstr_t *pcstr; - int iStrlen; - - if(numOperands != 1) - ABORT_FINALIZE(RS_RET_INVLD_NBR_ARGUMENTS); - - /* pop args and do operaton */ - CHKiRet(cstrConstruct(&pcstr)); - vmstk.PopString(pStk, &operand1); - pSrc = cstrGetSzStr(operand1->val.pStr); - iStrlen = strlen((char*)pSrc); // TODO: use count from string! - while(iStrlen--) { - CHKiRet(cstrAppendChar(pcstr, tolower(*pSrc++))); - } - - /* Store result and cleanup */ - CHKiRet(cstrFinalize(pcstr)); - var.SetString(operand1, pcstr); - vmstk.Push(pStk, operand1); -finalize_it: - RETiRet; -} - - -/* Standard-Constructor - */ -BEGINobjConstruct(vm) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(vm) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -static rsRetVal -vmConstructFinalize(vm_t __attribute__((unused)) *pThis) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vm); - - CHKiRet(vmstk.Construct(&pThis->pStk)); - CHKiRet(vmstk.ConstructFinalize(pThis->pStk)); - -finalize_it: - RETiRet; -} - - -/* destructor for the vm object */ -BEGINobjDestruct(vm) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(vm) - if(pThis->pStk != NULL) - vmstk.Destruct(&pThis->pStk); - if(pThis->pMsg != NULL) - msgDestruct(&pThis->pMsg); -ENDobjDestruct(vm) - - -/* debugprint for the vm object */ -BEGINobjDebugPrint(vm) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDebugPrint(vm) - dbgoprint((obj_t*) pThis, "rsyslog virtual machine, currently no state info available\n"); -ENDobjDebugPrint(vm) - - -/* execute a program - */ -static rsRetVal -execProg(vm_t *pThis, vmprg_t *pProg) -{ - DEFiRet; - vmop_t *pCurrOp; /* virtual instruction pointer */ - - ISOBJ_TYPE_assert(pThis, vm); - ISOBJ_TYPE_assert(pProg, vmprg); - -#define doOP(OP) case opcode_##OP: DBGPRINTF("rainerscript: opcode %s\n", #OP); \ - CHKiRet(op##OP(pThis, pCurrOp)); break - pCurrOp = pProg->vmopRoot; /* TODO: do this via a method! */ - while(pCurrOp != NULL && pCurrOp->opcode != opcode_END_PROG) { - DBGPRINTF("rainerscript: executing step, opcode %d...\n", pCurrOp->opcode); - switch(pCurrOp->opcode) { - doOP(OR); - doOP(AND); - doOP(CMP_EQ); - doOP(CMP_NEQ); - doOP(CMP_LT); - doOP(CMP_GT); - doOP(CMP_LTEQ); - doOP(CMP_GTEQ); - doOP(CMP_CONTAINS); - doOP(CMP_CONTAINSI); - doOP(CMP_STARTSWITH); - doOP(CMP_STARTSWITHI); - doOP(NOT); - doOP(PUSHCONSTANT); - doOP(PUSHMSGVAR); - doOP(PUSHCEEVAR); - doOP(PUSHSYSVAR); - doOP(STRADD); - doOP(PLUS); - doOP(MINUS); - doOP(TIMES); - doOP(DIV); - doOP(MOD); - doOP(UNARY_MINUS); - doOP(FUNC_CALL); - default: - dbgoprint((obj_t*) pThis, "invalid instruction %d in vmprg\n", pCurrOp->opcode); - ABORT_FINALIZE(RS_RET_INVALID_VMOP); - break; - } - /* so far, we have plain sequential execution, so on to next... */ - pCurrOp = pCurrOp->pNext; - } -#undef doOP - - /* if we reach this point, our program has intintionally terminated - * (no error state). - */ - -finalize_it: - DBGPRINTF("rainerscript: script execution terminated with state %d\n", iRet); - RETiRet; -} - - -/* Set the current message object for the VM. It *is* valid to set a - * NULL message object, what simply means there is none. Message - * objects are properly reference counted. - */ -static rsRetVal -SetMsg(vm_t *pThis, msg_t *pMsg) -{ - DEFiRet; - if(pThis->pMsg != NULL) { - msgDestruct(&pThis->pMsg); - } - - if(pMsg != NULL) { - pThis->pMsg = MsgAddRef(pMsg); - } - - RETiRet; -} - - -/* Pop a var from the stack and return it to caller. The variable type is not - * changed, it is taken from the stack as is. This functionality is - * partly needed. We may (or may not ;)) be able to remove it once we have - * full RainerScript support. -- rgerhards, 2008-02-25 - */ -static rsRetVal -PopVarFromStack(vm_t *pThis, var_t **ppVar) -{ - DEFiRet; - CHKiRet(vmstk.Pop(pThis->pStk, ppVar)); -finalize_it: - RETiRet; -} - - -/* Pop a boolean from the stack and return it to caller. This functionality is - * partly needed. We may (or may not ;)) be able to remove it once we have - * full RainerScript support. -- rgerhards, 2008-02-25 - */ -static rsRetVal -PopBoolFromStack(vm_t *pThis, var_t **ppVar) -{ - DEFiRet; - CHKiRet(vmstk.PopBool(pThis->pStk, ppVar)); -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(vm) -CODESTARTobjQueryInterface(vm) - if(pIf->ifVersion != vmCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = vmConstruct; - pIf->ConstructFinalize = vmConstructFinalize; - pIf->Destruct = vmDestruct; - pIf->DebugPrint = vmDebugPrint; - pIf->ExecProg = execProg; - pIf->PopBoolFromStack = PopBoolFromStack; - pIf->PopVarFromStack = PopVarFromStack; - pIf->SetMsg = SetMsg; - pIf->FindRSFunction = findRSFunction; - pIf->FindRSFunctionName = findRSFunctionName; -finalize_it: -ENDobjQueryInterface(vm) - - -/* Exit the vm class. - * rgerhards, 2009-04-06 - */ -BEGINObjClassExit(vm, OBJ_IS_CORE_MODULE) /* class, version */ - rsfrRemoveAll(); - objRelease(sysvar, CORE_COMPONENT); - objRelease(var, CORE_COMPONENT); - objRelease(vmstk, CORE_COMPONENT); - - pthread_mutex_destroy(&mutGetenv); -ENDObjClassExit(vm) - - -/* Initialize the vm class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(vm, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(vmstk, CORE_COMPONENT)); - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(sysvar, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_DEBUGPRINT, vmDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmConstructFinalize); - - /* register built-in functions // TODO: move to its own module */ - CHKiRet(rsfrAddFunction((uchar*)"strlen", rsf_strlen)); - CHKiRet(rsfrAddFunction((uchar*)"tolower", rsf_tolower)); - CHKiRet(rsfrAddFunction((uchar*)"getenv", rsf_getenv)); - - pthread_mutex_init(&mutGetenv, NULL); - -ENDObjClassInit(vm) - -/* vi:set ai: - */ diff --git a/runtime/vm.h b/runtime/vm.h deleted file mode 100644 index cb3c69d0..00000000 --- a/runtime/vm.h +++ /dev/null @@ -1,68 +0,0 @@ -/* The vm object. - * - * This implements the rsyslog virtual machine. The initial implementation is - * done to support complex user-defined expressions, but it may evolve into a - * much more useful thing over time. - * - * The virtual machine uses rsyslog variables as its memory storage system. - * All computation is done on a stack (vmstk). The vm supports a given - * instruction set and executes programs of type vmprg, which consist of - * single operations defined in vmop (which hold the instruction and the - * data). - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_VM_H -#define INCLUDED_VM_H - -#include "msg.h" -#include "vmstk.h" -#include "vmprg.h" - -/* the vm object */ -typedef struct vm_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - vmstk_t *pStk; /* The stack */ - msg_t *pMsg; /* the current message (or NULL, if we have none) */ -} vm_t; - - -/* interfaces */ -BEGINinterface(vm) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(vm); - rsRetVal (*Construct)(vm_t **ppThis); - rsRetVal (*ConstructFinalize)(vm_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(vm_t **ppThis); - rsRetVal (*ExecProg)(vm_t *pThis, vmprg_t *pProg); - rsRetVal (*PopBoolFromStack)(vm_t *pThis, var_t **ppVar); /* there are a few cases where we need this... */ - rsRetVal (*PopVarFromStack)(vm_t *pThis, var_t **ppVar); /* there are a few cases where we need this... */ - rsRetVal (*SetMsg)(vm_t *pThis, msg_t *pMsg); /* there are a few cases where we need this... */ - /* v2 (4.1.7) */ - rsRetVal (*FindRSFunction)(cstr_t *pcsName, prsf_t *prsf); /* 2009-06-04 */ - rsRetVal (*FindRSFunctionName)(prsf_t rsf, cstr_t **ppcsName); /* 2009-06-04 */ -ENDinterface(vm) -#define vmCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(vm); - -#endif /* #ifndef INCLUDED_VM_H */ diff --git a/runtime/vmop.c b/runtime/vmop.c deleted file mode 100644 index ea627220..00000000 --- a/runtime/vmop.c +++ /dev/null @@ -1,307 +0,0 @@ -/* vmop.c - abstracts an operation (instructed) supported by the - * rsyslog virtual machine - * - * Module begun 2008-02-20 by Rainer Gerhards - * - * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include - -#include "rsyslog.h" -#include "obj.h" -#include "vmop.h" -#include "vm.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(var) -DEFobjCurrIf(vm) - - -/* forward definitions */ -static rsRetVal vmopOpcode2Str(vmop_t *pThis, uchar **ppName); - -/* Standard-Constructor - */ -BEGINobjConstruct(vmop) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(vmop) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -rsRetVal vmopConstructFinalize(vmop_t __attribute__((unused)) *pThis) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - RETiRet; -} - - -/* destructor for the vmop object */ -BEGINobjDestruct(vmop) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(vmop) - if(pThis->opcode != opcode_FUNC_CALL) { - if(pThis->operand.pVar != NULL) - var.Destruct(&pThis->operand.pVar); - } -ENDobjDestruct(vmop) - - -/* DebugPrint support for the vmop object */ -BEGINobjDebugPrint(vmop) /* be sure to specify the object type also in END and CODESTART macros! */ - uchar *pOpcodeName; - cstr_t *pStrVar; -CODESTARTobjDebugPrint(vmop) - vmopOpcode2Str(pThis, &pOpcodeName); - if(pThis->opcode == opcode_FUNC_CALL) { - CHKiRet(vm.FindRSFunctionName(pThis->operand.rsf, &pStrVar)); - assert(pStrVar != NULL); - } else { - CHKiRet(rsCStrConstruct(&pStrVar)); - if(pThis->operand.pVar != NULL) { - CHKiRet(var.Obj2Str(pThis->operand.pVar, pStrVar)); - } - } - CHKiRet(cstrFinalize(pStrVar)); - dbgoprint((obj_t*) pThis, "%.12s\t%s\n", pOpcodeName, rsCStrGetSzStrNoNULL(pStrVar)); - if(pThis->opcode != opcode_FUNC_CALL) - rsCStrDestruct(&pStrVar); -finalize_it: -ENDobjDebugPrint(vmop) - - -/* This function is similar to DebugPrint, but does not send its output to - * the debug log but instead to a caller-provided string. The idea here is that - * we can use this string to get a textual representation of an operation. - * Among others, this is useful for creating testbenches, our first use case for - * it. Here, it enables simple comparison of the resulting program to a - * reference program by simple string compare. - * Note that the caller must initialize the string object. We always add - * data to it. So, it can be easily combined into a chain of methods - * to generate the final string. - * rgerhards, 2008-07-04 - */ -static rsRetVal -Obj2Str(vmop_t *pThis, cstr_t *pstrPrg) -{ - uchar *pOpcodeName; - cstr_t *pcsFuncName; - uchar szBuf[2048]; - size_t lenBuf; - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmop); - assert(pstrPrg != NULL); - vmopOpcode2Str(pThis, &pOpcodeName); - lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%s\t", pOpcodeName); - CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szBuf, lenBuf)); - if(pThis->opcode == opcode_FUNC_CALL) { - CHKiRet(vm.FindRSFunctionName(pThis->operand.rsf, &pcsFuncName)); - CHKiRet(rsCStrAppendCStr(pstrPrg, pcsFuncName)); - } else { - if(pThis->operand.pVar != NULL) - CHKiRet(var.Obj2Str(pThis->operand.pVar, pstrPrg)); - } - CHKiRet(cstrAppendChar(pstrPrg, '\n')); - -finalize_it: - RETiRet; -} - - -/* set function - * rgerhards, 2009-04-06 - */ -static rsRetVal -vmopSetFunc(vmop_t *pThis, cstr_t *pcsFuncName) -{ - prsf_t rsf; /* pointer to function */ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - CHKiRet(vm.FindRSFunction(pcsFuncName, &rsf)); /* check if function exists and obtain pointer to it */ - assert(rsf != NULL); /* just double-check, would be very hard to find! */ - pThis->operand.rsf = rsf; -finalize_it: - RETiRet; -} - - -/* set operand (variant case) - * rgerhards, 2008-02-20 - */ -static rsRetVal -vmopSetVar(vmop_t *pThis, var_t *pVar) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - ISOBJ_TYPE_assert(pVar, var); - pThis->operand.pVar = pVar; - RETiRet; -} - - -/* set operation - * rgerhards, 2008-02-20 - */ -static rsRetVal -vmopSetOpcode(vmop_t *pThis, opcode_t opcode) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - pThis->opcode = opcode; - RETiRet; -} - - -/* a way to turn an opcode into a readable string - */ -static rsRetVal -vmopOpcode2Str(vmop_t *pThis, uchar **ppName) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmop); - - switch(pThis->opcode) { - case opcode_OR: - *ppName = (uchar*) "or"; - break; - case opcode_AND: - *ppName = (uchar*) "and"; - break; - case opcode_PLUS: - *ppName = (uchar*) "add"; - break; - case opcode_MINUS: - *ppName = (uchar*) "sub"; - break; - case opcode_TIMES: - *ppName = (uchar*) "mul"; - break; - case opcode_DIV: - *ppName = (uchar*) "div"; - break; - case opcode_MOD: - *ppName = (uchar*) "mod"; - break; - case opcode_NOT: - *ppName = (uchar*) "not"; - break; - case opcode_CMP_EQ: - *ppName = (uchar*) "cmp_=="; - break; - case opcode_CMP_NEQ: - *ppName = (uchar*) "cmp_!="; - break; - case opcode_CMP_LT: - *ppName = (uchar*) "cmp_<"; - break; - case opcode_CMP_GT: - *ppName = (uchar*) "cmp_>"; - break; - case opcode_CMP_LTEQ: - *ppName = (uchar*) "cmp_<="; - break; - case opcode_CMP_CONTAINS: - *ppName = (uchar*) "contains"; - break; - case opcode_CMP_STARTSWITH: - *ppName = (uchar*) "startswith"; - break; - case opcode_CMP_GTEQ: - *ppName = (uchar*) "cmp_>="; - break; - case opcode_PUSHSYSVAR: - *ppName = (uchar*) "push_sysvar"; - break; - case opcode_PUSHMSGVAR: - *ppName = (uchar*) "push_msgvar"; - break; - case opcode_PUSHCONSTANT: - *ppName = (uchar*) "push_const"; - break; - case opcode_POP: - *ppName = (uchar*) "pop"; - break; - case opcode_UNARY_MINUS: - *ppName = (uchar*) "unary_minus"; - break; - case opcode_STRADD: - *ppName = (uchar*) "strconcat"; - break; - case opcode_FUNC_CALL: - *ppName = (uchar*) "func_call"; - break; - default: - *ppName = (uchar*) "!invalid_opcode!"; - break; - } - - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(vmop) -CODESTARTobjQueryInterface(vmop) - if(pIf->ifVersion != vmopCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = vmopConstruct; - pIf->ConstructFinalize = vmopConstructFinalize; - pIf->Destruct = vmopDestruct; - pIf->DebugPrint = vmopDebugPrint; - pIf->SetFunc = vmopSetFunc; - pIf->SetOpcode = vmopSetOpcode; - pIf->SetVar = vmopSetVar; - pIf->Opcode2Str = vmopOpcode2Str; - pIf->Obj2Str = Obj2Str; -finalize_it: -ENDobjQueryInterface(vmop) - - -/* Initialize the vmop class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(vmop, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(vm, CORE_COMPONENT)); - - OBJSetMethodHandler(objMethod_DEBUGPRINT, vmopDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmopConstructFinalize); -ENDObjClassInit(vmop) - -/* vi:set ai: - */ diff --git a/runtime/vmop.h b/runtime/vmop.h deleted file mode 100644 index c085a940..00000000 --- a/runtime/vmop.h +++ /dev/null @@ -1,129 +0,0 @@ -/* The vmop object. - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of rsyslog. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_VMOP_H -#define INCLUDED_VMOP_H - -#include "ctok_token.h" -#include "vmstk.h" -#include "stringbuf.h" - -/* machine instructions types */ -typedef enum { /* do NOT start at 0 to detect uninitialized types after calloc() */ - opcode_INVALID = 0, - /* for simplicity of debugging and reading dumps, we use the same IDs - * that the tokenizer uses where this applicable. - */ - opcode_OR = ctok_OR, - opcode_AND = ctok_AND, - opcode_STRADD= ctok_STRADD, - opcode_PLUS = ctok_PLUS, - opcode_MINUS = ctok_MINUS, - opcode_TIMES = ctok_TIMES, /* "*" */ - opcode_DIV = ctok_DIV, - opcode_MOD = ctok_MOD, - opcode_NOT = ctok_NOT, - opcode_CMP_EQ = ctok_CMP_EQ, /* all compare operations must be in a row */ - opcode_CMP_NEQ = ctok_CMP_NEQ, - opcode_CMP_LT = ctok_CMP_LT, - opcode_CMP_GT = ctok_CMP_GT, - opcode_CMP_LTEQ = ctok_CMP_LTEQ, - opcode_CMP_CONTAINS = ctok_CMP_CONTAINS, - opcode_CMP_STARTSWITH = ctok_CMP_STARTSWITH, - opcode_CMP_CONTAINSI = ctok_CMP_CONTAINSI, - opcode_CMP_STARTSWITHI = ctok_CMP_STARTSWITHI, - opcode_CMP_GTEQ = ctok_CMP_GTEQ, /* end compare operations */ - /* here we start our own codes */ - opcode_POP = 1000, /* requires var operand to receive result */ - opcode_PUSHSYSVAR = 1001, /* requires var operand */ - opcode_PUSHMSGVAR = 1002, /* requires var operand */ - opcode_PUSHCONSTANT = 1003, /* requires var operand */ - opcode_PUSHCEEVAR = 1004, /* requires var operand */ - opcode_UNARY_MINUS = 1010, - opcode_FUNC_CALL = 1012, - opcode_END_PROG = 2000 -} opcode_t; - - -/* Additional doc, operation specific - - FUNC_CALL - All parameter passing is via the stack. Parameters are placed onto the stack in reverse order, - that means the last parameter is on top of the stack, the first at the bottom location. - At the actual top of the stack is the number of parameters. This permits functions to be - called with variable number of arguments. The function itself is responsible for poping - the right number of parameters of the stack and complaining if the number is incorrect. - On exit, a single return value must be pushed onto the stack. The FUNC_CALL operation - is generic. Its pVar argument contains the function name string (TODO: very slow, make - faster in later releases). - - Sample Function call: sampleFunc(p1, p2, p3) ; returns number 4711 (sample) - Stacklayout on entry (order is top to bottom): - 3 - p3 - p2 - p1 - ... other vars ... - - Stack on exit - 4711 - ... other vars ... - - */ - - -/* the vmop object */ -typedef struct vmop_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - opcode_t opcode; - union { - var_t *pVar; - prsf_t rsf; /* pointer to function for "call" instruction */ - } operand; - struct vmop_s *pNext; /* next operation or NULL, if end of program (logically this belongs to vmprg) */ -} vmop_t; - - -/* interfaces */ -BEGINinterface(vmop) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(vmop); - rsRetVal (*Construct)(vmop_t **ppThis); - rsRetVal (*ConstructFinalize)(vmop_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(vmop_t **ppThis); - rsRetVal (*SetOpcode)(vmop_t *pThis, opcode_t opcode); - rsRetVal (*SetVar)(vmop_t *pThis, var_t *pVar); - rsRetVal (*Opcode2Str)(vmop_t *pThis, uchar **ppName); - rsRetVal (*Obj2Str)(vmop_t *pThis, cstr_t *pstr); - /* v2 */ - rsRetVal (*SetFunc)(vmop_t *pThis, cstr_t *pcsFuncName); -ENDinterface(vmop) -#define vmopCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ -/* interface changes, v1 -> v2 - * added SetFuct after existing function pointers -- rgerhards, 2009-04-06 - */ - -/* the remaining prototypes */ -PROTOTYPEObj(vmop); - -#endif /* #ifndef INCLUDED_VMOP_H */ diff --git a/runtime/vmprg.c b/runtime/vmprg.c deleted file mode 100644 index 07757b98..00000000 --- a/runtime/vmprg.c +++ /dev/null @@ -1,236 +0,0 @@ -/* vmprg.c - abstracts a program (bytecode) for the rsyslog virtual machine - * - * Module begun 2008-02-20 by Rainer Gerhards - * - * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include - -#include "rsyslog.h" -#include "obj.h" -#include "vmprg.h" -#include "stringbuf.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(vmop) - - -/* Standard-Constructor - */ -BEGINobjConstruct(vmprg) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(vmprg) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -static rsRetVal -vmprgConstructFinalize(vmprg_t __attribute__((unused)) *pThis) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmprg); - RETiRet; -} - - -/* destructor for the vmprg object */ -BEGINobjDestruct(vmprg) /* be sure to specify the object type also in END and CODESTART macros! */ - vmop_t *pOp; - vmop_t *pTmp; -CODESTARTobjDestruct(vmprg) - /* we need to destruct the program elements! */ - for(pOp = pThis->vmopRoot ; pOp != NULL ; ) { - pTmp = pOp; - pOp = pOp->pNext; - vmop.Destruct(&pTmp); - } -ENDobjDestruct(vmprg) - - -/* destructor for the vmop object */ -BEGINobjDebugPrint(vmprg) /* be sure to specify the object type also in END and CODESTART macros! */ - vmop_t *pOp; -CODESTARTobjDebugPrint(vmprg) - dbgoprint((obj_t*) pThis, "VM Program:\n"); - for(pOp = pThis->vmopRoot ; pOp != NULL ; pOp = pOp->pNext) { - vmop.DebugPrint(pOp); - } -ENDobjDebugPrint(vmprg) - - -/* This function is similar to DebugPrint, but does not send its output to - * the debug log but instead to a caller-provided string. The idea here is that - * we can use this string to get a textual representation of a bytecode program. - * Among others, this is useful for creating testbenches, our first use case for - * it. Here, it enables simple comparison of the resulting program to a - * reference program by simple string compare. - * Note that the caller must initialize the string object. We always add - * data to it. So, it can be easily combined into a chain of methods - * to generate the final string. - * rgerhards, 2008-07-04 - */ -static rsRetVal -Obj2Str(vmprg_t *pThis, cstr_t *pstrPrg) -{ - uchar szAddr[12]; - vmop_t *pOp; - int i; - int lenAddr; - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmprg); - assert(pstrPrg != NULL); - i = 0; /* "program counter" */ - for(pOp = pThis->vmopRoot ; pOp != NULL ; pOp = pOp->pNext) { - lenAddr = snprintf((char*)szAddr, sizeof(szAddr), "%8.8d: ", i++); - CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szAddr, lenAddr)); - vmop.Obj2Str(pOp, pstrPrg); - } - -finalize_it: - RETiRet; -} - - -/* add an operation (instruction) to the end of the current program. This - * function is expected to be called while creating the program, but never - * again after this is done and it is being executed. Results are undefined if - * it is called after execution. - */ -static rsRetVal -vmprgAddOperation(vmprg_t *pThis, vmop_t *pOp) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmprg); - ISOBJ_TYPE_assert(pOp, vmop); - - if(pThis->vmopRoot == NULL) { - pThis->vmopRoot = pOp; - } else { - pThis->vmopLast->pNext = pOp; - } - pThis->vmopLast = pOp; - - RETiRet; -} - - -/* this is a shortcut for high-level callers. It creates a new vmop, sets its - * parameters and adds it to the program - all in one big step. If there is no - * var associated with this operation, the caller can simply supply NULL as - * pVar. - */ -static rsRetVal -vmprgAddVarOperation(vmprg_t *pThis, opcode_t opcode, var_t *pVar) -{ - DEFiRet; - vmop_t *pOp; - - ISOBJ_TYPE_assert(pThis, vmprg); - - /* construct and fill vmop */ - CHKiRet(vmop.Construct(&pOp)); - CHKiRet(vmop.ConstructFinalize(pOp)); - CHKiRet(vmop.SetOpcode(pOp, opcode)); - if(pVar != NULL) - CHKiRet(vmop.SetVar(pOp, pVar)); - - /* and add it to the program */ - CHKiRet(vmprgAddOperation(pThis, pOp)); - -finalize_it: - RETiRet; -} - - -/* this is another shortcut for high-level callers. It is similar to vmprgAddVarOperation - * but adds a call operation. Among others, this include a check if the function - * is known. - */ -static rsRetVal -vmprgAddCallOperation(vmprg_t *pThis, cstr_t *pcsName) -{ - DEFiRet; - vmop_t *pOp; - - ISOBJ_TYPE_assert(pThis, vmprg); - - /* construct and fill vmop */ - CHKiRet(vmop.Construct(&pOp)); - CHKiRet(vmop.ConstructFinalize(pOp)); - CHKiRet(vmop.SetFunc(pOp, pcsName)); - CHKiRet(vmop.SetOpcode(pOp, opcode_FUNC_CALL)); - - /* and add it to the program */ - CHKiRet(vmprgAddOperation(pThis, pOp)); - -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(vmprg) -CODESTARTobjQueryInterface(vmprg) - if(pIf->ifVersion != vmprgCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = vmprgConstruct; - pIf->ConstructFinalize = vmprgConstructFinalize; - pIf->Destruct = vmprgDestruct; - pIf->DebugPrint = vmprgDebugPrint; - pIf->Obj2Str = Obj2Str; - pIf->AddOperation = vmprgAddOperation; - pIf->AddVarOperation = vmprgAddVarOperation; - pIf->AddCallOperation = vmprgAddCallOperation; -finalize_it: -ENDobjQueryInterface(vmprg) - - -/* Initialize the vmprg class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(vmprg, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(vmop, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_DEBUGPRINT, vmprgDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmprgConstructFinalize); -ENDObjClassInit(vmprg) - -/* vi:set ai: - */ diff --git a/runtime/vmprg.h b/runtime/vmprg.h deleted file mode 100644 index 66f03913..00000000 --- a/runtime/vmprg.h +++ /dev/null @@ -1,69 +0,0 @@ -/* The vmprg object. - * - * The program is made up of vmop_t's, one after another. When we support - * branching (or user-defined functions) at some time, well do this via - * special branch opcodes. They will then contain the actual memory - * address of a logical program entry that we shall branch to. Other than - * that, all execution is serial - that is one opcode is executed after - * the other. This class implements a logical program store, modelled - * after real main memory. A linked list of opcodes is used to implement it. - * In the future, we may use linked lists of array's to enhance performance, - * but for the time being we have taken the simplistic approach (which also - * reduces risk of bugs during initial development). The necessary pointers - * for this are already implemented in vmop. Though this is not the 100% - * correct place, we have opted this time in favor of performance, which - * made them go there. - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_VMPRG_H -#define INCLUDED_VMPRG_H - -#include "vmop.h" -#include "stringbuf.h" - -/* the vmprg object */ -typedef struct vmprg_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - vmop_t *vmopRoot; /* start of program */ - vmop_t *vmopLast; /* last vmop of program (for adding new ones) */ -} vmprg_t; - - -/* interfaces */ -BEGINinterface(vmprg) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(vmprg); - rsRetVal (*Construct)(vmprg_t **ppThis); - rsRetVal (*ConstructFinalize)(vmprg_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(vmprg_t **ppThis); - rsRetVal (*AddOperation)(vmprg_t *pThis, vmop_t *pOp); - rsRetVal (*AddVarOperation)(vmprg_t *pThis, opcode_t opcode, var_t *pVar); - rsRetVal (*Obj2Str)(vmprg_t *pThis, cstr_t *pstr); - /* v2 (4.1.7) */ - rsRetVal (*AddCallOperation)(vmprg_t *pThis, cstr_t *pVar); /* added 2009-04-06 */ -ENDinterface(vmprg) -#define vmprgCURR_IF_VERSION 2 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(vmprg); - -#endif /* #ifndef INCLUDED_VMPRG_H */ diff --git a/runtime/vmstk.c b/runtime/vmstk.c deleted file mode 100644 index 1ee3d485..00000000 --- a/runtime/vmstk.c +++ /dev/null @@ -1,234 +0,0 @@ -/* vmstk.c - the arithmetic stack of a virtual machine. - * - * Module begun 2008-02-21 by Rainer Gerhards - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include - -#include "rsyslog.h" -#include "obj.h" -#include "vmstk.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(var) - - -/* Standard-Constructor - */ -BEGINobjConstruct(vmstk) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(vmstk) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -static rsRetVal -vmstkConstructFinalize(vmstk_t __attribute__((unused)) *pThis) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, vmstk); - RETiRet; -} - - -/* destructor for the vmstk object */ -BEGINobjDestruct(vmstk) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(vmstk) -ENDobjDestruct(vmstk) - - -/* debugprint for the vmstk object */ -BEGINobjDebugPrint(vmstk) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDebugPrint(vmstk) - dbgoprint((obj_t*) pThis, "stack contents:\n"); -ENDobjDebugPrint(vmstk) - - -/* push a value on the stack. The provided pVar is now owned - * by the stack. If the user intends to continue use it, it - * must be duplicated. - */ -static rsRetVal -push(vmstk_t *pThis, var_t *pVar) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmstk); - ISOBJ_TYPE_assert(pVar, var); - - if(pThis->iStkPtr >= VMSTK_SIZE) - ABORT_FINALIZE(RS_RET_OUT_OF_STACKSPACE); - - pThis->vStk[pThis->iStkPtr++] = pVar; - -finalize_it: - RETiRet; -} - - -/* pop a value from the stack - * IMPORTANT: the stack pointer always points to the NEXT FREE entry. So in - * order to pop, we must access the element one below the stack pointer. - * The user is responsible for destructing the ppVar returned. - */ -static rsRetVal -pop(vmstk_t *pThis, var_t **ppVar) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, vmstk); - ASSERT(ppVar != NULL); - - if(pThis->iStkPtr == 0) - ABORT_FINALIZE(RS_RET_STACK_EMPTY); - - *ppVar = pThis->vStk[--pThis->iStkPtr]; - -finalize_it: - RETiRet; -} - - -/* pop a boolean value from the stack - * The user is responsible for destructing the ppVar returned. - */ -static rsRetVal -popBool(vmstk_t *pThis, var_t **ppVar) -{ - DEFiRet; - - /* assertions are done in pop(), we do not duplicate here */ - CHKiRet(pop(pThis, ppVar)); - CHKiRet(var.ConvToBool(*ppVar)); - -finalize_it: - RETiRet; -} - - -/* pop a number value from the stack - * The user is responsible for destructing the ppVar returned. - */ -static rsRetVal -popNumber(vmstk_t *pThis, var_t **ppVar) -{ - DEFiRet; - - /* assertions are done in pop(), we do not duplicate here */ - CHKiRet(pop(pThis, ppVar)); - CHKiRet(var.ConvToNumber(*ppVar)); - -finalize_it: - RETiRet; -} - - -/* pop a number value from the stack - * The user is responsible for destructing the ppVar returned. - */ -static rsRetVal -popString(vmstk_t *pThis, var_t **ppVar) -{ - DEFiRet; - - /* assertions are done in pop(), we do not duplicate here */ - CHKiRet(pop(pThis, ppVar)); - CHKiRet(var.ConvToString(*ppVar)); - -finalize_it: - RETiRet; -} - - -/* pop two variables for a common operation, e.g. a compare. When this - * functions returns, both variables have the same type, but the type - * is not set to anything specific. - * The user is responsible for destructing the ppVar's returned. - * A quick note on the name: it means pop 2 variable for a common - * opertion - just in case you wonder (I don't really like the name, - * but I didn't come up with a better one...). - * rgerhards, 2008-02-25 - */ -static rsRetVal -pop2CommOp(vmstk_t *pThis, var_t **ppVar1, var_t **ppVar2) -{ - DEFiRet; - - /* assertions are done in pop(), we do not duplicate here */ - /* operand two must be popped first, because it is at the top of stack */ - CHKiRet(pop(pThis, ppVar2)); - CHKiRet(pop(pThis, ppVar1)); - CHKiRet(var.ConvForOperation(*ppVar1, *ppVar2)); - -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(vmstk) -CODESTARTobjQueryInterface(vmstk) - if(pIf->ifVersion != vmstkCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = vmstkConstruct; - pIf->ConstructFinalize = vmstkConstructFinalize; - pIf->Destruct = vmstkDestruct; - pIf->DebugPrint = vmstkDebugPrint; - pIf->Push = push; - pIf->Pop = pop; - pIf->PopBool = popBool; - pIf->PopNumber = popNumber; - pIf->PopString = popString; - pIf->Pop2CommOp = pop2CommOp; - -finalize_it: -ENDobjQueryInterface(vmstk) - - -/* Initialize the vmstk class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(vmstk, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_DEBUGPRINT, vmstkDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, vmstkConstructFinalize); -ENDObjClassInit(vmstk) - -/* vi:set ai: - */ diff --git a/runtime/vmstk.h b/runtime/vmstk.h deleted file mode 100644 index 06657cf4..00000000 --- a/runtime/vmstk.h +++ /dev/null @@ -1,56 +0,0 @@ -/* The vmstk object. - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_VMSTK_H -#define INCLUDED_VMSTK_H - -/* The max size of the stack - TODO: make configurable */ -#define VMSTK_SIZE 256 - -/* the vmstk object */ -struct vmstk_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - var_t *vStk[VMSTK_SIZE];/* the actual stack */ - int iStkPtr; /* stack pointer, points to next free location, grows from 0 --> topend */ -}; - - -/* interfaces */ -BEGINinterface(vmstk) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(vmstk); - rsRetVal (*Construct)(vmstk_t **ppThis); - rsRetVal (*ConstructFinalize)(vmstk_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(vmstk_t **ppThis); - rsRetVal (*Push)(vmstk_t *pThis, var_t *pVar); - rsRetVal (*Pop)(vmstk_t *pThis, var_t **ppVar); - rsRetVal (*PopBool)(vmstk_t *pThis, var_t **ppVar); - rsRetVal (*PopNumber)(vmstk_t *pThis, var_t **ppVar); - rsRetVal (*PopString)(vmstk_t *pThis, var_t **ppVar); - rsRetVal (*Pop2CommOp)(vmstk_t *pThis, var_t **ppVar1, var_t **ppVar2); -ENDinterface(vmstk) -#define vmstkCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(vmstk); - -#endif /* #ifndef INCLUDED_VMSTK_H */ diff --git a/tools/syslogd.c b/tools/syslogd.c index f623b398..45abf1a7 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -121,7 +121,6 @@ #include "ruleset.h" #include "rule.h" #include "net.h" -#include "vm.h" #include "prop.h" #include "rsconf.h" #include "dnscache.h" @@ -132,7 +131,6 @@ DEFobjCurrIf(obj) DEFobjCurrIf(glbl) DEFobjCurrIf(datetime) /* TODO: make go away! */ DEFobjCurrIf(conf) -DEFobjCurrIf(expr) DEFobjCurrIf(module) DEFobjCurrIf(errmsg) DEFobjCurrIf(rule) @@ -1544,8 +1542,6 @@ InitGlobalClasses(void) CHKiRet(objUse(module, CORE_COMPONENT)); pErrObj = "datetime"; CHKiRet(objUse(datetime, CORE_COMPONENT)); - pErrObj = "expr"; - CHKiRet(objUse(expr, CORE_COMPONENT)); pErrObj = "rule"; CHKiRet(objUse(rule, CORE_COMPONENT)); pErrObj = "ruleset"; @@ -1601,7 +1597,6 @@ GlobalClassExit(void) objRelease(conf, CORE_COMPONENT); objRelease(ruleset, CORE_COMPONENT); objRelease(rule, CORE_COMPONENT); - objRelease(expr, CORE_COMPONENT); parserClassExit(); /* this is hack, currently core_modules do not get this automatically called */ rsconfClassExit(); /* this is hack, currently core_modules do not get this automatically called */ objRelease(datetime, CORE_COMPONENT); diff --git a/tools/syslogd.h b/tools/syslogd.h index c3b99f9d..7c5dde81 100644 --- a/tools/syslogd.h +++ b/tools/syslogd.h @@ -27,7 +27,6 @@ #include "template.h" #include "action.h" #include "linkedlist.h" -#include "expr.h" /* the following prototypes should go away once we have an input * module interface -- rgerhards, 2007-12-12 -- cgit v1.2.3 From c809f8d1d92307564cb1a4b071934b955211663a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 15:28:16 +0200 Subject: more cleanup --- runtime/Makefile.am | 4 - runtime/conf.c | 8 - runtime/ctok.c | 629 --------------------------------------------------- runtime/ctok.h | 56 ----- runtime/ctok_token.c | 129 ----------- runtime/ctok_token.h | 88 ------- runtime/rsyslog.c | 5 - 7 files changed, 919 deletions(-) delete mode 100644 runtime/ctok.c delete mode 100644 runtime/ctok.h delete mode 100644 runtime/ctok_token.c delete mode 100644 runtime/ctok_token.h diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 7f7e55fd..74ba2ab7 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -55,10 +55,6 @@ librsyslog_la_SOURCES = \ statsobj.h \ sync.c \ sync.h \ - ctok.c \ - ctok.h \ - ctok_token.c \ - ctok_token.h \ stream.c \ stream.h \ var.c \ diff --git a/runtime/conf.c b/runtime/conf.c index 413d02bb..8c7bc7b6 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -65,8 +65,6 @@ #include "srUtils.h" #include "errmsg.h" #include "net.h" -#include "ctok.h" -#include "ctok_token.h" #include "rule.h" #include "ruleset.h" #include "rsconf.h" @@ -82,8 +80,6 @@ static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); /* static data */ DEFobjStaticHelpers -DEFobjCurrIf(ctok) -DEFobjCurrIf(ctok_token) DEFobjCurrIf(module) DEFobjCurrIf(errmsg) DEFobjCurrIf(net) @@ -1082,8 +1078,6 @@ CODESTARTObjClassExit(conf) } /* release objects we no longer need */ - objRelease(ctok, CORE_COMPONENT); - objRelease(ctok_token, CORE_COMPONENT); objRelease(module, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); objRelease(net, LM_NET_FILENAME); @@ -1098,8 +1092,6 @@ ENDObjClassExit(conf) */ BEGINAbstractObjClassInit(conf, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */ /* request objects we use */ - CHKiRet(objUse(ctok, CORE_COMPONENT)); - CHKiRet(objUse(ctok_token, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(net, LM_NET_FILENAME)); /* TODO: make this dependcy go away! */ diff --git a/runtime/ctok.c b/runtime/ctok.c deleted file mode 100644 index 19c9bd24..00000000 --- a/runtime/ctok.c +++ /dev/null @@ -1,629 +0,0 @@ -/* ctok.c - helper class to tokenize an input stream - which surprisingly - * currently does not work with streams but with string. But that will - * probably change over time ;) This class was originally written to support - * the expression module but may evolve when (if) the expression module is - * expanded (or aggregated) by a full-fledged ctoken based config parser. - * Obviously, this class is used together with config files and not any other - * parse function. - * - * Module begun 2008-02-19 by Rainer Gerhards - * - * Copyright (C) 2008 by Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include -#include - -#include "rsyslog.h" -#include "template.h" -#include "ctok.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(ctok_token) -DEFobjCurrIf(var) - - -/* Standard-Constructor - */ -BEGINobjConstruct(ctok) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(ctok) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -rsRetVal ctokConstructFinalize(ctok_t __attribute__((unused)) *pThis) -{ - DEFiRet; - RETiRet; -} - - -/* destructor for the ctok object */ -BEGINobjDestruct(ctok) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(ctok) - /* ... then free resources */ -ENDobjDestruct(ctok) - - -/* unget character from input stream. At most one character can be ungotten. - * This funtion is only permitted to be called after at least one character - * has been read from the stream. Right now, we handle the situation simply by - * moving the string "stream" pointer one position backwards. If we work with - * real streams (some time), the strm object will handle the functionality - * itself. -- rgerhards, 2008-02-19 - */ -static rsRetVal -ctokUngetCharFromStream(ctok_t *pThis, uchar __attribute__((unused)) c) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok); - --pThis->pp; - - RETiRet; -} - - -/* get the next character from the input "stream". Note that this version - * does NOT look for comment characters as end-of-stream, so it is suitable - * when building constant strings! -- rgerhards, 2010-03-01 - */ -static inline rsRetVal -ctokGetCharFromStreamNoComment(ctok_t *pThis, uchar *pc) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pc != NULL); - - /* end of string or begin of comment terminates the "stream" */ - if(*pThis->pp == '\0') { - ABORT_FINALIZE(RS_RET_EOS); - } else { - *pc = *pThis->pp; - ++pThis->pp; - } - -finalize_it: - RETiRet; -} - - -/* get the next character from the input "stream" (currently just a in-memory - * string...) -- rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetCharFromStream(ctok_t *pThis, uchar *pc) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pc != NULL); - - CHKiRet(ctokGetCharFromStreamNoComment(pThis, pc)); - /* begin of comment terminates the "stream"! */ - if(*pc == '#') { - ABORT_FINALIZE(RS_RET_EOS); - } - -finalize_it: - RETiRet; -} - - -/* skip whitespace in the input "stream". - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokSkipWhitespaceFromStream(ctok_t *pThis) -{ - DEFiRet; - uchar c; - - ISOBJ_TYPE_assert(pThis, ctok); - - CHKiRet(ctokGetCharFromStream(pThis, &c)); - while(isspace(c)) { - CHKiRet(ctokGetCharFromStream(pThis, &c)); - } - - /* we must unget the one non-whitespace we found */ - CHKiRet(ctokUngetCharFromStream(pThis, c)); - -dbgprintf("skipped whitespace, stream now '%s'\n", pThis->pp); -finalize_it: - RETiRet; -} - - -/* get the next word from the input "stream" (currently just a in-memory - * string...). A word is anything from the current location until the - * first non-alphanumeric character. If the word is longer - * than the provided memory buffer, parsing terminates when buffer length - * has been reached. A buffer of 128 bytes or more should always be by - * far sufficient. -- rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetWordFromStream(ctok_t *pThis, uchar *pWordBuf, size_t lenWordBuf) -{ - DEFiRet; - uchar c; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pWordBuf != NULL); - ASSERT(lenWordBuf > 0); - - CHKiRet(ctokSkipWhitespaceFromStream(pThis)); - - CHKiRet(ctokGetCharFromStream(pThis, &c)); - while((isalnum(c) || c == '_' || c == '-') && lenWordBuf > 1) { - *pWordBuf++ = c; - --lenWordBuf; - CHKiRet(ctokGetCharFromStream(pThis, &c)); - } - *pWordBuf = '\0'; /* there is always space for this - see while() */ - - /* push back the char that we have read too much */ - CHKiRet(ctokUngetCharFromStream(pThis, c)); - -finalize_it: - RETiRet; -} - - -/* read in a constant number - * This is the "number" ABNF element - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetNumber(ctok_t *pThis, ctok_token_t *pToken) -{ - DEFiRet; - number_t n; /* the parsed number */ - uchar c; - int valC; - int iBase; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pToken != NULL); - - pToken->tok = ctok_NUMBER; - - CHKiRet(ctokGetCharFromStream(pThis, &c)); - if(c == '0') { /* octal? */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); - if(c == 'x') { /* nope, hex! */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); - c = tolower(c); - iBase = 16; - } else { - iBase = 8; - } - } else { - iBase = 10; - } - - n = 0; - /* this loop is quite simple, a variable name is terminated by whitespace. */ - while(isdigit(c) || (c >= 'a' && c <= 'f')) { - if(isdigit(c)) { - valC = c - '0'; - } else { - valC = c - 'a' + 10; - } - - if(valC >= iBase) { - if(iBase == 8) { - ABORT_FINALIZE(RS_RET_INVALID_OCTAL_DIGIT); - } else { - ABORT_FINALIZE(RS_RET_INVALID_HEX_DIGIT); - } - } - /* we now have the next value and know it is right */ - n = n * iBase + valC; - CHKiRet(ctokGetCharFromStream(pThis, &c)); - c = tolower(c); - } - - /* we need to unget the character that made the loop terminate */ - CHKiRet(ctokUngetCharFromStream(pThis, c)); - - CHKiRet(var.SetNumber(pToken->pVar, n)); - -finalize_it: - RETiRet; -} - - -/* read in a variable - * This covers both msgvar and sysvar from the ABNF. - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetVar(ctok_t *pThis, ctok_token_t *pToken) -{ - DEFiRet; - uchar c; - cstr_t *pstrVal = NULL; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pToken != NULL); - - CHKiRet(ctokGetCharFromStream(pThis, &c)); - - if(c == '$') { /* second dollar, we have a system variable */ - pToken->tok = ctok_SYSVAR; - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */ - } else if(c == '!') { /* cee variable indicator */ - pToken->tok = ctok_CEEVAR; - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* "eat" it... */ - } else { - pToken->tok = ctok_MSGVAR; - } - - CHKiRet(cstrConstruct(&pstrVal)); - /* this loop is quite simple, a variable name is terminated when a non-supported - * character is detected. Note that we currently permit a numerical digit as the - * first char, which is not permitted by ABNF. -- rgerhards, 2009-03-10 - */ - while(isalpha(c) || isdigit(c) || (c == '_') || (c == '-')) { - CHKiRet(cstrAppendChar(pstrVal, tolower(c))); - CHKiRet(ctokGetCharFromStream(pThis, &c)); - } - CHKiRet(ctokUngetCharFromStream(pThis, c)); /* put not processed char back */ - - CHKiRet(cstrFinalize(pstrVal)); - - CHKiRet(var.SetString(pToken->pVar, pstrVal)); - pstrVal = NULL; - -finalize_it: - if(iRet != RS_RET_OK) { - if(pstrVal != NULL) { - cstrDestruct(&pstrVal); - } - } - - RETiRet; -} - - -/* read in a simple string (simpstr in ABNF) - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetSimpStr(ctok_t *pThis, ctok_token_t *pToken) -{ - DEFiRet; - uchar c; - int bInEsc = 0; - cstr_t *pstrVal; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pToken != NULL); - - pToken->tok = ctok_SIMPSTR; - - CHKiRet(cstrConstruct(&pstrVal)); - CHKiRet(ctokGetCharFromStreamNoComment(pThis, &c)); - /* while we are in escape mode (had a backslash), no sequence - * terminates the loop. If outside, it is terminated by a single quote. - */ - while(bInEsc || c != '\'') { - if(bInEsc) { - CHKiRet(cstrAppendChar(pstrVal, c)); - bInEsc = 0; - } else { - if(c == '\\') { - bInEsc = 1; - } else { - CHKiRet(cstrAppendChar(pstrVal, c)); - } - } - CHKiRet(ctokGetCharFromStreamNoComment(pThis, &c)); - } - CHKiRet(cstrFinalize(pstrVal)); - - CHKiRet(var.SetString(pToken->pVar, pstrVal)); - pstrVal = NULL; - -finalize_it: - if(iRet != RS_RET_OK) { - if(pstrVal != NULL) { - cstrDestruct(&pstrVal); - } - } - - RETiRet; -} - - -/* Unget a token. The token ungotten will be returned the next time - * ctokGetToken() is called. Only one token can be ungotten at a time. - * If a second token is ungotten, the first is lost. This is considered - * a programming error. - * rgerhards, 2008-02-20 - */ -static rsRetVal -ctokUngetToken(ctok_t *pThis, ctok_token_t *pToken) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(pToken != NULL); - ASSERT(pThis->pUngotToken == NULL); - - pThis->pUngotToken = pToken; - - RETiRet; -} - - -/* skip an inine comment (just like a C-comment) - * rgerhards, 2008-02-20 - */ -static rsRetVal -ctokSkipInlineComment(ctok_t *pThis) -{ - DEFiRet; - uchar c; - int bHadAsterisk = 0; - - ISOBJ_TYPE_assert(pThis, ctok); - - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */ - while(!(bHadAsterisk && c == '/')) { - bHadAsterisk = (c == '*') ? 1 : 0; - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read next */ - } - -finalize_it: - RETiRet; -} - - - -/* Get the *next* token from the input stream. This parses the next token and - * ignores any whitespace in between. End of stream is communicated via iRet. - * The returned token must either be destructed by the caller OR being passed - * back to ctokUngetToken(). - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetToken(ctok_t *pThis, ctok_token_t **ppToken) -{ - DEFiRet; - ctok_token_t *pToken; - uchar c; - uchar szWord[128]; - int bRetry = 0; /* retry parse? Only needed for inline comments... */ - cstr_t *pstrVal; - - ISOBJ_TYPE_assert(pThis, ctok); - ASSERT(ppToken != NULL); - - /* first check if we have an ungotten token and, if so, provide that - * one back (without any parsing). -- rgerhards, 2008-02-20 - */ - if(pThis->pUngotToken != NULL) { - *ppToken = pThis->pUngotToken; - pThis->pUngotToken = NULL; - FINALIZE; - } - - /* setup the stage - create our token */ - CHKiRet(ctok_token.Construct(&pToken)); - CHKiRet(ctok_token.ConstructFinalize(pToken)); - - /* find the next token. We may loop when we have inline comments */ - do { - bRetry = 0; - CHKiRet(ctokSkipWhitespaceFromStream(pThis)); - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */ - switch(c) { - case '=': /* == */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a character */ - pToken->tok = (c == '=')? ctok_CMP_EQ : ctok_INVALID; - break; - case '!': /* != */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a character */ - pToken->tok = (c == '=')? ctok_CMP_NEQ : ctok_INVALID; - break; - case '<': /* <, <=, <> */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a character */ - if(c == '=') { - pToken->tok = ctok_CMP_LTEQ; - } else if(c == '>') { - pToken->tok = ctok_CMP_NEQ; - } else { - pToken->tok = ctok_CMP_LT; - } - break; - case '>': /* >, >= */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a character */ - if(c == '=') { - pToken->tok = ctok_CMP_GTEQ; - } else { - pToken->tok = ctok_CMP_GT; - } - break; - case '+': - pToken->tok = ctok_PLUS; - break; - case '-': - pToken->tok = ctok_MINUS; - break; - case '*': - pToken->tok = ctok_TIMES; - break; - case '/': /* /, /.* ... *./ (comments, mungled here for obvious reasons...) */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */ - if(c == '*') { - /* we have a comment and need to skip it */ - ctokSkipInlineComment(pThis); - bRetry = 1; - } else { - CHKiRet(ctokUngetCharFromStream(pThis, c)); /* put back, not processed */ - } - pToken->tok = ctok_DIV; - break; - case '%': - pToken->tok = ctok_MOD; - break; - case '(': - pToken->tok = ctok_LPAREN; - break; - case ')': - pToken->tok = ctok_RPAREN; - break; - case ',': - pToken->tok = ctok_COMMA; - break; - case '&': - pToken->tok = ctok_STRADD; - break; - case '$': - CHKiRet(ctokGetVar(pThis, pToken)); - break; - case '\'': /* simple string, this is somewhat more elaborate */ - CHKiRet(ctokGetSimpStr(pThis, pToken)); - break; - case '"': - /* TODO: template string parser */ - ABORT_FINALIZE(RS_RET_NOT_IMPLEMENTED); - break; - default: - CHKiRet(ctokUngetCharFromStream(pThis, c)); /* push back, we need it in any case */ - if(isdigit(c)) { - CHKiRet(ctokGetNumber(pThis, pToken)); - } else { /* now we check if we have a multi-char sequence */ - CHKiRet(ctokGetWordFromStream(pThis, szWord, sizeof(szWord)/sizeof(uchar))); - if(!strcasecmp((char*)szWord, "and")) { - pToken->tok = ctok_AND; - } else if(!strcasecmp((char*)szWord, "or")) { - pToken->tok = ctok_OR; - } else if(!strcasecmp((char*)szWord, "not")) { - pToken->tok = ctok_NOT; - } else if(!strcasecmp((char*)szWord, "contains")) { - pToken->tok = ctok_CMP_CONTAINS; - } else if(!strcasecmp((char*)szWord, "contains_i")) { - pToken->tok = ctok_CMP_CONTAINSI; - } else if(!strcasecmp((char*)szWord, "startswith")) { - pToken->tok = ctok_CMP_STARTSWITH; - } else if(!strcasecmp((char*)szWord, "startswith_i")) { - pToken->tok = ctok_CMP_STARTSWITHI; - } else if(!strcasecmp((char*)szWord, "then")) { - pToken->tok = ctok_THEN; - } else { - /* finally, we check if it is a function */ - CHKiRet(ctokGetCharFromStream(pThis, &c)); /* read a charater */ - if(c == '(') { - /* push c back, higher level parser needs it */ - CHKiRet(ctokUngetCharFromStream(pThis, c)); - pToken->tok = ctok_FUNCTION; - /* fill function name */ - CHKiRet(cstrConstruct(&pstrVal)); - CHKiRet(rsCStrSetSzStr(pstrVal, szWord)); - CHKiRet(cstrFinalize(pstrVal)); - CHKiRet(var.SetString(pToken->pVar, pstrVal)); - } else { /* give up... */ - dbgprintf("parser has an invalid word (token) '%s'\n", szWord); - pToken->tok = ctok_INVALID; - } - } - } - break; - } - } while(bRetry); /* warning: do ... while()! */ - - *ppToken = pToken; - dbgoprint((obj_t*) pToken, "token: %d\n", pToken->tok); - -finalize_it: -/*dbgprintf("ctokGetToken, returns %d, returns token %d, addr %p\n", iRet, (*ppToken)->tok, &((*ppToken)->tok));*/ - if(iRet != RS_RET_OK) { - if(pToken != NULL) - ctok_token.Destruct(&pToken); - } - - RETiRet; -} - - -/* property set methods */ -/* simple ones first */ -DEFpropSetMeth(ctok, pp, uchar*) - -/* return the current position of pp - most important as currently we do only - * partial parsing, so the rest must know where to start from... - * rgerhards, 2008-02-19 - */ -static rsRetVal -ctokGetpp(ctok_t *pThis, uchar **pp) -{ - DEFiRet; - ASSERT(pp != NULL); - *pp = pThis->pp; - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(ctok) -CODESTARTobjQueryInterface(ctok) - if(pIf->ifVersion != ctokCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = ctokConstruct; - pIf->ConstructFinalize = ctokConstructFinalize; - pIf->Destruct = ctokDestruct; - pIf->Getpp = ctokGetpp; - pIf->GetToken = ctokGetToken; - pIf->UngetToken = ctokUngetToken; - pIf->Setpp = ctokSetpp; -finalize_it: -ENDobjQueryInterface(ctok) - - - -BEGINObjClassInit(ctok, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(ctok_token, CORE_COMPONENT)); - CHKiRet(objUse(var, CORE_COMPONENT)); - - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, ctokConstructFinalize); -ENDObjClassInit(ctok) - -/* vi:set ai: - */ diff --git a/runtime/ctok.h b/runtime/ctok.h deleted file mode 100644 index 591f0838..00000000 --- a/runtime/ctok.h +++ /dev/null @@ -1,56 +0,0 @@ -/* The ctok object (implements a config file tokenizer). - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_CTOK_H -#define INCLUDED_CTOK_H - -#include "obj.h" -#include "stringbuf.h" -#include "ctok_token.h" - -/* the ctokession object */ -typedef struct ctok_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - uchar *pp; /* this points to the next unread character, it is a reminescent of pp in - the config parser code ;) */ - ctok_token_t *pUngotToken; /* buffer for ctokUngetToken(), NULL if not set */ -} ctok_t; - - -/* interfaces */ -BEGINinterface(ctok) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(ctok); - INTERFACEpropSetMeth(ctok, pp, uchar*); - rsRetVal (*Construct)(ctok_t **ppThis); - rsRetVal (*ConstructFinalize)(ctok_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(ctok_t **ppThis); - rsRetVal (*Getpp)(ctok_t *pThis, uchar **pp); - rsRetVal (*GetToken)(ctok_t *pThis, ctok_token_t **ppToken); - rsRetVal (*UngetToken)(ctok_t *pThis, ctok_token_t *pToken); -ENDinterface(ctok) -#define ctokCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(ctok); - -#endif /* #ifndef INCLUDED_CTOK_H */ diff --git a/runtime/ctok_token.c b/runtime/ctok_token.c deleted file mode 100644 index 8c17f693..00000000 --- a/runtime/ctok_token.c +++ /dev/null @@ -1,129 +0,0 @@ -/* ctok_token - implements the token_t class. - * - * Module begun 2008-02-20 by Rainer Gerhards - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include -#include - -#include "rsyslog.h" -#include "template.h" -#include "ctok_token.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(var) - - -/* Standard-Constructor - */ -BEGINobjConstruct(ctok_token) /* be sure to specify the object type also in END macro! */ - /* TODO: we may optimize the code below and alloc var only if actually - * needed (but we need it quite often) - */ - CHKiRet(var.Construct(&pThis->pVar)); - CHKiRet(var.ConstructFinalize(pThis->pVar)); -finalize_it: -ENDobjConstruct(ctok_token) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -rsRetVal ctok_tokenConstructFinalize(ctok_token_t __attribute__((unused)) *pThis) -{ - DEFiRet; - RETiRet; -} - - -/* destructor for the ctok object */ -BEGINobjDestruct(ctok_token) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(ctok_token) - if(pThis->pVar != NULL) { - var.Destruct(&pThis->pVar); - } -ENDobjDestruct(ctok_token) - - -/* get the cstr_t from the token, but do not destruct it. This is meant to - * be used by a caller who passes on the string to some other function. The - * caller is responsible for destructing it. - * rgerhards, 2008-02-20 - */ -static rsRetVal -ctok_tokenUnlinkVar(ctok_token_t *pThis, var_t **ppVar) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, ctok_token); - ASSERT(ppVar != NULL); - - *ppVar = pThis->pVar; - pThis->pVar = NULL; - - RETiRet; -} - - -/* tell the caller if the supplied token is a compare operation */ -static int ctok_tokenIsCmpOp(ctok_token_t *pThis) -{ - return(pThis->tok >= ctok_CMP_EQ && pThis->tok <= ctok_CMP_GTEQ); -} - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(ctok_token) -CODESTARTobjQueryInterface(ctok_token) - if(pIf->ifVersion != ctok_tokenCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = ctok_tokenConstruct; - pIf->ConstructFinalize = ctok_tokenConstructFinalize; - pIf->Destruct = ctok_tokenDestruct; - pIf->UnlinkVar = ctok_tokenUnlinkVar; - pIf->IsCmpOp = ctok_tokenIsCmpOp; -finalize_it: -ENDobjQueryInterface(ctok_token) - - -BEGINObjClassInit(ctok_token, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, ctok_tokenConstructFinalize); -ENDObjClassInit(ctok_token) - -/* vi:set ai: - */ diff --git a/runtime/ctok_token.h b/runtime/ctok_token.h deleted file mode 100644 index 1413c699..00000000 --- a/runtime/ctok_token.h +++ /dev/null @@ -1,88 +0,0 @@ -/* The ctok_token object - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_CTOK_TOKEN_H -#define INCLUDED_CTOK_TOKEN_H - -#include "obj.h" -#include "var.h" - -/* the tokens... I use numbers below so that the tokens can be easier - * identified in debug output. These ID's are also partly resused as opcodes. - * As such, they should be kept below 1,000 so that they do not interfer - * with the rest of the opcodes. - */ -typedef struct { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - enum { - ctok_INVALID = 0, - ctok_OR = 1, - ctok_AND = 2, - ctok_PLUS = 3, - ctok_MINUS = 4, - ctok_TIMES = 5, /* "*" */ - ctok_DIV = 6, - ctok_MOD = 7, - ctok_NOT = 8, - ctok_RPAREN = 9, - ctok_LPAREN = 10, - ctok_COMMA = 11, - ctok_SYSVAR = 12, - ctok_MSGVAR = 13, - ctok_SIMPSTR = 14, - ctok_TPLSTR = 15, - ctok_NUMBER = 16, - ctok_FUNCTION = 17, - ctok_THEN = 18, - ctok_STRADD = 19, - ctok_CEEVAR = 20, - ctok_CMP_EQ = 100, /* all compare operations must be in a row */ - ctok_CMP_NEQ = 101, - ctok_CMP_LT = 102, - ctok_CMP_GT = 103, - ctok_CMP_LTEQ = 104, - ctok_CMP_CONTAINS = 105, - ctok_CMP_STARTSWITH = 106, - ctok_CMP_CONTAINSI = 107, - ctok_CMP_STARTSWITHI = 108, - ctok_CMP_GTEQ = 109 /* end compare operations */ - } tok; - var_t *pVar; -} ctok_token_t; - - -/* interfaces */ -BEGINinterface(ctok_token) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(ctok_token); - rsRetVal (*Construct)(ctok_token_t **ppThis); - rsRetVal (*ConstructFinalize)(ctok_token_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(ctok_token_t **ppThis); - rsRetVal (*UnlinkVar)(ctok_token_t *pThis, var_t **ppVar); - int (*IsCmpOp)(ctok_token_t *pThis); -ENDinterface(ctok_token) -#define ctok_tokenCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(ctok_token); - -#endif /* #ifndef INCLUDED_CTOK_TOKEN_H */ diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index c5abcb2a..5d5fdda2 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -66,7 +66,6 @@ #include "stringbuf.h" #include "wti.h" #include "wtp.h" -#include "ctok.h" #include "datetime.h" #include "queue.h" #include "conf.h" @@ -173,10 +172,6 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(glblClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "msg"; CHKiRet(msgClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "ctok_token"; - CHKiRet(ctok_tokenClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "ctok"; - CHKiRet(ctokClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "sysvar"; CHKiRet(sysvarClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "rule"; -- cgit v1.2.3 From 31900e004bbfd6da025e64844e2a07247dc87e94 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 15:36:05 +0200 Subject: more cleanup... --- runtime/Makefile.am | 2 - runtime/datetime.c | 1 - runtime/errmsg.c | 1 - runtime/rsyslog.c | 3 - runtime/statsobj.c | 1 - runtime/sysvar.c | 204 ---------------------------------------------------- runtime/sysvar.h | 47 ------------ 7 files changed, 259 deletions(-) delete mode 100644 runtime/sysvar.c delete mode 100644 runtime/sysvar.h diff --git a/runtime/Makefile.am b/runtime/Makefile.am index 74ba2ab7..ac4f4279 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -63,8 +63,6 @@ librsyslog_la_SOURCES = \ wtp.h \ wti.c \ wti.h \ - sysvar.c \ - sysvar.h \ queue.c \ queue.h \ ruleset.c \ diff --git a/runtime/datetime.c b/runtime/datetime.c index 89452f1c..753d2068 100644 --- a/runtime/datetime.c +++ b/runtime/datetime.c @@ -40,7 +40,6 @@ #include "obj.h" #include "modules.h" #include "datetime.h" -#include "sysvar.h" #include "srUtils.h" #include "stringbuf.h" #include "errmsg.h" diff --git a/runtime/errmsg.c b/runtime/errmsg.c index 3c3ee02c..d9062931 100644 --- a/runtime/errmsg.c +++ b/runtime/errmsg.c @@ -35,7 +35,6 @@ #include "rsyslog.h" #include "obj.h" #include "errmsg.h" -#include "sysvar.h" #include "srUtils.h" #include "stringbuf.h" diff --git a/runtime/rsyslog.c b/runtime/rsyslog.c index 5d5fdda2..cbab06b7 100644 --- a/runtime/rsyslog.c +++ b/runtime/rsyslog.c @@ -62,7 +62,6 @@ #include "rsyslog.h" #include "obj.h" -#include "sysvar.h" #include "stringbuf.h" #include "wti.h" #include "wtp.h" @@ -172,8 +171,6 @@ rsrtInit(char **ppErrObj, obj_if_t *pObjIF) CHKiRet(glblClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "msg"; CHKiRet(msgClassInit(NULL)); - if(ppErrObj != NULL) *ppErrObj = "sysvar"; - CHKiRet(sysvarClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "rule"; CHKiRet(ruleClassInit(NULL)); if(ppErrObj != NULL) *ppErrObj = "ruleset"; diff --git a/runtime/statsobj.c b/runtime/statsobj.c index e1a89cf4..d1213a34 100644 --- a/runtime/statsobj.c +++ b/runtime/statsobj.c @@ -36,7 +36,6 @@ #include "unicode-helper.h" #include "obj.h" #include "statsobj.h" -#include "sysvar.h" #include "srUtils.h" #include "stringbuf.h" diff --git a/runtime/sysvar.c b/runtime/sysvar.c deleted file mode 100644 index ecc31e2d..00000000 --- a/runtime/sysvar.c +++ /dev/null @@ -1,204 +0,0 @@ -/* sysvar.c - imlements rsyslog system variables - * - * At least for now, this class only has static functions and no - * instances. - * - * Module begun 2008-02-25 by Rainer Gerhards - * - * Copyright (C) 2008 by Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include - -#include "rsyslog.h" -#include "obj.h" -#include "stringbuf.h" -#include "sysvar.h" -#include "datetime.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(var) -DEFobjCurrIf(datetime) -DEFobjCurrIf(glbl) - - -/* Standard-Constructor - */ -BEGINobjConstruct(sysvar) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(sysvar) - - -/* ConstructionFinalizer - * rgerhards, 2008-01-09 - */ -static rsRetVal -sysvarConstructFinalize(sysvar_t __attribute__((unused)) *pThis) -{ - DEFiRet; - RETiRet; -} - - -/* destructor for the sysvar object */ -BEGINobjDestruct(sysvar) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(sysvar) -ENDobjDestruct(sysvar) - - -/* This function returns the current date in different - * variants. It is used to construct the $NOW series of - * system properties. The returned buffer must be freed - * by the caller when no longer needed. If the function - * can not allocate memory, it returns a NULL pointer. - * Added 2007-07-10 rgerhards - * TODO: this was taken from msg.c and we should consolidate it with the code - * there. This is especially important when we increase the number of system - * variables (what we definitely want to do). - */ -typedef enum ENOWType { NOW_NOW, NOW_YEAR, NOW_MONTH, NOW_DAY, NOW_HOUR, NOW_MINUTE } eNOWType; -static rsRetVal -getNOW(eNOWType eNow, cstr_t **ppStr) -{ - DEFiRet; - uchar szBuf[16]; - struct syslogTime t; - - datetime.getCurrTime(&t, NULL); - switch(eNow) { - case NOW_NOW: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%4.4d-%2.2d-%2.2d", t.year, t.month, t.day); - break; - case NOW_YEAR: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%4.4d", t.year); - break; - case NOW_MONTH: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.month); - break; - case NOW_DAY: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.day); - break; - case NOW_HOUR: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.hour); - break; - case NOW_MINUTE: - snprintf((char*) szBuf, sizeof(szBuf)/sizeof(uchar), "%2.2d", t.minute); - break; - } - - /* now create a string object out of it and hand that over to the var */ - CHKiRet(rsCStrConstructFromszStr(ppStr, szBuf)); - -finalize_it: - RETiRet; -} - - -/* The function returns a system variable suitable for use with RainerScript. Most importantly, this means - * that the value is returned in a var_t object. The var_t is constructed inside this function and - * MUST be freed by the caller. - * rgerhards, 2008-02-25 - */ -static rsRetVal -GetVar(cstr_t *pstrVarName, var_t **ppVar) -{ - DEFiRet; - var_t *pVar; - cstr_t *pstrProp; - - ASSERT(pstrVarName != NULL); - ASSERT(ppVar != NULL); - - /* make sure we have a var_t instance */ - CHKiRet(var.Construct(&pVar)); - CHKiRet(var.ConstructFinalize(pVar)); - - /* now begin the actual variable evaluation */ - if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"now", sizeof("now") - 1)) { - CHKiRet(getNOW(NOW_NOW, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"year", sizeof("year") - 1)) { - CHKiRet(getNOW(NOW_YEAR, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"month", sizeof("month") - 1)) { - CHKiRet(getNOW(NOW_MONTH, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"day", sizeof("day") - 1)) { - CHKiRet(getNOW(NOW_DAY, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"hour", sizeof("hour") - 1)) { - CHKiRet(getNOW(NOW_HOUR, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"minute", sizeof("minute") - 1)) { - CHKiRet(getNOW(NOW_MINUTE, &pstrProp)); - } else if(!rsCStrSzStrCmp(pstrVarName, (uchar*)"myhostname", sizeof("myhostname") - 1)) { - CHKiRet(rsCStrConstructFromszStr(&pstrProp, glbl.GetLocalHostName())); - } else { - ABORT_FINALIZE(RS_RET_SYSVAR_NOT_FOUND); - } - - /* now hand the string over to the var object */ - CHKiRet(var.SetString(pVar, pstrProp)); - - /* finally store var */ - *ppVar = pVar; - -finalize_it: - RETiRet; -} - - -/* queryInterface function - * rgerhards, 2008-02-21 - */ -BEGINobjQueryInterface(sysvar) -CODESTARTobjQueryInterface(sysvar) - if(pIf->ifVersion != sysvarCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = sysvarConstruct; - pIf->ConstructFinalize = sysvarConstructFinalize; - pIf->Destruct = sysvarDestruct; - pIf->GetVar = GetVar; -finalize_it: -ENDobjQueryInterface(sysvar) - - -/* Initialize the sysvar class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(sysvar, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); - CHKiRet(objUse(datetime, CORE_COMPONENT)); - CHKiRet(objUse(glbl, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, sysvarConstructFinalize); -ENDObjClassInit(sysvar) - -/* vi:set ai: - */ diff --git a/runtime/sysvar.h b/runtime/sysvar.h deleted file mode 100644 index 35051b64..00000000 --- a/runtime/sysvar.h +++ /dev/null @@ -1,47 +0,0 @@ -/* The sysvar object. So far, no instance can be defined (makes logically no - * sense). - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_SYSVAR_H -#define INCLUDED_SYSVAR_H - -/* the sysvar object - not really used... */ -typedef struct sysvar_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ -} sysvar_t; - - -/* interfaces */ -BEGINinterface(sysvar) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(sysvar); - rsRetVal (*Construct)(sysvar_t **ppThis); - rsRetVal (*ConstructFinalize)(sysvar_t __attribute__((unused)) *pThis); - rsRetVal (*Destruct)(sysvar_t **ppThis); - rsRetVal (*GetVar)(cstr_t *pstrPropName, var_t **ppVar); -ENDinterface(sysvar) -#define sysvarCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(sysvar); - -#endif /* #ifndef INCLUDED_SYSVAR_H */ -- cgit v1.2.3 From 05ff79aa1f928e42bf9883e946923353eb2925ac Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 15:44:04 +0200 Subject: even more cleanup ;) --- runtime/msg.c | 99 ---------------------------------------------------------- runtime/rule.c | 6 ---- 2 files changed, 105 deletions(-) diff --git a/runtime/msg.c b/runtime/msg.c index 0de805a7..b440d6ca 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -47,7 +47,6 @@ #include "stringbuf.h" #include "template.h" #include "msg.h" -#include "var.h" #include "datetime.h" #include "glbl.h" #include "regexp.h" @@ -3146,104 +3145,6 @@ done: } -/* The function returns a cee variable suitable for use with RainerScript. Most importantly, this means - * that the value is returned in a var_t object. The var_t is constructed inside this function and - * MUST be freed by the caller. - * Note that we need to do a lot of conversions between es_str_t and cstr -- this will go away once - * we have moved larger parts of rsyslog to es_str_t. Acceptable for the moment, especially as we intend - * to rewrite the script engine as well! - * rgerhards, 2010-12-03 - * - */ -rsRetVal -msgGetCEEVar(msg_t *pMsg, cstr_t *propName, var_t **ppVar) -{ -#warning remove as part of cleanup - DEFiRet; - var_t *pVar; - cstr_t *pstrProp; - es_str_t *str = NULL; - es_str_t *epropName = NULL; - int r; - - ISOBJ_TYPE_assert(pMsg, msg); - ASSERT(propName != NULL); - ASSERT(ppVar != NULL); - - /* make sure we have a var_t instance */ - CHKiRet(var.Construct(&pVar)); - CHKiRet(var.ConstructFinalize(pVar)); - - epropName = es_newStrFromBuf((char*)propName->pBuf, propName->iStrLen); - r = ee_getEventFieldAsString(pMsg->event, epropName, &str); - - if(r != EE_OK) { - DBGPRINTF("msgGtCEEVar: libee error %d during ee_getEventFieldAsString\n", r); - CHKiRet(cstrConstruct(&pstrProp)); - CHKiRet(cstrFinalize(pstrProp)); - } else { - CHKiRet(cstrConstructFromESStr(&pstrProp, str)); - } - - /* now create a string object out of it and hand that over to the var */ - CHKiRet(var.SetString(pVar, pstrProp)); - es_deleteStr(str); - - /* finally store var */ - *ppVar = pVar; - -finalize_it: - if(epropName != NULL) - es_deleteStr(epropName); - RETiRet; -} - - -/* The returns a message variable suitable for use with RainerScript. Most importantly, this means - * that the value is returned in a var_t object. The var_t is constructed inside this function and - * MUST be freed by the caller. - * rgerhards, 2008-02-25 - */ -rsRetVal -msgGetMsgVar(msg_t *pThis, cstr_t *pstrPropName, var_t **ppVar) -{ - DEFiRet; - var_t *pVar; - size_t propLen; - uchar *pszProp = NULL; - cstr_t *pstrProp; - propid_t propid; - unsigned short bMustBeFreed = 0; - - ISOBJ_TYPE_assert(pThis, msg); - ASSERT(pstrPropName != NULL); - ASSERT(ppVar != NULL); - - /* make sure we have a var_t instance */ - CHKiRet(var.Construct(&pVar)); - CHKiRet(var.ConstructFinalize(pVar)); - - /* always call MsgGetProp() without a template specifier */ - /* TODO: optimize propNameToID() call -- rgerhards, 2009-06-26 */ - propNameToID(pstrPropName, &propid); - pszProp = (uchar*) MsgGetProp(pThis, NULL, propid, NULL, &propLen, &bMustBeFreed); - - /* now create a string object out of it and hand that over to the var */ - CHKiRet(rsCStrConstructFromszStr(&pstrProp, pszProp)); - CHKiRet(var.SetString(pVar, pstrProp)); - - /* finally store var */ - *ppVar = pVar; - -finalize_it: - if(bMustBeFreed) - free(pszProp); - - RETiRet; -} - - - /* Return an es_str_t for given message property. */ es_str_t* diff --git a/runtime/rule.c b/runtime/rule.c index 1a430577..cbd2660d 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -36,7 +36,6 @@ #include "action.h" #include "rule.h" #include "errmsg.h" -#include "var.h" #include "srUtils.h" #include "batch.h" #include "parserif.h" @@ -121,7 +120,6 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) uchar *pszPropVal; int bRet = 0; size_t propLen; - var_t *pResult = NULL; ISOBJ_TYPE_assert(pRule, rule); assert(pMsg != NULL); @@ -262,10 +260,6 @@ shouldProcessThisMessage(rule_t *pRule, msg_t *pMsg, sbool *bProcessMsg) } finalize_it: - /* destruct in any case, not just on error, but it makes error handling much easier */ - if(pResult != NULL) - var.Destruct(&pResult); - *bProcessMsg = bRet; RETiRet; } -- cgit v1.2.3 From cefa1fac08d4d67a4139146016fef206d59d5ddc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 16:51:30 +0200 Subject: fixed lexer: facilities local0-local7 were not correctly handled --- grammar/lexer.l | 6 +++++- runtime/rsconf.c | 3 ++- tests/diag.sh | 4 ++-- tests/imtcp_conndrop.sh | 1 - tests/testsuites/imtcp_conndrop.conf | 1 - 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/grammar/lexer.l b/grammar/lexer.l index 64a804fa..d56b4fc2 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -80,6 +80,8 @@ char *currfn; /* name of currently processed file */ int popfile(void); int cnfSetLexFile(char *fname); +extern int yydebug; + /* somehow, I need these prototype even though the headers are * included. I guess that's some autotools magic I don't understand... */ @@ -155,7 +157,7 @@ int fileno(FILE *stream); "action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { yylval.s = strdup(yytext); return PROPFILT; } -^[ \t]*[,\*a-z]+\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } +^[ \t]*[a-z][,\*a-z]*[0-7]*\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } "*" | \-\/[^*][^\n]* | \/[^*][^\n]* | @@ -203,6 +205,8 @@ cnfParseBuffer(char *buf, unsigned lenBuf) { struct bufstack *bs; int r = 0; + yydebug = 1; + BEGIN INITIAL; /* maintain stack */ if((bs = malloc(sizeof(struct bufstack))) == NULL) { r = 1; diff --git a/runtime/rsconf.c b/runtime/rsconf.c index ac969286..d2cb9332 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -1256,9 +1256,10 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!"); emergConf = "*.err " _PATH_CONSOLE "\n" - "syslog.*" _PATH_CONSOLE "\n" + "syslog.* " _PATH_CONSOLE "\n" "*.panic :omusrmsg:*" "\n" "syslog.* :omusrmsg:root" "\n"; +dbgprintf("Emer Config '%s'\n",emergConf); cnfParseBuffer(emergConf, strlen(emergConf)); r = yyparse(); if(r != 0) { diff --git a/tests/diag.sh b/tests/diag.sh index 1f7de2cf..f2bcc4b8 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -10,8 +10,8 @@ #valgrind="valgrind --tool=helgrind --log-fd=1" #valgrind="valgrind --tool=exp-ptrcheck --log-fd=1" #set -o xtrace -#export RSYSLOG_DEBUG="debug nologfuncflow noprintmutexaction stdout" -#export RSYSLOG_DEBUGLOG="log" +export RSYSLOG_DEBUG="debug nologfuncflow noprintmutexaction stdout" +export RSYSLOG_DEBUGLOG="log" case $1 in 'init') $srcdir/killrsyslog.sh # kill rsyslogd if it runs for some reason cp $srcdir/testsuites/diag-common.conf diag-common.conf diff --git a/tests/imtcp_conndrop.sh b/tests/imtcp_conndrop.sh index 0bfcd99c..c5073924 100755 --- a/tests/imtcp_conndrop.sh +++ b/tests/imtcp_conndrop.sh @@ -4,7 +4,6 @@ # This file is part of the rsyslog project, released under GPLv3 echo ==================================================================================== echo TEST: \[imtcp_conndrop.sh\]: test imtcp with random connection drops -cat rsyslog.action.1.include source $srcdir/diag.sh init source $srcdir/diag.sh startup imtcp_conndrop.conf # 100 byte messages to gain more practical data use diff --git a/tests/testsuites/imtcp_conndrop.conf b/tests/testsuites/imtcp_conndrop.conf index b64f132b..de41bc43 100644 --- a/tests/testsuites/imtcp_conndrop.conf +++ b/tests/testsuites/imtcp_conndrop.conf @@ -12,5 +12,4 @@ $template dynfile,"rsyslog.out.log" # trick to use relative path names! $OMFileFlushOnTXEnd off $OMFileFlushInterval 2 $OMFileIOBufferSize 256k -$IncludeConfig rsyslog.action.1.include local0.* ?dynfile;outfmt -- cgit v1.2.3 From 80701b698802efe1bcecac09afcd393dd4bd3d5c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 11 Jul 2011 17:32:26 +0200 Subject: more cleanup, working on emergency config system --- runtime/conf.c | 7 ++++-- runtime/conf.h | 1 - runtime/rsconf.c | 67 +++++++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 59 insertions(+), 16 deletions(-) diff --git a/runtime/conf.c b/runtime/conf.c index 8c7bc7b6..425d6259 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -75,7 +75,7 @@ #endif /* forward definitions */ -static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); +//static rsRetVal cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr); /* static data */ @@ -715,6 +715,7 @@ finalize_it: } +#if 0 /* read the filter part of a configuration line and store the filter * in the supplied rule_t * rgerhards, 2007-08-01 @@ -751,6 +752,7 @@ static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) finalize_it: RETiRet; } +#endif /* process the action part of a selector line @@ -817,6 +819,7 @@ rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) } +#if 0 /* Process a configuration file line in traditional "filter selector" format * or one that builds upon this format. Note that ppRule may be a NULL pointer, * which is valid and happens if there is no previous line (right at the start @@ -894,6 +897,7 @@ cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr) RETiRet; } +#endif /* return the current number of active actions @@ -926,7 +930,6 @@ CODESTARTobjQueryInterface(conf) pIf->doNameLine = doNameLine; pIf->cfsysline = cfsysline; pIf->doModLoad = doModLoad; - pIf->cfline = cfline; pIf->GetNbrActActions = GetNbrActActions; finalize_it: diff --git a/runtime/conf.h b/runtime/conf.h index a74b99c5..9253e880 100644 --- a/runtime/conf.h +++ b/runtime/conf.h @@ -37,7 +37,6 @@ BEGINinterface(conf) /* name must also be changed in ENDinterface macro! */ rsRetVal (*doNameLine)(uchar **pp, void* pVal); rsRetVal (*cfsysline)(uchar *p); rsRetVal (*doModLoad)(uchar **pp, __attribute__((unused)) void* pVal); - rsRetVal (*cfline)(rsconf_t *conf, uchar *line, rule_t **pfCurr); rsRetVal (*GetNbrActActions)(rsconf_t *conf, int *); /* version 4 -- 2010-07-23 rgerhards */ /* "just" added global variables diff --git a/runtime/rsconf.c b/runtime/rsconf.c index d2cb9332..2f0287c2 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -1206,6 +1206,56 @@ validateConf(void) } +#if 0 +/* create an emergency rule */ +static inline rsRetVal +createEmergRule(char *PRIFilt, char *legact) +{ + rule_t *pRule; + action_t *pAction; + DEFiRet; + + CHKiRet(rule.Construct(&pRule)); /* create "fresh" selector */ + CHKiRet(rule.SetAssRuleset(pRule, ruleset.GetCurrent(loadConf))); + CHKiRet(rule.ConstructFinalize(pRule)); + CHKiRet(cflineProcessTradPRIFilter((uchar**)&PRIFilt, pRule)); + iRet = cflineDoAction(loadConf, (uchar**)&legact, &pAction); + iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction); + CHKiRet(ruleset.AddRule(loadConf, rule.GetAssRuleset(pRule), &pRule)); + +finalize_it: + RETiRet; +} + + +/* start up an rsyslog emergency configuration. This is recovery if + * the config failed. + */ +static inline rsRetVal +createEmergConf(void) +{ + DEFiRet; + errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - " + "fix rsyslog config file!"); + /* + CHKiRet(rsconfConstruct(&loadConf)); +ourConf = loadConf; // TODO: remove, once ourConf is gone! + CHKiRet(loadBuildInModules()); + CHKiRet(initLegacyConf()); + */ + ruleset.SetDefaultRuleset(loadConf, (uchar*) "RSYSLOG_DefaultRuleset"); + + CHKiRet(createEmergRule("*.err", _PATH_CONSOLE)); + CHKiRet(createEmergRule("syslog.*", _PATH_CONSOLE)); + CHKiRet(createEmergRule("*.panic", ":omusrmsg:*")); + CHKiRet(createEmergRule("syslog.*", ":omusrmsg:root")); +CHKiRet(createEmergRule("*.*", "/tmp/emerg")); +finalize_it: + RETiRet; +} +#endif + + /* Load a configuration. This will do all necessary steps to create * the in-memory representation of the configuration, including support * for multiple configuration languages. @@ -1219,9 +1269,7 @@ load(rsconf_t **cnf, uchar *confFile) rsRetVal localRet; int iNbrActions; int bHadConfigErr = 0; - char cbuf[BUFSIZ]; int r; - char *emergConf; DEFiRet; CHKiRet(rsconfConstruct(&loadConf)); @@ -1253,17 +1301,10 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! * very clever... So we stick with what we have. * We ignore any errors while doing this - we would be lost anyhow... */ - errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - fix rsyslog config file!"); - emergConf = - "*.err " _PATH_CONSOLE "\n" - "syslog.* " _PATH_CONSOLE "\n" - "*.panic :omusrmsg:*" "\n" - "syslog.* :omusrmsg:root" "\n"; -dbgprintf("Emer Config '%s'\n",emergConf); - cnfParseBuffer(emergConf, strlen(emergConf)); - r = yyparse(); - if(r != 0) { - fprintf(stderr, "rsyslogd: could not even activate emergency conf - terminating\n"); + // TODO: think about this! iRet = createEmergConf(); + if(1) { //if(iRet != RS_RET_OK) { + fprintf(stderr, "rsyslogd: could not even activate emergency " + "conf - terminating\n"); exit(1); } } -- cgit v1.2.3 From a5bc2a8b4bdf8b7834326ae6410c3bc7285fa1e8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 12 Jul 2011 12:14:47 +0200 Subject: removed emergency config, do error reporting on fatal config file error --- grammar/lexer.l | 8 +-- grammar/parserif.h | 1 + runtime/rsconf.c | 101 ++++++----------------------------- runtime/rsyslog.h | 1 + tests/testsuites/imtcp_conndrop.conf | 2 +- tools/syslogd.c | 2 +- 6 files changed, 24 insertions(+), 91 deletions(-) diff --git a/grammar/lexer.l b/grammar/lexer.l index d56b4fc2..0c82a4af 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -75,7 +75,7 @@ struct bufstack { es_str_t *estr; } *currbs = NULL; -char *currfn; /* name of currently processed file */ +char *cnfcurrfn; /* name of currently processed file */ int popfile(void); int cnfSetLexFile(char *fname); @@ -220,7 +220,7 @@ cnfParseBuffer(char *buf, unsigned lenBuf) bs->bs = yy_scan_buffer(buf, lenBuf); bs->estr = NULL; currbs = bs; - currfn = bs->fn; + cnfcurrfn = bs->fn; yylineno = 1; done: return r; } @@ -259,7 +259,7 @@ cnfSetLexFile(char *fname) bs->bs = yy_scan_buffer((char*)es_getBufAddr(str), es_strlen(str)); bs->estr = str; /* needed so we can free it later */ currbs = bs; - currfn = bs->fn; + cnfcurrfn = bs->fn; yylineno = 1; done: @@ -294,6 +294,6 @@ popfile(void) yy_switch_to_buffer(currbs->bs); yylineno = currbs->lineno; - currfn = currbs->fn; + cnfcurrfn = currbs->fn; return 0; } diff --git a/grammar/parserif.h b/grammar/parserif.h index bebb1dfb..58b8fbdd 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -4,6 +4,7 @@ int cnfSetLexFile(char*); int yyparse(); int yydebug; +char *cnfcurrfn; void dbgprintf(char *fmt, ...) __attribute__((format(printf, 1, 2))); void parser_errmsg(char *fmt, ...) __attribute__((format(printf, 1, 2))); diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 2f0287c2..5df4c2c8 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -335,13 +335,14 @@ void parser_errmsg(char *fmt, ...) { va_list ap; + char errBuf[1024]; + va_start(ap, fmt); - // TODO: create useful code ;) 2011-07-06 - errmsg.LogError(0, NO_ERRCODE, "error during parsing on or before line %d", - yylineno); -dbgprintf("error on or before line %d: ", yylineno); - vprintf(fmt, ap); - printf("\n"); + if(vsnprintf(errBuf, sizeof(errBuf), fmt, ap) == sizeof(errBuf)) + errBuf[1024] = '\0'; + errmsg.LogError(0, RS_RET_CONF_PARSE_ERROR, + "error during parsing file %s, on or before line %d: %s", + cnfcurrfn, yylineno, errBuf); va_end(ap); } @@ -1206,56 +1207,6 @@ validateConf(void) } -#if 0 -/* create an emergency rule */ -static inline rsRetVal -createEmergRule(char *PRIFilt, char *legact) -{ - rule_t *pRule; - action_t *pAction; - DEFiRet; - - CHKiRet(rule.Construct(&pRule)); /* create "fresh" selector */ - CHKiRet(rule.SetAssRuleset(pRule, ruleset.GetCurrent(loadConf))); - CHKiRet(rule.ConstructFinalize(pRule)); - CHKiRet(cflineProcessTradPRIFilter((uchar**)&PRIFilt, pRule)); - iRet = cflineDoAction(loadConf, (uchar**)&legact, &pAction); - iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction); - CHKiRet(ruleset.AddRule(loadConf, rule.GetAssRuleset(pRule), &pRule)); - -finalize_it: - RETiRet; -} - - -/* start up an rsyslog emergency configuration. This is recovery if - * the config failed. - */ -static inline rsRetVal -createEmergConf(void) -{ - DEFiRet; - errmsg.LogError(0, NO_ERRCODE, "EMERGENCY CONFIGURATION ACTIVATED - " - "fix rsyslog config file!"); - /* - CHKiRet(rsconfConstruct(&loadConf)); -ourConf = loadConf; // TODO: remove, once ourConf is gone! - CHKiRet(loadBuildInModules()); - CHKiRet(initLegacyConf()); - */ - ruleset.SetDefaultRuleset(loadConf, (uchar*) "RSYSLOG_DefaultRuleset"); - - CHKiRet(createEmergRule("*.err", _PATH_CONSOLE)); - CHKiRet(createEmergRule("syslog.*", _PATH_CONSOLE)); - CHKiRet(createEmergRule("*.panic", ":omusrmsg:*")); - CHKiRet(createEmergRule("syslog.*", ":omusrmsg:root")); -CHKiRet(createEmergRule("*.*", "/tmp/emerg")); -finalize_it: - RETiRet; -} -#endif - - /* Load a configuration. This will do all necessary steps to create * the in-memory representation of the configuration, including support * for multiple configuration languages. @@ -1266,9 +1217,7 @@ finalize_it: rsRetVal load(rsconf_t **cnf, uchar *confFile) { - rsRetVal localRet; int iNbrActions; - int bHadConfigErr = 0; int r; DEFiRet; @@ -1286,37 +1235,19 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! } if(r == 1) { - errmsg.LogError(0, localRet, "CONFIG ERROR: could not interpret master config file '%s'.", confFile); - bHadConfigErr = 1; + errmsg.LogError(0, RS_RET_CONF_PARSE_ERROR, + "CONFIG ERROR: could not interpret master " + "config file '%s'.", confFile); + ABORT_FINALIZE(RS_RET_CONF_PARSE_ERROR); } else if(iNbrActions == 0) { - errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no active actions configured. Inputs will " - "run, but no output whatsoever is created."); - bHadConfigErr = 1; - } - - if(r == 1 || iNbrActions == 0) { - /* rgerhards: this code is executed to set defaults when the - * config file could not be opened. We might think about - * abandoning the run in this case - but this, too, is not - * very clever... So we stick with what we have. - * We ignore any errors while doing this - we would be lost anyhow... - */ - // TODO: think about this! iRet = createEmergConf(); - if(1) { //if(iRet != RS_RET_OK) { - fprintf(stderr, "rsyslogd: could not even activate emergency " - "conf - terminating\n"); - exit(1); - } + errmsg.LogError(0, RS_RET_NO_ACTIONS, "CONFIG ERROR: there are no " + "active actions configured. Inputs will " + "run, but no output whatsoever is created."); + ABORT_FINALIZE(RS_RET_NO_ACTIONS); } CHKiRet(validateConf()); - - /* return warning state if we had some acceptable problems */ - if(bHadConfigErr) { - iRet = RS_RET_NONFATAL_CONFIG_ERR; - } - /* we are done checking the config - now validate if we should actually run or not. * If not, terminate. -- rgerhards, 2008-07-25 * TODO: iConfigVerify -- should it be pulled from the config, or leave as is (option)? @@ -1331,7 +1262,7 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! *cnf = loadConf; // TODO: enable this once all config code is moved to here! loadConf = NULL; - dbgprintf("rsyslog finished loading initial config %p\n", loadConf); + dbgprintf("rsyslog finished loading master config %p\n", loadConf); rsconfDebugPrint(loadConf); finalize_it: diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index d1290aeb..05f45565 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -359,6 +359,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_CMD_GONE_AWAY = -2204,/**< config directive existed, but no longer supported */ RS_RET_ERR_SCHED_PARAMS = -2205,/**< there is a problem with configured thread scheduling params */ RS_RET_SOCKNAME_MISSING = -2206,/**< no socket name configured where one is required */ + RS_RET_CONF_PARSE_ERROR = -2207,/**< (fatal) error parsing config file */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/tests/testsuites/imtcp_conndrop.conf b/tests/testsuites/imtcp_conndrop.conf index de41bc43..c1508525 100644 --- a/tests/testsuites/imtcp_conndrop.conf +++ b/tests/testsuites/imtcp_conndrop.conf @@ -12,4 +12,4 @@ $template dynfile,"rsyslog.out.log" # trick to use relative path names! $OMFileFlushOnTXEnd off $OMFileFlushInterval 2 $OMFileIOBufferSize 256k -local0.* ?dynfile;outfmt +0local0.* ?dynfile;outfmt diff --git a/tools/syslogd.c b/tools/syslogd.c index 45abf1a7..72c0bdb3 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -2243,7 +2243,7 @@ finalize_it: if(iRet == RS_RET_VALIDATION_RUN) { fprintf(stderr, "rsyslogd: End of config validation run. Bye.\n"); } else if(iRet != RS_RET_OK) { - fprintf(stderr, "rsyslogd run failed with error %d (see rsyslog.h " + 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); } -- cgit v1.2.3 From 20607ba1695b99838db7bdf809b22cf52bbdf5ce Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 12 Jul 2011 12:29:55 +0200 Subject: removed compatibility mode as we expect people have adjusted their confs by now --- ChangeLog | 4 + tools/syslogd.c | 247 +++----------------------------------------------------- 2 files changed, 17 insertions(+), 234 deletions(-) diff --git a/ChangeLog b/ChangeLog index 52d5e4dd..93c9edbb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ --------------------------------------------------------------------------- +Version 6.3.3 [DEVEL] (rgerhards), 2011-06-?? +- removed compatibility mode as we expect people have adjusted their + confs by now +--------------------------------------------------------------------------- Version 6.3.2 [DEVEL] (rgerhards), 2011-06-?? - added support for obtaining timestamp for kernel message from message If the kernel time-stamps messages, time is now take from that diff --git a/tools/syslogd.c b/tools/syslogd.c index 72c0bdb3..91df6469 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -215,12 +215,6 @@ int repeatinterval[2] = { 30, 60 }; /* # of secs before flush */ static pid_t ppid; /* This is a quick and dirty hack used for spliting main/startup thread */ -typedef struct legacyOptsLL_s { - uchar *line; - struct legacyOptsLL_s *next; -} legacyOptsLL_t; -legacyOptsLL_t *pLegacyOptsLL = NULL; - /* global variables for config file state */ int iCompatibilityMode = 0; /* version we should be compatible with; 0 means sysklogd. It is the default, so if no -c option is given, we make ourselvs @@ -754,132 +748,6 @@ static void debug_switch() } -void legacyOptsEnq(uchar *line) -{ - legacyOptsLL_t *pNew; - - pNew = MALLOC(sizeof(legacyOptsLL_t)); - if(line == NULL) - pNew->line = NULL; - else - pNew->line = (uchar *) strdup((char *) line); - pNew->next = NULL; - - if(pLegacyOptsLL == NULL) - pLegacyOptsLL = pNew; - else { - legacyOptsLL_t *pThis = pLegacyOptsLL; - - while(pThis->next != NULL) - pThis = pThis->next; - pThis->next = pNew; - } -} - - -void legacyOptsFree(void) -{ - legacyOptsLL_t *pThis = pLegacyOptsLL, *pNext; - - while(pThis != NULL) { - if(pThis->line != NULL) - free(pThis->line); - pNext = pThis->next; - free(pThis); - pThis = pNext; - } -} - - -void legacyOptsHook(void) -{ - legacyOptsLL_t *pThis = pLegacyOptsLL; - - while(pThis != NULL) { - if(pThis->line != NULL) { - errno = 0; - errmsg.LogError(0, NO_ERRCODE, "Warning: backward compatibility layer added to following " - "directive to rsyslog.conf: %s", pThis->line); - conf.cfsysline(pThis->line); - } - pThis = pThis->next; - } -} - - -void legacyOptsParseTCP(char ch, char *arg) -{ - register int i; - register char *pArg = arg; - static char conflict = '\0'; - - if((conflict == 'g' && ch == 't') || (conflict == 't' && ch == 'g')) { - fprintf(stderr, "rsyslogd: If you want to use both -g and -t, use directives instead, -%c ignored.\n", ch); - return; - } else - conflict = ch; - - /* extract port */ - i = 0; - while(isdigit((int) *pArg)) - i = i * 10 + *pArg++ - '0'; - - /* number of sessions */ - if(*pArg == '\0' || *pArg == ',') { - if(ch == 't') - legacyOptsEnq((uchar *) "ModLoad imtcp"); - else if(ch == 'g') - legacyOptsEnq((uchar *) "ModLoad imgssapi"); - - if(i >= 0 && i <= 65535) { - uchar line[30]; - - if(ch == 't') { - snprintf((char *) line, sizeof(line), "InputTCPServerRun %d", i); - } else if(ch == 'g') { - snprintf((char *) line, sizeof(line), "InputGSSServerRun %d", i); - } - legacyOptsEnq(line); - } else { - if(ch == 't') { - fprintf(stderr, "rsyslogd: Invalid TCP listen port %d - changed to 514.\n", i); - legacyOptsEnq((uchar *) "InputTCPServerRun 514"); - } else if(ch == 'g') { - fprintf(stderr, "rsyslogd: Invalid GSS listen port %d - changed to 514.\n", i); - legacyOptsEnq((uchar *) "InputGSSServerRun 514"); - } - } - - if(*pArg == ',') { - ++pArg; - while(isspace((int) *pArg)) - ++pArg; - i = 0; - while(isdigit((int) *pArg)) { - i = i * 10 + *pArg++ - '0'; - } - if(i > 0) { - uchar line[30]; - - snprintf((char *) line, sizeof(line), "InputTCPMaxSessions %d", i); - legacyOptsEnq(line); - } else { - if(ch == 't') { - fprintf(stderr, "rsyslogd: TCP session max configured " - "to %d [-t %s] - changing to 1.\n", i, arg); - legacyOptsEnq((uchar *) "InputTCPMaxSessions 1"); - } else if (ch == 'g') { - fprintf(stderr, "rsyslogd: GSS session max configured " - "to %d [-g %s] - changing to 1.\n", i, arg); - legacyOptsEnq((uchar *) "InputTCPMaxSessions 1"); - } - } - } - } else - fprintf(stderr, "rsyslogd: Invalid -t %s command line option.\n", arg); -} - - /* doDie() is a signal handler. If called, it sets the bFinished variable * to indicate the program should terminate. However, it does not terminate * it itself, because that causes issues with multi-threading. The actual @@ -1003,8 +871,6 @@ die(int sig) */ unregCfSysLineHdlrs(); - legacyOptsFree(); - /* destruct our global properties */ if(pInternalInputName != NULL) prop.Destruct(&pInternalInputName); @@ -1305,8 +1171,6 @@ init(void) struct sigaction sigAct; DEFiRet; - legacyOptsHook(); - memset(&sigAct, 0, sizeof (sigAct)); sigemptyset(&sigAct.sa_mask); sigAct.sa_handler = sighup_handler; @@ -1824,11 +1688,9 @@ int realMain(int argc, char **argv) extern int optind; extern char *optarg; int bEOptionWasGiven = 0; - int bImUxSockLoaded = 0; /* already generated a $ModLoad imuxsock? */ int iHelperUOpt; int bChDirRoot = 1; /* change the current working directory to "/"? */ char *arg; /* for command line option processing */ - uchar legacyConfLine[80]; uchar *LocalHostName; uchar *LocalDomain; uchar *LocalFQDNName; @@ -1871,6 +1733,9 @@ int realMain(int argc, char **argv) case 'u': /* misc user settings */ case 'w': /* disable disallowed host warnings */ case 'x': /* disable dns for remote messages */ + case 'g': /* enable tcp gssapi logging */ + case 'r': /* accept remote messages */ + case 't': /* enable tcp logging */ CHKiRet(bufOptAdd(ch, optarg)); break; case 'c': /* compatibility mode */ @@ -1881,37 +1746,15 @@ int realMain(int argc, char **argv) Debug = 1; break; case 'e': /* log every message (no repeat message supression) */ - fprintf(stderr, "note: -e option is no longer supported, every message is now logged by default\n"); bEOptionWasGiven = 1; break; - case 'g': /* enable tcp gssapi logging */ -#if defined(SYSLOG_INET) && defined(USE_GSSAPI) - CHKiRet(bufOptAdd('g', optarg)); -#else - fprintf(stderr, "rsyslogd: -g not valid - not compiled with gssapi support"); -#endif - break; case 'M': /* default module load path -- this MUST be carried out immediately! */ glblModPath = (uchar*) optarg; break; - case 'r': /* accept remote messages */ -#ifdef SYSLOG_INET - CHKiRet(bufOptAdd(ch, optarg)); -#else - fprintf(stderr, "rsyslogd: -r not valid - not compiled with network support\n"); -#endif - break; - case 't': /* enable tcp logging */ -#ifdef SYSLOG_INET - CHKiRet(bufOptAdd(ch, optarg)); -#else - fprintf(stderr, "rsyslogd: -t not valid - not compiled with network support\n"); -#endif - break; case 'v': /* MUST be carried out immediately! */ printVersion(); exit(0); /* exit for -v option - so this is a "good one" */ - case '?': + case '?': default: usage(); } @@ -2020,32 +1863,15 @@ int realMain(int argc, char **argv) send_to_all++; break; case 'a': - if(iCompatibilityMode < 3) { - if(!bImUxSockLoaded) { - legacyOptsEnq((uchar *) "ModLoad imuxsock"); - bImUxSockLoaded = 1; - } - snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "addunixlistensocket %s", arg); - legacyOptsEnq(legacyConfLine); - } else { - fprintf(stderr, "error -a is no longer supported, use module imuxsock instead"); - } + fprintf(stderr, "rsyslogd: error -a is no longer supported, use module imuxsock instead"); break; case 'f': /* configuration file */ ConfFile = (uchar*) arg; break; case 'g': /* enable tcp gssapi logging */ - if(iCompatibilityMode < 3) { - legacyOptsParseTCP(ch, arg); - } else - fprintf(stderr, "-g option only supported in compatibility modes 0 to 2 - ignored\n"); - break; + fprintf(stderr, "rsyslogd: -g option no longer supported - ignored\n"); case 'h': - if(iCompatibilityMode < 3) { - errmsg.LogError(0, NO_ERRCODE, "WARNING: -h option is no longer supported - ignored"); - } else { - usage(); /* for v3 and above, it simply is an error */ - } + fprintf(stderr, "rsyslogd: error -h is no longer supported - ignored"); break; case 'i': /* pid file name */ PidFile = arg; @@ -2058,11 +1884,7 @@ int realMain(int argc, char **argv) } break; case 'm': /* mark interval */ - if(iCompatibilityMode < 3) { - MarkInterval = atoi(arg) * 60; - } else - fprintf(stderr, - "-m option only supported in compatibility modes 0 to 2 - ignored\n"); + fprintf(stderr, "rsyslogd: error -m is no longer supported - use immark instead"); break; case 'n': /* don't fork */ NoFork = 1; @@ -2071,27 +1893,10 @@ int realMain(int argc, char **argv) iConfigVerify = atoi(arg); break; case 'o': - if(iCompatibilityMode < 3) { - if(!bImUxSockLoaded) { - legacyOptsEnq((uchar *) "ModLoad imuxsock"); - bImUxSockLoaded = 1; - } - legacyOptsEnq((uchar *) "OmitLocalLogging"); - } else { - fprintf(stderr, "error -o is no longer supported, use module imuxsock instead"); - } + fprintf(stderr, "error -o is no longer supported, use module imuxsock instead"); break; case 'p': - if(iCompatibilityMode < 3) { - if(!bImUxSockLoaded) { - legacyOptsEnq((uchar *) "ModLoad imuxsock"); - bImUxSockLoaded = 1; - } - snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "SystemLogSocketName %s", arg); - legacyOptsEnq(legacyConfLine); - } else { - fprintf(stderr, "error -p is no longer supported, use module imuxsock instead"); - } + fprintf(stderr, "error -p is no longer supported, use module imuxsock instead"); break; case 'q': /* add hostname if DNS resolving has failed */ *(net.pACLAddHostnameOnFail) = 1; @@ -2100,12 +1905,7 @@ int realMain(int argc, char **argv) *(net.pACLDontResolve) = 1; break; case 'r': /* accept remote messages */ - if(iCompatibilityMode < 3) { - legacyOptsEnq((uchar *) "ModLoad imudp"); - snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "UDPServerRun %s", arg); - legacyOptsEnq(legacyConfLine); - } else - fprintf(stderr, "-r option only supported in compatibility modes 0 to 2 - ignored\n"); + fprintf(stderr, "rsyslogd: error option -r is no longer supported - ignored"); break; case 's': if(glbl.GetStripDomains() != NULL) { @@ -2115,10 +1915,7 @@ int realMain(int argc, char **argv) } break; case 't': /* enable tcp logging */ - if(iCompatibilityMode < 3) { - legacyOptsParseTCP(ch, arg); - } else - fprintf(stderr, "-t option only supported in compatibility modes 0 to 2 - ignored\n"); + fprintf(stderr, "rsyslogd: error option -t is no longer supported - ignored"); break; case 'T':/* chroot() immediately at program startup, but only for testing, NOT security yet */ if(chroot(arg) != 0) { @@ -2176,25 +1973,7 @@ int realMain(int argc, char **argv) } /* process compatibility mode settings */ - if(iCompatibilityMode < 4) { - errmsg.LogError(0, NO_ERRCODE, "WARNING: rsyslogd is running in compatibility mode. Automatically " - "generated config directives may interfer with your rsyslog.conf settings. " - "We suggest upgrading your config and adding -c5 as the first " - "rsyslogd option."); - } - - if(iCompatibilityMode < 3) { - if(MarkInterval > 0) { - legacyOptsEnq((uchar *) "ModLoad immark"); - snprintf((char *) legacyConfLine, sizeof(legacyConfLine), "MarkMessagePeriod %d", MarkInterval); - legacyOptsEnq(legacyConfLine); - } - if(!bImUxSockLoaded) { - legacyOptsEnq((uchar *) "ModLoad imuxsock"); - } - } - - if(bEOptionWasGiven && iCompatibilityMode < 3) { + if(bEOptionWasGiven) { errmsg.LogError(0, NO_ERRCODE, "WARNING: \"message repeated n times\" feature MUST be turned on in " "rsyslog.conf - CURRENTLY EVERY MESSAGE WILL BE LOGGED. Visit " "http://www.rsyslog.com/rptdmsgreduction to learn " -- cgit v1.2.3 From 9b7107111dac2a3d836063e576e465e5f3b791db Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 12 Jul 2011 12:51:23 +0200 Subject: proudly added new conf parser to ChangeLog ;-) --- ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index deeb246a..9b5f908d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ --------------------------------------------------------------------------- Version 6.3.3 [DEVEL] (rgerhards), 2011-06-?? +- rsyslog.conf format: now parsed by RainerScript parser + this provides the necessary base for future enhancements as well as some + minor immediate ones +- performance of script-based filters notably increased - removed compatibility mode as we expect people have adjusted their confs by now - added support for the ":omfile:" syntax for actions -- cgit v1.2.3 From 742afce7458505be1a82792c9b5728f58456565d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 13 Jul 2011 12:54:08 +0200 Subject: lexer bug: *.somewhat PRIs not detected regression from last update --- doc/v6compatibility.html | 30 ++++++++++++++++++++++++++++++ grammar/lexer.l | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 doc/v6compatibility.html diff --git a/doc/v6compatibility.html b/doc/v6compatibility.html new file mode 100644 index 00000000..6d60062f --- /dev/null +++ b/doc/v6compatibility.html @@ -0,0 +1,30 @@ + +Compatibility notes for rsyslog v5 + + +

        Compatibility Notes for rsyslog v5

        +

        Written by Rainer Gerhards +(2009-07-15)

        +

        The changes introduced in rsyslog v5 are numerous, but not very intrusive. +This document describes things to keep in mind when moving from v4 to v5. It +does not list enhancements nor does it talk about compatibility concerns introduced +by earlier versions (for this, see their respective compatibility documents). +

        HUP processing

        +

        The $HUPisRestart directive is supported by some early v5 versions, but has been removed +in 5.1.3 and above. That means that restart-type HUP processing is no longer +available. This processing was redundant and had a lot a drawbacks. +For details, please see the +rsyslog v4 compatibility notes which elaborate +on the reasons and the (few) things you may need to change. +

        Queue Worker Thread Shutdown

        +

        Previous rsyslog versions had the capability to "run" on zero queue worker +if no work was required. This was done to save a very limited number of resources. However, +it came at the price of great complexity. In v5, we have decided to let a minium of one +worker run all the time. The additional resource consumption is probably not noticable at +all, however, this enabled us to do some important code cleanups, resulting in faster +and more reliable code (complex code is hard to maintain and error-prone). From the +regular user's point of view, this change should be barely noticable. I am including the +note for expert users, who will notice it in rsyslog debug output and other analysis tools. +So it is no error if each queue in non-direct mode now always runs at least one worker +thread. + diff --git a/grammar/lexer.l b/grammar/lexer.l index 0c82a4af..8b30e4ab 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -157,7 +157,7 @@ int fileno(FILE *stream); "action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { yylval.s = strdup(yytext); return PROPFILT; } -^[ \t]*[a-z][,\*a-z]*[0-7]*\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } +^[ \t]*[\*a-z][,\*a-z]*[0-7]*\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } "*" | \-\/[^*][^\n]* | \/[^*][^\n]* | -- cgit v1.2.3 From 81b302eb654099a8919458cb3b18168cc7b98ff7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 13 Jul 2011 12:54:38 +0200 Subject: doc: v6 compatiblity doc added --- doc/manual.html | 7 +-- doc/v6compatibility.html | 115 +++++++++++++++++++++++++++++++++++++---------- grammar/debian.new | 7 +-- 3 files changed, 99 insertions(+), 30 deletions(-) diff --git a/doc/manual.html b/doc/manual.html index 19dcadb5..761417f1 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -30,10 +30,11 @@ between rsyslog and syslog-ng.

        If you are upgrading from rsyslog v2 or stock sysklogd, be sure to read the rsyslog v3 compatibility notes, and if you are upgrading from v3, read the -rsyslog v4 compatibility notes and +rsyslog v4 compatibility notes, if you upgrade from v4, read the -rsyslog v5 compatibility notes. Ther currently is -no compatibility mode document for v6, as none is required right now. +rsyslog v5 compatibility notes, and +if you upgrade from v5, read the +rsyslog v6 compatibility notes.

        Rsyslog will work even if you do not read the doc, but doing so will definitely improve your experience.

        Follow the links below for the

        diff --git a/doc/v6compatibility.html b/doc/v6compatibility.html index 6d60062f..e67efff3 100644 --- a/doc/v6compatibility.html +++ b/doc/v6compatibility.html @@ -1,30 +1,97 @@ -Compatibility notes for rsyslog v5 +Compatibility notes for rsyslog v6 -

        Compatibility Notes for rsyslog v5

        +

        Compatibility Notes for rsyslog v6

        Written by Rainer Gerhards -(2009-07-15)

        -

        The changes introduced in rsyslog v5 are numerous, but not very intrusive. -This document describes things to keep in mind when moving from v4 to v5. It +(2011-07-13)

        +

        +This document describes things to keep in mind when moving from v5 to v6. It does not list enhancements nor does it talk about compatibility concerns introduced -by earlier versions (for this, see their respective compatibility documents). -

        HUP processing

        -

        The $HUPisRestart directive is supported by some early v5 versions, but has been removed -in 5.1.3 and above. That means that restart-type HUP processing is no longer -available. This processing was redundant and had a lot a drawbacks. -For details, please see the -rsyslog v4 compatibility notes which elaborate -on the reasons and the (few) things you may need to change. -

        Queue Worker Thread Shutdown

        -

        Previous rsyslog versions had the capability to "run" on zero queue worker -if no work was required. This was done to save a very limited number of resources. However, -it came at the price of great complexity. In v5, we have decided to let a minium of one -worker run all the time. The additional resource consumption is probably not noticable at -all, however, this enabled us to do some important code cleanups, resulting in faster -and more reliable code (complex code is hard to maintain and error-prone). From the -regular user's point of view, this change should be barely noticable. I am including the -note for expert users, who will notice it in rsyslog debug output and other analysis tools. -So it is no error if each queue in non-direct mode now always runs at least one worker -thread. +by earlier versions (for this, see their respective compatibility documents). Its focus +is primarily on what you need to know if you used a previous version and want to use the +current one without hassle. Note that versions prior to 6.3.3 did not have any notable compatibility +concerns. So all said here is for 6.3.3 and above. +

        RainerScript based rsyslog.conf

        +

        A better config format was the main release target for rsyslog v6. It comes in the +flavor of so-called RainerScript +(why the +name RainerScript?). RainerScript supports legacy syslog.conf format, much as you know it +from other syslogd's (like sysklogd or the BSD syslogd's) as well as previous versions +of rsyslog. Initial work on RainerScript began in v4, and the if-construct was already +supported in v4 and v5. Version 6 has now taken this further. After long discussions we +decided to use the legacy format as a basis, and lightly extend it by native RainerScript +constructs. The main goal was to make sure that previous knowledge and config systems +could still be used while offering a much more intuitive and powerful way of configuring +rsyslog. +

        RainerScript has been implemented from scratch and with new tools (flex/bison, for those in the +know). Starting with 6.3.3, this new config file processor replaces the legacy one. Note that +the new processor handles all formats, extended RainerScript as well as legacy syslog.conf format. +There are some legacy construct that were especially hard to translate. You'll read about them in +other parts of this document (especially outchannels, which require a format change). + +

        In v6, all legacy formats are supported. In the long term, we may remove some of the ugly +rsyslog-specific constructs. Good candidates are all configuration commands starting with +a dollar sign, like "$ActionFileDefaultTemplate"). However, this will not be the case before +rsyslog v7 or (much more likely) v8/9. Right now, you also need to use these commands, because +not all have already been converted to the new RainerScript format. + +

        In 6.3.3, the new parser is used, but almost none of the extended RainerScript capabilities +are available. They will incrementally be introduced with the following releases. Note that for +some features (most importantly if-then-else nested blocks), the v6 core engine is not +capable enough. It is our aim to provide a much better config language to as many rsyslog +users as quickly as possible. As such, we refrain from doing big engine changes in v6. This +in turn means we cannot introduce some features into RainerScript that we really want to see. +These features will come up with rsyslog v7, which will have even better flow control +capabilities inside the core engine. Note that v7 will fully support v6 RainerScript. +Let us also say that the v6 version is not a low-end quick hack: it offers full-fledged +syslog message processing control, capable of doing the best you can find inside the +industry. We just say that v7 will come up with even more advanced capabilites. +

        Please note that we tried hard to make the RainerScript parser compatible with +all legacy config files. However, we may have failed in one case or another. So if you +experience problems during config processing, chances are there may be a problem +on the rsyslog side. In that case, please let us know. + +

        compatibility mode

        +

        Compatibility mode (specified via -c option) has been removed. This was a migration aid from +sysklogd and very early versions of rsyslog. As all major distros now have rsyslog as their +default, and thus ship rsyslog-compliant config files, there is no longer a need for +compatibility mode. Removing it provides easier to maintain code. Also, practice has shown +that many users were confused by compatibility mode (and even some package maintainers got +it wrong). So this not only cleans up the code but rather removes a frequent source of +error. +

        It must be noted, though, that this means rsyslog is no longer a 100% drop-in replacement +for sysklogd. If you convert an extremely old system, you need to checks its config and +probably need to apply some very mild changes to the config file. +

        abort on config errors

        +

        Previous versions accepted some malformedness inside the config file without aborting. This +could lead to some uncertainty about which configuration was actually running. In v6 there +are some situations where config file errors can not be ignored. In these cases rsyslog +emits error messages to stderr, and then exists with a non-zero exit code. It is important +to check for those cases as this means log data is potentially lost. +Please note that +the root problem is the same for earlier versions as well. With them, it was just harder +to spot why things went wrong (and if at all). +

        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 +for the action. Let's assume your outchannel is named "channel". The previous syntax was +

        +*.* $channel + +
        +This was deprecated in v5 and no longer works in v6. Instead, you need to specify +
        +*.* :omfile:$channel +
        +Note that this syntax is available starting with rsyslog v4. It is important to keep on your +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. +

        [manual index] [rsyslog site]

        +

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

        diff --git a/grammar/debian.new b/grammar/debian.new index 6cf9b5e5..4dbb5907 100644 --- a/grammar/debian.new +++ b/grammar/debian.new @@ -154,11 +154,12 @@ then /dev/tty10 # remote host is: name/ip:port, e.g. 192.168.0.1:514, port optional #*.* @@remote-host:514 # ### end of the forwarding rule ### -if $msg contains "error" then +if $msg contains "error" then { action(type="omfwd" protocol="tcp" target="10.0.0.1:514" action.retryCount="-1" queue.type="linkedList" queue.fileName="fwdRule" queue.maxDiskSpace="1g" queue.saveOnShutdown="on" ) - & action(type="omfile" target="/var/log/somelog.log") - & action(type="omuser" target="all") + action(type="omfile" target="/var/log/somelog.log") + action(type="omuser" target="all") +} -- cgit v1.2.3 From bb8ab61f4fb630f5e3a338c0fb3a3b68f207bedb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 13 Jul 2011 13:49:34 +0200 Subject: reverting back to non-debug settings debug settings in testbench were accidently left on, including a special test case --- tests/diag.sh | 4 ++-- tests/testsuites/imtcp_conndrop.conf | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/diag.sh b/tests/diag.sh index 0c7942da..9fd878a4 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -10,8 +10,8 @@ #valgrind="valgrind --tool=helgrind --log-fd=1" #valgrind="valgrind --tool=exp-ptrcheck --log-fd=1" #set -o xtrace -export RSYSLOG_DEBUG="debug nologfuncflow noprintmutexaction stdout" -export RSYSLOG_DEBUGLOG="log" +#export RSYSLOG_DEBUG="debug nologfuncflow noprintmutexaction stdout" +#export RSYSLOG_DEBUGLOG="log" case $1 in 'init') $srcdir/killrsyslog.sh # kill rsyslogd if it runs for some reason cp $srcdir/testsuites/diag-common.conf diag-common.conf diff --git a/tests/testsuites/imtcp_conndrop.conf b/tests/testsuites/imtcp_conndrop.conf index c1508525..de41bc43 100644 --- a/tests/testsuites/imtcp_conndrop.conf +++ b/tests/testsuites/imtcp_conndrop.conf @@ -12,4 +12,4 @@ $template dynfile,"rsyslog.out.log" # trick to use relative path names! $OMFileFlushOnTXEnd off $OMFileFlushInterval 2 $OMFileIOBufferSize 256k -0local0.* ?dynfile;outfmt +local0.* ?dynfile;outfmt -- cgit v1.2.3 From 744fae0f148d13bd936a47bf25db15b7d3bd44b2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 13 Jul 2011 14:30:08 +0200 Subject: forgotten to support the discard action ("~") --- grammar/lexer.l | 1 + 1 file changed, 1 insertion(+) diff --git a/grammar/lexer.l b/grammar/lexer.l index 8b30e4ab..760ed903 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -158,6 +158,7 @@ int fileno(FILE *stream); ^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { yylval.s = strdup(yytext); return PROPFILT; } ^[ \t]*[\*a-z][,\*a-z]*[0-7]*\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } +"~" | "*" | \-\/[^*][^\n]* | \/[^*][^\n]* | -- cgit v1.2.3 From fa5c1371db8669043c30f402d9a096e7036a8dcd Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 13 Jul 2011 14:49:14 +0200 Subject: preparing for 6.3.3 --- ChangeLog | 5 +++-- configure.ac | 2 +- doc/manual.html | 2 +- doc/v6compatibility.html | 4 ++++ grammar/Makefile.am | 1 + tests/diag.sh | 2 +- 6 files changed, 11 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9b5f908d..9fbf1d53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,9 @@ --------------------------------------------------------------------------- -Version 6.3.3 [DEVEL] (rgerhards), 2011-06-?? +Version 6.3.3 [DEVEL] (rgerhards), 2011-07-13 - rsyslog.conf format: now parsed by RainerScript parser this provides the necessary base for future enhancements as well as some - minor immediate ones + minor immediate ones. For details see: + http://blog.gerhards.net/2011/07/rsyslog-633-config-format-improvements.html - performance of script-based filters notably increased - removed compatibility mode as we expect people have adjusted their confs by now diff --git a/configure.ac b/configure.ac index b9208bc7..0093d860 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.2],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[6.3.3],[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 761417f1..6c3b52a8 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.3.2 (devel branch) of rsyslog. +

        If you like rsyslog, you might diff --git a/doc/v6compatibility.html b/doc/v6compatibility.html index e67efff3..67f7f0d8 100644 --- a/doc/v6compatibility.html +++ b/doc/v6compatibility.html @@ -52,6 +52,10 @@ all legacy config files. However, we may have failed in one case or another. So experience problems during config processing, chances are there may be a problem on the rsyslog side. In that case, please let us know. +

        Please see the +blog +post about rsyslog 6.3.3 config format for details of what is currently supported. +

        compatibility mode

        Compatibility mode (specified via -c option) has been removed. This was a migration aid from sysklogd and very early versions of rsyslog. As all major distros now have rsyslog as their diff --git a/grammar/Makefile.am b/grammar/Makefile.am index 2b149abe..9767c12f 100644 --- a/grammar/Makefile.am +++ b/grammar/Makefile.am @@ -9,6 +9,7 @@ libgrammar_la_SOURCES = \ lexer.l \ rainerscript.c \ rainerscript.h \ + parserif.h \ grammar.h testdriver_SOURCES = testdriver.c libgrammar.la diff --git a/tests/diag.sh b/tests/diag.sh index 9fd878a4..b278d2c5 100755 --- a/tests/diag.sh +++ b/tests/diag.sh @@ -10,7 +10,7 @@ #valgrind="valgrind --tool=helgrind --log-fd=1" #valgrind="valgrind --tool=exp-ptrcheck --log-fd=1" #set -o xtrace -#export RSYSLOG_DEBUG="debug nologfuncflow noprintmutexaction stdout" +#export RSYSLOG_DEBUG="debug nologfuncflow noprintmutexaction nostdout" #export RSYSLOG_DEBUGLOG="log" case $1 in 'init') $srcdir/killrsyslog.sh # kill rsyslogd if it runs for some reason -- cgit v1.2.3 From 03a21b56f237fa33198c3124ea66e3cfd7848552 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 15 Jul 2011 14:42:17 +0200 Subject: some more cleanup preparing for a new, higher performance, variant object type --- ChangeLog | 2 + runtime/msg.c | 44 -------- runtime/rule.c | 3 - runtime/var.c | 326 --------------------------------------------------------- runtime/var.h | 11 +- 5 files changed, 4 insertions(+), 382 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9fbf1d53..7ae5dffc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,6 @@ --------------------------------------------------------------------------- +Version 6.3.4 [DEVEL] (rgerhards), 2011-07-?? +--------------------------------------------------------------------------- Version 6.3.3 [DEVEL] (rgerhards), 2011-07-13 - rsyslog.conf format: now parsed by RainerScript parser this provides the necessary base for future enhancements as well as some diff --git a/runtime/msg.c b/runtime/msg.c index b440d6ca..0a79bec2 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -58,7 +58,6 @@ /* static data */ DEFobjStaticHelpers -DEFobjCurrIf(var) DEFobjCurrIf(datetime) DEFobjCurrIf(glbl) DEFobjCurrIf(regexp) @@ -501,11 +500,6 @@ propNameStrToID(uchar *pName, propid_t *pPropID) *pPropID = PROP_SYSLOGTAG; } else if(!strcmp((char*) pName, "rawmsg")) { *pPropID = PROP_RAWMSG; - /* enable this, if someone actually uses UxTradMsg, delete after some time has - * passed and nobody complained -- rgerhards, 2009-06-16 - } else if(!strcmp((char*) pName, "uxtradmsg")) { - pRes = getUxTradMsg(pMsg); - */ } else if(!strcmp((char*) pName, "inputname")) { *pPropID = PROP_INPUTNAME; } else if(!strcmp((char*) pName, "fromhost")) { @@ -603,12 +597,6 @@ uchar *propIDToName(propid_t propID) return UCHAR_CONSTANT("syslogtag"); case PROP_RAWMSG: return UCHAR_CONSTANT("rawmsg"); - /* enable this, if someone actually uses UxTradMsg, delete after some time has - * passed and nobody complained -- rgerhards, 2009-06-16 - case PROP_UXTRADMSG: - pRes = getUxTradMsg(pMsg); - break; - */ case PROP_INPUTNAME: return UCHAR_CONSTANT("inputname"); case PROP_FROMHOST: @@ -985,10 +973,6 @@ msg_t* MsgDup(msg_t* pOld) pNew->pInputName = pOld->pInputName; prop.AddRef(pNew->pInputName); } - /* enable this, if someone actually uses UxTradMsg, delete after some time has - * passed and nobody complained -- rgerhards, 2009-06-16 - pNew->offAfterPRI = pOld->offAfterPRI; - */ if(pOld->iLenTAG > 0) { if(pOld->iLenTAG < CONF_TAG_BUFSIZE) { memcpy(pNew->TAG.szBuf, pOld->TAG.szBuf, pOld->iLenTAG); @@ -1060,10 +1044,6 @@ static rsRetVal MsgSerialize(msg_t *pThis, strm_t *pStrm) objSerializeSCALAR(pStrm, ttGenTime, INT); objSerializeSCALAR(pStrm, tRcvdAt, SYSLOGTIME); objSerializeSCALAR(pStrm, tTIMESTAMP, SYSLOGTIME); - /* enable this, if someone actually uses UxTradMsg, delete after some time has - * passed and nobody complained -- rgerhards, 2009-06-16 - objSerializeSCALAR(pStrm, offsAfterPRI, SHORT); - */ CHKiRet(obj.SerializeProp(pStrm, UCHAR_CONSTANT("pszTAG"), PROPTYPE_PSZ, (void*) ((pThis->iLenTAG < CONF_TAG_BUFSIZE) ? pThis->TAG.szBuf : pThis->TAG.pszTAG))); @@ -1257,18 +1237,6 @@ getRawMsg(msg_t *pM, uchar **pBuf, int *piLen) } -/* enable this, if someone actually uses UxTradMsg, delete after some time has - * passed and nobody complained -- rgerhards, 2009-06-16 -char *getUxTradMsg(msg_t *pM) -{ - if(pM == NULL) - return ""; - else - return (char*)pM->pszRawMsg + pM->offAfterPRI; -} -*/ - - int getMSGLen(msg_t *pM) { return((pM == NULL) ? 0 : pM->iLenMSG); @@ -2378,12 +2346,6 @@ uchar *MsgGetProp(msg_t *pMsg, struct templateEntry *pTpe, case PROP_RAWMSG: getRawMsg(pMsg, &pRes, &bufLen); break; - /* enable this, if someone actually uses UxTradMsg, delete after some time has - * passed and nobody complained -- rgerhards, 2009-06-16 - case PROP_UXTRADMSG: - pRes = getUxTradMsg(pMsg); - break; - */ case PROP_INPUTNAME: getInputName(pMsg, &pRes, &bufLen); break; @@ -3201,11 +3163,6 @@ rsRetVal MsgSetProperty(msg_t *pThis, var_t *pProp) MsgSetMSGoffs(pThis, pProp->val.num); } else if(isProp("pszRawMsg")) { MsgSetRawMsg(pThis, (char*) rsCStrGetSzStrNoNULL(pProp->val.pStr), cstrLen(pProp->val.pStr)); - /* enable this, if someone actually uses UxTradMsg, delete after some time has - * passed and nobody complained -- rgerhards, 2009-06-16 - } else if(isProp("offAfterPRI")) { - pThis->offAfterPRI = pProp->val.num; - */ } else if(isProp("pszUxTradMsg")) { /*IGNORE*/; /* this *was* a property, but does no longer exist */ } else if(isProp("pszTAG")) { @@ -3284,7 +3241,6 @@ rsRetVal msgQueryInterface(void) { return RS_RET_NOT_IMPLEMENTED; } */ BEGINObjClassInit(msg, 1, OBJ_IS_CORE_MODULE) /* request objects we use */ - CHKiRet(objUse(var, CORE_COMPONENT)); CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); CHKiRet(objUse(prop, CORE_COMPONENT)); diff --git a/runtime/rule.c b/runtime/rule.c index cbd2660d..1d707634 100644 --- a/runtime/rule.c +++ b/runtime/rule.c @@ -44,7 +44,6 @@ /* static data */ DEFobjStaticHelpers DEFobjCurrIf(errmsg) -DEFobjCurrIf(var) /* support for simple textual representation of FIOP names @@ -455,7 +454,6 @@ ENDobjQueryInterface(rule) */ BEGINObjClassExit(rule, OBJ_IS_CORE_MODULE) /* class, version */ objRelease(errmsg, CORE_COMPONENT); - objRelease(var, CORE_COMPONENT); ENDObjClassExit(rule) @@ -466,7 +464,6 @@ ENDObjClassExit(rule) BEGINObjClassInit(rule, 1, OBJ_IS_CORE_MODULE) /* class, version */ /* request objects we use */ CHKiRet(objUse(errmsg, CORE_COMPONENT)); - CHKiRet(objUse(var, CORE_COMPONENT)); /* set our own handlers */ OBJSetMethodHandler(objMethod_DEBUGPRINT, ruleDebugPrint); diff --git a/runtime/var.c b/runtime/var.c index ef7cc8e6..eecc5d6a 100644 --- a/runtime/var.c +++ b/runtime/var.c @@ -90,324 +90,6 @@ CODESTARTobjDebugPrint(var) ENDobjDebugPrint(var) -/* This function is similar to DebugPrint, but does not send its output to - * the debug log but instead to a caller-provided string. The idea here is that - * we can use this string to get a textual representation of a variable. - * Among others, this is useful for creating testbenches, our first use case for - * it. Here, it enables simple comparison of the resulting program to a - * reference program by simple string compare. - * Note that the caller must initialize the string object. We always add - * data to it. So, it can be easily combined into a chain of methods - * to generate the final string. - * rgerhards, 2008-07-07 - */ -static rsRetVal -Obj2Str(var_t *pThis, cstr_t *pstrPrg) -{ - DEFiRet; - size_t lenBuf; - uchar szBuf[2048]; - - ISOBJ_TYPE_assert(pThis, var); - assert(pstrPrg != NULL); - switch(pThis->varType) { - case VARTYPE_STR: - lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%s[cstr]", rsCStrGetSzStr(pThis->val.pStr)); - break; - case VARTYPE_NUMBER: - lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "%lld[nbr]", pThis->val.num); - break; - default: - lenBuf = snprintf((char*) szBuf, sizeof(szBuf), "**UNKNOWN**[%d]", pThis->varType); - break; - } - CHKiRet(rsCStrAppendStrWithLen(pstrPrg, szBuf, lenBuf)); - -finalize_it: - RETiRet; -} - - -/* duplicates a var instance - * rgerhards, 2008-02-25 - */ -static rsRetVal -Duplicate(var_t *pThis, var_t **ppNew) -{ - DEFiRet; - var_t *pNew = NULL; - cstr_t *pstr; - - ISOBJ_TYPE_assert(pThis, var); - assert(ppNew != NULL); - - CHKiRet(varConstruct(&pNew)); - CHKiRet(varConstructFinalize(pNew)); - - /* we have the object, now copy value */ - pNew->varType = pThis->varType; - if(pThis->varType == VARTYPE_NUMBER) { - pNew->val.num = pThis->val.num; - } else if(pThis->varType == VARTYPE_STR) { - CHKiRet(rsCStrConstructFromCStr(&pstr, pThis->val.pStr)); - pNew->val.pStr = pstr; - } - - *ppNew = pNew; - -finalize_it: - if(iRet != RS_RET_OK && pNew != NULL) - varDestruct(&pNew); - - RETiRet; -} - - -/* free the current values (destructs objects if necessary) - */ -static rsRetVal -varUnsetValues(var_t *pThis) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, var); - if(pThis->varType == VARTYPE_STR) - rsCStrDestruct(&pThis->val.pStr); - - pThis->varType = VARTYPE_NONE; - - RETiRet; -} - - -/* set a string value - * The caller hands over the string and must n longer use it after this method - * has been called. - */ -static rsRetVal -varSetString(var_t *pThis, cstr_t *pStr) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, var); - - CHKiRet(varUnsetValues(pThis)); - pThis->varType = VARTYPE_STR; - pThis->val.pStr = pStr; - -finalize_it: - RETiRet; -} - - -/* set an int64 value */ -static rsRetVal -varSetNumber(var_t *pThis, number_t iVal) -{ - DEFiRet; - - ISOBJ_TYPE_assert(pThis, var); - - CHKiRet(varUnsetValues(pThis)); - pThis->varType = VARTYPE_NUMBER; - pThis->val.num = iVal; - -finalize_it: - RETiRet; -} - - -/* Change the provided object to be of type number. - * rgerhards, 2008-02-22 - */ -rsRetVal -ConvToNumber(var_t *pThis) -{ - DEFiRet; - number_t n; - - if(pThis->varType == VARTYPE_NUMBER) { - FINALIZE; - } else if(pThis->varType == VARTYPE_STR) { - iRet = rsCStrConvertToNumber(pThis->val.pStr, &n); - if(iRet == RS_RET_NOT_A_NUMBER) { - n = 0; - iRet = RS_RET_OK; /* we accept this as part of the language definition */ - } else if (iRet != RS_RET_OK) { - FINALIZE; - } - - /* we need to destruct the string first, because string and number are - * inside a union and share the memory area! -- rgerhards, 2008-04-03 - */ - rsCStrDestruct(&pThis->val.pStr); - - pThis->val.num = n; - pThis->varType = VARTYPE_NUMBER; - } - -finalize_it: - RETiRet; -} - - -/* convert the provided var to type string. This is always possible - * (except, of course, for things like out of memory...) - * TODO: finish implementation!!!!!!!!! - * rgerhards, 2008-02-24 - */ -rsRetVal -ConvToString(var_t *pThis) -{ - DEFiRet; - uchar szNumBuf[64]; - - if(pThis->varType == VARTYPE_STR) { - FINALIZE; - } else if(pThis->varType == VARTYPE_NUMBER) { - CHKiRet(srUtilItoA((char*)szNumBuf, sizeof(szNumBuf)/sizeof(uchar), pThis->val.num)); - CHKiRet(rsCStrConstructFromszStr(&pThis->val.pStr, szNumBuf)); - pThis->varType = VARTYPE_STR; - } - -finalize_it: - RETiRet; -} - - -/* convert (if necessary) the value to a boolean. In essence, this means the - * value must be a number, but in case of a string special logic is used as - * some string-values may represent a boolean (e.g. "true"). - * rgerhards, 2008-02-25 - */ -rsRetVal -ConvToBool(var_t *pThis) -{ - DEFiRet; - number_t n; - - if(pThis->varType == VARTYPE_NUMBER) { - FINALIZE; - } else if(pThis->varType == VARTYPE_STR) { - iRet = rsCStrConvertToBool(pThis->val.pStr, &n); - if(iRet == RS_RET_NOT_A_NUMBER) { - n = 0; - iRet = RS_RET_OK; /* we accept this as part of the language definition */ - } else if (iRet != RS_RET_OK) { - FINALIZE; - } - - /* we need to destruct the string first, because string and number are - * inside a union and share the memory area! -- rgerhards, 2008-04-03 - */ - rsCStrDestruct(&pThis->val.pStr); - pThis->val.num = n; - pThis->varType = VARTYPE_NUMBER; - } - -finalize_it: - RETiRet; -} - - -/* This function is used to prepare two var_t objects for a common operation, - * e.g before they are added, compared. The function looks at - * the data types of both operands and finds the best data type suitable for - * the operation (in respect to current types). Then, it converts those - * operands that need conversion. Please note that the passed-in var objects - * *are* modified and returned as new type. So do call this function only if - * you actually need the conversion. - * - * This is how the common data type is selected. Note that op1 and op2 are - * just the two operands, their order is irrelevant (this would just take up - * more table space - so string/number is the same thing as number/string). - * - * Common Types: - * op1 op2 operation data type - * string string string - * string number number if op1 can be converted to number, string else - * date string date if op1 can be converted to date, string else - * number number number - * date number string (maybe we can do better?) - * date date date - * none n/a error - * - * If a boolean value is required, we need to have a number inside the - * operand. If it is not, conversion rules to number apply. Once we - * have a number, things get easy: 0 is false, anything else is true. - * Please note that due to this conversion rules, "0" becomes false - * while "-4712" becomes true. Using a date as boolen is not a good - * idea. Depending on the ultimate conversion rules, it may always - * become true or false. As such, using dates as booleans is - * prohibited and the result defined to be undefined. - * - * rgerhards, 2008-02-22 - */ -static rsRetVal -ConvForOperation(var_t *pThis, var_t *pOther) -{ - DEFiRet; - - if(pThis->varType == VARTYPE_NONE || pOther->varType == VARTYPE_NONE) - ABORT_FINALIZE(RS_RET_INVALID_VAR); - - switch(pThis->varType) { - case VARTYPE_NONE: - ABORT_FINALIZE(RS_RET_INVALID_VAR); - break; - case VARTYPE_STR: - switch(pOther->varType) { - case VARTYPE_NONE: - ABORT_FINALIZE(RS_RET_INVALID_VAR); - break; - case VARTYPE_STR: - FINALIZE; /* two strings, we are all set */ - break; - case VARTYPE_NUMBER: - /* check if we can convert pThis to a number, if so use number format. */ - iRet = ConvToNumber(pThis); - if(iRet == RS_RET_NOT_A_NUMBER) { - CHKiRet(ConvToString(pOther)); - } else { - FINALIZE; /* OK or error */ - } - break; - case VARTYPE_SYSLOGTIME: - ABORT_FINALIZE(RS_RET_NOT_IMPLEMENTED); - break; - } - break; - case VARTYPE_NUMBER: - switch(pOther->varType) { - case VARTYPE_NONE: - ABORT_FINALIZE(RS_RET_INVALID_VAR); - break; - case VARTYPE_STR: - iRet = ConvToNumber(pOther); - if(iRet == RS_RET_NOT_A_NUMBER) { - CHKiRet(ConvToString(pThis)); - } else { - FINALIZE; /* OK or error */ - } - break; - case VARTYPE_NUMBER: - FINALIZE; /* two numbers, so we are all set */ - break; - case VARTYPE_SYSLOGTIME: - ABORT_FINALIZE(RS_RET_NOT_IMPLEMENTED); - break; - } - break; - case VARTYPE_SYSLOGTIME: - ABORT_FINALIZE(RS_RET_NOT_IMPLEMENTED); - break; - } - -finalize_it: - RETiRet; -} - - /* queryInterface function * rgerhards, 2008-02-21 */ @@ -426,14 +108,6 @@ CODESTARTobjQueryInterface(var) pIf->ConstructFinalize = varConstructFinalize; pIf->Destruct = varDestruct; pIf->DebugPrint = varDebugPrint; - pIf->Obj2Str = Obj2Str; - pIf->SetNumber = varSetNumber; - pIf->SetString = varSetString; - pIf->ConvForOperation = ConvForOperation; - pIf->ConvToNumber = ConvToNumber; - pIf->ConvToBool = ConvToBool; - pIf->ConvToString = ConvToString; - pIf->Duplicate = Duplicate; finalize_it: ENDobjQueryInterface(var) diff --git a/runtime/var.h b/runtime/var.h index ae971bb5..75584c82 100644 --- a/runtime/var.h +++ b/runtime/var.h @@ -54,16 +54,9 @@ BEGINinterface(var) /* name must also be changed in ENDinterface macro! */ rsRetVal (*Construct)(var_t **ppThis); rsRetVal (*ConstructFinalize)(var_t __attribute__((unused)) *pThis); rsRetVal (*Destruct)(var_t **ppThis); - rsRetVal (*SetNumber)(var_t *pThis, number_t iVal); - rsRetVal (*SetString)(var_t *pThis, cstr_t *pCStr); - rsRetVal (*ConvForOperation)(var_t *pThis, var_t *pOther); - rsRetVal (*ConvToNumber)(var_t *pThis); - rsRetVal (*ConvToBool)(var_t *pThis); - rsRetVal (*ConvToString)(var_t *pThis); - rsRetVal (*Obj2Str)(var_t *pThis, cstr_t*); - rsRetVal (*Duplicate)(var_t *pThis, var_t **ppNew); ENDinterface(var) -#define varCURR_IF_VERSION 1 /* increment whenever you change the interface above! */ +#define varCURR_IF_VERSION 2 /* increment whenever you change the interface above! */ +/* v2 - 2011-07-15/rger: on the way to remove var */ /* prototypes */ -- cgit v1.2.3 From 384cf4702406a69825190ce0e28cfbcd1e3ccb8e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 15 Jul 2011 14:51:53 +0200 Subject: renamed exprret type to var in spite of more generic use --- grammar/rainerscript.c | 92 +++++++++++++++++++++++++------------------------- grammar/rainerscript.h | 12 +++++-- 2 files changed, 55 insertions(+), 49 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 680f8775..5d64abb4 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -294,7 +294,7 @@ done: * are used (bSuccess tells if the conversion went well or not). */ static inline long long -exprret2Number(struct exprret *r, int *bSuccess) +var2Number(struct var *r, int *bSuccess) { long long n; if(r->datatype == 'S') { @@ -309,7 +309,7 @@ exprret2Number(struct exprret *r, int *bSuccess) * emit error message and set number to 0. */ static inline es_str_t * -exprret2String(struct exprret *r, int *bMustFree) +var2String(struct var *r, int *bMustFree) { if(r->datatype == 'N') { *bMustFree = 1; @@ -323,14 +323,14 @@ exprret2String(struct exprret *r, int *bMustFree) * to keep the code small and easier to maintain. */ static inline void -doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) +doFuncCall(struct cnffunc *func, struct var *ret, void* usrptr) { char *fname; char *envvar; int bMustFree; es_str_t *estr; char *str; - struct exprret r[CNFFUNC_MAX_ARGS]; + struct var r[CNFFUNC_MAX_ARGS]; dbgprintf("rainerscript: executing function id %d\n", func->fID); switch(func->fID) { @@ -342,7 +342,7 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) ret->d.n = es_strlen(((struct cnfstringval*) func->expr[0])->estr); } else { cnfexprEval(func->expr[0], &r[0], usrptr); - estr = exprret2String(&r[0], &bMustFree); + estr = var2String(&r[0], &bMustFree); ret->d.n = es_strlen(estr); if(bMustFree) es_deleteStr(estr); } @@ -355,7 +355,7 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) * string following. */ cnfexprEval(func->expr[0], &r[0], usrptr); - estr = exprret2String(&r[0], &bMustFree); + estr = var2String(&r[0], &bMustFree); str = (char*) es_str2cstr(estr, NULL); envvar = getenv(str); ret->datatype = 'S'; @@ -366,7 +366,7 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) break; case CNFFUNC_TOLOWER: cnfexprEval(func->expr[0], &r[0], usrptr); - estr = exprret2String(&r[0], &bMustFree); + estr = var2String(&r[0], &bMustFree); if(!bMustFree) /* let caller handle that M) */ estr = es_strdup(estr); es_tolower(estr); @@ -375,7 +375,7 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) break; case CNFFUNC_CSTR: cnfexprEval(func->expr[0], &r[0], usrptr); - estr = exprret2String(&r[0], &bMustFree); + estr = var2String(&r[0], &bMustFree); if(!bMustFree) /* let caller handle that M) */ estr = es_strdup(estr); ret->datatype = 'S'; @@ -389,7 +389,7 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) NULL); } else { cnfexprEval(func->expr[0], &r[0], usrptr); - ret->d.n = exprret2Number(&r[0], NULL); + ret->d.n = var2Number(&r[0], NULL); if(r[0].datatype == 'S') es_deleteStr(r[0].d.estr); } ret->datatype = 'N'; @@ -414,14 +414,14 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) cnfexprEval(expr->l, &l, usrptr); \ cnfexprEval(expr->r, &r, usrptr); \ ret->datatype = 'N'; \ - ret->d.n = exprret2Number(&l, &convok_l) x exprret2Number(&r, &convok_r); \ + ret->d.n = var2Number(&l, &convok_l) x var2Number(&r, &convok_r); \ FREE_BOTH_RET #define PREP_TWO_STRINGS \ cnfexprEval(expr->l, &l, usrptr); \ - estr_l = exprret2String(&l, &bMustFree2); \ + estr_l = var2String(&l, &bMustFree2); \ cnfexprEval(expr->r, &r, usrptr); \ - estr_r = exprret2String(&r, &bMustFree) + estr_r = var2String(&r, &bMustFree) #define FREE_TWO_STRINGS \ if(bMustFree) es_deleteStr(estr_r); \ @@ -439,9 +439,9 @@ doFuncCall(struct cnffunc *func, struct exprret *ret, void* usrptr) * simply is no case where full evaluation would make any sense at all. */ void -cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) +cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) { - struct exprret r, l; /* memory for subexpression results */ + struct var r, l; /* memory for subexpression results */ es_str_t *estr_r, *estr_l; int convok_r, convok_l; int bMustFree, bMustFree2; @@ -460,22 +460,22 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = !es_strcmp(l.d.estr, r.d.estr); /*CMP*/ } else { - n_l = exprret2Number(&l, &convok_l); + n_l = var2Number(&l, &convok_l); if(convok_l) { ret->d.n = (n_l == r.d.n); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); + estr_r = var2String(&r, &bMustFree); ret->d.n = !es_strcmp(l.d.estr, estr_r); /*CMP*/ if(bMustFree) es_deleteStr(estr_r); } } } else { if(r.datatype == 'S') { - n_r = exprret2Number(&r, &convok_r); + n_r = var2Number(&r, &convok_r); if(convok_r) { ret->d.n = (l.d.n == n_r); /*CMP*/ } else { - estr_l = exprret2String(&l, &bMustFree); + estr_l = var2String(&l, &bMustFree); ret->d.n = !es_strcmp(r.d.estr, estr_l); /*CMP*/ if(bMustFree) es_deleteStr(estr_l); } @@ -493,22 +493,22 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = es_strcmp(l.d.estr, r.d.estr); /*CMP*/ } else { - n_l = exprret2Number(&l, &convok_l); + n_l = var2Number(&l, &convok_l); if(convok_l) { ret->d.n = (n_l != r.d.n); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); + estr_r = var2String(&r, &bMustFree); ret->d.n = es_strcmp(l.d.estr, estr_r); /*CMP*/ if(bMustFree) es_deleteStr(estr_r); } } } else { if(r.datatype == 'S') { - n_r = exprret2Number(&r, &convok_r); + n_r = var2Number(&r, &convok_r); if(convok_r) { ret->d.n = (l.d.n != n_r); /*CMP*/ } else { - estr_l = exprret2String(&l, &bMustFree); + estr_l = var2String(&l, &bMustFree); ret->d.n = es_strcmp(r.d.estr, estr_l); /*CMP*/ if(bMustFree) es_deleteStr(estr_l); } @@ -526,22 +526,22 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = es_strcmp(l.d.estr, r.d.estr) <= 0; /*CMP*/ } else { - n_l = exprret2Number(&l, &convok_l); + n_l = var2Number(&l, &convok_l); if(convok_l) { ret->d.n = (n_l <= r.d.n); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); + estr_r = var2String(&r, &bMustFree); ret->d.n = es_strcmp(l.d.estr, estr_r) <= 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_r); } } } else { if(r.datatype == 'S') { - n_r = exprret2Number(&r, &convok_r); + n_r = var2Number(&r, &convok_r); if(convok_r) { ret->d.n = (l.d.n <= n_r); /*CMP*/ } else { - estr_l = exprret2String(&l, &bMustFree); + estr_l = var2String(&l, &bMustFree); ret->d.n = es_strcmp(r.d.estr, estr_l) <= 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_l); } @@ -559,22 +559,22 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = es_strcmp(l.d.estr, r.d.estr) >= 0; /*CMP*/ } else { - n_l = exprret2Number(&l, &convok_l); + n_l = var2Number(&l, &convok_l); if(convok_l) { ret->d.n = (n_l >= r.d.n); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); + estr_r = var2String(&r, &bMustFree); ret->d.n = es_strcmp(l.d.estr, estr_r) >= 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_r); } } } else { if(r.datatype == 'S') { - n_r = exprret2Number(&r, &convok_r); + n_r = var2Number(&r, &convok_r); if(convok_r) { ret->d.n = (l.d.n >= n_r); /*CMP*/ } else { - estr_l = exprret2String(&l, &bMustFree); + estr_l = var2String(&l, &bMustFree); ret->d.n = es_strcmp(r.d.estr, estr_l) >= 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_l); } @@ -592,22 +592,22 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = es_strcmp(l.d.estr, r.d.estr) < 0; /*CMP*/ } else { - n_l = exprret2Number(&l, &convok_l); + n_l = var2Number(&l, &convok_l); if(convok_l) { ret->d.n = (n_l < r.d.n); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); + estr_r = var2String(&r, &bMustFree); ret->d.n = es_strcmp(l.d.estr, estr_r) < 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_r); } } } else { if(r.datatype == 'S') { - n_r = exprret2Number(&r, &convok_r); + n_r = var2Number(&r, &convok_r); if(convok_r) { ret->d.n = (l.d.n < n_r); /*CMP*/ } else { - estr_l = exprret2String(&l, &bMustFree); + estr_l = var2String(&l, &bMustFree); ret->d.n = es_strcmp(r.d.estr, estr_l) < 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_l); } @@ -625,22 +625,22 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) if(r.datatype == 'S') { ret->d.n = es_strcmp(l.d.estr, r.d.estr) > 0; /*CMP*/ } else { - n_l = exprret2Number(&l, &convok_l); + n_l = var2Number(&l, &convok_l); if(convok_l) { ret->d.n = (n_l > r.d.n); /*CMP*/ } else { - estr_r = exprret2String(&r, &bMustFree); + estr_r = var2String(&r, &bMustFree); ret->d.n = es_strcmp(l.d.estr, estr_r) > 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_r); } } } else { if(r.datatype == 'S') { - n_r = exprret2Number(&r, &convok_r); + n_r = var2Number(&r, &convok_r); if(convok_r) { ret->d.n = (l.d.n > n_r); /*CMP*/ } else { - estr_l = exprret2String(&l, &bMustFree); + estr_l = var2String(&l, &bMustFree); ret->d.n = es_strcmp(r.d.estr, estr_l) > 0; /*CMP*/ if(bMustFree) es_deleteStr(estr_l); } @@ -677,11 +677,11 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) case OR: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; - if(exprret2Number(&l, &convok_l)) { + if(var2Number(&l, &convok_l)) { ret->d.n = 1ll; } else { cnfexprEval(expr->r, &r, usrptr); - if(exprret2Number(&r, &convok_r)) + if(var2Number(&r, &convok_r)) ret->d.n = 1ll; else ret->d.n = 0ll; @@ -691,9 +691,9 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) case AND: cnfexprEval(expr->l, &l, usrptr); ret->datatype = 'N'; - if(exprret2Number(&l, &convok_l)) { + if(var2Number(&l, &convok_l)) { cnfexprEval(expr->r, &r, usrptr); - if(exprret2Number(&r, &convok_r)) + if(var2Number(&r, &convok_r)) ret->d.n = 1ll; else ret->d.n = 0ll; @@ -705,7 +705,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) case NOT: cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; - ret->d.n = !exprret2Number(&r, &convok_r); + ret->d.n = !var2Number(&r, &convok_r); if(r.datatype == 'S') es_deleteStr(r.d.estr); break; case 'N': @@ -738,7 +738,7 @@ cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void* usrptr) case 'M': cnfexprEval(expr->r, &r, usrptr); ret->datatype = 'N'; - ret->d.n = -exprret2Number(&r, &convok_r); + ret->d.n = -var2Number(&r, &convok_r); if(r.datatype == 'S') es_deleteStr(r.d.estr); break; case 'F': @@ -761,9 +761,9 @@ int cnfexprEvalBool(struct cnfexpr *expr, void *usrptr) { int convok; - struct exprret ret; + struct var ret; cnfexprEval(expr, &ret, usrptr); - return exprret2Number(&ret, &convok); + return var2Number(&ret, &convok); } inline static void diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 62c2aa50..3129ed25 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -156,8 +156,14 @@ struct x { }; */ -/* the return value of an expresion evaluation */ -struct exprret { +/* a variant type, for example used for expression evaluation + * 2011-07-15/rger: note that there exists a "legacy" object var_t, + * which implements the same idea, but in a suboptimal manner. I have + * stipped this down as much as possible, but will keep it for a while + * to avoid unnecessary complexity during development. TODO: in the long + * term, var_t shall be replaced by struct var. + */ +struct var { union { es_str_t *estr; long long n; @@ -181,7 +187,7 @@ struct cnfactlst* cnfactlstAddSysline(struct cnfactlst* actlst, char *line); struct cnfactlst* cnfactlstReverse(struct cnfactlst *actlst); struct cnfexpr* cnfexprNew(unsigned nodetype, struct cnfexpr *l, struct cnfexpr *r); void cnfexprPrint(struct cnfexpr *expr, int indent); -void cnfexprEval(struct cnfexpr *expr, struct exprret *ret, void *pusr); +void cnfexprEval(struct cnfexpr *expr, struct var *ret, void *pusr); int cnfexprEvalBool(struct cnfexpr *expr, void *usrptr); struct cnfnumval* cnfnumvalNew(long long val); struct cnfstringval* cnfstringvalNew(es_str_t *estr); -- cgit v1.2.3 From e579791a78267353566c79c83043805a54d85b74 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 15 Jul 2011 15:01:30 +0200 Subject: more cleanup --- runtime/rsconf.c | 6 +++--- runtime/ruleset.c | 4 ++-- runtime/ruleset.h | 11 +++++++---- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 5df4c2c8..0ccf2d57 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -403,7 +403,7 @@ void cnfDoRule(struct cnfrule *cnfrule) cnfDoActlst(cnfrule->actlst, pRule); - CHKiRet(ruleset.AddRule(loadConf, rule.GetAssRuleset(pRule), &pRule)); + CHKiRet(ruleset.AddRule(rule.GetAssRuleset(pRule), &pRule)); finalize_it: //TODO: do something with error states @@ -832,7 +832,7 @@ setCurrRuleset(void __attribute__((unused)) *pVal, uchar *pszName) if(localRet == RS_RET_NOT_FOUND) { DBGPRINTF("begin new current rule set '%s'\n", pszName); CHKiRet(ruleset.Construct(&pRuleset)); - CHKiRet(ruleset.SetName(ourConf, pRuleset, pszName)); + CHKiRet(ruleset.SetName(pRuleset, pszName)); CHKiRet(ruleset.ConstructFinalize(ourConf, pRuleset)); } else { ABORT_FINALIZE(localRet); @@ -1030,7 +1030,7 @@ initLegacyConf(void) DBGPRINTF("doing legacy config system init\n"); /* construct the default ruleset */ ruleset.Construct(&pRuleset); - ruleset.SetName(loadConf, pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset")); + ruleset.SetName(pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset")); ruleset.ConstructFinalize(loadConf, pRuleset); /* now register config handlers */ diff --git a/runtime/ruleset.c b/runtime/ruleset.c index d472a560..23007a63 100644 --- a/runtime/ruleset.c +++ b/runtime/ruleset.c @@ -252,7 +252,7 @@ GetParserList(rsconf_t *conf, msg_t *pMsg) * of checks and ignore the rule if it does not pass them. */ static rsRetVal -addRule(rsconf_t *conf, ruleset_t *pThis, rule_t **ppRule) +addRule(ruleset_t *pThis, rule_t **ppRule) { int iActionCnt; DEFiRet; @@ -275,7 +275,7 @@ finalize_it: /* set name for ruleset */ -static rsRetVal setName(rsconf_t *conf, ruleset_t *pThis, uchar *pszName) +static rsRetVal setName(ruleset_t *pThis, uchar *pszName) { DEFiRet; free(pThis->pszName); diff --git a/runtime/ruleset.h b/runtime/ruleset.h index 8966a884..83b06947 100644 --- a/runtime/ruleset.h +++ b/runtime/ruleset.h @@ -2,7 +2,7 @@ * * This implements rulesets within rsyslog. * - * Copyright 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2009-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -46,8 +46,8 @@ BEGINinterface(ruleset) /* name must also be changed in ENDinterface macro! */ rsRetVal (*Destruct)(ruleset_t **ppThis); rsRetVal (*IterateAllActions)(rsconf_t *conf, rsRetVal (*pFunc)(void*, void*), void* pParam); rsRetVal (*DestructAllActions)(rsconf_t *conf); - rsRetVal (*AddRule)(rsconf_t *conf, ruleset_t *pThis, rule_t **ppRule); - rsRetVal (*SetName)(rsconf_t *conf, ruleset_t *pThis, uchar *pszName); + rsRetVal (*AddRule)(ruleset_t *pThis, rule_t **ppRule); + rsRetVal (*SetName)(ruleset_t *pThis, uchar *pszName); rsRetVal (*ProcessBatch)(batch_t*); rsRetVal (*GetRuleset)(rsconf_t *conf, ruleset_t **ppThis, uchar*); rsRetVal (*SetDefaultRuleset)(rsconf_t *conf, uchar*); @@ -58,9 +58,12 @@ BEGINinterface(ruleset) /* name must also be changed in ENDinterface macro! */ parserList_t* (*GetParserList)(rsconf_t *conf, msg_t *); /* v5, 2011-04-19 * added support for the rsconf object -- fundamental change + * v6, 2011-07-15 + * removed conf ptr from SetName, AddRule as the flex/bison based + * system uses globals in any case. */ ENDinterface(ruleset) -#define rulesetCURR_IF_VERSION 5 /* increment whenever you change the interface structure! */ +#define rulesetCURR_IF_VERSION 6 /* increment whenever you change the interface structure! */ /* prototypes */ -- cgit v1.2.3 From 84ca2c443680de2c7e98f27972fb6300a025d62d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 15 Jul 2011 15:32:11 +0200 Subject: better check for config errors --- grammar/mini.samp | 4 ++-- grammar/rainerscript.c | 44 +++++++++++++++++++++++++++++++++++++++++--- grammar/rainerscript.h | 35 ++++++++++++++++++----------------- grammar/testdriver.c | 3 ++- 4 files changed, 63 insertions(+), 23 deletions(-) diff --git a/grammar/mini.samp b/grammar/mini.samp index 505ae67a..3bb0de44 100644 --- a/grammar/mini.samp +++ b/grammar/mini.samp @@ -1,5 +1,5 @@ #global (dnscache="yes" arg1="1 2" arg2 = "1 2" arg3 ="1=2\"3") -action(type="omuser" target="all") +action(type="omuser" target="all" target="all2") global (dnscache="no" b="2") $FileOwner root *.* * @@ -28,6 +28,6 @@ if not (1==0) and 2*4/-5--(10-3)>7/*pri("*.*")*/ then { action(type="omfile" taget="/var/log/log5") action(type="omfile" taget="/var/log/log6") action(type="omfwd" taget="10.0.0.1" port="514") - action(type="omwusr" taget="rger") + action(type="omwusr" taget="rger" taget="rger2") } if getenv("user") == "test" then /var/log/testlog diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 5d64abb4..16140a3f 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -95,7 +95,8 @@ nvlstNew(es_str_t *name, es_str_t *value) if((lst = malloc(sizeof(struct nvlst))) != NULL) { lst->next = NULL; lst->name = name; - lst->value = value; + lst->val.datatype = 'S'; + lst->val.d.estr = value; } return lst; @@ -110,7 +111,8 @@ nvlstDestruct(struct nvlst *lst) toDel = lst; lst = lst->next; es_deleteStr(toDel->name); - es_deleteStr(toDel->value); + if(toDel->val.datatype == 'S') + es_deleteStr(toDel->val.d.estr); free(toDel); } } @@ -122,7 +124,8 @@ nvlstPrint(struct nvlst *lst) dbgprintf("nvlst %p:\n", lst); while(lst != NULL) { name = es_str2cstr(lst->name, NULL); - value = es_str2cstr(lst->value, NULL); + // TODO: support for non-string types + value = es_str2cstr(lst->val.d.estr, NULL); dbgprintf("\tname: '%s', value '%s'\n", name, value); free(name); free(value); @@ -130,12 +133,47 @@ nvlstPrint(struct nvlst *lst) } } +/* find a name starting at node lst. Returns node with this + * name or NULL, if none found. + */ +struct nvlst* +nvlstFindName(struct nvlst *lst, es_str_t *name) +{ + while(lst != NULL && es_strcmp(lst->name, name)) + lst = lst->next; + return lst; +} + + +/* check if there are duplicate names inside a nvlst and emit + * an error message, if so. + */ +static inline void +nvlstChkDupes(struct nvlst *lst) +{ + char *cstr; + + while(lst != NULL) { + if(nvlstFindName(lst->next, lst->name) != NULL) { + cstr = es_str2cstr(lst->name, NULL); + parser_errmsg("duplicate parameter '%s' -- " + "interpretation is ambigious, one value " + "will be randomly selected. Fix this problem.", + cstr); + free(cstr); + } + lst = lst->next; + } +} + + struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst) { struct cnfobj *o; if((o = malloc(sizeof(struct nvlst))) != NULL) { + nvlstChkDupes(lst); o->objType = objType; o->nvlst = lst; } diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 3129ed25..2c4d764f 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -40,6 +40,22 @@ cnfobjType2str(enum cnfobjType ot) enum cnfactType { CNFACT_V2, CNFACT_LEGACY }; +/* a variant type, for example used for expression evaluation + * 2011-07-15/rger: note that there exists a "legacy" object var_t, + * which implements the same idea, but in a suboptimal manner. I have + * stipped this down as much as possible, but will keep it for a while + * to avoid unnecessary complexity during development. TODO: in the long + * term, var_t shall be replaced by struct var. + */ +struct var { + union { + es_str_t *estr; + struct cnfexpr *expr; + long long n; + } d; + char datatype; /* 'N' number, 'S' string, 'E' expression */ +}; + struct cnfobj { enum cnfobjType objType; struct nvlst *nvlst; @@ -48,7 +64,7 @@ struct cnfobj { struct nvlst { struct nvlst *next; es_str_t *name; - es_str_t *value; + struct var val; }; struct cnfcfsyslinelst { @@ -156,27 +172,12 @@ struct x { }; */ -/* a variant type, for example used for expression evaluation - * 2011-07-15/rger: note that there exists a "legacy" object var_t, - * which implements the same idea, but in a suboptimal manner. I have - * stipped this down as much as possible, but will keep it for a while - * to avoid unnecessary complexity during development. TODO: in the long - * term, var_t shall be replaced by struct var. - */ -struct var { - union { - es_str_t *estr; - long long n; - } d; - char datatype; /* 'N' - number, 'S' - string */ -}; - - int cnfParseBuffer(char *buf, unsigned lenBuf); void readConfFile(FILE *fp, es_str_t **str); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); void nvlstDestruct(struct nvlst *lst); void nvlstPrint(struct nvlst *lst); +struct nvlst* nvlstFindName(struct nvlst *lst, es_str_t *name); struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst); void cnfobjDestruct(struct cnfobj *o); void cnfobjPrint(struct cnfobj *o); diff --git a/grammar/testdriver.c b/grammar/testdriver.c index 784e286e..b29626d4 100644 --- a/grammar/testdriver.c +++ b/grammar/testdriver.c @@ -88,7 +88,8 @@ void cnfDoBSDHost(char *ln) } es_str_t* -cnfGetVar(char *name, void *usrptr) +cnfGetVar(char __attribute__((unused)) *name, + void __attribute__((unused)) *usrptr) { es_str_t *estr; estr = es_newStrFromCStr("", 1); -- cgit v1.2.3 From 162b409c2c8d3e33e6dbc7543862a9b82baaa44d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 15 Jul 2011 17:07:09 +0200 Subject: bugfix: misaddressing in config handler In theory, can cause segfault, in practice this is extremely unlikely Thanks to Marcin for alertig me. --- ChangeLog | 3 +++ runtime/rsconf.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 7ae5dffc..be11c02f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ --------------------------------------------------------------------------- Version 6.3.4 [DEVEL] (rgerhards), 2011-07-?? +- bugfix: misaddressing in config handler + In theory, can cause segfault, in practice this is extremely unlikely + Thanks to Marcin for alertig me. --------------------------------------------------------------------------- Version 6.3.3 [DEVEL] (rgerhards), 2011-07-13 - rsyslog.conf format: now parsed by RainerScript parser diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 0ccf2d57..f369dadf 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -339,7 +339,7 @@ parser_errmsg(char *fmt, ...) va_start(ap, fmt); if(vsnprintf(errBuf, sizeof(errBuf), fmt, ap) == sizeof(errBuf)) - errBuf[1024] = '\0'; + errBuf[1023] = '\0'; errmsg.LogError(0, RS_RET_CONF_PARSE_ERROR, "error during parsing file %s, on or before line %d: %s", cnfcurrfn, yylineno, errBuf); -- cgit v1.2.3 From 63d357862051fd8fea4e26bd424bdfc0e837a158 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 15 Jul 2011 18:03:02 +0200 Subject: removed some printf's left in lexer may cause some mild confusion if someone actually uses the not-yet-officially-supported construct --- grammar/lexer.l | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/grammar/lexer.l b/grammar/lexer.l index 760ed903..5ad646ad 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -64,6 +64,7 @@ #include #include #include "rainerscript.h" +#include "parserif.h" #include "grammar.h" static int preCommentState; /* save for lex state before a comment */ @@ -128,11 +129,11 @@ int fileno(FILE *stream); [ \t\n] [a-z][a-z0-9_]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); return FUNC; } -. { printf("invalid char in expr: %s\n", yytext); } +. { dbgprintf("invalid char in expr: %s\n", yytext); } "&" { return '&'; } "{" { return '{'; } "}" { return '}'; } -"ruleset" { printf("RULESET\n"); } +"ruleset" { dbgprintf("RULESET\n"); } /* line number support because the "preprocessor" combines lines and so needs * to tell us the real source line. */ @@ -180,7 +181,7 @@ int fileno(FILE *stream); ([^*]|\n)+|. #.*$ /* skip comments in input */ [ \n\t] -. { printf("INOBJ: invalid char '%s'\n", yytext); } +. { dbgprintf("INOBJ: invalid char '%s'\n", yytext); } \$[a-z]+.*$ { /* see common on $IncludeConfig above */ if(!strncasecmp(yytext, "$includeconfig ", 14)) { yyless(14); @@ -196,7 +197,7 @@ int fileno(FILE *stream); ^[ \t]*[+-][a-z0-9.:-]+[ \t]*$ { yylval.s = strdup(yytext); return BSD_HOST_SELECTOR; } \#.*\n /* skip comments in input */ [\n\t ] /* drop whitespace */ -. { printf("invalid char: %s\n", yytext); +. { dbgprintf("invalid char: %s\n", yytext); } <> { if(popfile() != 0) yyterminate(); } -- cgit v1.2.3 From 127d61fea78c967d2cdc536f898da425ffdd8a11 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Jul 2011 09:31:17 +0200 Subject: milestone: first steps at global() conf obj implementation also, the foundation for accessing conf file params has been laid. Still more work to do... --- grammar/Makefile.am | 2 + grammar/rainerscript.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++ grammar/rainerscript.h | 43 +++++++++++++++ runtime/glbl.c | 40 +++++++++++++- runtime/rsconf.c | 5 ++ runtime/typedefs.h | 1 + 6 files changed, 228 insertions(+), 2 deletions(-) diff --git a/grammar/Makefile.am b/grammar/Makefile.am index 9767c12f..4746a9de 100644 --- a/grammar/Makefile.am +++ b/grammar/Makefile.am @@ -11,7 +11,9 @@ libgrammar_la_SOURCES = \ rainerscript.h \ parserif.h \ grammar.h +libgrammar_la_CPPFLAGS = $(RSRT_CFLAGS) testdriver_SOURCES = testdriver.c libgrammar.la +testdriver_CPPFLAGS = $(RSRT_CFLAGS) testdriver_LDADD = libgrammar.la testdriver_LDFLAGS = -lestr diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 16140a3f..754910da 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -97,6 +97,7 @@ nvlstNew(es_str_t *name, es_str_t *value) lst->name = name; lst->val.datatype = 'S'; lst->val.d.estr = value; + lst->bUsed = 0; } return lst; @@ -145,6 +146,18 @@ nvlstFindName(struct nvlst *lst, es_str_t *name) } +/* find a name starting at node lst. SAme as nvlstFindName, but + * for classical C strings. This is useful because the config system + * uses C string constants. + */ +static inline struct nvlst* +nvlstFindNameCStr(struct nvlst *lst, char *name) +{ + while(lst != NULL && es_strbufcmp(lst->name, (uchar*)name, strlen(name))) + lst = lst->next; + return lst; +} + /* check if there are duplicate names inside a nvlst and emit * an error message, if so. */ @@ -167,6 +180,113 @@ nvlstChkDupes(struct nvlst *lst) } +/* check for unused params and emit error message is found. This must + * be called after all config params have been pulled from the object + * (otherwise the flags are not correctly set). + */ +void +nvlstChkUnused(struct nvlst *lst) +{ + char *cstr; + + while(lst != NULL) { + if(!lst->bUsed) { + cstr = es_str2cstr(lst->name, NULL); + parser_errmsg("parameter '%s' not known -- " + "typo in config file?", + cstr); + free(cstr); + } + lst = lst->next; + } +} + + +/* get a single parameter according to its definition. Helper to + * nvlstGetParams. + */ +static inline void +nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *vals) +{ + dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d\n", + param->name, (int) param->type); + switch(param->type) { + case eCmdHdlrUID: + break; + case eCmdHdlrGID: + break; + case eCmdHdlrBinary: + break; + case eCmdHdlrFileCreateMode: + break; + case eCmdHdlrInt: + break; + case eCmdHdlrSize: + break; + case eCmdHdlrGetChar: + break; + case eCmdHdlrFacility: + break; + case eCmdHdlrSeverity: + break; + case eCmdHdlrGetWord: + break; + case eCmdHdlrString: + break; + case eCmdHdlrGoneAway: + parser_errmsg("parameter '%s' is no longer supported", + param->name); + break; + default: + dbgprintf("error: invalid param type\n"); + break; + } +} + + +/* obtain conf params from an nvlst and emit error messages if + * necessary. If an already-existing param value is passed, that is + * used. If NULL is passed instead, a new one is allocated. In that case, + * it is the caller's duty to free it when no longer needed. + * NULL is returned on error, otherwise a pointer to the vals array. + */ +struct cnfparamvals* +nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, + struct cnfparamvals *vals) +{ + int i; + struct nvlst *valnode; + struct cnfparamdescr *param; + + if(params->version != CNFPARAMBLK_VERSION) { + dbgprintf("nvlstGetParams: invalid param block version " + "%d, expected %d\n", + params->version, CNFPARAMBLK_VERSION); + return NULL; + } + + if(vals == NULL) { + if((vals = malloc(params->nParams * + sizeof(struct cnfparamvals))) == NULL) + return NULL; + } + + for(i = 0 ; i < params->nParams ; ++i) { + param = params->descr + i; + if((valnode = nvlstFindNameCStr(lst, param->name)) == NULL) + continue; + if(vals[i].bUsed) { + parser_errmsg("parameter '%s' specified more than once - " + "one instance is ignored. Fix config", param->name); + continue; + } + nvlstGetParam(lst, param, vals + i); + } + return vals; +} + + struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst) { @@ -1140,6 +1260,25 @@ cnfDoInclude(char *name) return 0; } +/* find the index (or -1!) for a config param by name. This is used to + * address the parameter array. Of course, we could use with static + * indices, but that would create some extra bug potential. So we + * resort to names. As we do this only during the initial config parsing + * stage the (considerable!) extra overhead is OK. -- rgerhards, 2011-07-19 + */ +int +cnfparamGetIdx(struct cnfparamblk *params, char *name) +{ + int i; + for(i = 0 ; i < params->nParams ; ++i) + if(!strcmp(params->descr[i].name, name)) + break; + if(i == params->nParams) + i = -1; /* not found */ + return i; +} + + void cstrPrint(char *text, es_str_t *estr) { diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 2c4d764f..1dc5719d 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -2,6 +2,7 @@ #define INC_UTILS_H #include #include +#include #define CNFFUNC_MAX_ARGS 32 /**< maximum number of arguments that any function can have (among @@ -65,6 +66,11 @@ struct nvlst { struct nvlst *next; es_str_t *name; struct var val; + unsigned char *bUsed; + /**< was this node used during config processing? If not, this + * indicates an error. After all, the user specified a setting + * that the software does not know. + */ }; struct cnfcfsyslinelst { @@ -172,6 +178,40 @@ struct x { }; */ + +/* the following defines describe the parameter block for puling + * config parameters. Note that the focus is on ease and saveness of + * use, not performance. For example, we address parameters by name + * instead of index, because the former is less error-prone. The (severe) + * performance hit does not matter, as it is a one-time hit during config + * load but never during actual processing. So there is really no reason + * to care. + */ +struct cnfparamdescr { /* first the param description */ + char *name; /**< not a es_str_t to ease definition in code */ + ecslCmdHdrlType type; + unsigned flags; +}; +/* flags for cnfparamdescr: */ +#define CNFPARAM_REQUIRED 0x0001 + +struct cnfparamblk { /* now the actual param block use in API calls */ + unsigned short version; + unsigned short nParams; + struct cnfparamdescr *descr; +}; +#define CNFPARAMBLK_VERSION 1 + /**< caller must have same version as engine -- else things may + * be messed up. But note that we may support multiple versions + * inside the engine, if at some later stage we want to do + * that. -- rgerhards, 2011-07-15 + */ +struct cnfparamvals { /* the values we obtained for param descr. */ + struct var val; + unsigned char bUsed; +}; + + int cnfParseBuffer(char *buf, unsigned lenBuf); void readConfFile(FILE *fp, es_str_t **str); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); @@ -198,6 +238,9 @@ struct cnfvar* cnfvarNew(char *name); struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst); struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next); int cnfDoInclude(char *name); +int cnfparamGetIdx(struct cnfparamblk *params, char *name); +struct cnfparamvals* nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, + struct cnfparamvals *vals); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); diff --git a/runtime/glbl.c b/runtime/glbl.c index 2fd52a5a..f978e1b3 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -7,7 +7,7 @@ * * Module begun 2008-04-16 by Rainer Gerhards * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. + * Copyright 2008-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -44,6 +44,7 @@ #include "prop.h" #include "atomic.h" #include "errmsg.h" +#include "rainerscript.h" /* some defaults */ #ifndef DFLT_NETSTRM_DRVR @@ -88,6 +89,28 @@ static int iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask); /* si #endif +/* tables for interfacing with the v6 config system */ +static struct cnfparamdescr cnfparamdescr[] = { + { "workdirectory", eCmdHdlrString, 0 }, + { "dropmsgswithmaliciousdnsptrrecords", eCmdHdlrBinary, 0 }, + { "localhostname", eCmdHdlrGetWord, 0 }, + { "preservefqdn", eCmdHdlrBinary, 0 }, + { "defaultnetstreamdrivercafile", eCmdHdlrString, 0 }, + { "defaultnetstreamdriverkeyfile", eCmdHdlrString, 0 }, + { "defaultnetstreamdriver", eCmdHdlrString, 0 }, +}; +static struct cnfparamblk paramblk = + { CNFPARAMBLK_VERSION, + sizeof(cnfparamdescr)/sizeof(struct cnfparamdescr), + cnfparamdescr + }; + +static struct cnfparamvals *cnfparamvals = NULL; +/* we need to support multiple calls into our param block, so we need + * to persist the current settings. Note that this must be re-set + * each time a new config load begins (TODO: create interface?) + */ + /* define a macro for the simple properties' set and get functions * (which are always the same). This is only suitable for pretty * simple cases which require neither checks nor memory allocation. @@ -143,7 +166,7 @@ static int GetGlobalInputTermState(void) } -/* set global termiantion state to "terminate". Note that this is a +/* set global termination state to "terminate". Note that this is a * "once in a lifetime" action which can not be undone. -- gerhards, 2009-07-20 */ static void SetGlobalInputTermination(void) @@ -407,6 +430,17 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a } +/* handle a global config object. Note that multiple global config statements + * are permitted (because of plugin support), so once we got a param block, + * we need to hold to it. + * rgerhards, 2011-07-19 + */ +void +glblProcessCnf(struct cnfobj *o) +{ + cnfparamvals = nvlstGetParams(o->nvlst, ¶mblk, cnfparamvals); +} + /* Initialize the glbl class. Must be called as the very first method * before anything else is called inside this class. @@ -456,5 +490,7 @@ BEGINObjClassExit(glbl, OBJ_IS_CORE_MODULE) /* class, version */ DESTROY_ATOMIC_HELPER_MUT(mutTerminateInputs); ENDObjClassExit(glbl) +void glblProcessCnf(struct cnfobj *o); + /* vi:set ai: */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index f369dadf..aa7a3e3b 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -356,6 +356,11 @@ void cnfDoObj(struct cnfobj *o) { dbgprintf("cnf:global:obj: "); cnfobjPrint(o); + switch(o->objType) { + case CNFOBJ_GLOBAL: + glblProcessCnf(o); + break; + } cnfobjDestruct(o); } diff --git a/runtime/typedefs.h b/runtime/typedefs.h index 11061e14..d46851f6 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -159,6 +159,7 @@ typedef enum cslCmdHdlrType { eCmdHdlrFacility, eCmdHdlrSeverity, eCmdHdlrGetWord, + eCmdHdlrString, eCmdHdlrGoneAway /* statment existed, but is no longer supported */ } ecslCmdHdrlType; -- cgit v1.2.3 From 47c961eac280f72a472ad82764f8fd450ba3643f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Jul 2011 11:23:57 +0200 Subject: milestone: two syntaxes for get conf param implemented --- grammar/rainerscript.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++--- grammar/rainerscript.h | 1 + runtime/glbl.c | 2 ++ 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 754910da..502deece 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -202,21 +202,59 @@ nvlstChkUnused(struct nvlst *lst) } +static inline void +doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + val->val.datatype = 'N'; + if(!es_strbufcmp(valnode->val.d.estr, (unsigned char*) "on", 2)) { + val->val.d.n = 1; + } else if(!es_strbufcmp(valnode->val.d.estr, (unsigned char*) "off", 3)) { + val->val.d.n = 0; + } else { + parser_errmsg("parameter '%s' must be \"on\" or \"off\" but " + "is neither. Results unpredictable.", param->name); + val->val.d.n = 0; + } +} + + +static inline void +doGetWord(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + es_size_t i; + unsigned char *c; + val->val.datatype = 'S'; + val->val.d.estr = es_newStr(32); + c = es_getBufAddr(valnode->val.d.estr); + for(i = 0 ; i < es_strlen(valnode->val.d.estr) && !isspace(c[i]) ; ++i) { + es_addChar(&val->val.d.estr, c[i]); + } + if(i != es_strlen(valnode->val.d.estr)) { + parser_errmsg("parameter '%s' contains whitespace, which is not " + "permitted - data after first whitespace ignored", + param->name); + } +} + /* get a single parameter according to its definition. Helper to * nvlstGetParams. */ static inline void nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, - struct cnfparamvals *vals) + struct cnfparamvals *val) { dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d\n", param->name, (int) param->type); + val->bUsed = 1; switch(param->type) { case eCmdHdlrUID: break; case eCmdHdlrGID: break; case eCmdHdlrBinary: + doGetBinary(valnode, param, val); break; case eCmdHdlrFileCreateMode: break; @@ -231,8 +269,11 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, case eCmdHdlrSeverity: break; case eCmdHdlrGetWord: + doGetWord(valnode, param, val); break; case eCmdHdlrString: + val->val.datatype = 'S'; + val->val.d.estr = es_strdup(valnode->val.d.estr); break; case eCmdHdlrGoneAway: parser_errmsg("parameter '%s' is no longer supported", @@ -267,9 +308,9 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, } if(vals == NULL) { - if((vals = malloc(params->nParams * + if((vals = calloc(params->nParams, sizeof(struct cnfparamvals))) == NULL) - return NULL; + return NULL; } for(i = 0 ; i < params->nParams ; ++i) { @@ -281,12 +322,42 @@ nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, "one instance is ignored. Fix config", param->name); continue; } - nvlstGetParam(lst, param, vals + i); + nvlstGetParam(valnode, param, vals + i); } return vals; } +void +cnfparamsPrint(struct cnfparamblk *params, struct cnfparamvals *vals) +{ + int i; + char *cstr; + + for(i = 0 ; i < params->nParams ; ++i) { + dbgprintf("%s: ", params->descr[i].name); + if(vals[i].bUsed) { + // TODO: other types! + switch(vals[i].val.datatype) { + case 'S': + cstr = es_str2cstr(vals[i].val.d.estr, NULL); + dbgprintf(" '%s'", cstr); + free(cstr); + break; + case 'N': + dbgprintf("%lld", vals[i].val.d.n); + break; + default: + dbgprintf("(unsupported datatype %c)", + vals[i].val.datatype); + } + } else { + dbgprintf("(unset)"); + } + dbgprintf("\n"); + } +} + struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst) { diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 1dc5719d..03e59895 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -241,6 +241,7 @@ int cnfDoInclude(char *name); int cnfparamGetIdx(struct cnfparamblk *params, char *name); struct cnfparamvals* nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, struct cnfparamvals *vals); +void cnfparamsPrint(struct cnfparamblk *params, struct cnfparamvals *vals); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); diff --git a/runtime/glbl.c b/runtime/glbl.c index f978e1b3..4ca99303 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -439,6 +439,8 @@ void glblProcessCnf(struct cnfobj *o) { cnfparamvals = nvlstGetParams(o->nvlst, ¶mblk, cnfparamvals); + dbgprintf("glbl param blk after glblProcessCnf:\n"); + cnfparamsPrint(¶mblk, cnfparamvals); } -- cgit v1.2.3 From 74c2e98c13daf60bf5371f77111196679dd7df55 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Jul 2011 17:53:23 +0200 Subject: milestone: glbl obj parameters settable via new conf interface --- grammar/rainerscript.c | 2 ++ grammar/rainerscript.h | 1 + runtime/glbl.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ runtime/glbl.h | 4 ++++ runtime/rsconf.c | 19 +++++++++++++++--- 5 files changed, 77 insertions(+), 3 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 502deece..92b07a5f 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -158,6 +158,7 @@ nvlstFindNameCStr(struct nvlst *lst, char *name) return lst; } + /* check if there are duplicate names inside a nvlst and emit * an error message, if so. */ @@ -247,6 +248,7 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, { dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d\n", param->name, (int) param->type); + valnode->bUsed = 1; val->bUsed = 1; switch(param->type) { case eCmdHdlrUID: diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 03e59895..f7454ef5 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -217,6 +217,7 @@ void readConfFile(FILE *fp, es_str_t **str); struct nvlst* nvlstNew(es_str_t *name, es_str_t *value); void nvlstDestruct(struct nvlst *lst); void nvlstPrint(struct nvlst *lst); +void nvlstChkUnused(struct nvlst *lst); struct nvlst* nvlstFindName(struct nvlst *lst, es_str_t *name); struct cnfobj* cnfobjNew(enum cnfobjType objType, struct nvlst *lst); void cnfobjDestruct(struct cnfobj *o); diff --git a/runtime/glbl.c b/runtime/glbl.c index 4ca99303..6b7d487f 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -430,6 +430,15 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a } +/* Prepare for new config + */ +void +glblPrepCnf(void) +{ + free(cnfparamvals); + cnfparamvals = NULL; +} + /* handle a global config object. Note that multiple global config statements * are permitted (because of plugin support), so once we got a param block, * we need to hold to it. @@ -443,6 +452,51 @@ glblProcessCnf(struct cnfobj *o) cnfparamsPrint(¶mblk, cnfparamvals); } +rsRetVal +glblCheckCnf() +{ +} + +void +glblDoneLoadCnf() +{ + int i; + unsigned char *cstr; + + for(i = 0 ; i < paramblk.nParams ; ++i) { + if(!cnfparamvals[i].bUsed) + continue; + if(!strcmp(paramblk.descr[i].name, "workdirectory")) { + cstr = (uchar*) es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + setWorkDir(NULL, cstr); + } else if(!strcmp(paramblk.descr[i].name, "localhostname")) { + free(LocalHostNameOverride); + LocalHostNameOverride = (uchar*) + es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + } else if(!strcmp(paramblk.descr[i].name, "defaultnetstreamdriverkeyfile")) { + free(pszDfltNetstrmDrvrKeyFile); + pszDfltNetstrmDrvrKeyFile = (uchar*) + es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + } else if(!strcmp(paramblk.descr[i].name, "defaultnetstreamdrivercafile")) { + free(pszDfltNetstrmDrvrCAF); + pszDfltNetstrmDrvrCAF = (uchar*) + es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + } else if(!strcmp(paramblk.descr[i].name, "defaultnetstreamdriver")) { + free(pszDfltNetstrmDrvr); + pszDfltNetstrmDrvr = (uchar*) + es_str2cstr(cnfparamvals[i].val.d.estr, NULL); + } else if(!strcmp(paramblk.descr[i].name, "preservefqdn")) { + bPreserveFQDN = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, + "dropmsgswithmaliciousdnsptrrecords")) { + bDropMalPTRMsgs = (int) cnfparamvals[i].val.d.n; + } else { + dbgprintf("glblDoneLoadCnf: program error, non-handled " + "param '%s'\n", paramblk.descr[i].name); + } + } +} + /* Initialize the glbl class. Must be called as the very first method * before anything else is called inside this class. diff --git a/runtime/glbl.h b/runtime/glbl.h index 82bd1a7a..94eec23d 100644 --- a/runtime/glbl.h +++ b/runtime/glbl.h @@ -32,6 +32,7 @@ #ifndef GLBL_H_INCLUDED #define GLBL_H_INCLUDED +#include "rainerscript.h" #include "prop.h" #define glblGetIOBufSize() 4096 /* size of the IO buffer, e.g. for strm class */ @@ -85,4 +86,7 @@ ENDinterface(glbl) /* the remaining prototypes */ PROTOTYPEObj(glbl); +void glblPrepCnf(void); +void glblProcessCnf(struct cnfobj *o); + #endif /* #ifndef GLBL_H_INCLUDED */ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index aa7a3e3b..fd42caf9 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -361,6 +361,7 @@ void cnfDoObj(struct cnfobj *o) glblProcessCnf(o); break; } + nvlstChkUnused(o->nvlst); cnfobjDestruct(o); } @@ -542,6 +543,16 @@ dropPrivileges(rsconf_t *cnf) } +/* tell the rsysog core (including ourselfs) that the config load is done and + * we need to prepare to move over to activate mode. + */ +static inline void +tellCoreConfigLoadDone(void) +{ + glblDoneLoadCnf(); +} + + /* Tell input modules that the config parsing stage is over. */ static rsRetVal tellModulesConfigLoadDone(void) @@ -755,9 +766,7 @@ activate(rsconf_t *cnf) if(ourConf->globals.pszConfDAGFile != NULL) generateConfigDAG(ourConf->globals.pszConfDAGFile); # endif - tellModulesConfigLoadDone(); setUmask(cnf->globals.umask); - tellModulesCheckConfig(); /* the output part and the queue is now ready to run. So it is a good time * to initialize the inputs. Please note that the net code above should be @@ -911,7 +920,7 @@ finalize_it: } -/* legac config system: reset config variables to default values. */ +/* legacy config system: reset config variables to default values. */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { loadConf->globals.bLogStatusMsgs = DFLT_bLogStatusMsgs; @@ -1251,6 +1260,10 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! ABORT_FINALIZE(RS_RET_NO_ACTIONS); } + tellCoreConfigLoadDone(); + tellModulesConfigLoadDone(); + + tellModulesCheckConfig(); CHKiRet(validateConf()); /* we are done checking the config - now validate if we should actually run or not. -- cgit v1.2.3 From 02d44ba72d450199838dfa25eafcdf8c759ee5d4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 19 Jul 2011 18:26:26 +0200 Subject: milestone: size syntax implemented --- grammar/rainerscript.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ runtime/glbl.c | 8 +++++++- runtime/rsconf.c | 9 --------- 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 92b07a5f..76e3a0a4 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -203,6 +203,53 @@ nvlstChkUnused(struct nvlst *lst) } +static inline void +doGetSize(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + unsigned char *c; + es_size_t i; + long long n; + c = es_getBufAddr(valnode->val.d.estr); + n = 0; + i = 0; + while(i < es_strlen(valnode->val.d.estr) && isdigit(*c)) { + n = 10 * n + *c - '0'; + ++i; + ++c; + } + if(i < es_strlen(valnode->val.d.estr)) { + ++i; + switch(*c) { + /* traditional binary-based definitions */ + case 'k': n *= 1024; break; + case 'm': n *= 1024 * 1024; break; + case 'g': n *= 1024 * 1024 * 1024; break; + case 't': n *= (int64) 1024 * 1024 * 1024 * 1024; break; /* tera */ + case 'p': n *= (int64) 1024 * 1024 * 1024 * 1024 * 1024; break; /* peta */ + case 'e': n *= (int64) 1024 * 1024 * 1024 * 1024 * 1024 * 1024; break; /* exa */ + /* and now the "new" 1000-based definitions */ + case 'K': n *= 1000; break; + case 'M': n *= 1000000; break; + case 'G': n *= 1000000000; break; + /* we need to use the multiplication below because otherwise + * the compiler gets an error during constant parsing */ + case 'T': n *= (int64) 1000 * 1000000000; break; /* tera */ + case 'P': n *= (int64) 1000000 * 1000000000; break; /* peta */ + case 'E': n *= (int64) 1000000000 * 1000000000; break; /* exa */ + default: --i; break; /* indicates error */ + } + } + if(i == es_strlen(valnode->val.d.estr)) { + val->val.datatype = 'N'; + val->val.d.n = n; + } else { + parser_errmsg("parameter '%s' does not contain a valid size", + param->name); + } +} + + static inline void doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) @@ -263,6 +310,7 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, case eCmdHdlrInt: break; case eCmdHdlrSize: + doGetSize(valnode, param, val); break; case eCmdHdlrGetChar: break; diff --git a/runtime/glbl.c b/runtime/glbl.c index 6b7d487f..eeca347a 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -64,7 +64,7 @@ static uchar *pszWorkDir = NULL; static int bOptimizeUniProc = 1; /* enable uniprocessor optimizations */ static int bParseHOSTNAMEandTAG = 1; /* parser modification (based on startup params!) */ static int bPreserveFQDN = 0; /* should FQDNs always be preserved? */ -static int iMaxLine = 2048; /* maximum length of a syslog message */ +static int iMaxLine = 8096; /* maximum length of a syslog message */ static int iDefPFFamily = PF_UNSPEC; /* protocol family (IPv4, IPv6 or both) */ static int bDropMalPTRMsgs = 0;/* Drop messages which have malicious PTR records during DNS lookup */ static int option_DisallowWarning = 1; /* complain if message from disallowed sender is received */ @@ -98,6 +98,7 @@ static struct cnfparamdescr cnfparamdescr[] = { { "defaultnetstreamdrivercafile", eCmdHdlrString, 0 }, { "defaultnetstreamdriverkeyfile", eCmdHdlrString, 0 }, { "defaultnetstreamdriver", eCmdHdlrString, 0 }, + { "maxmessagesize", eCmdHdlrSize, 0 }, }; static struct cnfparamblk paramblk = { CNFPARAMBLK_VERSION, @@ -423,6 +424,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a bDropMalPTRMsgs = 0; bOptimizeUniProc = 1; bPreserveFQDN = 0; + iMaxLine = 8192; #ifdef USE_UNLIMITED_SELECT iFdSetSize = howmany(FD_SETSIZE, __NFDBITS) * sizeof (fd_mask); #endif @@ -490,6 +492,8 @@ glblDoneLoadCnf() } else if(!strcmp(paramblk.descr[i].name, "dropmsgswithmaliciousdnsptrrecords")) { bDropMalPTRMsgs = (int) cnfparamvals[i].val.d.n; + } else if(!strcmp(paramblk.descr[i].name, "maxmessagesize")) { + iMaxLine = (int) cnfparamvals[i].val.d.n; } else { dbgprintf("glblDoneLoadCnf: program error, non-handled " "param '%s'\n", paramblk.descr[i].name); @@ -517,6 +521,8 @@ BEGINAbstractObjClassInit(glbl, 1, OBJ_IS_CORE_MODULE) /* class, version */ CHKiRet(regCfSysLineHdlr((uchar *)"localhostname", 0, eCmdHdlrGetWord, NULL, &LocalHostNameOverride, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"optimizeforuniprocessor", 0, eCmdHdlrBinary, NULL, &bOptimizeUniProc, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"preservefqdn", 0, eCmdHdlrBinary, NULL, &bPreserveFQDN, NULL, eConfObjGlobal)); + CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, + NULL, &iMaxLine, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL, eConfObjGlobal)); INIT_ATOMIC_HELPER_MUT(mutTerminateInputs); diff --git a/runtime/rsconf.c b/runtime/rsconf.c index fd42caf9..26105e88 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -805,13 +805,6 @@ static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int } -/* set the maximum message size */ -static rsRetVal setMaxMsgSize(void __attribute__((unused)) *pVal, long iNewVal) -{ - return glbl.SetMaxLine(iNewVal); -} - - /* Switch the default ruleset (that, what servcies bind to if nothing specific * is specified). * rgerhards, 2009-06-12 @@ -1083,8 +1076,6 @@ initLegacyConf(void) setActionResumeInterval, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler, conf.doModLoad, NULL, NULL, eConfObjGlobal)); - CHKiRet(regCfSysLineHdlr((uchar *)"maxmessagesize", 0, eCmdHdlrSize, - setMaxMsgSize, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord, setDefaultRuleset, NULL, NULL, eConfObjGlobal)); CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord, -- cgit v1.2.3 From a7e3afb20b461f608f478e8fca15b02e67d6d9c3 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 20 Jul 2011 10:47:24 +0200 Subject: milestone: added module config names --- plugins/im3195/im3195.c | 1 + plugins/imdiag/imdiag.c | 1 + plugins/imfile/imfile.c | 1 + plugins/imgssapi/imgssapi.c | 1 + plugins/imklog/imklog.c | 1 + plugins/immark/immark.c | 1 + plugins/impstats/impstats.c | 1 + plugins/imptcp/imptcp.c | 1 + plugins/imrelp/imrelp.c | 1 + plugins/imsolaris/imsolaris.c | 1 + plugins/imtcp/imtcp.c | 1 + plugins/imtemplate/imtemplate.c | 1 + plugins/imttcp/imttcp.c | 1 + plugins/imudp/imudp.c | 1 + plugins/imuxsock/imuxsock.c | 1 + plugins/mmnormalize/mmnormalize.c | 1 + plugins/mmsnmptrapd/mmsnmptrapd.c | 1 + plugins/omdbalerting/omdbalerting.c | 1 + plugins/omgssapi/omgssapi.c | 1 + plugins/omhdfs/omhdfs.c | 1 + plugins/omlibdbi/omlibdbi.c | 1 + plugins/ommail/ommail.c | 1 + plugins/ommongodb/ommongodb.c | 3 +- plugins/ommysql/ommysql.c | 1 + plugins/omoracle/omoracle.c | 1 + plugins/ompgsql/ompgsql.c | 1 + plugins/omprog/omprog.c | 1 + plugins/omrelp/omrelp.c | 1 + plugins/omruleset/omruleset.c | 1 + plugins/omsnmp/omsnmp.c | 1 + plugins/omstdout/omstdout.c | 1 + plugins/omtemplate/omtemplate.c | 1 + plugins/omtesting/omtesting.c | 1 + plugins/omudpspoof/omudpspoof.c | 1 + plugins/omuxsock/omuxsock.c | 1 + plugins/pmaixforwardedfrom/pmaixforwardedfrom.c | 1 + plugins/pmcisconames/pmcisconames.c | 1 + plugins/pmlastmsg/pmlastmsg.c | 1 + plugins/pmrfc3164sd/pmrfc3164sd.c | 1 + plugins/pmsnare/pmsnare.c | 1 + plugins/sm_cust_bindcdr/sm_cust_bindcdr.c | 1 + runtime/conf.c | 81 ------------------------- runtime/glbl.c | 4 ++ runtime/module-template.h | 12 ++++ runtime/modules.c | 11 +++- runtime/modules.h | 3 +- 46 files changed, 69 insertions(+), 85 deletions(-) diff --git a/plugins/im3195/im3195.c b/plugins/im3195/im3195.c index fd642aaa..4214ab95 100644 --- a/plugins/im3195/im3195.c +++ b/plugins/im3195/im3195.c @@ -52,6 +52,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("im3195") /* Module static data */ DEF_IMOD_STATIC_DATA diff --git a/plugins/imdiag/imdiag.c b/plugins/imdiag/imdiag.c index b0025464..0ff5684d 100644 --- a/plugins/imdiag/imdiag.c +++ b/plugins/imdiag/imdiag.c @@ -58,6 +58,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("imdiag") /* static data */ DEF_IMOD_STATIC_DATA diff --git a/plugins/imfile/imfile.c b/plugins/imfile/imfile.c index 3537d809..8dc618ab 100644 --- a/plugins/imfile/imfile.c +++ b/plugins/imfile/imfile.c @@ -52,6 +52,7 @@ MODULE_TYPE_INPUT /* must be present for input modules, do not remove */ MODULE_TYPE_NOKEEP +MODULE_CNFNAME("imfile") /* defines */ diff --git a/plugins/imgssapi/imgssapi.c b/plugins/imgssapi/imgssapi.c index 868fca75..d5acbe40 100644 --- a/plugins/imgssapi/imgssapi.c +++ b/plugins/imgssapi/imgssapi.c @@ -63,6 +63,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("imgssapi") /* defines */ #define ALLOWEDMETHOD_GSS 2 diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c index b64a8f1f..239fccb7 100644 --- a/plugins/imklog/imklog.c +++ b/plugins/imklog/imklog.c @@ -62,6 +62,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("imklog") /* Module static data */ DEF_IMOD_STATIC_DATA diff --git a/plugins/immark/immark.c b/plugins/immark/immark.c index c7d6b554..9a768e49 100644 --- a/plugins/immark/immark.c +++ b/plugins/immark/immark.c @@ -47,6 +47,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("immark") /* defines */ #define DEFAULT_MARK_PERIOD (20 * 60) diff --git a/plugins/impstats/impstats.c b/plugins/impstats/impstats.c index 5e60d073..c3efb330 100644 --- a/plugins/impstats/impstats.c +++ b/plugins/impstats/impstats.c @@ -50,6 +50,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("impstats") /* defines */ #define DEFAULT_STATS_PERIOD (5 * 60) diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 1ee91bb7..645bddc7 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -75,6 +75,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("imptcp") /* static data */ DEF_IMOD_STATIC_DATA diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c index 1b03dcd3..5465b2a9 100644 --- a/plugins/imrelp/imrelp.c +++ b/plugins/imrelp/imrelp.c @@ -49,6 +49,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("imrelp") /* static data */ DEF_IMOD_STATIC_DATA diff --git a/plugins/imsolaris/imsolaris.c b/plugins/imsolaris/imsolaris.c index 05827a18..8b607a84 100644 --- a/plugins/imsolaris/imsolaris.c +++ b/plugins/imsolaris/imsolaris.c @@ -86,6 +86,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("imsolaris") /* defines */ #define PATH_LOG "/dev/log" diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index 142f0791..4fd717d7 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -66,6 +66,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("imtcp") /* static data */ DEF_IMOD_STATIC_DATA diff --git a/plugins/imtemplate/imtemplate.c b/plugins/imtemplate/imtemplate.c index f2b4752d..8d8b8ac4 100644 --- a/plugins/imtemplate/imtemplate.c +++ b/plugins/imtemplate/imtemplate.c @@ -81,6 +81,7 @@ MODULE_TYPE_INPUT /* must be present for input modules, do not remove */ MODULE_TYPE_NOKEEP +MODULE_CNFNAME("imtemplate") /* defines */ diff --git a/plugins/imttcp/imttcp.c b/plugins/imttcp/imttcp.c index 89c1dfd2..6f99aaad 100644 --- a/plugins/imttcp/imttcp.c +++ b/plugins/imttcp/imttcp.c @@ -122,6 +122,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("imttcp") /* static data */ DEF_IMOD_STATIC_DATA diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 0df80e87..161223fd 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -55,6 +55,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("imudp") /* defines */ diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 4eafe92a..f5330146 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -57,6 +57,7 @@ MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("imuxsock") /* defines */ #define MAXFUNIX 50 diff --git a/plugins/mmnormalize/mmnormalize.c b/plugins/mmnormalize/mmnormalize.c index 9c23afde..7679e788 100644 --- a/plugins/mmnormalize/mmnormalize.c +++ b/plugins/mmnormalize/mmnormalize.c @@ -48,6 +48,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("mmnormalize") static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); diff --git a/plugins/mmsnmptrapd/mmsnmptrapd.c b/plugins/mmsnmptrapd/mmsnmptrapd.c index aebd9af1..e4e2dcf4 100644 --- a/plugins/mmsnmptrapd/mmsnmptrapd.c +++ b/plugins/mmsnmptrapd/mmsnmptrapd.c @@ -49,6 +49,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("mmsnmptrapd") static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); diff --git a/plugins/omdbalerting/omdbalerting.c b/plugins/omdbalerting/omdbalerting.c index 35de5818..ec9cf346 100644 --- a/plugins/omdbalerting/omdbalerting.c +++ b/plugins/omdbalerting/omdbalerting.c @@ -45,6 +45,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omdbalerting") /* internal structures */ diff --git a/plugins/omgssapi/omgssapi.c b/plugins/omgssapi/omgssapi.c index 6b75540f..111bdd95 100644 --- a/plugins/omgssapi/omgssapi.c +++ b/plugins/omgssapi/omgssapi.c @@ -59,6 +59,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omgssapi") static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); diff --git a/plugins/omhdfs/omhdfs.c b/plugins/omhdfs/omhdfs.c index 48168f28..dc809f8d 100644 --- a/plugins/omhdfs/omhdfs.c +++ b/plugins/omhdfs/omhdfs.c @@ -51,6 +51,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omhdfs") /* internal structures */ diff --git a/plugins/omlibdbi/omlibdbi.c b/plugins/omlibdbi/omlibdbi.c index 98da2224..05a58369 100644 --- a/plugins/omlibdbi/omlibdbi.c +++ b/plugins/omlibdbi/omlibdbi.c @@ -53,6 +53,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omlibdbi") /* internal structures */ diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c index 6468dcf2..c2c797dd 100644 --- a/plugins/ommail/ommail.c +++ b/plugins/ommail/ommail.c @@ -55,6 +55,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("ommail") /* internal structures */ diff --git a/plugins/ommongodb/ommongodb.c b/plugins/ommongodb/ommongodb.c index 8e19105f..07050c14 100644 --- a/plugins/ommongodb/ommongodb.c +++ b/plugins/ommongodb/ommongodb.c @@ -31,6 +31,7 @@ #define MONGO_COLLECTION_NAME_SIZE 128 MODULE_TYPE_OUTPUT +MODULE_CNFNAME("ommongodb") /* internal structures */ DEF_OMOD_STATIC_DATA @@ -277,4 +278,4 @@ CODEmodInit_QueryRegCFSLineHdlr INITChkCoreFeature(bCoreSupportsBatching, CORE_FEATURE_BATCHING); DBGPRINTF("ompgsql: module compiled with rsyslog version %s.\n", VERSION); DBGPRINTF("ompgsql: %susing transactional output interface.\n", bCoreSupportsBatching ? "" : "not "); -ENDmodInit \ No newline at end of file +ENDmodInit diff --git a/plugins/ommysql/ommysql.c b/plugins/ommysql/ommysql.c index 978f3517..28cb25e6 100644 --- a/plugins/ommysql/ommysql.c +++ b/plugins/ommysql/ommysql.c @@ -47,6 +47,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("ommysql") static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); diff --git a/plugins/omoracle/omoracle.c b/plugins/omoracle/omoracle.c index a37533ee..736629a6 100644 --- a/plugins/omoracle/omoracle.c +++ b/plugins/omoracle/omoracle.c @@ -83,6 +83,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omoracle") /** */ DEF_OMOD_STATIC_DATA diff --git a/plugins/ompgsql/ompgsql.c b/plugins/ompgsql/ompgsql.c index df9cc3fe..46e929dd 100644 --- a/plugins/ompgsql/ompgsql.c +++ b/plugins/ompgsql/ompgsql.c @@ -50,6 +50,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("ompgsql") /* internal structures */ diff --git a/plugins/omprog/omprog.c b/plugins/omprog/omprog.c index 81098257..f2cee271 100644 --- a/plugins/omprog/omprog.c +++ b/plugins/omprog/omprog.c @@ -46,6 +46,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omprog") /* internal structures */ diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c index 26e8ccd3..493f5771 100644 --- a/plugins/omrelp/omrelp.c +++ b/plugins/omrelp/omrelp.c @@ -47,6 +47,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omrelp") /* internal structures */ diff --git a/plugins/omruleset/omruleset.c b/plugins/omruleset/omruleset.c index bb140764..05c228cf 100644 --- a/plugins/omruleset/omruleset.c +++ b/plugins/omruleset/omruleset.c @@ -50,6 +50,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omruleset") static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); diff --git a/plugins/omsnmp/omsnmp.c b/plugins/omsnmp/omsnmp.c index 777a8074..ff8b8a11 100644 --- a/plugins/omsnmp/omsnmp.c +++ b/plugins/omsnmp/omsnmp.c @@ -48,6 +48,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omsnmp") /* internal structures */ diff --git a/plugins/omstdout/omstdout.c b/plugins/omstdout/omstdout.c index f57cbe57..f0d5a62c 100644 --- a/plugins/omstdout/omstdout.c +++ b/plugins/omstdout/omstdout.c @@ -45,6 +45,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omstdout") static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); diff --git a/plugins/omtemplate/omtemplate.c b/plugins/omtemplate/omtemplate.c index 238ec0ae..09320a72 100644 --- a/plugins/omtemplate/omtemplate.c +++ b/plugins/omtemplate/omtemplate.c @@ -46,6 +46,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omtemplate") static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); diff --git a/plugins/omtesting/omtesting.c b/plugins/omtesting/omtesting.c index 414ecfc5..833041f5 100644 --- a/plugins/omtesting/omtesting.c +++ b/plugins/omtesting/omtesting.c @@ -58,6 +58,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omtesting") /* internal structures */ diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c index 217de1c8..7fdcb75b 100644 --- a/plugins/omudpspoof/omudpspoof.c +++ b/plugins/omudpspoof/omudpspoof.c @@ -83,6 +83,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omudpspoof") /* internal structures */ diff --git a/plugins/omuxsock/omuxsock.c b/plugins/omuxsock/omuxsock.c index ea1c8014..279f6820 100644 --- a/plugins/omuxsock/omuxsock.c +++ b/plugins/omuxsock/omuxsock.c @@ -53,6 +53,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omuxsock") /* internal structures */ diff --git a/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c b/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c index fe3e85fa..76198e9c 100644 --- a/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c +++ b/plugins/pmaixforwardedfrom/pmaixforwardedfrom.c @@ -42,6 +42,7 @@ MODULE_TYPE_PARSER MODULE_TYPE_NOKEEP +MODULE_CNFNAME("pmaixforwardedfrom") PARSER_NAME("rsyslog.aixforwardedfrom") /* internal structures diff --git a/plugins/pmcisconames/pmcisconames.c b/plugins/pmcisconames/pmcisconames.c index 61688cbf..d8235752 100644 --- a/plugins/pmcisconames/pmcisconames.c +++ b/plugins/pmcisconames/pmcisconames.c @@ -42,6 +42,7 @@ MODULE_TYPE_PARSER MODULE_TYPE_NOKEEP +MODULE_CNFNAME("pmcisconames") PARSER_NAME("rsyslog.cisconames") /* internal structures diff --git a/plugins/pmlastmsg/pmlastmsg.c b/plugins/pmlastmsg/pmlastmsg.c index 259c5d41..a290c446 100644 --- a/plugins/pmlastmsg/pmlastmsg.c +++ b/plugins/pmlastmsg/pmlastmsg.c @@ -48,6 +48,7 @@ MODULE_TYPE_PARSER MODULE_TYPE_NOKEEP +MODULE_CNFNAME("pmlastmsg") PARSER_NAME("rsyslog.lastline") /* internal structures diff --git a/plugins/pmrfc3164sd/pmrfc3164sd.c b/plugins/pmrfc3164sd/pmrfc3164sd.c index 53204ece..de5805bc 100644 --- a/plugins/pmrfc3164sd/pmrfc3164sd.c +++ b/plugins/pmrfc3164sd/pmrfc3164sd.c @@ -46,6 +46,7 @@ MODULE_TYPE_PARSER MODULE_TYPE_NOKEEP +MODULE_CNFNAME("pmrfc3164sd") PARSER_NAME("contrib.rfc3164sd") /* internal structures diff --git a/plugins/pmsnare/pmsnare.c b/plugins/pmsnare/pmsnare.c index f3658d11..aca0271f 100644 --- a/plugins/pmsnare/pmsnare.c +++ b/plugins/pmsnare/pmsnare.c @@ -59,6 +59,7 @@ MODULE_TYPE_PARSER MODULE_TYPE_NOKEEP +MODULE_CNFNAME("pmsnare") PARSER_NAME("rsyslog.snare") /* internal structures diff --git a/plugins/sm_cust_bindcdr/sm_cust_bindcdr.c b/plugins/sm_cust_bindcdr/sm_cust_bindcdr.c index 0fa1a4c4..fa5f70b3 100644 --- a/plugins/sm_cust_bindcdr/sm_cust_bindcdr.c +++ b/plugins/sm_cust_bindcdr/sm_cust_bindcdr.c @@ -52,6 +52,7 @@ MODULE_TYPE_STRGEN MODULE_TYPE_NOKEEP +MODULE_CNFNAME("sm_cust_bindcdr") STRGEN_NAME("Custom_BindCDR,sql") /* internal structures diff --git a/runtime/conf.c b/runtime/conf.c index 27077ea9..1757c944 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -812,87 +812,6 @@ rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) } -#if 0 -/* Process a configuration file line in traditional "filter selector" format - * or one that builds upon this format. Note that ppRule may be a NULL pointer, - * which is valid and happens if there is no previous line (right at the start - * of the master config file!). - */ -static rsRetVal -cflineClassic(rsconf_t *conf, uchar *p, rule_t **ppRule) -{ - DEFiRet; - action_t *pAction; - - /* lines starting with '&' have no new filters and just add - * new actions to the currently processed selector. - */ - if(*p == '&') { - ++p; /* eat '&' */ - skipWhiteSpace(&p); /* on to command */ - } else { - /* we are finished with the current selector (on previous line). - * So we now need to check - * if it has any actions associated and, if so, link it to the linked - * list. If it has nothing associated with it, we can simply discard - * it. In any case, we create a fresh selector for our new filter. - * We have one special case during initialization: then, the current - * selector is NULL, which means we do not need to care about it at - * all. -- rgerhards, 2007-08-01 - */ - if(*ppRule != NULL) { - CHKiRet(ruleset.AddRule(conf, rule.GetAssRuleset(*ppRule), ppRule)); - } - CHKiRet(rule.Construct(ppRule)); /* create "fresh" selector */ - CHKiRet(rule.SetAssRuleset(*ppRule, ruleset.GetCurrent(conf))); /* create "fresh" selector */ - CHKiRet(rule.ConstructFinalize(*ppRule)); /* create "fresh" selector */ - CHKiRet(cflineDoFilter(&p, *ppRule)); /* pull filters */ - } - - CHKiRet(cflineDoAction(conf, &p, &pAction)); - CHKiRet(llAppend(&(*ppRule)->llActList, NULL, (void*) pAction)); - -finalize_it: - RETiRet; -} - - -/* process a configuration line - * I re-did this functon because it was desperately time to do so - * rgerhards, 2007-08-01 - */ -static rsRetVal -cfline(rsconf_t *conf, uchar *line, rule_t **pfCurr) -{ - DEFiRet; - - ASSERT(line != NULL); - - dbgprintf("cfline: '%s'\n", line); - - /* check type of line and call respective processing */ - switch(*line) { - case '!': - iRet = cflineProcessTagSelector(&line); - break; - case '+': - case '-': - iRet = cflineProcessHostSelector(&line); - break; - case '$': - ++line; /* eat '$' */ - iRet = cfsysline(line); - break; - default: - iRet = cflineClassic(conf, line, pfCurr); - break; - } - - RETiRet; -} -#endif - - /* return the current number of active actions * rgerhards, 2008-07-28 */ diff --git a/runtime/glbl.c b/runtime/glbl.c index eeca347a..ccc39e45 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -465,6 +465,9 @@ glblDoneLoadCnf() int i; unsigned char *cstr; + if(cnfparamvals == NULL) + goto finalize_it; + for(i = 0 ; i < paramblk.nParams ; ++i) { if(!cnfparamvals[i].bUsed) continue; @@ -499,6 +502,7 @@ glblDoneLoadCnf() "param '%s'\n", paramblk.descr[i].name); } } +finalize_it: ; } diff --git a/runtime/module-template.h b/runtime/module-template.h index 0440d02d..37c1cde8 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -110,6 +110,16 @@ static rsRetVal modGetID(void **pID) \ return RS_RET_OK;\ } +/* macro to provide the v6 config system module name + */ +#define MODULE_CNFNAME(name) \ +static __attribute__((unused)) rsRetVal modGetCnfName(uchar **cnfName) \ + { \ + *cnfName = (uchar*) name; \ + return RS_RET_OK;\ + } + + /* to following macros are used to generate function headers and standard * functionality. It works as follows (described on the sample case of * createInstance()): @@ -476,6 +486,8 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\ *pEtryPoint = activateCnf;\ } else if(!strcmp((char*) name, "freeCnf")) {\ *pEtryPoint = freeCnf;\ + } else if(!strcmp((char*) name, "getModCnfName")) {\ + *pEtryPoint = modGetCnfName;\ } diff --git a/runtime/modules.c b/runtime/modules.c index ad93ff38..9ab03574 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -485,6 +485,8 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ rsRetVal (*modGetType)(eModType_t *pType); rsRetVal (*modGetKeepType)(eModKeepType_t *pKeepType); struct dlhandle_s *pHandle = NULL; + rsRetVal (*getModCnfName)(uchar **cnfName); + uchar *cnfName; DEFiRet; assert(modInit != NULL); @@ -507,7 +509,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 of type %d being loaded.\n", pNew->eType); + dbgprintf("module %s of type %d being loaded.\n", name, pNew->eType); /* 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 @@ -524,6 +526,7 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ /* optional calls for new config system */ localRet = (*pNew->modQueryEtryPt)((uchar*)"beginCnfLoad", &pNew->beginCnfLoad); if(localRet == RS_RET_OK) { + dbgprintf("module %s supports rsyslog v6 config interface\n", name); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"endCnfLoad", &pNew->endCnfLoad)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeCnf", &pNew->freeCnf)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"checkCnf", &pNew->checkCnf)); @@ -534,6 +537,11 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ } else { CHKiRet(localRet); } + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getModCnfName", &getModCnfName)); + getModCnfName(&cnfName); + pNew->cnfName = (uchar*) strdup((char*)cnfName); + /**< we do not care if strdup() fails, we can accept that */ + dbgprintf("module config name is '%s'\n", cnfName); } else if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { pNew->beginCnfLoad = NULL; /* flag as non-present */ } else { @@ -626,7 +634,6 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ pNew->pszName = (uchar*) strdup((char*)name); /* we do not care if strdup() fails, we can accept that */ pNew->pModHdlr = pModHdlr; - /* TODO: take this from module */ if(pModHdlr == NULL) { pNew->eLinkType = eMOD_LINK_STATIC; } else { diff --git a/runtime/modules.h b/runtime/modules.h index a62b1750..1579fb86 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -12,7 +12,7 @@ * * File begun on 2007-07-22 by RGerhards * - * Copyright 2007-2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -99,6 +99,7 @@ struct modInfo_s { eModLinkType_t eLinkType; eModKeepType_t eKeepType; /* keep the module dynamically linked on unload */ 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 */ /* functions supported by all types of modules */ rsRetVal (*modInit)(int, int*, rsRetVal(**)()); /* initialize the module */ -- cgit v1.2.3 From 58de33b9cea431d03e3e4bd539704d67d5398a90 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 20 Jul 2011 10:55:10 +0200 Subject: cleanup --- tools/omfile.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/tools/omfile.c b/tools/omfile.c index 4dd32b08..42406bd1 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -719,13 +719,6 @@ CODESTARTparseSelectorAct */ if(!strncmp((char*) p, ":omfile:", sizeof(":omfile:") - 1)) { p += sizeof(":omfile:") - 1; - } else { - if(*p == '$') { - errmsg.LogError(0, RS_RET_OUTDATED_STMT, - "action '%s' treated as ':omfile:%s' - please " - "change syntax, '%s' will not be supported in " - "rsyslog v6 and above.", p, p, p); - } } if(!(*p == '$' || *p == '?' || *p == '/' || *p == '.' || *p == '-')) ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); @@ -773,23 +766,10 @@ CODESTARTparseSelectorAct calloc(cs.iDynaFileCacheSize, sizeof(dynaFileCacheEntry*))); break; - /* case '|': while pipe support has been removed, I leave the code in in case we - * need high-performance pipes at a later stage (unlikely). -- rgerhards, 2010-02-28 - */ case '/': case '.': CODE_STD_STRING_REQUESTparseSelectorAct(1) - /* we now have *almost* the same semantics for files and pipes, but we still need - * to know we deal with a pipe, because we must do non-blocking opens in that case - * (to keep consistent with traditional semantics and prevent rsyslog from hanging). - */ - if(*p == '|') { - ++p; - pData->strmType = STREAMTYPE_NAMED_PIPE; - } else { - pData->strmType = STREAMTYPE_FILE_SINGLE; - } - + pData->strmType = STREAMTYPE_FILE_SINGLE; CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); pData->bDynamicName = 0; -- cgit v1.2.3 From 686540cebee2920341911860c0019e687174daa8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 20 Jul 2011 14:27:20 +0200 Subject: milestone: on the way to a new action conf interface to plugins... --- runtime/module-template.h | 65 ++++++++++++++++++++++++++++++++++--- runtime/modules.c | 14 +++++--- tools/omfile.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 9 deletions(-) diff --git a/runtime/module-template.h b/runtime/module-template.h index 37c1cde8..2fa8e2e2 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -304,6 +304,54 @@ finalize_it:\ } +/* newActInst() + * Extra comments: + * This creates a new instance of a the action that implements the call. + * This is part of the conf2 (rsyslog v6) config system. It is called by + * the core when an action object has been obtained. The output module + * must then verify parameters and create a new action instance (if + * parameters are acceptable) or return an error code. + * On exit, ppModData must point to instance data. Also, a string + * request object must be created and filled. A macro is defined + * for that. + * For the most usual case, we have defined a macro below. + * If more than one string is requested, the macro can be used together + * with own code that overwrites the entry count. In this case, the + * macro must come before the own code. It is recommended to be + * placed right after CODESTARTnewActInst. + */ +#define BEGINnewActInst \ +static rsRetVal newActInst(struct nvlst *lst, void **ppModData, omodStringRequest_t **ppOMSR)\ +{\ + DEFiRet;\ + uchar *p;\ + instanceData *pData = NULL; + +#define CODESTARTnewActInst \ + +#define CODE_STD_STRING_REQUESTnewActInst(NumStrReqEntries) \ + CHKiRet(OMSRconstruct(ppOMSR, NumStrReqEntries)); + +#define CODE_STD_FINALIZERnewActInst \ +finalize_it:\ + if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) {\ + *ppModData = pData;\ + } else {\ + /* cleanup, we failed */\ + if(*ppOMSR != NULL) {\ + OMSRdestruct(*ppOMSR);\ + *ppOMSR = NULL;\ + }\ + if(pData != NULL) {\ + freeInstance(pData);\ + } \ + } + +#define ENDnewActInst \ + 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, @@ -473,7 +521,7 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\ /* the following block is to be added for modules that support the v2 - * config system. + * config system. The config name is also provided. */ #define CODEqueryEtryPt_STD_CONF2_QUERIES \ else if(!strcmp((char*) name, "beginCnfLoad")) {\ @@ -486,9 +534,8 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\ *pEtryPoint = activateCnf;\ } else if(!strcmp((char*) name, "freeCnf")) {\ *pEtryPoint = freeCnf;\ - } else if(!strcmp((char*) name, "getModCnfName")) {\ - *pEtryPoint = modGetCnfName;\ - } + } \ + CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES /* the following block is to be added for modules that require @@ -499,6 +546,16 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\ *pEtryPoint = activateCnfPrePrivDrop;\ } +/* the following block is to be added for modules that support + * their config name. This is required for the rsyslog v6 config + * system, especially for outout modules which do not require + * the new set of begin/end config settings. + */ +#define CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES \ + else if(!strcmp((char*) name, "getModCnfName")) {\ + *pEtryPoint = modGetCnfName;\ + } + /* the following definition is the standard block for queryEtryPt for LIBRARY * modules. This can be used if no specific handling (e.g. to cover version * differences) is needed. diff --git a/runtime/modules.c b/runtime/modules.c index 9ab03574..d09ba770 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -524,6 +524,15 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ ABORT_FINALIZE(localRet); /* optional calls for new config system */ + localRet = (*pNew->modQueryEtryPt)((uchar*)"getModCnfName", &getModCnfName); + if(localRet == RS_RET_OK) { + if(getModCnfName(&cnfName) == RS_RET_OK) + pNew->cnfName = (uchar*) strdup((char*)cnfName); + /**< we do not care if strdup() fails, we can accept that */ + else + pNew->cnfName = NULL; + dbgprintf("module config name is '%s'\n", cnfName); + } localRet = (*pNew->modQueryEtryPt)((uchar*)"beginCnfLoad", &pNew->beginCnfLoad); if(localRet == RS_RET_OK) { dbgprintf("module %s supports rsyslog v6 config interface\n", name); @@ -537,11 +546,6 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ } else { CHKiRet(localRet); } - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getModCnfName", &getModCnfName)); - getModCnfName(&cnfName); - pNew->cnfName = (uchar*) strdup((char*)cnfName); - /**< we do not care if strdup() fails, we can accept that */ - dbgprintf("module config name is '%s'\n", cnfName); } else if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { pNew->beginCnfLoad = NULL; /* flag as non-present */ } else { diff --git a/tools/omfile.c b/tools/omfile.c index 42406bd1..0735e48d 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -71,6 +71,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omfile") /* forward definitions */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); @@ -710,6 +711,85 @@ finalize_it: ENDdoAction +BEGINnewActInst +CODESTARTnewActInst + // TODO: valid lst params +#if 0 + CHKiRet(createInstance(&pData)); + + if(*p == '-') { + pData->bSyncFile = 0; + p++; + } else { + pData->bSyncFile = cs.bEnableSync; + } + + switch(*p) { + case '$': + CODE_STD_STRING_REQUESTnewActInst(1) + /* rgerhards 2005-06-21: this is a special setting for output-channel + * definitions. In the long term, this setting will probably replace + * anything else, but for the time being we must co-exist with the + * traditional mode lines. + * rgerhards, 2007-07-24: output-channels will go away. We keep them + * for compatibility reasons, but seems to have been a bad idea. + */ + CHKiRet(cflineParseOutchannel(pData, p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS)); + pData->bDynamicName = 0; + break; + + case '?': /* This is much like a regular file handle, but we need to obtain + * a template name. rgerhards, 2007-07-03 + */ + CODE_STD_STRING_REQUESTnewActInst(2) + ++p; /* eat '?' */ + CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, + (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); + /* "filename" is actually a template name, we need this as string 1. So let's add it + * to the pOMSR. -- rgerhards, 2007-07-27 + */ + CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(pData->f_fname), OMSR_NO_RQD_TPL_OPTS)); + + pData->bDynamicName = 1; + pData->iCurrElt = -1; /* no current element */ + /* we now allocate the cache table */ + CHKmalloc(pData->dynCache = (dynaFileCacheEntry**) + calloc(cs.iDynaFileCacheSize, sizeof(dynaFileCacheEntry*))); + break; + + case '/': + case '.': + CODE_STD_STRING_REQUESTnewActInst(1) + pData->strmType = STREAMTYPE_FILE_SINGLE; + CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, + (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); + pData->bDynamicName = 0; + break; + default: + ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); + } + + /* freeze current paremeters for this action */ + pData->iSizeLimit = 0; /* default value, use outchannels to configure! */ + pData->iDynaFileCacheSize = cs.iDynaFileCacheSize; + pData->fCreateMode = cs.fCreateMode; + pData->fDirCreateMode = cs.fDirCreateMode; + pData->bCreateDirs = cs.bCreateDirs; + pData->bFailOnChown = cs.bFailOnChown; + pData->fileUID = cs.fileUID; + pData->fileGID = cs.fileGID; + pData->dirUID = cs.dirUID; + pData->dirGID = cs.dirGID; + pData->iZipLevel = cs.iZipLevel; + pData->bFlushOnTXEnd = cs.bFlushOnTXEnd; + pData->iIOBufSize = (int) cs.iIOBufSize; + pData->iFlushInterval = cs.iFlushInterval; + pData->bUseAsyncWriter = cs.bUseAsyncWriter; +#endif +CODE_STD_FINALIZERnewActInst +ENDnewActInst + + BEGINparseSelectorAct CODESTARTparseSelectorAct /* Note: the indicator sequence permits us to use '$' to signify @@ -851,6 +931,7 @@ CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */ CODEqueryEtryPt_doHUP +CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From 5820c5f3e8dc69bdee969d6487d084e884595069 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 20 Jul 2011 17:37:44 +0200 Subject: milestone: done plumbing to call plugin create action instance entry point --- action.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++ action.h | 1 + configure.ac | 2 +- grammar/rainerscript.c | 5 ++- runtime/conf.c | 40 -------------------- runtime/modules.c | 22 ++++++++++- runtime/modules.h | 3 +- runtime/rsconf.c | 6 ++- runtime/rsyslog.h | 2 + 9 files changed, 135 insertions(+), 46 deletions(-) diff --git a/action.c b/action.c index 0fb660bb..f24fee06 100644 --- a/action.c +++ b/action.c @@ -178,6 +178,51 @@ configSettings_t cs_save; /* our saved (scope!) config settings */ */ static int iActionNbr = 0; +/* tables for interfacing with the v6 config system */ +static struct cnfparamdescr cnfparamdescr[] = { + { "name", eCmdHdlrGetWord, 0 }, /* legacy: actionname */ + { "type", eCmdHdlrString, CNFPARAM_REQUIRED }, /* legacy: actionname */ + { "action.writeallmarkmessages", eCmdHdlrBinary, 0 }, /* legacy: actionwriteallmarkmessages */ + { "action.execonlyeverynthtime", eCmdHdlrInt, 0 }, /* legacy: actionexeconlyeverynthtime */ + { "action.execonlyeverynthtimetimeout", eCmdHdlrInt, 0 }, /* legacy: actionexeconlyeverynthtimetimeout */ + { "action.execonlyonceeveryinterval", eCmdHdlrInt, 0 }, /* legacy: actionexeconlyonceeveryinterval */ + { "action.execonlywhenpreviousissuspended", eCmdHdlrInt, 0 }, /* legacy: actionexeconlywhenpreviousissuspended */ + { "action.repeatedmsgcontainsoriginalmsg", eCmdHdlrBinary, 0 }, /* legacy: repeatedmsgcontainsoriginalmsg */ + { "action.resumeretrycount ", eCmdHdlrGetWord, 0 } /* legacy: actionresumeretrycount */ + //{ "", eCmdHdlrGetWord, 0 }, /* legacy: */ +}; +static struct cnfparamblk paramblk = + { CNFPARAMBLK_VERSION, + sizeof(cnfparamdescr)/sizeof(struct cnfparamdescr), + cnfparamdescr + }; + +/* Still TODO: */ +#if 0 + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuefilename", 0, eCmdHdlrGetWord, NULL, &cs.pszActionQFName, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesize", 0, eCmdHdlrInt, NULL, &cs.iActionQueueSize, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuebatchsize", 0, eCmdHdlrInt, NULL, &cs.iActionQueueDeqBatchSize, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuemaxdiskspace", 0, eCmdHdlrSize, NULL, &cs.iActionQueMaxDiskSpace, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuehighwatermark", 0, eCmdHdlrInt, NULL, &cs.iActionQHighWtrMark, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuelowwatermark", 0, eCmdHdlrInt, NULL, &cs.iActionQLowWtrMark, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuediscardmark", 0, eCmdHdlrInt, NULL, &cs.iActionQDiscardMark, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuediscardseverity", 0, eCmdHdlrInt, NULL, &cs.iActionQDiscardSeverity, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuecheckpointinterval", 0, eCmdHdlrInt, NULL, &cs.iActionQPersistUpdCnt, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesyncqueuefiles", 0, eCmdHdlrBinary, NULL, &cs.bActionQSyncQeueFiles, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetype", 0, eCmdHdlrGetWord, setActionQueType, NULL, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueueworkerthreads", 0, eCmdHdlrInt, NULL, &cs.iActionQueueNumWorkers, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetimeoutshutdown", 0, eCmdHdlrInt, NULL, &cs.iActionQtoQShutdown, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetimeoutactioncompletion", 0, eCmdHdlrInt, NULL, &cs.iActionQtoActShutdown, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetimeoutenqueue", 0, eCmdHdlrInt, NULL, &cs.iActionQtoEnq, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueueworkertimeoutthreadshutdown", 0, eCmdHdlrInt, NULL, &cs.iActionQtoWrkShutdown, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueueworkerthreadminimummessages", 0, eCmdHdlrInt, NULL, &cs.iActionQWrkMinMsgs, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuemaxfilesize", 0, eCmdHdlrSize, NULL, &cs.iActionQueMaxFileSize, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesaveonshutdown", 0, eCmdHdlrBinary, NULL, &cs.bActionQSaveOnShutdown, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeueslowdown", 0, eCmdHdlrInt, NULL, &cs.iActionQueueDeqSlowdown, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuetimebegin", 0, eCmdHdlrInt, NULL, &cs.iActionQueueDeqtWinFromHr, NULL, eConfObjAction)); + CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuetimeend", 0, eCmdHdlrInt, NULL, &cs.iActionQueueDeqtWinToHr, NULL, eConfObjAction)); +#endif + /* ------------------------------ methods ------------------------------ */ /* This function returns the "current" time for this action. Current time @@ -1889,6 +1934,61 @@ actionRestoreScope(void) +rsRetVal +actionNewInst(struct nvlst *lst, action_t **ppAction) +{ + struct cnfparamvals *paramvals; + modInfo_t *pMod; + uchar *cnfModName = NULL; + DEFiRet; + + paramvals = nvlstGetParams(lst, ¶mblk, NULL); + if(paramvals == NULL) { + iRet = RS_RET_ERR; + goto finalize_it; + } + dbgprintf("action param blk after actionNewInst:\n"); + cnfparamsPrint(¶mblk, paramvals); + if(paramvals[cnfparamGetIdx(¶mblk, "type")].bUsed == 0) { + ABORT_FINALIZE(RS_RET_CONF_RQRD_PARAM_MISSING); // TODO: move this into rainerscript handlers + } + cnfModName = (uchar*)es_str2cstr(paramvals[cnfparamGetIdx(¶mblk, ("type"))].val.d.estr, NULL); + if((pMod = module.FindWithCnfName(loadConf, cnfModName, eMOD_OUT)) == NULL) { + errmsg.LogError(0, RS_RET_MOD_UNKNOWN, "module name '%s' is unknown", cnfModName); + ABORT_FINALIZE(RS_RET_MOD_UNKNOWN); + } +dbgprintf("XXXX:actionNewInst for module '%s'/%p\n", cnfModName, pMod); +finalize_it: + free(cnfModName); + RETiRet; +} + + +/* Process a rsyslog v6 action config object (the now-primary config method). + * rgerhards, 2011-07-19 + */ +rsRetVal +actionProcessCnf(struct cnfobj *o) +{ + DEFiRet; +#if 0 /* we need to check if we actually need this functionality -- later! */ + struct cnfparamvals *paramvals; + + paramvals = nvlstGetParams(o->nvlst, ¶mblk, NULL); + if(paramvals == NULL) { + iRet = RS_RET_ERR; + goto finalize_it; + } + DBGPRINTF("action param blk after actionProcessCnf:\n"); + cnfparamsPrint(¶mblk, paramvals); + + /* now find module to activate */ +finalize_it: +#endif + RETiRet; +} + + /* TODO: we are not yet a real object, the ClassInit here just looks like it is.. */ rsRetVal actionClassInit(void) diff --git a/action.h b/action.h index 253514df..4d56106b 100644 --- a/action.h +++ b/action.h @@ -107,5 +107,6 @@ rsRetVal addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStr rsRetVal actionNewScope(void); rsRetVal actionRestoreScope(void); rsRetVal activateActions(void); +rsRetVal actionNewInst(struct nvlst *lst, action_t **ppAction); #endif /* #ifndef ACTION_H_INCLUDED */ diff --git a/configure.ac b/configure.ac index 0093d860..48e6a94e 100644 --- a/configure.ac +++ b/configure.ac @@ -38,7 +38,7 @@ AC_CANONICAL_HOST PKG_PROG_PKG_CONFIG # modules we require -PKG_CHECK_MODULES(LIBESTR, libestr >= 0.1.1) +PKG_CHECK_MODULES(LIBESTR, libestr >= 0.1.2) PKG_CHECK_MODULES(LIBEE, libee >= 0.3.1) case "${host}" in diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 76e3a0a4..c953c840 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -146,14 +146,15 @@ nvlstFindName(struct nvlst *lst, es_str_t *name) } -/* find a name starting at node lst. SAme as nvlstFindName, but +/* find a name starting at node lst. Same as nvlstFindName, but * for classical C strings. This is useful because the config system * uses C string constants. */ static inline struct nvlst* nvlstFindNameCStr(struct nvlst *lst, char *name) { - while(lst != NULL && es_strbufcmp(lst->name, (uchar*)name, strlen(name))) + es_size_t lenName = strlen(name); + while(lst != NULL && es_strcasebufcmp(lst->name, (uchar*)name, lenName)) lst = lst->next; return lst; } diff --git a/runtime/conf.c b/runtime/conf.c index 1757c944..6136262e 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -708,46 +708,6 @@ finalize_it: } -#if 0 -/* read the filter part of a configuration line and store the filter - * in the supplied rule_t - * rgerhards, 2007-08-01 - */ -static rsRetVal cflineDoFilter(uchar **pp, rule_t *f) -{ - DEFiRet; - - ASSERT(pp != NULL); - ISOBJ_TYPE_assert(f, rule); - - /* check which filter we need to pull... */ - switch(**pp) { - case ':': - CHKiRet(cflineProcessPropFilter(pp, f)); - break; - default: - CHKiRet(cflineProcessTradPRIFilter(pp, f)); - break; - } - - /* we now check if there are some global (BSD-style) filter conditions - * and, if so, we copy them over. rgerhards, 2005-10-18 - */ - if(pDfltProgNameCmp != NULL) { - CHKiRet(rsCStrConstructFromCStr(&(f->pCSProgNameComp), pDfltProgNameCmp)); - } - - if(eDfltHostnameCmpMode != HN_NO_COMP) { - f->eHostnameCmpMode = eDfltHostnameCmpMode; - CHKiRet(rsCStrConstructFromCStr(&(f->pCSHostnameComp), pDfltHostnameCmp)); - } - -finalize_it: - RETiRet; -} -#endif - - /* process the action part of a selector line * rgerhards, 2007-08-01 */ diff --git a/runtime/modules.c b/runtime/modules.c index d09ba770..59eaec34 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -427,7 +427,7 @@ static cfgmodules_etry_t if(rqtdType != eMOD_ANY) { /* if any, we already have the right one! */ while(node != NULL && node->pMod->eType != rqtdType) { - node = node->next; /* warning: do ... while() */ + node = node->next; } } @@ -435,6 +435,25 @@ static cfgmodules_etry_t } +/* Find a module with the given conf name and type. Returns NULL if none + * can be found, otherwise module found. + */ +static modInfo_t * +FindWithCnfName(rsconf_t *cnf, uchar *name, eModType_t rqtdType) +{ + cfgmodules_etry_t *node; + + node = cnf->modules.root; + while(node != NULL && node->pMod->eType != rqtdType) { + if(!strcasecmp((char*)node->pMod->cnfName, (char*)name)) + break; + node = node->next; + } + + return node == NULL ? NULL : node->pMod; +} + + /* Prepare a module for unloading. * This is currently a dummy, to be filled when we have a plug-in * interface - rgerhards, 2007-08-09 @@ -1179,6 +1198,7 @@ CODESTARTobjQueryInterface(module) pIf->GetName = modGetName; pIf->GetStateName = modGetStateName; pIf->PrintList = modPrintList; + pIf->FindWithCnfName = FindWithCnfName; pIf->UnloadAndDestructAll = modUnloadAndDestructAll; pIf->doModInit = doModInit; pIf->SetModDir = SetModDir; diff --git a/runtime/modules.h b/runtime/modules.h index 1579fb86..ebde1219 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -174,8 +174,9 @@ BEGINinterface(module) /* name must also be changed in ENDinterface macro! */ rsRetVal (*doModInit)(rsRetVal (*modInit)(), uchar *name, void *pModHdlr, modInfo_t **pNew); rsRetVal (*Load)(uchar *name, sbool bConfLoad); 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 2 /* increment whenever you change the interface structure! */ +#define moduleCURR_IF_VERSION 3 /* increment whenever you change the interface structure! */ /* Changes: * v2 * - added param bCondLoad to Load call - 2011-04-27 diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 26105e88..4fe17534 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -230,7 +230,8 @@ cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) while(actlst != NULL) { dbgprintf("aclst %p: ", actlst); if(actlst->actType == CNFACT_V2) { - dbgprintf("V2 action type not yet handled\n"); + dbgprintf("v6+ action object\n"); + actionNewInst(actlst->data.lst, &pAction); } else { dbgprintf("legacy action line:%s\n", actlst->data.legActLine); str = (uchar*) actlst->data.legActLine; @@ -360,6 +361,9 @@ void cnfDoObj(struct cnfobj *o) case CNFOBJ_GLOBAL: glblProcessCnf(o); break; + case CNFOBJ_ACTION: + actionProcessCnf(o); + break; } nvlstChkUnused(o->nvlst); cnfobjDestruct(o); diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index 39f00ebc..dc2f15be 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -361,6 +361,8 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_ERR_SCHED_PARAMS = -2205,/**< there is a problem with configured thread scheduling params */ RS_RET_SOCKNAME_MISSING = -2206,/**< no socket name configured where one is required */ RS_RET_CONF_PARSE_ERROR = -2207,/**< (fatal) error parsing config file */ + RS_RET_CONF_RQRD_PARAM_MISSING = -2208,/**< required parameter in config object is missing */ + RS_RET_MOD_UNKNOWN = -2209,/**< module (config name) is unknown */ /* 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 9ce9fbb28f7a7a1a0380cc272a90be077cd9c1bc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Jul 2011 11:14:52 +0200 Subject: milestone: new output plugin interface call added --- action.c | 6 ++++- runtime/glbl.c | 2 +- runtime/glbl.h | 1 + runtime/module-template.h | 13 +++++++++-- runtime/modules.c | 58 ++++++++++++++++++++++++++++++++--------------- runtime/modules.h | 3 ++- runtime/rsyslog.h | 1 + tools/omfile.c | 2 ++ tools/ompipe.c | 2 ++ 9 files changed, 65 insertions(+), 23 deletions(-) diff --git a/action.c b/action.c index f24fee06..450b0691 100644 --- a/action.c +++ b/action.c @@ -1018,7 +1018,7 @@ tryDoAction(action_t *pAction, batch_t *pBatch, int *pnElem) i = pBatch->iDoneUpTo; /* all messages below that index are processed */ iElemProcessed = 0; iCommittedUpTo = i; -dbgprintf("XXXXX: tryDoAction %p, pnElem %d, nElem %d\n", pAction, *pnElem, pBatch->nElem); + DBGPRINTF("tryDoAction %p, pnElem %d, nElem %d\n", pAction, *pnElem, pBatch->nElem); while(iElemProcessed <= *pnElem && i < pBatch->nElem) { if(*(pBatch->pbShutdownImmediate)) ABORT_FINALIZE(RS_RET_FORCE_TERM); @@ -1940,6 +1940,8 @@ actionNewInst(struct nvlst *lst, action_t **ppAction) struct cnfparamvals *paramvals; modInfo_t *pMod; uchar *cnfModName = NULL; + omodStringRequest_t *pOMSR; + void *pModData; DEFiRet; paramvals = nvlstGetParams(lst, ¶mblk, NULL); @@ -1958,6 +1960,8 @@ actionNewInst(struct nvlst *lst, action_t **ppAction) ABORT_FINALIZE(RS_RET_MOD_UNKNOWN); } dbgprintf("XXXX:actionNewInst for module '%s'/%p\n", cnfModName, pMod); + CHKiRet(pMod->mod.om.newActInst(cnfModName, lst, &pModData, &pOMSR)); +dbgprintf("XXXX:actionNewInst CALLED module '%s'/%p\n", cnfModName, pMod); finalize_it: free(cnfModName); RETiRet; diff --git a/runtime/glbl.c b/runtime/glbl.c index ccc39e45..5df0c329 100644 --- a/runtime/glbl.c +++ b/runtime/glbl.c @@ -460,7 +460,7 @@ glblCheckCnf() } void -glblDoneLoadCnf() +glblDoneLoadCnf(void) { int i; unsigned char *cstr; diff --git a/runtime/glbl.h b/runtime/glbl.h index 94eec23d..262b2cc2 100644 --- a/runtime/glbl.h +++ b/runtime/glbl.h @@ -88,5 +88,6 @@ PROTOTYPEObj(glbl); void glblPrepCnf(void); void glblProcessCnf(struct cnfobj *o); +void glblDoneLoadCnf(void); #endif /* #ifndef GLBL_H_INCLUDED */ diff --git a/runtime/module-template.h b/runtime/module-template.h index 2fa8e2e2..6238d0f4 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -321,10 +321,10 @@ finalize_it:\ * placed right after CODESTARTnewActInst. */ #define BEGINnewActInst \ -static rsRetVal newActInst(struct nvlst *lst, void **ppModData, omodStringRequest_t **ppOMSR)\ +static rsRetVal newActInst(uchar __attribute__((unused)) *modName, \ + struct nvlst *lst, void **ppModData, omodStringRequest_t **ppOMSR)\ {\ DEFiRet;\ - uchar *p;\ instanceData *pData = NULL; #define CODESTARTnewActInst \ @@ -537,6 +537,15 @@ static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)())\ } \ CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES +/* the following block is to be added for output modules that support the v2 + * config system. The config name is also provided. + */ +#define CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES \ + else if(!strcmp((char*) name, "newActInst")) {\ + *pEtryPoint = newActInst;\ + } \ + 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 59eaec34..f6b4bad9 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -90,18 +90,30 @@ static uchar *pModDir; /* directory where loadable modules are found */ * harm. This simplifies things as in action processing we do not need to check * if the transactional entry points exist. */ -static rsRetVal dummyBeginTransaction() +static rsRetVal +dummyBeginTransaction() { return RS_RET_OK; } -static rsRetVal dummyEndTransaction() +static rsRetVal +dummyEndTransaction() { return RS_RET_OK; } -static rsRetVal dummyIsCompatibleWithFeature() +static rsRetVal +dummyIsCompatibleWithFeature() { return RS_RET_INCOMPATIBLE; } +static rsRetVal +dummynewActInst(uchar *modName, struct nvlst __attribute__((unused)) *dummy1, + void __attribute__((unused)) **dummy2, omodStringRequest_t __attribute__((unused)) **dummy3) +{ + errmsg.LogError(0, RS_RET_CONFOBJ_UNSUPPORTED, "config objects are not " + "supported by module '%s' -- legacy config options " + "MUST be used instead", modName); + return RS_RET_CONFOBJ_UNSUPPORTED; +} #ifdef DEBUG /* we add some home-grown support to track our users (and detect who does not free us). In @@ -443,11 +455,14 @@ FindWithCnfName(rsconf_t *cnf, uchar *name, eModType_t rqtdType) { cfgmodules_etry_t *node; - node = cnf->modules.root; - while(node != NULL && node->pMod->eType != rqtdType) { + ; + for( node = cnf->modules.root + ; node != NULL + ; node = node->next) { + if(node->pMod->eType != rqtdType || node->pMod->cnfName == NULL) + continue; if(!strcasecmp((char*)node->pMod->cnfName, (char*)name)) break; - node = node->next; } return node == NULL ? NULL : node->pMod; @@ -603,6 +618,13 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ } else if(localRet != RS_RET_OK) { ABORT_FINALIZE(localRet); } + + localRet = (*pNew->modQueryEtryPt)((uchar*)"newActInst", &pNew->mod.om.newActInst); + if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { + pNew->mod.om.newActInst = dummynewActInst; + } else if(localRet != RS_RET_OK) { + ABORT_FINALIZE(localRet); + } break; case eMOD_LIB: break; @@ -749,18 +771,18 @@ static void modPrintList(void) switch(pMod->eType) { case eMOD_OUT: dbgprintf("Output Module Entry Points:\n"); - dbgprintf("\tdoAction: 0x%lx\n", (unsigned long) pMod->mod.om.doAction); - dbgprintf("\tparseSelectorAct: 0x%lx\n", (unsigned long) pMod->mod.om.parseSelectorAct); - dbgprintf("\ttryResume: 0x%lx\n", (unsigned long) pMod->tryResume); - dbgprintf("\tdoHUP: 0x%lx\n", (unsigned long) pMod->doHUP); - dbgprintf("\tnewScope: 0x%lx\n", (unsigned long) pMod->mod.om.newScope); - dbgprintf("\trestoreScope: 0x%lx\n", (unsigned long) pMod->mod.om.restoreScope); - dbgprintf("\tBeginTransaction: 0x%lx\n", (unsigned long) - ((pMod->mod.om.beginTransaction == dummyBeginTransaction) ? - 0 : pMod->mod.om.beginTransaction)); - dbgprintf("\tEndTransaction: 0x%lx\n", (unsigned long) - ((pMod->mod.om.endTransaction == dummyEndTransaction) ? - 0 : pMod->mod.om.endTransaction)); + dbgprintf("\tdoAction: %p\n", pMod->mod.om.doAction); + dbgprintf("\tparseSelectorAct: %p\n", pMod->mod.om.parseSelectorAct); + dbgprintf("\tnewActInst: %p\n", (pMod->mod.om.newActInst == dummynewActInst) ? + NULL : pMod->mod.om.newActInst); + dbgprintf("\ttryResume: %p\n", pMod->tryResume); + dbgprintf("\tdoHUP: %p\n", pMod->doHUP); + dbgprintf("\tnewScope: %p\n", pMod->mod.om.newScope); + dbgprintf("\trestoreScope: %p\n", pMod->mod.om.restoreScope); + dbgprintf("\tBeginTransaction: %p\n", ((pMod->mod.om.beginTransaction == dummyBeginTransaction) ? + NULL : pMod->mod.om.beginTransaction)); + dbgprintf("\tEndTransaction: %p\n", ((pMod->mod.om.endTransaction == dummyEndTransaction) ? + NULL : pMod->mod.om.endTransaction)); break; case eMOD_IN: dbgprintf("Input Module Entry Points\n"); diff --git a/runtime/modules.h b/runtime/modules.h index ebde1219..4956dd4a 100644 --- a/runtime/modules.h +++ b/runtime/modules.h @@ -36,7 +36,7 @@ #define MODULES_H_INCLUDED 1 #include "objomsr.h" - +#include "rainerscript.h" /* the following define defines the current version of the module interface. * It can be used by any module which want's to simply prevent version conflicts @@ -140,6 +140,7 @@ struct modInfo_s { rsRetVal (*parseSelectorAct)(uchar**, void**,omodStringRequest_t**); rsRetVal (*newScope)(void); rsRetVal (*restoreScope)(void); + rsRetVal (*newActInst)(uchar *modName, struct nvlst *lst, void **, omodStringRequest_t **); } om; struct { /* data for library modules */ char dummy; diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index dc2f15be..dd770f26 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -363,6 +363,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_CONF_PARSE_ERROR = -2207,/**< (fatal) error parsing config file */ RS_RET_CONF_RQRD_PARAM_MISSING = -2208,/**< required parameter in config object is missing */ RS_RET_MOD_UNKNOWN = -2209,/**< module (config name) is unknown */ + RS_RET_CONFOBJ_UNSUPPORTED = -2210,/**< config objects (v6 conf) are not supported here */ /* 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 0735e48d..8d332ee9 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -714,6 +714,7 @@ ENDdoAction BEGINnewActInst CODESTARTnewActInst // TODO: valid lst params + dbgprintf("XXXX: in newActInst (omfile)\n"); #if 0 CHKiRet(createInstance(&pData)); @@ -929,6 +930,7 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */ CODEqueryEtryPt_doHUP CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES diff --git a/tools/ompipe.c b/tools/ompipe.c index 5d9397e1..d5faffc8 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -58,6 +58,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("ompipe") /* internal structures */ @@ -244,6 +245,7 @@ BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES CODEqueryEtryPt_doHUP +CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From 448f2eeea247fe4bf7bbbc982fb6df0f7a1b72f9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Jul 2011 13:31:57 +0200 Subject: doc: clarified that pmlastmsg does not drop those messages --- doc/pmlastmsg.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/pmlastmsg.html b/doc/pmlastmsg.html index 2abeac6a..247178c3 100644 --- a/doc/pmlastmsg.html +++ b/doc/pmlastmsg.html @@ -27,6 +27,11 @@ parser chain. It processes all those messages that contain a PRI, then none some spaces and then the exact text (case-insensitive) "last message repeated n times" where n must be an integer. All other messages are left untouched. +

        Please note: this parser module makes it possible that these messages +are properly detected. It does not drop them. If you intend to drop those +messages, you need to use the usual filter logic in combination with the discard +action. +

        Configuration Directives:

        There do not currently exist any configuration directives for this module.

        Examples:

        -- cgit v1.2.3 From 63446424c057f527c9c17be7e06f306a130789b4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Jul 2011 13:55:45 +0200 Subject: fixing minor memory leaks --- action.c | 1 + grammar/rainerscript.c | 41 +++++++++++++++++++++++++++++++++++++++++ grammar/rainerscript.h | 6 +++++- runtime/modules.c | 4 ++-- runtime/rsconf.c | 10 +++++----- 5 files changed, 54 insertions(+), 8 deletions(-) diff --git a/action.c b/action.c index 450b0691..1ee3ef29 100644 --- a/action.c +++ b/action.c @@ -1964,6 +1964,7 @@ dbgprintf("XXXX:actionNewInst for module '%s'/%p\n", cnfModName, pMod); dbgprintf("XXXX:actionNewInst CALLED module '%s'/%p\n", cnfModName, pMod); finalize_it: free(cnfModName); + cnfparamvalsDestruct(paramvals, ¶mblk); RETiRet; } diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index c953c840..0b2ee7cb 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -475,6 +475,7 @@ cnfactlstAddSysline(struct cnfactlst* actlst, char *line) return actlst; } + void cnfactlstDestruct(struct cnfactlst *actlst) { @@ -483,6 +484,7 @@ cnfactlstDestruct(struct cnfactlst *actlst) while(actlst != NULL) { toDel = actlst; actlst = actlst->next; + cnfcfsyslinelstDestruct(toDel->syslines); if(toDel->actType == CNFACT_V2) nvlstDestruct(toDel->data.lst); else @@ -1245,6 +1247,28 @@ cnfrulePrint(struct cnfrule *rule) dbgprintf("------ end rule %p\n", rule); } +void +cnfcfsyslinelstDestruct(struct cnfcfsyslinelst *cfslst) +{ + struct cnfcfsyslinelst *toDel; + while(cfslst != NULL) { + toDel = cfslst; + cfslst = cfslst->next; + free(toDel->line); + free(toDel); + } +} + +void +cnfruleDestruct(struct cnfrule *rule) +{ + if( rule->filttype == CNFFILT_PRI + || rule->filttype == CNFFILT_PROP) + free(rule->filt.s); + cnfactlstDestruct(rule->actlst); + free(rule); +} + struct cnffparamlst * cnffparamlstNew(struct cnfexpr *expr, struct cnffparamlst *next) { @@ -1382,6 +1406,23 @@ cnfDoInclude(char *name) return 0; } +void +varDelete(struct var *v) +{ + if(v->datatype == 'S') + es_deleteStr(v->d.estr); +} + +void +cnfparamvalsDestruct(struct cnfparamvals *paramvals, struct cnfparamblk *blk) +{ + int i; + for(i = 0 ; i < blk->nParams ; ++i) { + varDelete(¶mvals[i].val); + } + free(paramvals); +} + /* find the index (or -1!) for a config param by name. This is used to * address the parameter array. Of course, we could use with static * indices, but that would create some extra bug potential. So we diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index f7454ef5..7cc38abb 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -66,7 +66,7 @@ struct nvlst { struct nvlst *next; es_str_t *name; struct var val; - unsigned char *bUsed; + unsigned char bUsed; /**< was this node used during config processing? If not, this * indicates an error. After all, the user specified a setting * that the software does not know. @@ -234,6 +234,7 @@ int cnfexprEvalBool(struct cnfexpr *expr, void *usrptr); struct cnfnumval* cnfnumvalNew(long long val); struct cnfstringval* cnfstringvalNew(es_str_t *estr); struct cnfrule * cnfruleNew(enum cnfFiltType filttype, struct cnfactlst *actlst); +void cnfruleDestruct(struct cnfrule *rule); void cnfrulePrint(struct cnfrule *rule); struct cnfvar* cnfvarNew(char *name); struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst); @@ -243,6 +244,9 @@ int cnfparamGetIdx(struct cnfparamblk *params, char *name); struct cnfparamvals* nvlstGetParams(struct nvlst *lst, struct cnfparamblk *params, struct cnfparamvals *vals); 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); /* debug helper */ void cstrPrint(char *text, es_str_t *estr); diff --git a/runtime/modules.c b/runtime/modules.c index f6b4bad9..0f132bdf 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -240,8 +240,8 @@ static rsRetVal moduleConstruct(modInfo_t **pThis) static void moduleDestruct(modInfo_t *pThis) { assert(pThis != NULL); - if(pThis->pszName != NULL) - free(pThis->pszName); + free(pThis->pszName); + free(pThis->cnfName); if(pThis->pModHdlr != NULL) { # ifdef VALGRIND # warning "dlclose disabled for valgrind" diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 4fe17534..f93bd7bc 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -417,26 +417,26 @@ void cnfDoRule(struct cnfrule *cnfrule) finalize_it: //TODO: do something with error states - ; + cnfruleDestruct(cnfrule); } void cnfDoCfsysline(char *ln) { - dbgprintf("cnf:global:cfsysline: %s\n", ln); + DBGPRINTF("cnf:global:cfsysline: %s\n", ln); /* the legacy system needs the "$" stripped */ conf.cfsysline((uchar*) ln+1); - dbgprintf("cnf:cfsysline call done\n"); + free(ln); /* cfsysline is just a simple string */ } void cnfDoBSDTag(char *ln) { - dbgprintf("cnf:global:BSD tag: %s\n", ln); + DBGPRINTF("cnf:global:BSD tag: %s\n", ln); cflineProcessTagSelector((uchar**)&ln); } void cnfDoBSDHost(char *ln) { - dbgprintf("cnf:global:BSD host: %s\n", ln); + DBGPRINTF("cnf:global:BSD host: %s\n", ln); cflineProcessHostSelector((uchar**)&ln); } -- cgit v1.2.3 From 35b71135033e1be0c7759167d8151533f98b93e9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Jul 2011 17:21:36 +0200 Subject: milestone: omfile basically gets its parameters via the new system but not all syntax handlers are present (so it does not yet fully work). --- action.c | 23 ++++++- doc/pmlastmsg.html | 4 +- runtime/rsconf.c | 1 + runtime/rsyslog.h | 1 + tools/omfile.c | 198 ++++++++++++++++++++++++++++++++++++++++------------- 5 files changed, 176 insertions(+), 51 deletions(-) diff --git a/action.c b/action.c index 1ee3ef29..c459a738 100644 --- a/action.c +++ b/action.c @@ -1942,6 +1942,7 @@ actionNewInst(struct nvlst *lst, action_t **ppAction) uchar *cnfModName = NULL; omodStringRequest_t *pOMSR; void *pModData; + action_t *pAction; DEFiRet; paramvals = nvlstGetParams(lst, ¶mblk, NULL); @@ -1959,9 +1960,25 @@ actionNewInst(struct nvlst *lst, action_t **ppAction) errmsg.LogError(0, RS_RET_MOD_UNKNOWN, "module name '%s' is unknown", cnfModName); ABORT_FINALIZE(RS_RET_MOD_UNKNOWN); } -dbgprintf("XXXX:actionNewInst for module '%s'/%p\n", cnfModName, pMod); - CHKiRet(pMod->mod.om.newActInst(cnfModName, lst, &pModData, &pOMSR)); -dbgprintf("XXXX:actionNewInst CALLED module '%s'/%p\n", cnfModName, pMod); + iRet = pMod->mod.om.newActInst(cnfModName, lst, &pModData, &pOMSR); + // TODO: check if RS_RET_SUSPENDED is still valid in v6! + if(iRet != RS_RET_OK && iRet != RS_RET_SUSPENDED) { + FINALIZE; /* iRet is already set to error state */ + } + + if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { + /* now check if the module is compatible with select features */ + if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) + pAction->f_ReduceRepeated = loadConf->globals.bReduceRepeatMsgs; + else { + DBGPRINTF("module is incompatible with RepeatedMsgReduction - turned off\n"); + pAction->f_ReduceRepeated = 0; + } + pAction->eState = ACT_STATE_RDY; /* action is enabled */ + loadConf->actions.nbrActions++; /* one more active action! */ + } + *ppAction = pAction; + finalize_it: free(cnfModName); cnfparamvalsDestruct(paramvals, ¶mblk); diff --git a/doc/pmlastmsg.html b/doc/pmlastmsg.html index 247178c3..fd26dbd5 100644 --- a/doc/pmlastmsg.html +++ b/doc/pmlastmsg.html @@ -30,7 +30,9 @@ where n must be an integer. All other messages are left untouched.

        Please note: this parser module makes it possible that these messages are properly detected. It does not drop them. If you intend to drop those messages, you need to use the usual filter logic in combination with the discard -action. +action. As a side-note, please keep on your mind that the sender discarded messages +when the "last message repeated n times" message is emited. You want to consider if +that really is what you intend to happen. If not, go change the sender.

        Configuration Directives:

        There do not currently exist any configuration directives for this module. diff --git a/runtime/rsconf.c b/runtime/rsconf.c index f93bd7bc..e85597f8 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -232,6 +232,7 @@ cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) if(actlst->actType == CNFACT_V2) { dbgprintf("v6+ action object\n"); actionNewInst(actlst->data.lst, &pAction); + iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction); } else { dbgprintf("legacy action line:%s\n", actlst->data.legActLine); str = (uchar*) actlst->data.legActLine; diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index dd770f26..c2dbc2b2 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -364,6 +364,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_CONF_RQRD_PARAM_MISSING = -2208,/**< required parameter in config object is missing */ RS_RET_MOD_UNKNOWN = -2209,/**< module (config name) is unknown */ RS_RET_CONFOBJ_UNSUPPORTED = -2210,/**< config objects (v6 conf) are not supported here */ + RS_RET_MISSING_CNFPARAMS = -2211, /**< missing configuration parameters */ /* 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 8d332ee9..22dacc8a 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -128,9 +128,9 @@ typedef struct s_dynaFileCacheEntry dynaFileCacheEntry; typedef struct _instanceData { - uchar f_fname[MAXFNAME];/* file or template name (display only) */ + uchar *f_fname; /* file or template name (display only) */ + uchar *tplName; /* name of assigned template */ strm_t *pStrm; /* our output stream */ - strmType_t strmType; /* stream type, used for named pipes */ char bDynamicName; /* 0 - static name, 1 - dynamic name (with properties) */ int fCreateMode; /* file creation mode for open() */ int fDirCreateMode; /* creation mode for mkdir() */ @@ -181,6 +181,36 @@ uchar *pszFileDfltTplName; /* name of the default template to use */ SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "dynafilecachesize", eCmdHdlrInt, 0 }, /* legacy: dynafilecachesize */ + { "ziplevel", eCmdHdlrInt, 0 }, /* legacy: omfileziplevel */ + { "flushinterval", eCmdHdlrInt, 0 }, /* legacy: omfileflushinterval */ + { "asyncwriting", eCmdHdlrBinary, 0 }, /* legacy: omfileasyncwriting */ + { "flushontxend", eCmdHdlrBinary, 0 }, /* legacy: omfileflushontxend */ + { "iobuffersize", eCmdHdlrSize, 0 }, /* legacy: omfileiobuffersize */ + { "dirowner", eCmdHdlrUID, 0 }, /* legacy: dirowner */ + { "dirgroup", eCmdHdlrGID, 0 }, /* legacy: dirgroup */ + { "fileowner", eCmdHdlrUID, 0 }, /* legacy: fileowner */ + { "filegroup", eCmdHdlrGID, 0 }, /* legacy: filegroup */ + { "dircreatemode", eCmdHdlrFileCreateMode, 0 }, /* legacy: dircreatemode */ + { "filecreatemode", eCmdHdlrFileCreateMode, 0 }, /* legacy: filecreatemode */ + { "failonchownfailure", eCmdHdlrBinary, 0 }, /* legacy: failonchownfailure */ + { "createdirs", eCmdHdlrBinary, 0 }, /* legacy: createdirs */ + { "sync", eCmdHdlrBinary, 0 }, /* legacy: actionfileenablesync */ + { "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, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + + BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars pszFileDfltTplName = NULL; /* make sure this can be free'ed! */ @@ -297,7 +327,7 @@ static rsRetVal cflineParseOutchannel(instanceData *pData, uchar* p, omodStringR } /* OK, we finally got a correct template. So let's use it... */ - ustrncpy(pData->f_fname, pOch->pszFileTemplate, MAXFNAME); + pData->f_fname = ustrdup(pOch->pszFileTemplate); pData->iSizeLimit = pOch->uSizeLimit; /* WARNING: It is dangerous "just" to pass the pointer. As we * never rebuild the output channel description, this is acceptable here. @@ -454,7 +484,7 @@ prepareFile(instanceData *pData, uchar *newFileName) CHKiRet(strm.SettOperationsMode(pData->pStrm, STREAMMODE_WRITE_APPEND)); CHKiRet(strm.SettOpenMode(pData->pStrm, cs.fCreateMode)); CHKiRet(strm.SetbSync(pData->pStrm, pData->bSyncFile)); - CHKiRet(strm.SetsType(pData->pStrm, pData->strmType)); + CHKiRet(strm.SetsType(pData->pStrm, STREAMTYPE_FILE_SINGLE)); CHKiRet(strm.SetiSizeLimit(pData->pStrm, pData->iSizeLimit)); /* set the flush interval only if we actually use it - otherwise it will activate * async processing, which is a real performance waste if we do not do buffered @@ -654,11 +684,8 @@ writeFile(uchar **ppString, unsigned iMsgOpts, instanceData *pData) finalize_it: if(iRet != RS_RET_OK) { - /* in v5, we shall return different states for message-caused failure (but only there!) */ - if(pData->strmType == STREAMTYPE_NAMED_PIPE) - iRet = RS_RET_DISABLE_ACTION; /* this is the traditional semantic -- rgerhards, 2010-01-15 */ - else - iRet = RS_RET_SUSPENDED; + + iRet = RS_RET_SUSPENDED; } RETiRet; } @@ -672,6 +699,7 @@ ENDcreateInstance BEGINfreeInstance CODESTARTfreeInstance + free(pData->f_fname); if(pData->bDynamicName) { dynaFileFreeCache(pData); } else if(pData->pStrm != NULL) @@ -711,20 +739,121 @@ finalize_it: ENDdoAction +static inline void +setInstParamDefaults(instanceData *pData) +{ + pData->f_fname = NULL; + pData->tplName = NULL; + pData->fileUID = -1; + pData->fileGID = -1; + pData->dirUID = -1; + pData->dirGID = -1; + pData->bFailOnChown = 1; + pData->iDynaFileCacheSize = 10; + pData->fCreateMode = 0644; + pData->fDirCreateMode = 0700; + pData->bCreateDirs = 1; + pData->bSyncFile = 0; + pData->iZipLevel = 0; + pData->bFlushOnTXEnd = FLUSHONTX_DFLT; + pData->iIOBufSize = IOBUF_DFLT_SIZE; + pData->iFlushInterval = FLUSH_INTRVL_DFLT; + pData->bUseAsyncWriter = USE_ASYNCWRITER_DFLT; +} + BEGINnewActInst + struct cnfparamvals *pvals; + int i; CODESTARTnewActInst - // TODO: valid lst params dbgprintf("XXXX: in newActInst (omfile)\n"); -#if 0 + + pvals = nvlstGetParams(lst, &actpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "omfile: either the \"file\" or " + "\"dynfile\" parameter must be given"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("action param blk in omfile:\n"); + cnfparamsPrint(&actpblk, pvals); + } + CHKiRet(createInstance(&pData)); + setInstParamDefaults(pData); + + for(i = 0 ; i < actpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(actpblk.descr[i].name, "dynafilecachesize")) { + pData->iDynaFileCacheSize = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "ziplevel")) { + pData->iZipLevel = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "flushinterval")) { + pData->iFlushInterval = pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "asyncwriting")) { + pData->bUseAsyncWriter = pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "flushontxend")) { + pData->bFlushOnTXEnd = pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "iobuffersize")) { + pData->iIOBufSize = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "dirowner")) { + pData->dirUID = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "dirgroup")) { + pData->dirGID = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "fileowner")) { + pData->fileUID = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "filegroup")) { + pData->fileGID = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "dircreatemode")) { + pData->fDirCreateMode = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "filecreatemode")) { + pData->fCreateMode = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "failonchownfailure")) { + pData->bFailOnChown = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "sync")) { + pData->bSyncFile = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "createdirs")) { + pData->bCreateDirs = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "file")) { + pData->f_fname = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + CODE_STD_STRING_REQUESTnewActInst(1) + pData->bDynamicName = 0; + } else if(!strcmp(actpblk.descr[i].name, "dynafile")) { + pData->f_fname = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + CODE_STD_STRING_REQUESTnewActInst(2) + pData->bDynamicName = 1; + } else if(!strcmp(actpblk.descr[i].name, "template")) { + pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + dbgprintf("omfile: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } - if(*p == '-') { - pData->bSyncFile = 0; - p++; - } else { - pData->bSyncFile = cs.bEnableSync; + if(pData->f_fname == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "omfile: either the \"file\" or " + "\"dynfile\" parameter must be given"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); } + CHKiRet(OMSRsetEntry(*ppOMSR, 0, ustrdup((pData->tplName == NULL) ? + (uchar*)"RSYSLOG_FileFormat" : (uchar*)"??"), + 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 + * to the pOMSR. -- rgerhards, 2007-07-27 + */ + CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(pData->f_fname), OMSR_NO_RQD_TPL_OPTS)); + // TODO: create unified code for this (legacy+v6 system) + /* we now allocate the cache table */ + CHKmalloc(pData->dynCache = (dynaFileCacheEntry**) + calloc(cs.iDynaFileCacheSize, sizeof(dynaFileCacheEntry*))); + pData->iCurrElt = -1; /* no current element */ + } +// TODO: add pData->iSizeLimit = 0; /* default value, use outchannels to configure! */ +#if 0 switch(*p) { case '$': CODE_STD_STRING_REQUESTnewActInst(1) @@ -757,41 +886,15 @@ CODESTARTnewActInst CHKmalloc(pData->dynCache = (dynaFileCacheEntry**) calloc(cs.iDynaFileCacheSize, sizeof(dynaFileCacheEntry*))); break; - - case '/': - case '.': - CODE_STD_STRING_REQUESTnewActInst(1) - pData->strmType = STREAMTYPE_FILE_SINGLE; - CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, - (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); - pData->bDynamicName = 0; - break; - default: - ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); } - - /* freeze current paremeters for this action */ - pData->iSizeLimit = 0; /* default value, use outchannels to configure! */ - pData->iDynaFileCacheSize = cs.iDynaFileCacheSize; - pData->fCreateMode = cs.fCreateMode; - pData->fDirCreateMode = cs.fDirCreateMode; - pData->bCreateDirs = cs.bCreateDirs; - pData->bFailOnChown = cs.bFailOnChown; - pData->fileUID = cs.fileUID; - pData->fileGID = cs.fileGID; - pData->dirUID = cs.dirUID; - pData->dirGID = cs.dirGID; - pData->iZipLevel = cs.iZipLevel; - pData->bFlushOnTXEnd = cs.bFlushOnTXEnd; - pData->iIOBufSize = (int) cs.iIOBufSize; - pData->iFlushInterval = cs.iFlushInterval; - pData->bUseAsyncWriter = cs.bUseAsyncWriter; #endif CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); ENDnewActInst BEGINparseSelectorAct + uchar fname[MAXFNAME]; CODESTARTparseSelectorAct /* Note: the indicator sequence permits us to use '$' to signify * outchannel, what otherwise is not possible due to truely @@ -833,13 +936,14 @@ CODESTARTparseSelectorAct */ CODE_STD_STRING_REQUESTparseSelectorAct(2) ++p; /* eat '?' */ - CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, + CHKiRet(cflineParseFileName(p, fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); /* "filename" is actually a template name, we need this as string 1. So let's add it * to the pOMSR. -- rgerhards, 2007-07-27 */ CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(pData->f_fname), OMSR_NO_RQD_TPL_OPTS)); + pData->f_fname = ustrdup(fname); pData->bDynamicName = 1; pData->iCurrElt = -1; /* no current element */ /* we now allocate the cache table */ @@ -850,9 +954,9 @@ CODESTARTparseSelectorAct case '/': case '.': CODE_STD_STRING_REQUESTparseSelectorAct(1) - pData->strmType = STREAMTYPE_FILE_SINGLE; - CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, + CHKiRet(cflineParseFileName(p, fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); + pData->f_fname = ustrdup(fname); pData->bDynamicName = 0; break; default: -- cgit v1.2.3 From 052f8e2ef64ca039219ac83a9d9372f3eb3a5aed Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Jul 2011 17:45:39 +0200 Subject: bugfix: abort in omfile (in brand-new code) --- grammar/parserif.h | 3 ++- grammar/rainerscript.c | 3 +++ grammar/rainerscript.h | 2 ++ runtime/module-template.h | 3 ++- runtime/rsconf.c | 8 ++++++-- 5 files changed, 15 insertions(+), 4 deletions(-) diff --git a/grammar/parserif.h b/grammar/parserif.h index 58b8fbdd..adb0f42f 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -3,10 +3,11 @@ #include "rainerscript.h" int cnfSetLexFile(char*); int yyparse(); -int yydebug; char *cnfcurrfn; void dbgprintf(char *fmt, ...) __attribute__((format(printf, 1, 2))); void parser_errmsg(char *fmt, ...) __attribute__((format(printf, 1, 2))); +extern int yydebug; +extern int yylineno; /* entry points to be called after the parser has processed the * element in question. Actual processing must than be done inside diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 0b2ee7cb..43c5a677 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -449,6 +449,8 @@ cnfactlstNew(enum cnfactType actType, struct nvlst *lst, char *actLine) actlst->next = NULL; actlst->syslines = NULL; actlst->actType = actType; + actlst->lineno = yylineno; + actlst->cnfFile = strdup(cnfcurrfn); if(actType == CNFACT_V2) actlst->data.lst = lst; else @@ -484,6 +486,7 @@ cnfactlstDestruct(struct cnfactlst *actlst) while(actlst != NULL) { toDel = actlst; actlst = actlst->next; + free(toDel->cnfFile); cnfcfsyslinelstDestruct(toDel->syslines); if(toDel->actType == CNFACT_V2) nvlstDestruct(toDel->data.lst); diff --git a/grammar/rainerscript.h b/grammar/rainerscript.h index 7cc38abb..e11ae62f 100644 --- a/grammar/rainerscript.h +++ b/grammar/rainerscript.h @@ -86,6 +86,8 @@ struct cnfactlst { struct nvlst *lst; char *legActLine; } data; + char *cnfFile; + int lineno; }; /* the following structures support expressions, and may (very much later diff --git a/runtime/module-template.h b/runtime/module-template.h index 6238d0f4..d360447a 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -325,7 +325,8 @@ static rsRetVal newActInst(uchar __attribute__((unused)) *modName, \ struct nvlst *lst, void **ppModData, omodStringRequest_t **ppOMSR)\ {\ DEFiRet;\ - instanceData *pData = NULL; + instanceData *pData = NULL; \ + *ppOMSR = NULL; #define CODESTARTnewActInst \ diff --git a/runtime/rsconf.c b/runtime/rsconf.c index e85597f8..c4a0ed51 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -231,8 +231,12 @@ cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) dbgprintf("aclst %p: ", actlst); if(actlst->actType == CNFACT_V2) { dbgprintf("v6+ action object\n"); - actionNewInst(actlst->data.lst, &pAction); - iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction); + if(actionNewInst(actlst->data.lst, &pAction) == RS_RET_OK) { + iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction); + } else { + errmsg.LogError(0, RS_RET_ERR, "errors occured in file '%s' " + "around line %d", actlst->cnfFile, actlst->lineno); + } } else { dbgprintf("legacy action line:%s\n", actlst->data.legActLine); str = (uchar*) actlst->data.legActLine; -- cgit v1.2.3 From be804fecf0e383e2b9c4fa646bcd838f1d2545ef Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Jul 2011 19:02:26 +0200 Subject: omusrmsg now supports the new config system --- ChangeLog | 1 + grammar/lexer.l | 2 +- tools/omfile.c | 1 - tools/omusrmsg.c | 166 ++++++++++++++++++++++++++++++++++++++++++------------- 4 files changed, 130 insertions(+), 40 deletions(-) diff --git a/ChangeLog b/ChangeLog index be11c02f..c35c81b3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ --------------------------------------------------------------------------- Version 6.3.4 [DEVEL] (rgerhards), 2011-07-?? +- bugfix: omusrmsg format usr1,usr2 was no longer supported - bugfix: misaddressing in config handler In theory, can cause segfault, in practice this is extremely unlikely Thanks to Marcin for alertig me. diff --git a/grammar/lexer.l b/grammar/lexer.l index 5ad646ad..a89cf180 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -165,7 +165,7 @@ int fileno(FILE *stream); \/[^*][^\n]* | :[a-z0-9]+:[^\n]* | [\|\.\-\@\^?~>][^\n]+ | -[a-z0-9_][a-z0-9_\-\+]* { yylval.s = strdup(yytext); +[a-z0-9_][a-z0-9_\-\+,; ]* { yylval.s = strdup(yytext); // printf("lex: LEGA ACT: '%s'\n", yytext); return LEGACY_ACTION; } ")" { BEGIN INITIAL; return ENDOBJ; } diff --git a/tools/omfile.c b/tools/omfile.c index 22dacc8a..a0a7b186 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -1037,7 +1037,6 @@ CODEqueryEtryPt_STD_OMOD_QUERIES CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */ CODEqueryEtryPt_doHUP -CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES ENDqueryEtryPt diff --git a/tools/omusrmsg.c b/tools/omusrmsg.c index 3ee01612..358b6ce7 100644 --- a/tools/omusrmsg.c +++ b/tools/omusrmsg.c @@ -11,18 +11,7 @@ * of the "old" message code without any modifications. However, it * helps to have things at the right place one we go to the meat of it. * - * Copyright 2007, 2008 Rainer Gerhards and Adiscon GmbH. - * - * rgerhards, 2008-07-04 (happy Independence Day!): rsyslog inherited the - * wall functionality from sysklogd. Sysklogd was single-threaded and could - * not afford to spent a lot of time inside a single action. Thus, it forked - * off a new process to do the wall. In rsyslog, however, this creates some - * grief with the threading model. Also, we do not really need to de-couple - * processing, because we have ample ways to do it in rsyslog. Plus, the - * default main message queue will care for a somewhat longer execution time. - * So in short, the real fix to the problem is an architecture change. From - * now on, we will not fork off a new process but rather do the notification - * within the current one. This also reduces system overhead. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -49,6 +38,7 @@ #include #include #include +#include #include #ifdef HAVE_UTMP_H # include @@ -88,6 +78,7 @@ MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omusrmsg") /* internal structures */ @@ -97,6 +88,7 @@ DEFobjCurrIf(errmsg) typedef struct _instanceData { int bIsWall; /* 1- is wall, 0 - individual users */ char uname[MAXUNAMES][UNAMESZ+1]; + uchar *tplName; } instanceData; typedef struct configSettings_s { @@ -105,6 +97,19 @@ typedef struct configSettings_s { SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ + +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "users", eCmdHdlrString, CNFPARAM_REQUIRED }, + { "template", eCmdHdlrGetWord, 0 } +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars ENDinitConfVars @@ -124,7 +129,7 @@ ENDisCompatibleWithFeature BEGINfreeInstance CODESTARTfreeInstance - /* TODO: free the instance pointer (currently a leak, will go away) */ + free(pData->tplName); ENDfreeInstance @@ -280,15 +285,111 @@ CODESTARTdoAction ENDdoAction -BEGINparseSelectorAct - uchar *q; +static inline void +populateUsers(instanceData *pData, es_str_t *usrs) +{ + int i; + int iDst; + es_size_t iUsr; + es_size_t len; + uchar *c; + + len = es_strlen(usrs); + c = es_getBufAddr(usrs); + pData->bIsWall = 0; /* write to individual users */ + iUsr = 0; + for(i = 0 ; i < MAXUNAMES && iUsr < len ; ++i) { + for( iDst = 0 + ; iDst < UNAMESZ && iUsr < len && c[iUsr] != ',' + ; ++iDst, ++iUsr) { + pData->uname[i][iDst] = c[iUsr]; + } + pData->uname[i][iDst] = '\0'; + DBGPRINTF("omusrmsg: send to user '%s'\n", pData->uname[i]); + if(iUsr < len && c[iUsr] != ',') { + errmsg.LogError(0, RS_RET_ERR, "user name '%s...' too long - " + "ignored", pData->uname[i]); + --i; + ++iUsr; + while(iUsr < len && c[iUsr] != ',') + ++iUsr; /* skip to next name */ + } else if(iDst == 0) { + errmsg.LogError(0, RS_RET_ERR, "no user name given - " + "ignored"); + --i; + ++iUsr; + while(iUsr < len && c[iUsr] != ',') + ++iUsr; /* skip to next name */ + } + if(iUsr < len) { + ++iUsr; /* skip "," */ + while(iUsr < len && isspace(c[iUsr])) + ++iUsr; /* skip whitespace */ + } + } + if(i == MAXUNAMES && iUsr != len) { + errmsg.LogError(0, RS_RET_ERR, "omusrmsg supports only up to %d " + "user names in a single action - all others have been ignored", + MAXUNAMES); + } +} + + +static inline void +setInstParamDefaults(instanceData *pData) +{ + pData->bIsWall = 0; + pData->tplName = NULL; +} + +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, "users")) { + if(!es_strbufcmp(pvals[i].val.d.estr, (uchar*)"*", 1)) { + pData->bIsWall = 1; + } else { + populateUsers(pData, pvals[i].val.d.estr); + } + } else if(!strcmp(actpblk.descr[i].name, "template")) { + pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + dbgprintf("omusrmsg: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + + if(pData->tplName == NULL) { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, + (uchar*) strdup(pData->bIsWall ? " WallFmt" : " StdUsrMsgFmt"), + OMSR_NO_RQD_TPL_OPTS)); + } else { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, + (uchar*) strdup((char*) pData->tplName), + OMSR_NO_RQD_TPL_OPTS)); + } +CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + + + +BEGINparseSelectorAct + es_str_t *usrs; CODESTARTparseSelectorAct CODE_STD_STRING_REQUESTparseSelectorAct(1) - /* User names must begin with a gnu e-regex: - * [a-zA-Z0-9_.] - * plus '*' for wall - */ if(!strncmp((char*) p, ":omusrmsg:", sizeof(":omusrmsg:") - 1)) { p += sizeof(":omusrmsg:") - 1; /* eat indicator sequence (-1 because of '\0'!) */ } else { @@ -311,26 +412,14 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) pData->bIsWall = 1; /* write to all users */ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) " WallFmt")); } else { - /* everything else beginning with the regex above - * is currently treated as a user name -- TODO: is this portable? - */ - dbgprintf("users: %s\n", p); /* ASP */ - pData->bIsWall = 0; /* write to individual users */ - for (i = 0; i < MAXUNAMES && *p && *p != ';'; i++) { - for (q = p; *q && *q != ',' && *q != ';'; ) - q++; - (void) strncpy((char*) pData->uname[i], (char*) p, UNAMESZ); - if ((q - p) > UNAMESZ) - pData->uname[i][UNAMESZ] = '\0'; - else - pData->uname[i][q - p] = '\0'; - while (*q == ',' || *q == ' ') - q++; - p = q; + /* everything else is currently treated as a user name */ + usrs = es_newStr(128); + while(*p && *p != ';') { + es_addChar(&usrs, *p); + ++p; } - /* done, on to the template - * TODO: we need to handle the case where i >= MAXUNAME! - */ + populateUsers(pData, usrs); + es_deleteStr(usrs); if((iRet = cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*)" StdUsrMsgFmt")) != RS_RET_OK) goto finalize_it; @@ -347,6 +436,7 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From 5ecb71776b517b19bc94c8ae688e842bed6e3f53 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 22 Jul 2011 09:27:53 +0200 Subject: build system cleanup/improvement --- configure.ac | 6 ------ tools/Makefile.am | 3 ++- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/configure.ac b/configure.ac index 48e6a94e..46c50bbf 100644 --- a/configure.ac +++ b/configure.ac @@ -17,12 +17,6 @@ AC_GNU_SOURCE AC_CHECK_PROG(have_valgrind, [valgrind], [yes]) AM_CONDITIONAL(HAVE_VALGRIND, test x$have_valgrind = xyes) -# check for Java compiler -AC_CHECK_PROG(HAVE_JAVAC, [javac], [yes]) -if test x"$HAVE_JAVAC" = x""; then - AC_MSG_WARN([no javac found, disabling features depending on it]) -fi - # Checks for programs. AC_PROG_LEX AC_PROG_YACC diff --git a/tools/Makefile.am b/tools/Makefile.am index 1bed5ae8..84b0b6f0 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -34,7 +34,8 @@ rsyslogd_SOURCES = \ pidfile.c \ pidfile.h \ \ - ../dirty.h + ../dirty.h \ + ../runtime/librsyslog.la rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) $(CNF_LIBS) rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) $(CNF_LIBS) ../grammar/libgrammar.la rsyslogd_LDFLAGS = -export-dynamic -- cgit v1.2.3 From 8ad3716cb230d0c13b6ed6f98a96939c69987509 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 22 Jul 2011 09:42:28 +0200 Subject: working around automake curiosity --- tools/Makefile.am | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/Makefile.am b/tools/Makefile.am index 84b0b6f0..d5c7537b 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -37,7 +37,10 @@ rsyslogd_SOURCES = \ ../dirty.h \ ../runtime/librsyslog.la rsyslogd_CPPFLAGS = $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) $(CNF_LIBS) -rsyslogd_LDADD = $(ZLIB_LIBS) $(PTHREADS_LIBS) $(RSRT_LIBS) $(SOL_LIBS) $(LIBEE_LIBS) $(LIBLOGNORM_LIBS) $(CNF_LIBS) ../grammar/libgrammar.la +# 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_LDFLAGS = -export-dynamic if ENABLE_DIAGTOOLS -- cgit v1.2.3 From ca377701e0200a0766abe3bb33f4cab3ccaad451 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 22 Jul 2011 11:32:26 +0200 Subject: milestone: all syntaxes for new config handler implemented so far, mostly compile-time tested. Real testing happens as side-activity when implementing other parts of the new config system --- grammar/Makefile.am | 2 +- grammar/rainerscript.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ runtime/cfsysline.c | 5 +- runtime/cfsysline.h | 2 +- runtime/rsconf.c | 1 - 5 files changed, 135 insertions(+), 5 deletions(-) diff --git a/grammar/Makefile.am b/grammar/Makefile.am index 4746a9de..5911f443 100644 --- a/grammar/Makefile.am +++ b/grammar/Makefile.am @@ -2,7 +2,7 @@ BUILT_SOURCES = grammar.h CLEANFILES = grammar.h grammar.c AM_YFLAGS = -d noinst_LTLIBRARIES = libgrammar.la -bin_PROGRAMS = testdriver # TODO: make this conditional +#bin_PROGRAMS = testdriver # TODO: make this conditional libgrammar_la_SOURCES = \ grammar.y \ diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 43c5a677..fe99e4aa 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -30,11 +30,15 @@ #include #include #include +#include +#include #include +#include #include #include "rainerscript.h" #include "parserif.h" #include "grammar.h" +#include "srUtils.h" void readConfFile(FILE *fp, es_str_t **str) @@ -267,6 +271,104 @@ doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param, } } +/* A file create-mode must be a four-digit octal number + * starting with '0'. + */ +static inline void +doGetFileCreateMode(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + int fmtOK = 0; + char *cstr; + uchar *c; + + if(es_strlen(valnode->val.d.estr) == 4) { + c = es_getBufAddr(valnode->val.d.estr); + if(!( (c[0] == '0') + && (c[1] >= '0' && c[1] <= '7') + && (c[2] >= '0' && c[2] <= '7') + && (c[3] >= '0' && c[3] <= '7') ) ) { + fmtOK = 1; + } + } + + if(fmtOK) { + val->val.datatype = 'N'; + val->val.d.n = (c[1]-'0') * 64 + (c[2]-'0') * 8 + (c[3]-'0');; + } else { + cstr = es_str2cstr(valnode->val.d.estr, NULL); + parser_errmsg("file modes need to be specified as " + "4-digit octal numbers starting with '0' -" + "parameter '%s=\"%s\"' is not a file mode", + param->name, cstr); + free(cstr); + } +} + +static inline void +doGetGID(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + char *cstr; + struct group *resultBuf; + struct group wrkBuf; + char stringBuf[2048]; /* 2048 has been proven to be large enough */ + + cstr = es_str2cstr(valnode->val.d.estr, NULL); + getgrnam_r(cstr, &wrkBuf, stringBuf, sizeof(stringBuf), &resultBuf); + if(resultBuf == NULL) { + parser_errmsg("parameter '%s': ID for group %s could not " + "be found", param->name, cstr); + } 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); + } + free(cstr); +} + +static inline void +doGetUID(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + char *cstr; + struct passwd *resultBuf; + struct passwd wrkBuf; + char stringBuf[2048]; /* 2048 has been proven to be large enough */ + + cstr = es_str2cstr(valnode->val.d.estr, NULL); + getpwnam_r(cstr, &wrkBuf, stringBuf, sizeof(stringBuf), &resultBuf); + if(resultBuf == NULL) { + parser_errmsg("parameter '%s': ID for user %s could not " + "be found", param->name, cstr); + } 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); + } + free(cstr); +} + +/* note: we support all integer formats that es_str2num support, + * so hex and octal representations are also valid. + */ +static inline void +doGetInt(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + long long n; + int bSuccess; + + n = es_str2num(valnode->val.d.estr, &bSuccess); + if(!bSuccess) { + parser_errmsg("parameter '%s' is not a proper number", + param->name); + } + val->val.datatype = 'N'; + val->val.d.n = n; +} static inline void doGetWord(struct nvlst *valnode, struct cnfparamdescr *param, @@ -287,6 +389,19 @@ doGetWord(struct nvlst *valnode, struct cnfparamdescr *param, } } +static inline void +doGetChar(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + 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)); + } + val->val.datatype = 'S'; + val->val.d.estr = es_strdup(valnode->val.d.estr); +} + /* get a single parameter according to its definition. Helper to * nvlstGetParams. */ @@ -294,30 +409,45 @@ static inline void nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, struct cnfparamvals *val) { + uchar *cstr; + dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d\n", param->name, (int) param->type); valnode->bUsed = 1; val->bUsed = 1; switch(param->type) { case eCmdHdlrUID: + doGetUID(valnode, param, val); break; case eCmdHdlrGID: + doGetGID(valnode, param, val); break; case eCmdHdlrBinary: doGetBinary(valnode, param, val); break; case eCmdHdlrFileCreateMode: + doGetFileCreateMode(valnode, param, val); break; case eCmdHdlrInt: + doGetInt(valnode, param, val); break; case eCmdHdlrSize: doGetSize(valnode, param, val); break; case eCmdHdlrGetChar: + 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); 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); break; case eCmdHdlrGetWord: doGetWord(valnode, param, val); diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c index f6581ccd..288e6974 100644 --- a/runtime/cfsysline.c +++ b/runtime/cfsysline.c @@ -3,7 +3,7 @@ * * File begun on 2007-07-30 by RGerhards * - * Copyright (C) 2007, 2008 by Rainer Gerhards and Adiscon GmbH. + * Copyright (C) 2007-2011 by Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -544,7 +544,8 @@ finalize_it: * time (TODO). -- rgerhards, 2008-02-14 */ static rsRetVal -doSyslogName(uchar **pp, rsRetVal (*pSetHdlr)(void*, int), void *pVal, syslogName_t *pNameTable) +doSyslogName(uchar **pp, rsRetVal (*pSetHdlr)(void*, int), + void *pVal, syslogName_t *pNameTable) { DEFiRet; cstr_t *pStrB; diff --git a/runtime/cfsysline.h b/runtime/cfsysline.h index a4502672..5e9532fc 100644 --- a/runtime/cfsysline.h +++ b/runtime/cfsysline.h @@ -1,6 +1,6 @@ /* Definition of the cfsysline (config file system line) object. * - * Copyright 2007 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * diff --git a/runtime/rsconf.c b/runtime/rsconf.c index c4a0ed51..20c3b4f0 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -430,7 +430,6 @@ void cnfDoCfsysline(char *ln) DBGPRINTF("cnf:global:cfsysline: %s\n", ln); /* the legacy system needs the "$" stripped */ conf.cfsysline((uchar*) ln+1); - free(ln); /* cfsysline is just a simple string */ } void cnfDoBSDTag(char *ln) -- cgit v1.2.3 From 6b8b7ba0091a4e59b9a45057756fc7f754576242 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 22 Jul 2011 11:58:39 +0200 Subject: need to handle legacy-legacy omusrmsg format stricter otherwise, the grammar for if-constructs was broken --- doc/v6compatibility.html | 38 ++++++++++++++++++++++++++++++++++++-- grammar/lexer.l | 2 +- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/doc/v6compatibility.html b/doc/v6compatibility.html index 67f7f0d8..cf621943 100644 --- a/doc/v6compatibility.html +++ b/doc/v6compatibility.html @@ -82,8 +82,7 @@ syntax is concerned. Nevertheless, v6 still supports it, but a new syntax is req for the action. Let's assume your outchannel is named "channel". The previous syntax was

        *.* $channel - -
        + This was deprecated in v5 and no longer works in v6. Instead, you need to specify
        *.* :omfile:$channel @@ -92,6 +91,41 @@ 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. +

        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 +just the user name to call this action, like in this example: +

        +*.* rgerhards +
        +This format is very ambigious and causes headache (see +blog post +on omusrmsg for details). Thus the format has been superseded by this syntax +(which is legacy format ;-)): +
        +*.* :omusrmsg:rgerhards +
        +That syntax is supported since later subversions of version 4. +

        Rsyslog v6 still supports the legacy-legacy format, but in a very strict +sense. For example, if multiple users or templates are given, no spaces +must be included in the action line. For example, this works up to v5, but no +longer in v6: +

        +*.* rgerhards, bgerhards +
        +To fix it in a way that is compatible with pre-v6, use (note the removed space!): +
        +*.* rgerhards,bgerhards +
        +Of course, it probably is better to understand in native v6 format: +
        +*.* action(type="omusrmsg" users="rgerhards, bgerhards") +
        +As you see, here you may include spaces between user names. +

        In the long term, legacy-legacy format will most probably totally disappear, +so it is a wise decision to change config files at least to the legacy +format (with ":omusrmsg:" in front of the name). +

        [manual index] [rsyslog site]

        This documentation is part of the rsyslog project.
        diff --git a/grammar/lexer.l b/grammar/lexer.l index a89cf180..cf912db3 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -165,7 +165,7 @@ int fileno(FILE *stream); \/[^*][^\n]* | :[a-z0-9]+:[^\n]* | [\|\.\-\@\^?~>][^\n]+ | -[a-z0-9_][a-z0-9_\-\+,; ]* { yylval.s = strdup(yytext); +[a-z0-9_][a-z0-9_\-\+,;]* { yylval.s = strdup(yytext); // printf("lex: LEGA ACT: '%s'\n", yytext); return LEGACY_ACTION; } ")" { BEGIN INITIAL; return ENDOBJ; } -- cgit v1.2.3 From 9757aeb56445eee3aca2b43e6b3efa1f1cb59ba3 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 22 Jul 2011 18:03:43 +0200 Subject: milestone: queue object now has a param handler for new conf interface ... and action queue defs use this new interface (but not yet the main queues) --- action.c | 88 +++++++++----------- action.h | 6 +- doc/v6compatibility.html | 2 +- grammar/lexer.l | 21 ++++- grammar/parserif.h | 1 + grammar/rainerscript.c | 29 +++++++ runtime/conf.c | 2 +- runtime/queue.c | 207 ++++++++++++++++++++++++++++++++++++++--------- runtime/queue.h | 3 + runtime/rsconf.c | 6 +- runtime/typedefs.h | 1 + 11 files changed, 267 insertions(+), 99 deletions(-) diff --git a/action.c b/action.c index c459a738..74f6f7f7 100644 --- a/action.c +++ b/action.c @@ -8,7 +8,7 @@ * the right code in question): For performance reasons, this module * uses different methods of message submission based on the user-selected * configuration. This code is similar, but can not be abstracted because - * of the performanse-affecting differences in it. As such, it is often + * of the performance-affecting differences in it. As such, it is often * necessary to triple-check that everything works well in *all* modes. * The different modes (and calling sequence) are: * @@ -197,32 +197,6 @@ static struct cnfparamblk paramblk = cnfparamdescr }; -/* Still TODO: */ -#if 0 - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuefilename", 0, eCmdHdlrGetWord, NULL, &cs.pszActionQFName, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesize", 0, eCmdHdlrInt, NULL, &cs.iActionQueueSize, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuebatchsize", 0, eCmdHdlrInt, NULL, &cs.iActionQueueDeqBatchSize, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuemaxdiskspace", 0, eCmdHdlrSize, NULL, &cs.iActionQueMaxDiskSpace, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuehighwatermark", 0, eCmdHdlrInt, NULL, &cs.iActionQHighWtrMark, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuelowwatermark", 0, eCmdHdlrInt, NULL, &cs.iActionQLowWtrMark, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuediscardmark", 0, eCmdHdlrInt, NULL, &cs.iActionQDiscardMark, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuediscardseverity", 0, eCmdHdlrInt, NULL, &cs.iActionQDiscardSeverity, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuecheckpointinterval", 0, eCmdHdlrInt, NULL, &cs.iActionQPersistUpdCnt, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesyncqueuefiles", 0, eCmdHdlrBinary, NULL, &cs.bActionQSyncQeueFiles, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetype", 0, eCmdHdlrGetWord, setActionQueType, NULL, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueueworkerthreads", 0, eCmdHdlrInt, NULL, &cs.iActionQueueNumWorkers, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetimeoutshutdown", 0, eCmdHdlrInt, NULL, &cs.iActionQtoQShutdown, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetimeoutactioncompletion", 0, eCmdHdlrInt, NULL, &cs.iActionQtoActShutdown, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuetimeoutenqueue", 0, eCmdHdlrInt, NULL, &cs.iActionQtoEnq, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueueworkertimeoutthreadshutdown", 0, eCmdHdlrInt, NULL, &cs.iActionQtoWrkShutdown, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueueworkerthreadminimummessages", 0, eCmdHdlrInt, NULL, &cs.iActionQWrkMinMsgs, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuemaxfilesize", 0, eCmdHdlrSize, NULL, &cs.iActionQueMaxFileSize, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuesaveonshutdown", 0, eCmdHdlrBinary, NULL, &cs.bActionQSaveOnShutdown, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeueslowdown", 0, eCmdHdlrInt, NULL, &cs.iActionQueueDeqSlowdown, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuetimebegin", 0, eCmdHdlrInt, NULL, &cs.iActionQueueDeqtWinFromHr, NULL, eConfObjAction)); - CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuedequeuetimeend", 0, eCmdHdlrInt, NULL, &cs.iActionQueueDeqtWinToHr, NULL, eConfObjAction)); -#endif - /* ------------------------------ methods ------------------------------ */ /* This function returns the "current" time for this action. Current time @@ -364,7 +338,7 @@ finalize_it: /* action construction finalizer */ rsRetVal -actionConstructFinalize(action_t *pThis) +actionConstructFinalize(action_t *pThis, struct cnfparamvals *queueParams) { DEFiRet; uchar pszQName[64]; /* friendly name of our queue */ @@ -434,25 +408,31 @@ actionConstructFinalize(action_t *pThis) } qqueueSetpUsr(pThis->pQueue, pThis); - setQPROP(qqueueSetsizeOnDiskMax, "$ActionQueueMaxDiskSpace", cs.iActionQueMaxDiskSpace); - setQPROP(qqueueSetiDeqBatchSize, "$ActionQueueDequeueBatchSize", cs.iActionQueueDeqBatchSize); - setQPROP(qqueueSetMaxFileSize, "$ActionQueueFileSize", cs.iActionQueMaxFileSize); - setQPROPstr(qqueueSetFilePrefix, "$ActionQueueFileName", cs.pszActionQFName); - setQPROP(qqueueSetiPersistUpdCnt, "$ActionQueueCheckpointInterval", cs.iActionQPersistUpdCnt); - setQPROP(qqueueSetbSyncQueueFiles, "$ActionQueueSyncQueueFiles", cs.bActionQSyncQeueFiles); - setQPROP(qqueueSettoQShutdown, "$ActionQueueTimeoutShutdown", cs.iActionQtoQShutdown ); - setQPROP(qqueueSettoActShutdown, "$ActionQueueTimeoutActionCompletion", cs.iActionQtoActShutdown); - setQPROP(qqueueSettoWrkShutdown, "$ActionQueueWorkerTimeoutThreadShutdown", cs.iActionQtoWrkShutdown); - setQPROP(qqueueSettoEnq, "$ActionQueueTimeoutEnqueue", cs.iActionQtoEnq); - setQPROP(qqueueSetiHighWtrMrk, "$ActionQueueHighWaterMark", cs.iActionQHighWtrMark); - setQPROP(qqueueSetiLowWtrMrk, "$ActionQueueLowWaterMark", cs.iActionQLowWtrMark); - setQPROP(qqueueSetiDiscardMrk, "$ActionQueueDiscardMark", cs.iActionQDiscardMark); - setQPROP(qqueueSetiDiscardSeverity, "$ActionQueueDiscardSeverity", cs.iActionQDiscardSeverity); - setQPROP(qqueueSetiMinMsgsPerWrkr, "$ActionQueueWorkerThreadMinimumMessages", cs.iActionQWrkMinMsgs); - setQPROP(qqueueSetbSaveOnShutdown, "$ActionQueueSaveOnShutdown", cs.bActionQSaveOnShutdown); - setQPROP(qqueueSetiDeqSlowdown, "$ActionQueueDequeueSlowdown", cs.iActionQueueDeqSlowdown); - setQPROP(qqueueSetiDeqtWinFromHr, "$ActionQueueDequeueTimeBegin", cs.iActionQueueDeqtWinFromHr); - setQPROP(qqueueSetiDeqtWinToHr, "$ActionQueueDequeueTimeEnd", cs.iActionQueueDeqtWinToHr); + if(queueParams == NULL) { + /* use legacy params */ + setQPROP(qqueueSetsizeOnDiskMax, "$ActionQueueMaxDiskSpace", cs.iActionQueMaxDiskSpace); + setQPROP(qqueueSetiDeqBatchSize, "$ActionQueueDequeueBatchSize", cs.iActionQueueDeqBatchSize); + setQPROP(qqueueSetMaxFileSize, "$ActionQueueFileSize", cs.iActionQueMaxFileSize); + setQPROPstr(qqueueSetFilePrefix, "$ActionQueueFileName", cs.pszActionQFName); + setQPROP(qqueueSetiPersistUpdCnt, "$ActionQueueCheckpointInterval", cs.iActionQPersistUpdCnt); + setQPROP(qqueueSetbSyncQueueFiles, "$ActionQueueSyncQueueFiles", cs.bActionQSyncQeueFiles); + setQPROP(qqueueSettoQShutdown, "$ActionQueueTimeoutShutdown", cs.iActionQtoQShutdown ); + setQPROP(qqueueSettoActShutdown, "$ActionQueueTimeoutActionCompletion", cs.iActionQtoActShutdown); + setQPROP(qqueueSettoWrkShutdown, "$ActionQueueWorkerTimeoutThreadShutdown", cs.iActionQtoWrkShutdown); + setQPROP(qqueueSettoEnq, "$ActionQueueTimeoutEnqueue", cs.iActionQtoEnq); + setQPROP(qqueueSetiHighWtrMrk, "$ActionQueueHighWaterMark", cs.iActionQHighWtrMark); + setQPROP(qqueueSetiLowWtrMrk, "$ActionQueueLowWaterMark", cs.iActionQLowWtrMark); + setQPROP(qqueueSetiDiscardMrk, "$ActionQueueDiscardMark", cs.iActionQDiscardMark); + setQPROP(qqueueSetiDiscardSeverity, "$ActionQueueDiscardSeverity", cs.iActionQDiscardSeverity); + setQPROP(qqueueSetiMinMsgsPerWrkr, "$ActionQueueWorkerThreadMinimumMessages", cs.iActionQWrkMinMsgs); + setQPROP(qqueueSetbSaveOnShutdown, "$ActionQueueSaveOnShutdown", cs.bActionQSaveOnShutdown); + setQPROP(qqueueSetiDeqSlowdown, "$ActionQueueDequeueSlowdown", cs.iActionQueueDeqSlowdown); + setQPROP(qqueueSetiDeqtWinFromHr, "$ActionQueueDequeueTimeBegin", cs.iActionQueueDeqtWinFromHr); + setQPROP(qqueueSetiDeqtWinToHr, "$ActionQueueDequeueTimeEnd", cs.iActionQueueDeqtWinToHr); + } else { + /* we have v6-style config params */ + qqueueApplyCnfParam(pThis->pQueue, queueParams); + } # undef setQPROP # undef setQPROPstr @@ -1762,7 +1742,8 @@ doSubmitToActionQComplexBatch(action_t *pAction, batch_t *pBatch) * rgerhards, 2007-07-27 */ rsRetVal -addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringRequest_t *pOMSR, int bSuspended) +addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, + omodStringRequest_t *pOMSR, struct cnfparamvals *queueParams, int bSuspended) { DEFiRet; int i; @@ -1774,7 +1755,7 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringReques assert(ppAction != NULL); assert(pMod != NULL); assert(pOMSR != NULL); - DBGPRINTF("Module %s processed this config line.\n", module.GetName(pMod)); + DBGPRINTF("Module %s processes this action.\n", module.GetName(pMod)); CHKiRet(actionConstruct(&pAction)); /* create action object first */ pAction->pMod = pMod; @@ -1851,7 +1832,7 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringReques if(bSuspended) actionSuspend(pAction, datetime.GetTime(NULL)); /* "good" time call, only during init and unavoidable */ - CHKiRet(actionConstructFinalize(pAction)); + CHKiRet(actionConstructFinalize(pAction, queueParams)); /* TODO: if we exit here, we have a memory leak... */ @@ -1938,6 +1919,7 @@ rsRetVal actionNewInst(struct nvlst *lst, action_t **ppAction) { struct cnfparamvals *paramvals; + struct cnfparamvals *queueParams; modInfo_t *pMod; uchar *cnfModName = NULL; omodStringRequest_t *pOMSR; @@ -1966,7 +1948,10 @@ actionNewInst(struct nvlst *lst, action_t **ppAction) FINALIZE; /* iRet is already set to error state */ } - if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { + qqueueDoCnfParams(lst, &queueParams); + + if((iRet = addAction(&pAction, pMod, pModData, pOMSR, queueParams, + (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { /* now check if the module is compatible with select features */ if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) pAction->f_ReduceRepeated = loadConf->globals.bReduceRepeatMsgs; @@ -1994,6 +1979,7 @@ actionProcessCnf(struct cnfobj *o) { DEFiRet; #if 0 /* we need to check if we actually need this functionality -- later! */ +// This is for STAND-ALONE actions at the conf file TOP level struct cnfparamvals *paramvals; paramvals = nvlstGetParams(o->nvlst, ¶mblk, NULL); diff --git a/action.h b/action.h index 4d56106b..5d1f387b 100644 --- a/action.h +++ b/action.h @@ -3,7 +3,7 @@ * * File begun on 2007-08-06 by RGerhards (extracted from syslogd.c) * - * Copyright 2007 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -95,7 +95,7 @@ struct action_s { /* function prototypes */ rsRetVal actionConstruct(action_t **ppThis); -rsRetVal actionConstructFinalize(action_t *pThis); +rsRetVal actionConstructFinalize(action_t *pThis, struct cnfparamvals *queueParams); rsRetVal actionDestruct(action_t *pThis); rsRetVal actionDbgPrint(action_t *pThis); rsRetVal actionSetGlobalResumeInterval(int iNewVal); @@ -103,7 +103,7 @@ rsRetVal actionDoAction(action_t *pAction); rsRetVal actionWriteToAction(action_t *pAction); rsRetVal actionCallHUPHdlr(action_t *pAction); rsRetVal actionClassInit(void); -rsRetVal addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringRequest_t *pOMSR, int bSuspended); +rsRetVal addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringRequest_t *pOMSR, struct cnfparamvals *queueParams, int bSuspended); rsRetVal actionNewScope(void); rsRetVal actionRestoreScope(void); rsRetVal activateActions(void); diff --git a/doc/v6compatibility.html b/doc/v6compatibility.html index cf621943..38f1e622 100644 --- a/doc/v6compatibility.html +++ b/doc/v6compatibility.html @@ -113,7 +113,7 @@ longer in v6:

        *.* rgerhards, bgerhards
        -To fix it in a way that is compatible with pre-v6, use (note the removed space!): +To fix it in a way that is compatible with pre-v4, use (note the removed space!):
        *.* rgerhards,bgerhards
        diff --git a/grammar/lexer.l b/grammar/lexer.l index cf912db3..f7691c4a 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -182,7 +182,7 @@ int fileno(FILE *stream); #.*$ /* skip comments in input */ [ \n\t] . { dbgprintf("INOBJ: invalid char '%s'\n", yytext); } -\$[a-z]+.*$ { /* see common on $IncludeConfig above */ +\$[a-z]+.*$ { /* see comment on $IncludeConfig above */ if(!strncasecmp(yytext, "$includeconfig ", 14)) { yyless(14); BEGIN INCL; @@ -282,9 +282,17 @@ popfile(void) if(bs == NULL) return 1; - /* delte current entry */ + /* delete current entry. But we must not free the file name if + * this is the top-level file, because then it may still be used + * in error messages for other processing steps. + * TODO: change this to another method which stores the file + * name inside the config objects. In the longer term, this is + * necessary, as otherwise we may provide wrong file name information + * at the end of include files as well. -- rgerhards, 2011-07-22 + */ yy_delete_buffer(bs->bs); - free(bs->fn); + if(bs->prev != NULL) + free(bs->fn); free(bs->estr); /* switch back to previous */ @@ -299,3 +307,10 @@ popfile(void) cnfcurrfn = currbs->fn; return 0; } + +void +tellLexEndParsing(void) +{ + free(cnfcurrfn); + cnfcurrfn= NULL; +} diff --git a/grammar/parserif.h b/grammar/parserif.h index adb0f42f..597cfe40 100644 --- a/grammar/parserif.h +++ b/grammar/parserif.h @@ -6,6 +6,7 @@ int yyparse(); char *cnfcurrfn; void dbgprintf(char *fmt, ...) __attribute__((format(printf, 1, 2))); void parser_errmsg(char *fmt, ...) __attribute__((format(printf, 1, 2))); +void tellLexEndParsing(void); extern int yydebug; extern int yylineno; diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index fe99e4aa..1b44974c 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -35,9 +35,11 @@ #include #include #include +#include "rsyslog.h" #include "rainerscript.h" #include "parserif.h" #include "grammar.h" +#include "queue.h" #include "srUtils.h" void @@ -271,6 +273,30 @@ doGetBinary(struct nvlst *valnode, struct cnfparamdescr *param, } } +static inline void +doGetQueueType(struct nvlst *valnode, struct cnfparamdescr *param, + struct cnfparamvals *val) +{ + char *cstr; + 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)) { + val->val.d.n = QUEUETYPE_LINKEDLIST; + } else if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"disk", 4)) { + val->val.d.n = QUEUETYPE_DISK; + } else if(!es_strcasebufcmp(valnode->val.d.estr, (uchar*)"direct", 6)) { + val->val.d.n = QUEUETYPE_DIRECT; + } else { + cstr = es_str2cstr(valnode->val.d.estr, NULL); + parser_errmsg("param '%s': unknown queue type: '%s'", + param->name, cstr); + free(cstr); + } +dbgprintf("XXXXX: queue type: %d\n", (int)val->val.d.n); + val->val.datatype = 'N'; +} + + /* A file create-mode must be a four-digit octal number * starting with '0'. */ @@ -416,6 +442,9 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, valnode->bUsed = 1; val->bUsed = 1; switch(param->type) { + case eCmdHdlrQueueType: + doGetQueueType(valnode, param, val); + break; case eCmdHdlrUID: doGetUID(valnode, param, val); break; diff --git a/runtime/conf.c b/runtime/conf.c index 6136262e..d98a147b 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -741,7 +741,7 @@ rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) */ if(currConfObj == eConfObjAction) currConfObj = eConfObjActionWaitEnd; - if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { + if((iRet = addAction(&pAction, pMod, pModData, pOMSR, NULL, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { /* now check if the module is compatible with select features */ if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) pAction->f_ReduceRepeated = loadConf->globals.bReduceRepeatMsgs; diff --git a/runtime/queue.c b/runtime/queue.c index c831836d..1ceec5da 100644 --- a/runtime/queue.c +++ b/runtime/queue.c @@ -12,7 +12,7 @@ * function names - this makes it really hard to read and does not provide much * benefit, at least I (now) think so... * - * Copyright 2008, 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2008-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -93,6 +93,41 @@ static rsRetVal qDestructDisk(qqueue_t *pThis); #define QUEUE_CHECKPOINT 1 #define QUEUE_NO_CHECKPOINT 0 + +/* tables for interfacing with the v6 config system */ +static struct cnfparamdescr cnfpdescr[] = { + { "queue.filename", eCmdHdlrGetWord, 0 }, + { "queue.size", eCmdHdlrSize, 0 }, + { "queue.dequeuebatchsize", eCmdHdlrInt, 0 }, + { "queue.maxdiskspace", eCmdHdlrSize, 0 }, + { "queue.highwatermark", eCmdHdlrInt, 0 }, + { "queue.lowwatermark", eCmdHdlrInt, 0 }, + { "queue.fulldelaymark", eCmdHdlrInt, 0 }, + { "queue.lightdelaymark", eCmdHdlrInt, 0 }, + { "queue.discardmark", eCmdHdlrInt, 0 }, + { "queue.discardseverity", eCmdHdlrFacility, 0 }, + { "queue.checkpointinterval", eCmdHdlrInt, 0 }, + { "queue.syncqueuefiles", eCmdHdlrBinary, 0 }, + { "queue.type", eCmdHdlrQueueType, 0 }, + { "queue.workerthreads", eCmdHdlrInt, 0 }, + { "queue.timeoutshutdown", eCmdHdlrInt, 0 }, + { "queue.timeoutactioncompletion", eCmdHdlrInt, 0 }, + { "queue.timeoutenqueue", eCmdHdlrInt, 0 }, + { "queue.timeoutworkerthreadshutdown", eCmdHdlrInt, 0 }, + { "queue.workerthreadminimummessages", eCmdHdlrInt, 0 }, + { "queue.maxfilesize", eCmdHdlrSize, 0 }, + { "queue.saveonshutdown", eCmdHdlrBinary, 0 }, + { "queue.dequeueslowdown", eCmdHdlrInt, 0 }, + { "queue.dequeuetimebegin", eCmdHdlrInt, 0 }, + { "queue.dequeuetimeend", eCmdHdlrInt, 0 }, +}; +static struct cnfparamblk pblk = + { CNFPARAMBLK_VERSION, + sizeof(cnfpdescr)/sizeof(struct cnfparamdescr), + cnfpdescr + }; + + /*********************************************************************** * we need a private data structure, the "to-delete" list. As C does * not provide any partly private data structures, we implement this @@ -1258,8 +1293,8 @@ rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThread ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); /* set some water marks so that we have useful defaults if none are set specifically */ - pThis->iFullDlyMrk = iMaxQueueSize - (iMaxQueueSize / 100) * 3; /* default 97% */ - pThis->iLightDlyMrk = iMaxQueueSize - (iMaxQueueSize / 100) * 30; /* default 70% */ + pThis->iFullDlyMrk = -1; + pThis->iLightDlyMrk = -1; pThis->lenSpoolDir = ustrlen(pThis->pszSpoolDir); pThis->iMaxFileSize = 1024 * 1024; /* default is 1 MiB */ pThis->iQueueSize = 0; @@ -1273,42 +1308,6 @@ rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThread pThis->pszFilePrefix = NULL; pThis->qType = qType; - /* set type-specific handlers and other very type-specific things (we can not totally hide it...) */ - switch(qType) { - case QUEUETYPE_FIXED_ARRAY: - pThis->qConstruct = qConstructFixedArray; - pThis->qDestruct = qDestructFixedArray; - pThis->qAdd = qAddFixedArray; - pThis->qDeq = qDeqFixedArray; - pThis->qDel = qDelFixedArray; - pThis->MultiEnq = qqueueMultiEnqObjNonDirect; - break; - case QUEUETYPE_LINKEDLIST: - pThis->qConstruct = qConstructLinkedList; - pThis->qDestruct = qDestructLinkedList; - pThis->qAdd = qAddLinkedList; - pThis->qDeq = (rsRetVal (*)(qqueue_t*,void**)) qDeqLinkedList; - pThis->qDel = (rsRetVal (*)(qqueue_t*)) qDelLinkedList; - pThis->MultiEnq = qqueueMultiEnqObjNonDirect; - break; - case QUEUETYPE_DISK: - pThis->qConstruct = qConstructDisk; - pThis->qDestruct = qDestructDisk; - pThis->qAdd = qAddDisk; - pThis->qDeq = qDeqDisk; - pThis->qDel = qDelDisk; - pThis->MultiEnq = qqueueMultiEnqObjNonDirect; - /* special handling */ - pThis->iNumWorkerThreads = 1; /* we need exactly one worker */ - break; - case QUEUETYPE_DIRECT: - pThis->qConstruct = qConstructDirect; - pThis->qDestruct = qDestructDirect; - pThis->qAdd = qAddDirect; - pThis->qDel = qDelDirect; - pThis->MultiEnq = qqueueMultiEnqObjDirect; - break; - } INIT_ATOMIC_HELPER_MUT(pThis->mutQueueSize); INIT_ATOMIC_HELPER_MUT(pThis->mutLogDeq); @@ -1891,6 +1890,52 @@ qqueueStart(qqueue_t *pThis) /* this is the ConstructionFinalizer */ ASSERT(pThis != NULL); + /* set type-specific handlers and other very type-specific things + * (we can not totally hide it...) + */ + switch(pThis->qType) { + case QUEUETYPE_FIXED_ARRAY: + pThis->qConstruct = qConstructFixedArray; + pThis->qDestruct = qDestructFixedArray; + pThis->qAdd = qAddFixedArray; + pThis->qDeq = qDeqFixedArray; + pThis->qDel = qDelFixedArray; + pThis->MultiEnq = qqueueMultiEnqObjNonDirect; + break; + case QUEUETYPE_LINKEDLIST: + pThis->qConstruct = qConstructLinkedList; + pThis->qDestruct = qDestructLinkedList; + pThis->qAdd = qAddLinkedList; + pThis->qDeq = (rsRetVal (*)(qqueue_t*,void**)) qDeqLinkedList; + pThis->qDel = (rsRetVal (*)(qqueue_t*)) qDelLinkedList; + pThis->MultiEnq = qqueueMultiEnqObjNonDirect; + break; + case QUEUETYPE_DISK: + pThis->qConstruct = qConstructDisk; + pThis->qDestruct = qDestructDisk; + pThis->qAdd = qAddDisk; + pThis->qDeq = qDeqDisk; + pThis->qDel = qDelDisk; + pThis->MultiEnq = qqueueMultiEnqObjNonDirect; + /* special handling */ + pThis->iNumWorkerThreads = 1; /* we need exactly one worker */ + break; + case QUEUETYPE_DIRECT: + pThis->qConstruct = qConstructDirect; + pThis->qDestruct = qDestructDirect; + pThis->qAdd = qAddDirect; + pThis->qDel = qDelDirect; + pThis->MultiEnq = qqueueMultiEnqObjDirect; + break; + } + + if(pThis->iFullDlyMrk == -1) + pThis->iFullDlyMrk = pThis->iMaxQueueSize + - (pThis->iMaxQueueSize / 100) * 3; /* default 97% */ + if(pThis->iLightDlyMrk == -1) + pThis->iLightDlyMrk = pThis->iMaxQueueSize + - (pThis->iMaxQueueSize / 100) * 30; /* default 70% */ + /* we need to do a quick check if our water marks are set plausible. If not, * we correct the most important shortcomings. TODO: do that!!!! -- rgerhards, 2008-03-14 */ @@ -2459,6 +2504,90 @@ finalize_it: } +/* take v6 config list and extract the queue params out of it. Hand the + * param values back to the caler. Caller is responsible for destructing + * them when no longer needed. Caller can use this param block to configure + * all parameters for a newly created queue with one call to qqueueSetParams(). + * rgerhards, 2011-07-22 + */ +rsRetVal +qqueueDoCnfParams(struct nvlst *lst, struct cnfparamvals **ppvals) +{ + *ppvals = nvlstGetParams(lst, &pblk, NULL); + return RS_RET_OK; +} + +/* apply all params from param block to queue. Must be called before + * finalizing. This supports the v6 config system. Defaults were already + * set during queue creation. The pvals object is destructed by this + * function. + */ +rsRetVal +qqueueApplyCnfParam(qqueue_t *pThis, struct cnfparamvals *pvals) +{ + int i; + for(i = 0 ; i < pblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(pblk.descr[i].name, "queue.filename")) { + pThis->pszFilePrefix = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + pThis->lenFilePrefix = es_strlen(pvals[i].val.d.estr); + } else if(!strcmp(pblk.descr[i].name, "queue.size")) { + pThis->iMaxQueueSize = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.dequeuebatchsize")) { + pThis->iDeqBatchSize = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.maxdiskspace")) { + pThis->iMaxFileSize = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.highwatermark")) { + pThis->iHighWtrMrk = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.lowwatermark")) { + pThis->iLowWtrMrk = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.fulldelaymark")) { + pThis->iFullDlyMrk = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.lightdelaymark")) { + pThis->iLightDlyMrk = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.discardmark")) { + pThis->iDiscardMrk = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.discardseverity")) { + pThis->iDiscardSeverity = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.checkpointinterval")) { + pThis->iPersistUpdCnt = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.syncqueuefiles")) { + pThis->bSyncQueueFiles = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.type")) { + pThis->qType = (queueType_t) pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.workerthreads")) { + pThis->iNumWorkerThreads = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.timeoutshutdown")) { + pThis->toQShutdown = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.timeoutactioncompletion")) { + pThis->toActShutdown = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.timeoutenqueue")) { + pThis->toEnq = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.timeoutworkerthreadshutdown")) { + pThis->toWrkShutdown = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.workerthreadminimummessages")) { + pThis->iMinMsgsPerWrkr = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.maxfilesize")) { + pThis->iMaxFileSize = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.saveonshutdown")) { + pThis->bSaveOnShutdown = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.dequeueslowdown")) { + pThis->iDeqSlowdown = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queue.dequeuetimebegin")) { + pThis->iDeqtWinFromHr = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "queuedequeuetimend.")) { + pThis->iDeqtWinToHr = pvals[i].val.d.n; + } else { + dbgprintf("queue: program error, non-handled " + "param '%s'\n", pblk.descr[i].name); + } + } + cnfparamvalsDestruct(pvals, &pblk); + return RS_RET_OK; +} + + /* some simple object access methods */ DEFpropSetMeth(qqueue, bSyncQueueFiles, int) DEFpropSetMeth(qqueue, iPersistUpdCnt, int) diff --git a/runtime/queue.h b/runtime/queue.h index 97057180..c18b9f47 100644 --- a/runtime/queue.h +++ b/runtime/queue.h @@ -190,6 +190,9 @@ rsRetVal qqueueSetFilePrefix(qqueue_t *pThis, uchar *pszPrefix, size_t iLenPrefi rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThreads, int iMaxQueueSize, rsRetVal (*pConsumer)(void*,batch_t*, int*)); rsRetVal qqueueEnqObjDirectBatch(qqueue_t *pThis, batch_t *pBatch); +rsRetVal qqueueDoCnfParams(struct nvlst *lst, struct cnfparamvals **ppvals); +rsRetVal qqueueApplyCnfParam(qqueue_t *pThis, struct cnfparamvals *pvals); + PROTOTYPEObjClassInit(qqueue); PROTOTYPEpropSetMeth(qqueue, iPersistUpdCnt, int); PROTOTYPEpropSetMeth(qqueue, bSyncQueueFiles, int); diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 20c3b4f0..61e8ca96 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -345,7 +345,10 @@ parser_errmsg(char *fmt, ...) va_start(ap, fmt); if(vsnprintf(errBuf, sizeof(errBuf), fmt, ap) == sizeof(errBuf)) - errBuf[1023] = '\0'; + errBuf[sizeof(errBuf)-1] = '\0'; +dbgprintf("XXXX: msg: %s\n", errBuf); +dbgprintf("XXXX: cnfcurrfn: %s\n", cnfcurrfn); +dbgprintf("XXXX: yylineno: %d\n", yylineno); errmsg.LogError(0, RS_RET_CONF_PARSE_ERROR, "error during parsing file %s, on or before line %d: %s", cnfcurrfn, yylineno, errBuf); @@ -1258,6 +1261,7 @@ ourConf = loadConf; // TODO: remove, once ourConf is gone! "run, but no output whatsoever is created."); ABORT_FINALIZE(RS_RET_NO_ACTIONS); } + tellLexEndParsing(); tellCoreConfigLoadDone(); tellModulesConfigLoadDone(); diff --git a/runtime/typedefs.h b/runtime/typedefs.h index d46851f6..f994cbc4 100644 --- a/runtime/typedefs.h +++ b/runtime/typedefs.h @@ -160,6 +160,7 @@ typedef enum cslCmdHdlrType { eCmdHdlrSeverity, eCmdHdlrGetWord, eCmdHdlrString, + eCmdHdlrQueueType, eCmdHdlrGoneAway /* statment existed, but is no longer supported */ } ecslCmdHdrlType; -- cgit v1.2.3 From a8122314f96cf8e2e0e08f9a58a3f3fde4aa60ae Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 1 Aug 2011 13:15:47 +0200 Subject: milestone: generic action parameters parsed via new config system --- action.c | 114 ++++++++++++++++++++++++++++++++++++++++++-------------- action.h | 2 +- runtime/conf.c | 3 +- runtime/queue.c | 2 +- 4 files changed, 91 insertions(+), 30 deletions(-) diff --git a/action.c b/action.c index 74f6f7f7..7be5841c 100644 --- a/action.c +++ b/action.c @@ -188,10 +188,10 @@ static struct cnfparamdescr cnfparamdescr[] = { { "action.execonlyonceeveryinterval", eCmdHdlrInt, 0 }, /* legacy: actionexeconlyonceeveryinterval */ { "action.execonlywhenpreviousissuspended", eCmdHdlrInt, 0 }, /* legacy: actionexeconlywhenpreviousissuspended */ { "action.repeatedmsgcontainsoriginalmsg", eCmdHdlrBinary, 0 }, /* legacy: repeatedmsgcontainsoriginalmsg */ - { "action.resumeretrycount ", eCmdHdlrGetWord, 0 } /* legacy: actionresumeretrycount */ - //{ "", eCmdHdlrGetWord, 0 }, /* legacy: */ + { "action.resumeretrycount", eCmdHdlrInt, 0 }, /* legacy: actionresumeretrycount */ + { "action.resumeinterval", eCmdHdlrInt, 0 } }; -static struct cnfparamblk paramblk = +static struct cnfparamblk pblk = { CNFPARAMBLK_VERSION, sizeof(cnfparamdescr)/sizeof(struct cnfparamdescr), cnfparamdescr @@ -310,6 +310,8 @@ rsRetVal actionDestruct(action_t *pThis) /* create a new action descriptor object * rgerhards, 2007-08-01 + * Note that it is vital to set proper initial values as the v6 config + * system depends on these! */ rsRetVal actionConstruct(action_t **ppThis) { @@ -318,9 +320,20 @@ 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 = cs.glbliActionResumeInterval; - pThis->iResumeRetryCount = cs.glbliActionResumeRetryCount; + pThis->iResumeInterval = 30; + pThis->iResumeRetryCount = 0; + pThis->pszName = NULL; + pThis->bWriteAllMarkMsgs = FALSE; + pThis->iExecEveryNthOccur = 0; + pThis->iExecEveryNthOccurTO = 0; + pThis->iSecsExecOnceInterval = 0; + pThis->bExecWhenPrevSusp = 0; + pThis->bRepMsgHasMsg = 0; pThis->tLastOccur = datetime.GetTime(NULL); /* done once per action on startup only */ pthread_mutex_init(&pThis->mutActExec, NULL); INIT_ATOMIC_HELPER_MUT(pThis->mutCAS); @@ -1736,6 +1749,47 @@ doSubmitToActionQComplexBatch(action_t *pAction, batch_t *pBatch) } #pragma GCC diagnostic warning "-Wempty-body" + +/* apply all params from param block to action. This supports the v6 config system. + * Defaults must have been set appropriately during action construct! + * rgerhards, 2011-08-01 + */ +rsRetVal +actionApplyCnfParam(action_t *pAction, struct cnfparamvals *pvals) +{ + int i; + for(i = 0 ; i < pblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(pblk.descr[i].name, "name")) { + pAction->pszName = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(pblk.descr[i].name, "action.writeallmarkmessages")) { + pAction->bWriteAllMarkMsgs = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "action.execonlyeverynthtime")) { + pAction->iExecEveryNthOccur = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "action.execonlyeverynthtimetimeout")) { + pAction->iExecEveryNthOccurTO = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "action.execonlyonceeveryinterval")) { + pAction->iSecsExecOnceInterval = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "action.execonlywhenpreviousissuspended")) { + pAction->bExecWhenPrevSusp = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "action.repeatedmsgcontainsoriginalmsg")) { + pAction->bRepMsgHasMsg = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "action.resumeretrycount")) { + pAction->iResumeRetryCount = pvals[i].val.d.n; + } else if(!strcmp(pblk.descr[i].name, "action.resumeinterval")) { + pAction->iResumeInterval = pvals[i].val.d.n; + } else { + dbgprintf("action: program error, non-handled " + "param '%s'\n", pblk.descr[i].name); + } + } + cnfparamvalsDestruct(pvals, &pblk); + return RS_RET_OK; +} + + + /* add an Action to the current selector * The pOMSR is freed, as it is not needed after this function. * Note: this function pulls global data that specifies action config state. @@ -1743,7 +1797,8 @@ doSubmitToActionQComplexBatch(action_t *pAction, batch_t *pBatch) */ rsRetVal addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, - omodStringRequest_t *pOMSR, struct cnfparamvals *queueParams, int bSuspended) + omodStringRequest_t *pOMSR, struct cnfparamvals *actParams, + struct cnfparamvals *queueParams, int bSuspended) { DEFiRet; int i; @@ -1760,17 +1815,23 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, CHKiRet(actionConstruct(&pAction)); /* create action object first */ pAction->pMod = pMod; pAction->pModData = pModData; - pAction->pszName = cs.pszActionName; - cs.pszActionName = NULL; /* free again! */ - pAction->bWriteAllMarkMsgs = cs.bActionWriteAllMarkMsgs; - cs.bActionWriteAllMarkMsgs = FALSE; /* reset */ - pAction->bExecWhenPrevSusp = cs.bActExecWhenPrevSusp; - pAction->iSecsExecOnceInterval = cs.iActExecOnceInterval; - pAction->iExecEveryNthOccur = cs.iActExecEveryNthOccur; - pAction->iExecEveryNthOccurTO = cs.iActExecEveryNthOccurTO; - pAction->bRepMsgHasMsg = cs.bActionRepMsgHasMsg; - cs.iActExecEveryNthOccur = 0; /* auto-reset */ - cs.iActExecEveryNthOccurTO = 0; /* auto-reset */ + if(actParams == NULL) { /* use legacy systemn */ + pAction->pszName = cs.pszActionName; + pAction->iResumeInterval = cs.glbliActionResumeInterval; + pAction->iResumeRetryCount = cs.glbliActionResumeRetryCount; + pAction->bWriteAllMarkMsgs = cs.bActionWriteAllMarkMsgs; + pAction->bExecWhenPrevSusp = cs.bActExecWhenPrevSusp; + pAction->iSecsExecOnceInterval = cs.iActExecOnceInterval; + pAction->iExecEveryNthOccur = cs.iActExecEveryNthOccur; + pAction->iExecEveryNthOccurTO = cs.iActExecEveryNthOccurTO; + pAction->bRepMsgHasMsg = cs.bActionRepMsgHasMsg; + cs.iActExecEveryNthOccur = 0; /* auto-reset */ + cs.iActExecEveryNthOccurTO = 0; /* auto-reset */ + cs.bActionWriteAllMarkMsgs = FALSE; /* auto-reset */ + cs.pszActionName = NULL; /* free again! */ + } else { + actionApplyCnfParam(pAction, actParams); + } /* check if we can obtain the template pointers - TODO: move to separate function? */ pAction->iNumTpls = OMSRgetEntryCount(pOMSR); @@ -1927,17 +1988,16 @@ actionNewInst(struct nvlst *lst, action_t **ppAction) action_t *pAction; DEFiRet; - paramvals = nvlstGetParams(lst, ¶mblk, NULL); + paramvals = nvlstGetParams(lst, &pblk, NULL); if(paramvals == NULL) { - iRet = RS_RET_ERR; - goto finalize_it; + ABORT_FINALIZE(RS_RET_ERR); } dbgprintf("action param blk after actionNewInst:\n"); - cnfparamsPrint(¶mblk, paramvals); - if(paramvals[cnfparamGetIdx(¶mblk, "type")].bUsed == 0) { + cnfparamsPrint(&pblk, paramvals); + if(paramvals[cnfparamGetIdx(&pblk, "type")].bUsed == 0) { ABORT_FINALIZE(RS_RET_CONF_RQRD_PARAM_MISSING); // TODO: move this into rainerscript handlers } - cnfModName = (uchar*)es_str2cstr(paramvals[cnfparamGetIdx(¶mblk, ("type"))].val.d.estr, NULL); + cnfModName = (uchar*)es_str2cstr(paramvals[cnfparamGetIdx(&pblk, ("type"))].val.d.estr, NULL); if((pMod = module.FindWithCnfName(loadConf, cnfModName, eMOD_OUT)) == NULL) { errmsg.LogError(0, RS_RET_MOD_UNKNOWN, "module name '%s' is unknown", cnfModName); ABORT_FINALIZE(RS_RET_MOD_UNKNOWN); @@ -1950,7 +2010,7 @@ actionNewInst(struct nvlst *lst, action_t **ppAction) qqueueDoCnfParams(lst, &queueParams); - if((iRet = addAction(&pAction, pMod, pModData, pOMSR, queueParams, + if((iRet = addAction(&pAction, pMod, pModData, pOMSR, paramvals, queueParams, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { /* now check if the module is compatible with select features */ if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) @@ -1966,7 +2026,7 @@ actionNewInst(struct nvlst *lst, action_t **ppAction) finalize_it: free(cnfModName); - cnfparamvalsDestruct(paramvals, ¶mblk); + cnfparamvalsDestruct(paramvals, &pblk); RETiRet; } @@ -1982,13 +2042,13 @@ actionProcessCnf(struct cnfobj *o) // This is for STAND-ALONE actions at the conf file TOP level struct cnfparamvals *paramvals; - paramvals = nvlstGetParams(o->nvlst, ¶mblk, NULL); + paramvals = nvlstGetParams(o->nvlst, &pblk, NULL); if(paramvals == NULL) { iRet = RS_RET_ERR; goto finalize_it; } DBGPRINTF("action param blk after actionProcessCnf:\n"); - cnfparamsPrint(¶mblk, paramvals); + cnfparamsPrint(&pblk, paramvals); /* now find module to activate */ finalize_it: diff --git a/action.h b/action.h index 5d1f387b..4ced894c 100644 --- a/action.h +++ b/action.h @@ -103,7 +103,7 @@ rsRetVal actionDoAction(action_t *pAction); rsRetVal actionWriteToAction(action_t *pAction); rsRetVal actionCallHUPHdlr(action_t *pAction); rsRetVal actionClassInit(void); -rsRetVal addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringRequest_t *pOMSR, struct cnfparamvals *queueParams, int bSuspended); +rsRetVal addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringRequest_t *pOMSR, struct cnfparamvals *actParams, struct cnfparamvals *queueParams, int bSuspended); rsRetVal actionNewScope(void); rsRetVal actionRestoreScope(void); rsRetVal activateActions(void); diff --git a/runtime/conf.c b/runtime/conf.c index d98a147b..f47ac501 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -741,7 +741,8 @@ rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) */ if(currConfObj == eConfObjAction) currConfObj = eConfObjActionWaitEnd; - if((iRet = addAction(&pAction, pMod, pModData, pOMSR, NULL, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { + if((iRet = addAction(&pAction, pMod, pModData, pOMSR, NULL, NULL, + (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { /* now check if the module is compatible with select features */ if(pMod->isCompatibleWithFeature(sFEATURERepeatedMsgReduction) == RS_RET_OK) pAction->f_ReduceRepeated = loadConf->globals.bReduceRepeatMsgs; diff --git a/runtime/queue.c b/runtime/queue.c index 1ceec5da..5f224e7e 100644 --- a/runtime/queue.c +++ b/runtime/queue.c @@ -2505,7 +2505,7 @@ finalize_it: /* take v6 config list and extract the queue params out of it. Hand the - * param values back to the caler. Caller is responsible for destructing + * param values back to the caller. Caller is responsible for destructing * them when no longer needed. Caller can use this param block to configure * all parameters for a newly created queue with one call to qqueueSetParams(). * rgerhards, 2011-07-22 -- cgit v1.2.3 From d0bab973d2ddf93af71c859f3ed47dd40d561c76 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 1 Aug 2011 15:46:48 +0200 Subject: regression: omfile aborted on dynafiles (never released bug) --- tools/omfile.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/omfile.c b/tools/omfile.c index a0a7b186..3cc3a7f9 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -938,14 +938,13 @@ CODESTARTparseSelectorAct ++p; /* eat '?' */ CHKiRet(cflineParseFileName(p, fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); + pData->f_fname = ustrdup(fname); + pData->bDynamicName = 1; + pData->iCurrElt = -1; /* no current element */ /* "filename" is actually a template name, we need this as string 1. So let's add it * to the pOMSR. -- rgerhards, 2007-07-27 */ CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(pData->f_fname), OMSR_NO_RQD_TPL_OPTS)); - - pData->f_fname = ustrdup(fname); - pData->bDynamicName = 1; - pData->iCurrElt = -1; /* no current element */ /* we now allocate the cache table */ CHKmalloc(pData->dynCache = (dynaFileCacheEntry**) calloc(cs.iDynaFileCacheSize, sizeof(dynaFileCacheEntry*))); -- cgit v1.2.3 From a789813b14de79c5ecac8b0d7f7c222ae7f47412 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 1 Aug 2011 15:56:34 +0200 Subject: milestone: queue-params are properly initialized for action queues --- action.c | 29 +++++++++++++++-------------- doc/v6compatibility.html | 4 ++++ runtime/queue.c | 34 ++++++++++++++++++++++++++++++++++ runtime/queue.h | 1 + 4 files changed, 54 insertions(+), 14 deletions(-) diff --git a/action.c b/action.c index 7be5841c..477051ca 100644 --- a/action.c +++ b/action.c @@ -363,7 +363,7 @@ actionConstructFinalize(action_t *pThis, struct cnfparamvals *queueParams) snprintf((char*) pszQName, sizeof(pszQName)/sizeof(uchar), "action %d queue", iActionNbr); } else { ustrncpy(pszQName, pThis->pszName, sizeof(pszQName)); - pszQName[63] = '\0'; /* to be on the save side */ + pszQName[sizeof(pszQName)-1] = '\0'; /* to be on the save side */ } /* now check if we can run the action in "firehose mode" during stage one of @@ -409,20 +409,20 @@ actionConstructFinalize(action_t *pThis, struct cnfparamvals *queueParams) CHKiRet(qqueueConstruct(&pThis->pQueue, cs.ActionQueType, 1, cs.iActionQueueSize, (rsRetVal (*)(void*, batch_t*, int*))processBatchMain)); obj.SetName((obj_t*) pThis->pQueue, pszQName); - - /* ... set some properties ... */ -# define setQPROP(func, directive, data) \ - CHKiRet_Hdlr(func(pThis->pQueue, data)) { \ - errmsg.LogError(0, NO_ERRCODE, "Invalid " #directive ", error %d. Ignored, running with default setting", iRet); \ - } -# define setQPROPstr(func, directive, data) \ - CHKiRet_Hdlr(func(pThis->pQueue, data, (data == NULL)? 0 : strlen((char*) data))) { \ - errmsg.LogError(0, NO_ERRCODE, "Invalid " #directive ", error %d. Ignored, running with default setting", iRet); \ - } - qqueueSetpUsr(pThis->pQueue, pThis); - if(queueParams == NULL) { - /* use legacy params */ + + if(queueParams == NULL) { /* use legacy params? */ + /* ... set some properties ... */ +# define setQPROP(func, directive, data) \ + CHKiRet_Hdlr(func(pThis->pQueue, data)) { \ + errmsg.LogError(0, NO_ERRCODE, "Invalid " #directive ", \ + error %d. Ignored, running with default setting", iRet); \ + } +# define setQPROPstr(func, directive, data) \ + CHKiRet_Hdlr(func(pThis->pQueue, data, (data == NULL)? 0 : strlen((char*) data))) { \ + errmsg.LogError(0, NO_ERRCODE, "Invalid " #directive ", \ + error %d. Ignored, running with default setting", iRet); \ + } setQPROP(qqueueSetsizeOnDiskMax, "$ActionQueueMaxDiskSpace", cs.iActionQueMaxDiskSpace); setQPROP(qqueueSetiDeqBatchSize, "$ActionQueueDequeueBatchSize", cs.iActionQueueDeqBatchSize); setQPROP(qqueueSetMaxFileSize, "$ActionQueueFileSize", cs.iActionQueMaxFileSize); @@ -444,6 +444,7 @@ actionConstructFinalize(action_t *pThis, struct cnfparamvals *queueParams) setQPROP(qqueueSetiDeqtWinToHr, "$ActionQueueDequeueTimeEnd", cs.iActionQueueDeqtWinToHr); } else { /* we have v6-style config params */ + qqueueSetDefaultsActionQueue(pThis->pQueue); qqueueApplyCnfParam(pThis->pQueue, queueParams); } diff --git a/doc/v6compatibility.html b/doc/v6compatibility.html index 38f1e622..7c99ab63 100644 --- a/doc/v6compatibility.html +++ b/doc/v6compatibility.html @@ -76,6 +76,10 @@ to check for those cases as this means log data is potentially lost. Please note that the root problem is the same for earlier versions as well. With them, it was just harder to spot why things went wrong (and if at all). +

        Default Batch Sizes

        +

        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.

        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 diff --git a/runtime/queue.c b/runtime/queue.c index 5f224e7e..f390d987 100644 --- a/runtime/queue.c +++ b/runtime/queue.c @@ -1318,6 +1318,40 @@ finalize_it: } +/* set default inisde queue object suitable for action queues. + * This shall be called directly after queue construction. This functions has + * been added in support of the new v6 config system. It expect properly pre-initialized + * objects, but we need to differentiate between ruleset main and action queues. + * In order to avoid unnecessary complexity, we provide the necessary defaults + * via specific function calls. + */ +void +qqueueSetDefaultsActionQueue(qqueue_t *pThis) +{ + pThis->qType = QUEUETYPE_DIRECT; /* type of the main message queue above */ + pThis->iMaxQueueSize = 1000; /* size of the main message queue above */ + pThis->iDeqBatchSize = 128; /* default batch size */ + pThis->iHighWtrMrk = 800; /* high water mark for disk-assisted queues */ + pThis->iLowWtrMrk = 200; /* low water mark for disk-assisted queues */ + pThis->iDiscardMrk = 9800; /* begin to discard messages */ + pThis->iDiscardSeverity = 8; /* turn off */ + pThis->iNumWorkerThreads = 1; /* number of worker threads for the mm queue above */ + pThis->iMaxFileSize = 1024*1024; + pThis->iPersistUpdCnt = 0; /* persist queue info every n updates */ + pThis->bSyncQueueFiles = 0; + pThis->toQShutdown = 0; /* queue shutdown */ + pThis->toActShutdown = 1000; /* action shutdown (in phase 2) */ + pThis->toEnq = 2000; /* timeout for queue enque */ + pThis->toWrkShutdown = 60000; /* timeout for worker thread shutdown */ + pThis->iMinMsgsPerWrkr = 100; /* minimum messages per worker needed to start a new one */ + pThis->bSaveOnShutdown = 1; /* save queue on shutdown (when DA enabled)? */ + pThis->sizeOnDiskMax = 0; /* unlimited */ + pThis->iDeqSlowdown = 0; + pThis->iDeqtWinFromHr = 0; + pThis->iDeqtWinToHr = 25; /* disable time-windowed dequeuing by default */ +} + + /* This function checks if the provided message shall be discarded and does so, if needed. * In DA mode, we do not discard any messages as we assume the disk subsystem is fast enough to * provide real-time creation of spool files. diff --git a/runtime/queue.h b/runtime/queue.h index c18b9f47..2b1fcfa8 100644 --- a/runtime/queue.h +++ b/runtime/queue.h @@ -192,6 +192,7 @@ rsRetVal qqueueConstruct(qqueue_t **ppThis, queueType_t qType, int iWorkerThread rsRetVal qqueueEnqObjDirectBatch(qqueue_t *pThis, batch_t *pBatch); rsRetVal qqueueDoCnfParams(struct nvlst *lst, struct cnfparamvals **ppvals); rsRetVal qqueueApplyCnfParam(qqueue_t *pThis, struct cnfparamvals *pvals); +void qqueueSetDefaultsActionQueue(qqueue_t *pThis); PROTOTYPEObjClassInit(qqueue); PROTOTYPEpropSetMeth(qqueue, iPersistUpdCnt, int); -- cgit v1.2.3 From 202fc4af6cc6e751434aeac7b5120eabc87ab03f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 2 Aug 2011 09:04:55 +0200 Subject: added new functionality to ChangeLog --- ChangeLog | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChangeLog b/ChangeLog index c35c81b3..6dba629e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ --------------------------------------------------------------------------- Version 6.3.4 [DEVEL] (rgerhards), 2011-07-?? +- added support for action() config object + * in rsyslog core engine + * in omfile + * in omusrmsg - bugfix: omusrmsg format usr1,usr2 was no longer supported - bugfix: misaddressing in config handler In theory, can cause segfault, in practice this is extremely unlikely -- cgit v1.2.3 From b04a5b89e4c730f861a4e21479d9f2c69b28828f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 2 Aug 2011 11:51:35 +0200 Subject: preparing for 6.3.4 release --- ChangeLog | 2 +- configure.ac | 2 +- doc/manual.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6dba629e..b7e04890 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 6.3.4 [DEVEL] (rgerhards), 2011-07-?? +Version 6.3.4 [DEVEL] (rgerhards), 2011-08-02 - added support for action() config object * in rsyslog core engine * in omfile diff --git a/configure.ac b/configure.ac index 46c50bbf..b3e75d45 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.3],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[6.3.4],[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 6c3b52a8..e6001c73 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.3.3 (devel branch) of rsyslog. +

        If you like rsyslog, you might -- cgit v1.2.3 From f8342ced6f7c17ecd2f043254151c786257b3fbb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 5 Aug 2011 14:56:20 +0200 Subject: - imudp&imtcp now report error if no listener at all was defined Thanks to Marcin for suggesting this error message --- ChangeLog | 4 +++- plugins/imtcp/imtcp.c | 5 +++++ plugins/imudp/imudp.c | 5 +++++ runtime/rsyslog.h | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 86520526..458ae483 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ --------------------------------------------------------------------------- -Version 6.3.5 [DEVEL] (al), 2011-??-?? +Version 6.3.5 [DEVEL] (rgerhards/al), 2011-??-?? +- imudp&imtcp now report error if no listener at all was defined + Thanks to Marcin for suggesting this error message. - bugfix: potential misadressing in property replacer --------------------------------------------------------------------------- Version 6.3.4 [DEVEL] (rgerhards), 2011-08-02 diff --git a/plugins/imtcp/imtcp.c b/plugins/imtcp/imtcp.c index 4fd717d7..98f49051 100644 --- a/plugins/imtcp/imtcp.c +++ b/plugins/imtcp/imtcp.c @@ -332,6 +332,11 @@ 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 , "imtcp: module loaded, but " + "no listeners defined - no input will be gathered"); + iRet = RS_RET_NO_LISTNERS; + } ENDcheckCnf diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 161223fd..b5cae4df 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -655,6 +655,11 @@ 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 , "imudp: module loaded, but " + "no listeners defined - no input will be gathered"); + iRet = RS_RET_NO_LISTNERS; + } ENDcheckCnf diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index c2dbc2b2..cc1044a1 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -365,6 +365,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_MOD_UNKNOWN = -2209,/**< module (config name) is unknown */ RS_RET_CONFOBJ_UNSUPPORTED = -2210,/**< config objects (v6 conf) are not supported here */ RS_RET_MISSING_CNFPARAMS = -2211, /**< missing configuration parameters */ + RS_RET_NO_LISTNERS = -2212, /**< module loaded, but no listeners are defined */ /* 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 3c1f4123e2959e787e100762c96cbae133314e0e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 5 Aug 2011 15:01:49 +0200 Subject: mostly cosmetic: error message did incorrectly contain errno-info --- 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 b5cae4df..31f5cce9 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -672,7 +672,7 @@ CODESTARTactivateCnfPrePrivDrop } /* if we could not set up any listners, there is no point in running... */ if(udpLstnSocks == NULL) { - errmsg.LogError(errno, NO_ERRCODE, "imudp: no listeners could be started, " + errmsg.LogError(0, NO_ERRCODE, "imudp: no listeners could be started, " "input not activated.\n"); ABORT_FINALIZE(RS_RET_NO_RUN); } -- cgit v1.2.3 From 77b93c21711c35d5935f3d55fb74968491cd133a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 5 Aug 2011 15:07:32 +0200 Subject: somewhat more informative imklog status messages (mostly cosmetic) --- plugins/imklog/linux.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/imklog/linux.c b/plugins/imklog/linux.c index 38250efa..efa25dcc 100644 --- a/plugins/imklog/linux.c +++ b/plugins/imklog/linux.c @@ -156,7 +156,8 @@ static enum LOGSRC GetKernelLogSrc(modConfData_t *pModConf) return(none); } - imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, GetPath(pModConf)); + imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s, fd = %d started.", + VERSION, GetPath(pModConf), kmsg); return(proc); } @@ -532,7 +533,8 @@ static void LogProcLine(modConfData_t *pModConf) if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 ) { if ( errno == EINTR ) return; - imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno)); + imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s " + "(fd %d)", errno, strerror(errno), kmsg); } else { LogLine(pModConf, log_buffer, rdcnt); } -- cgit v1.2.3 From d6b6b30c189bf8ea78b59b8b4d3008d1f89ef1b3 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 9 Aug 2011 11:48:52 +0200 Subject: added capability to emit config error location info for warnings otherwise, omusrmsg's warning about new config format was not accompanied by problem location. --- ChangeLog | 3 +++ runtime/conf.c | 31 ++++++++++++++++++++++++++----- runtime/module-template.h | 2 +- runtime/rsyslog.h | 1 + tools/omusrmsg.c | 4 ++++ 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 173cc63f..d80e7c4e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ --------------------------------------------------------------------------- Version 5.9.3 [V5-DEVEL] (al), 2011-??-?? +- added capability to emit config error location info for warnings + otherwise, omusrmsg's warning about new config format was not + accompanied by problem location. - bugfix: potential misadressing in property replacer --------------------------------------------------------------------------- Version 5.9.2 [V5-DEVEL] (rgerhards), 2011-07-11 diff --git a/runtime/conf.c b/runtime/conf.c index cc8c205e..858dbbfa 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -403,6 +403,7 @@ processConfFile(uchar *pConfFile) uchar cbuf[CFGLNSIZ]; uchar *cline; int i; + rsRetVal localRet; int bHadAnError = 0; uchar *pszOrgLine = NULL; size_t lenLine; @@ -461,16 +462,20 @@ processConfFile(uchar *pConfFile) /* we now have the complete line, and are positioned at the first non-whitespace * character. So let's process it */ - if(cfline(cbuf, &pCurrRule) != RS_RET_OK) { + if((localRet = cfline(cbuf, &pCurrRule)) != RS_RET_OK) { /* we log a message, but otherwise ignore the error. After all, the next * line can be correct. -- rgerhards, 2007-08-02 */ uchar szErrLoc[MAXFNAME + 64]; - dbgprintf("config line NOT successfully processed\n"); + if(localRet != RS_RET_OK_WARN) { + dbgprintf("config line NOT successfully processed\n"); + bHadAnError = 1; + } snprintf((char*)szErrLoc, sizeof(szErrLoc) / sizeof(uchar), "%s, line %d", pConfFile, iLnNbr); - errmsg.LogError(0, NO_ERRCODE, "the last error occured in %s:\"%s\"", (char*)szErrLoc, (char*)pszOrgLine); - bHadAnError = 1; + errmsg.LogError(0, NO_ERRCODE, "the last %s occured in %s:\"%s\"", + (localRet == RS_RET_OK_WARN) ? "warning" : "error", + (char*)szErrLoc, (char*)pszOrgLine); } } @@ -1079,6 +1084,7 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction) omodStringRequest_t *pOMSR; action_t *pAction = NULL; void *pModData; + int bHadWarning = 0; ASSERT(p != NULL); ASSERT(ppAction != NULL); @@ -1094,6 +1100,10 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction) pOMSR = NULL; iRet = pMod->mod.om.parseSelectorAct(p, &pModData, &pOMSR); dbgprintf("tried selector action for %s: %d\n", module.GetName(pMod), iRet); + if(iRet == RS_RET_OK_WARN) { + bHadWarning = 1; + iRet = RS_RET_OK; + } if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) { if((iRet = addAction(&pAction, pMod, pModData, pOMSR, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { /* now check if the module is compatible with select features */ @@ -1122,6 +1132,8 @@ static rsRetVal cflineDoAction(uchar **p, action_t **ppAction) } *ppAction = pAction; + if(iRet == RS_RET_OK && bHadWarning) + iRet = RS_RET_OK_WARN; RETiRet; } @@ -1136,6 +1148,8 @@ cflineClassic(uchar *p, rule_t **ppRule) { DEFiRet; action_t *pAction; + rsRetVal localRet; + int bHadWarning = 0; /* lines starting with '&' have no new filters and just add * new actions to the currently processed selector. @@ -1162,10 +1176,17 @@ cflineClassic(uchar *p, rule_t **ppRule) CHKiRet(cflineDoFilter(&p, *ppRule)); /* pull filters */ } - CHKiRet(cflineDoAction(&p, &pAction)); + localRet = cflineDoAction(&p, &pAction); + if(localRet == RS_RET_OK_WARN) { + bHadWarning = 1; + } else { + CHKiRet(localRet); + } CHKiRet(llAppend(&(*ppRule)->llActList, NULL, (void*) pAction)); finalize_it: + if(iRet == RS_RET_OK && bHadWarning) + iRet = RS_RET_OK_WARN; RETiRet; } diff --git a/runtime/module-template.h b/runtime/module-template.h index c2585e67..54c67135 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -275,7 +275,7 @@ static rsRetVal parseSelectorAct(uchar **pp, void **ppModData, omodStringRequest #define CODE_STD_FINALIZERparseSelectorAct \ finalize_it:\ - if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) {\ + if(iRet == RS_RET_OK || iRet == RS_RET_OK_WARN || iRet == RS_RET_SUSPENDED) {\ *ppModData = pData;\ *pp = p;\ } else {\ diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index d20cd5bb..65ed70db 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -345,6 +345,7 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_WRN_WRKDIR = -2182, /**< correctable problems with the rsyslog working directory */ RS_RET_ERR_QUEUE_EMERGENCY = -2183, /**< some fatal error caused queue to switch to emergency mode */ RS_RET_OUTDATED_STMT = -2184, /**< some outdated statement/functionality is being used in conf file */ + RS_RET_OK_WARN = -2185, /**< config part: everything was OK, but a warning message was emitted */ /* RainerScript error messages (range 1000.. 1999) */ RS_RET_SYSVAR_NOT_FOUND = 1001, /**< system variable could not be found (maybe misspelled) */ diff --git a/tools/omusrmsg.c b/tools/omusrmsg.c index 6d46813e..459e5fd6 100644 --- a/tools/omusrmsg.c +++ b/tools/omusrmsg.c @@ -273,6 +273,7 @@ ENDdoAction BEGINparseSelectorAct uchar *q; int i; + int bHadWarning = 0; CODESTARTparseSelectorAct CODE_STD_STRING_REQUESTparseSelectorAct(1) /* User names must begin with a gnu e-regex: @@ -290,6 +291,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) "action '%s' treated as ':omusrmsg:%s' - please " "change syntax, '%s' will not be supported in the future", p, p, p); + bHadWarning = 1; } } @@ -325,6 +327,8 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) != RS_RET_OK) goto finalize_it; } + if(iRet == RS_RET_OK && bHadWarning) + iRet = RS_RET_OK_WARN; CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct -- cgit v1.2.3 From afb4f8e6a24398e7eeafb1f7e76189e0abbc430d Mon Sep 17 00:00:00 2001 From: Andre Lorbach Date: Wed, 10 Aug 2011 11:24:15 +0200 Subject: Added changelog entry for bugid 275 --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index febe6c0b..5675d334 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,8 @@ --------------------------------------------------------------------------- Version 5.9.3 [V5-DEVEL] (al), 2011-??-?? - bugfix: potential misadressing in property replacer +- bugfix: MSGID corruption in RFC5424 parser under some circumstances + closes: http://bugzilla.adiscon.com/show_bug.cgi?id=275 --------------------------------------------------------------------------- Version 5.9.2 [V5-DEVEL] (rgerhards), 2011-07-11 - systemd support: set stdout/stderr to null - thx to Lennart for the patch -- cgit v1.2.3 From 4443bb511dfb631f585d4dc09d1688449aee8341 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 31 Aug 2011 11:19:03 +0200 Subject: cosmetic: adding imported bugfix to ChangeLog --- ChangeLog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 072c5f7b..c180110c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ --------------------------------------------------------------------------- -Version 5.9.3 [V5-DEVEL] (al), 2011-09-01 +Version 5.9.3 [V5-DEVEL], 2011-09-01 - bugfix/security: off-by-two bug in legacy syslog parser, CVE-2011-3200 +- bugfix: mark message processing did not work correctly - added capability to emit config error location info for warnings otherwise, omusrmsg's warning about new config format was not accompanied by problem location. -- cgit v1.2.3 From a808123d370cf965fc03ea7c04c042b67252a107 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 31 Aug 2011 12:32:28 +0200 Subject: preparing for 5.9.3 release --- configure.ac | 2 +- doc/manual.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 5d6fe7d7..f1c83fa4 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],[5.9.3-pre2],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.9.3],[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 901e2f7d..a15c5a0b 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 5.9.2 (stable branch) of rsyslog. +

        This documentation is for version 5.9.3 (stable 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 dd55f8311f9eba74bd17692696f1225f8df512d2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 31 Aug 2011 13:07:06 +0200 Subject: preparing for 6.3.5 release --- configure.ac | 2 +- doc/manual.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index b3e75d45..76b0ed6b 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.4],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[6.3.5],[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 e6001c73..f440afdd 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.3.4 (devel branch) of rsyslog. +

        This documentation is for version 6.3.5 (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 c55997638f8833daec34d7f51b9ff6694620f6f8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 8 Sep 2011 15:05:04 +0200 Subject: added $InputRELPServerBindRuleset directive to specify rulesets for RELP --- ChangeLog | 3 +++ dirty.h | 2 +- doc/imrelp.html | 9 ++++--- plugins/im3195/im3195.c | 2 +- plugins/imrelp/imrelp.c | 62 ++++++++++++++++++++++++++++++++++++++----------- tools/syslogd.c | 3 ++- 6 files changed, 62 insertions(+), 19 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0cc502b6..335972e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,7 @@ --------------------------------------------------------------------------- +Version 6.3.6 [DEVEL] 2011-09-?? +- added $InputRELPServerBindRuleset directive to specify rulesets for RELP +--------------------------------------------------------------------------- Version 6.3.5 [DEVEL] (rgerhards/al), 2011-09-01 - bugfix/security: off-by-two bug in legacy syslog parser, CVE-2011-3200 - bugfix: mark message processing did not work correctly diff --git a/dirty.h b/dirty.h index a831dd06..a3940cb9 100644 --- a/dirty.h +++ b/dirty.h @@ -30,7 +30,7 @@ rsRetVal multiSubmitMsg(multi_submit_t *pMultiSub); rsRetVal submitMsg(msg_t *pMsg); rsRetVal logmsgInternal(int iErr, int pri, uchar *msg, int flags); -rsRetVal parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int flags, flowControl_t flowCtlTypeu, prop_t *pInputName, struct syslogTime *stTime, time_t ttGenTime); +rsRetVal parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int flags, flowControl_t flowCtlTypeu, prop_t *pInputName, struct syslogTime *stTime, time_t ttGenTime, ruleset_t *pRuleset); rsRetVal diagGetMainMsgQSize(int *piSize); /* for imdiag */ rsRetVal createMainQueue(qqueue_t **ppQueue, uchar *pszQueueName); diff --git a/doc/imrelp.html b/doc/imrelp.html index 2cf9c1f7..d83b2a15 100644 --- a/doc/imrelp.html +++ b/doc/imrelp.html @@ -29,6 +29,8 @@ 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+)
          +Binds the specified ruleset to all RELP listeners.
        • InputRELPServerRun <port>
          Starts a RELP server on selected port
        @@ -38,6 +40,8 @@ Starts a RELP server on selected port

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

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

      • 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.
      @@ -48,9 +52,8 @@ $InputRELPServerRun 20514

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

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

      diff --git a/plugins/im3195/im3195.c b/plugins/im3195/im3195.c index 4214ab95..3967372f 100644 --- a/plugins/im3195/im3195.c +++ b/plugins/im3195/im3195.c @@ -91,7 +91,7 @@ void OnReceive(srAPIObj __attribute__((unused)) *pMyAPI, srSLMGObj* pSLMG) srSLMGGetRawMSG(pSLMG, &pszRawMsg); parseAndSubmitMessage(fromHost, fromHostIP, pszRawMsg, strlen((char*)pszRawMsg), - PARSE_HOSTNAME, eFLOWCTL_FULL_DELAY, (uchar*)"im3195", NULL, 0); + PARSE_HOSTNAME, eFLOWCTL_FULL_DELAY, (uchar*)"im3195", NULL, 0, NULL); } diff --git a/plugins/imrelp/imrelp.c b/plugins/imrelp/imrelp.c index 5465b2a9..05a7ce31 100644 --- a/plugins/imrelp/imrelp.c +++ b/plugins/imrelp/imrelp.c @@ -46,6 +46,7 @@ #include "msg.h" #include "unicode-helper.h" #include "prop.h" +#include "ruleset.h" MODULE_TYPE_INPUT MODULE_TYPE_NOKEEP @@ -56,14 +57,19 @@ DEF_IMOD_STATIC_DATA DEFobjCurrIf(net) DEFobjCurrIf(prop) DEFobjCurrIf(errmsg) +DEFobjCurrIf(ruleset) /* forward definitions */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); /* Module static data */ +/* config vars for legacy config system */ static relpEngine_t *pRelpEngine; /* our relp engine */ static prop_t *pInputName = NULL; /* there is only one global inputName for all messages generated by this module */ +static struct configSettings_s { + uchar *pszBindRuleset; /* name of Ruleset to bind to */ +} cs; struct instanceConf_s { uchar *pszBindPort; /* port to bind to */ @@ -74,21 +80,13 @@ struct instanceConf_s { struct modConfData_s { rsconf_t *pConf; /* our overall config object */ instanceConf_t *root, *tail; - int iTCPSessMax; /* max number of sessions */ - int iTCPLstnMax; /* max number of sessions */ - int iStrmDrvrMode; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */ - int bEmitMsgOnClose; /* emit an informational message on close by remote peer */ - int iAddtlFrameDelim; /* addtl frame delimiter, e.g. for netscreen, default none */ - int bDisableLFDelim; /* disable standard LF delimiter */ - int bUseFlowControl; /* use flow control, what means indicate ourselfs a "light delayable" */ - uchar *pszStrmDrvrAuthMode; /* authentication mode to use */ + uchar *pszBindRuleset; /* name of Ruleset to bind to */ + ruleset_t *pBindRuleset; /* due to librelp limitation, we need to bind all listerns to the same set */ }; 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 */ -//#include "im-helper.h" /* must be included AFTER the type definitions! */ - /* ------------------------------ callbacks ------------------------------ */ @@ -107,7 +105,7 @@ onSyslogRcv(uchar *pHostname, uchar *pIP, uchar *pMsg, size_t lenMsg) { DEFiRet; parseAndSubmitMessage(pHostname, pIP, pMsg, lenMsg, PARSE_HOSTNAME, - eFLOWCTL_LIGHT_DELAY, pInputName, NULL, 0); + eFLOWCTL_LIGHT_DELAY, pInputName, NULL, 0, runModConf->pBindRuleset); RETiRet; } @@ -116,6 +114,15 @@ onSyslogRcv(uchar *pHostname, uchar *pIP, uchar *pMsg, size_t lenMsg) /* ------------------------------ end callbacks ------------------------------ */ +/* modified to work for module, not instance (as usual) */ +static inline void +std_checkRuleset_genErrMsg(modConfData_t *modConf, __attribute__((unused)) instanceConf_t *inst) +{ + errmsg.LogError(0, NO_ERRCODE, "imrelp: ruleset '%s' not found - " + "using default ruleset instead", modConf->pszBindRuleset); +} + + /* 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. @@ -170,19 +177,42 @@ CODESTARTbeginCnfLoad loadModConf = pModConf; pModConf->pConf = pConf; /* init legacy config variables */ - resetConfigVariables(NULL, NULL); /* dummy parameters just to fulfill interface def */ + cs.pszBindRuleset = NULL; ENDbeginCnfLoad BEGINendCnfLoad CODESTARTendCnfLoad + if((cs.pszBindRuleset == NULL) || (cs.pszBindRuleset[0] == '\0')) { + loadModConf->pszBindRuleset = NULL; + } else { + CHKmalloc(loadModConf->pszBindRuleset = ustrdup(cs.pszBindRuleset)); + } + loadModConf->pBindRuleset = NULL; +finalize_it: + free(cs.pszBindRuleset); loadModConf = NULL; /* done loading */ ENDendCnfLoad BEGINcheckCnf + rsRetVal localRet; + ruleset_t *pRuleset; CODESTARTcheckCnf - /* so far, we have nothing to check... */ + /* we emulate the standard "ruleset query" code provided by the framework + * for *instances* (which we can currently not support due to librelp). + */ + if(pModConf->pszBindRuleset == NULL) { + pModConf->pBindRuleset = NULL; + } else { + localRet = ruleset.GetRuleset(pModConf->pConf, &pRuleset, pModConf->pszBindRuleset); + if(localRet == RS_RET_NOT_FOUND) { + std_checkRuleset_genErrMsg(pModConf, NULL); + } + CHKiRet(localRet); + pModConf->pBindRuleset = pRuleset; + } +finalize_it: ENDcheckCnf @@ -239,6 +269,7 @@ CODESTARTmodExit prop.Destruct(&pInputName); /* release objects we used */ + objRelease(ruleset, CORE_COMPONENT); objRelease(prop, CORE_COMPONENT); objRelease(net, LM_NET_FILENAME); objRelease(errmsg, CORE_COMPONENT); @@ -248,6 +279,8 @@ ENDmodExit static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { + free(cs.pszBindRuleset); + cs.pszBindRuleset = NULL; return RS_RET_OK; } @@ -270,8 +303,11 @@ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(prop, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(net, LM_NET_FILENAME)); + CHKiRet(objUse(ruleset, CORE_COMPONENT)); /* register config file handlers */ + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputrelpserverbindruleset", 0, eCmdHdlrGetWord, + NULL, &cs.pszBindRuleset, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputrelpserverrun", 0, eCmdHdlrGetWord, addInstance, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, diff --git a/tools/syslogd.c b/tools/syslogd.c index 91df6469..6d794260 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -383,7 +383,7 @@ void untty(void) */ rsRetVal parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int flags, flowControl_t flowCtlType, - prop_t *pInputName, struct syslogTime *stTime, time_t ttGenTime) + prop_t *pInputName, struct syslogTime *stTime, time_t ttGenTime, ruleset_t *pRuleset) { prop_t *pProp = NULL; msg_t *pMsg; @@ -399,6 +399,7 @@ parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int fla MsgSetInputName(pMsg, pInputName); MsgSetRawMsg(pMsg, (char*)msg, len); MsgSetFlowControlType(pMsg, flowCtlType); + MsgSetRuleset(pMsg, pRuleset); pMsg->msgFlags = flags | NEEDS_PARSING; MsgSetRcvFromStr(pMsg, hname, ustrlen(hname), &pProp); -- cgit v1.2.3 From 6ce87411a6c93b674a9c813928bc853620a4ae3b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 15 Sep 2011 08:00:23 +0200 Subject: bugfix: config parser did not support properties with dashes in them MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ...inside property-based filters. Thanks to Gerrit Seré for reporting this. --- ChangeLog | 2 ++ grammar/lexer.l | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 335972e8..73b1e5d3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,8 @@ --------------------------------------------------------------------------- Version 6.3.6 [DEVEL] 2011-09-?? - added $InputRELPServerBindRuleset directive to specify rulesets for RELP +- bugfix: config parser did not support properties with dashes in them + inside property-based filters. Thanks to Gerrit Seré for reporting this. --------------------------------------------------------------------------- Version 6.3.5 [DEVEL] (rgerhards/al), 2011-09-01 - bugfix/security: off-by-two bug in legacy syslog parser, CVE-2011-3200 diff --git a/grammar/lexer.l b/grammar/lexer.l index f7691c4a..5c8542dd 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -156,7 +156,7 @@ int fileno(FILE *stream); "module"[ \n\t]*"(" { yylval.objType = CNFOBJ_MODULE; BEGIN INOBJ; return BEGINOBJ; } "action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } -^[ \t]*:\$?[a-z]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { +^[ \t]*:\$?[a-z\-]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { yylval.s = strdup(yytext); return PROPFILT; } ^[ \t]*[\*a-z][,\*a-z]*[0-7]*\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } "~" | -- cgit v1.2.3 From ceb336f0398e37ab51b4b54a14fa394d53ccdf3f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 Sep 2011 12:47:21 +0200 Subject: preparing for 6.3.6 release --- ChangeLog | 2 +- configure.ac | 2 +- doc/manual.html | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 73b1e5d3..e6ea72ea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 6.3.6 [DEVEL] 2011-09-?? +Version 6.3.6 [DEVEL] 2011-09-19 - added $InputRELPServerBindRuleset directive to specify rulesets for RELP - bugfix: config parser did not support properties with dashes in them inside property-based filters. Thanks to Gerrit Seré for reporting this. diff --git a/configure.ac b/configure.ac index 76b0ed6b..40f5bc8f 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.5],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[6.3.6],[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 f440afdd..07de4530 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.3.5 (devel branch) of rsyslog. +

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

      If you like rsyslog, you might @@ -40,6 +40,7 @@ if you do not read the doc, but doing so will definitely improve your experience

      Follow the links below for the

      • troubleshooting rsyslog problems
      • +
      • rsyslog.conf, new RainerScript-based format (v6+)
      • configuration file format (rsyslog.conf)
      • a regular expression checker/generator tool for rsyslog
      • property replacer, an important core component
      • -- cgit v1.2.3 From 0714cce5bb2c89beeeaece259f11ee4cedce02c4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 28 Sep 2011 12:34:01 +0200 Subject: bugfix: facility local was not correctly interpreted in legacy filters Was only accepted if it was the first PRI in a multi-filter PRI. Thanks to forum user Mark for bringing this to our attention. --- ChangeLog | 3 +++ grammar/lexer.l | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 3bf95fc9..a54a08fc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ --------------------------------------------------------------------------- Version 6.3.7 [DEVEL] 2011-0?-?? +- bugfix: facility local was not correctly interpreted in legacy filters + Was only accepted if it was the first PRI in a multi-filter PRI. + Thanks to forum user Mark for bringing this to our attention. - bugfix: imuxsock did no longer ignore message-provided timestamp, if so configured (the *default*). Lead to no longer sub-second timestamps. closes: http://bugzilla.adiscon.com/show_bug.cgi?id=281 diff --git a/grammar/lexer.l b/grammar/lexer.l index 5c8542dd..a3f8bedd 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -158,7 +158,7 @@ int fileno(FILE *stream); "action"[ \n\t]*"(" { BEGIN INOBJ; return BEGIN_ACTION; } ^[ \t]*:\$?[a-z\-]+[ ]*,[ ]*!?[a-z]+[ ]*,[ ]*\".*\" { yylval.s = strdup(yytext); return PROPFILT; } -^[ \t]*[\*a-z][,\*a-z]*[0-7]*\.[,!=;\.\*a-z]+ { yylval.s = strdup(yytext); return PRIFILT; } +^[ \t]*[\*a-z][,\*a-z]*[0-7]*\.[,!=;\.\*a-z0-7]+ { yylval.s = strdup(yytext); return PRIFILT; } "~" | "*" | \-\/[^*][^\n]* | -- cgit v1.2.3 From 26a668f8fa352e63aefcc762eadd123002b3895d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Oct 2011 12:26:48 +0200 Subject: added support for v6 config system to omfwd --- ChangeLog | 2 + action.c | 7 +- grammar/rainerscript.c | 4 +- runtime/rsyslog.h | 2 + tools/omfile.c | 36 +------ tools/omfwd.c | 269 ++++++++++++++++++++++++++++++++++++++++++------- 6 files changed, 244 insertions(+), 76 deletions(-) diff --git a/ChangeLog b/ChangeLog index a54a08fc..78979103 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ --------------------------------------------------------------------------- Version 6.3.7 [DEVEL] 2011-0?-?? +- improved support for new v6 config system. Now also supported by + - omfwd - bugfix: facility local was not correctly interpreted in legacy filters Was only accepted if it was the first PRI in a multi-filter PRI. Thanks to forum user Mark for bringing this to our attention. diff --git a/action.c b/action.c index f8c12c60..3a66c773 100644 --- a/action.c +++ b/action.c @@ -1775,6 +1775,8 @@ actionApplyCnfParam(action_t *pAction, struct cnfparamvals *pvals) continue; if(!strcmp(pblk.descr[i].name, "name")) { pAction->pszName = (uchar*) es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(pblk.descr[i].name, "type")) { + continue; /* this is handled seperately during module select! */ } else if(!strcmp(pblk.descr[i].name, "action.writeallmarkmessages")) { pAction->bWriteAllMarkMsgs = pvals[i].val.d.n; } else if(!strcmp(pblk.descr[i].name, "action.execonlyeverynthtime")) { @@ -1998,6 +2000,7 @@ actionNewInst(struct nvlst *lst, action_t **ppAction) omodStringRequest_t *pOMSR; void *pModData; action_t *pAction; + int typeIdx; DEFiRet; paramvals = nvlstGetParams(lst, &pblk, NULL); @@ -2006,7 +2009,9 @@ actionNewInst(struct nvlst *lst, action_t **ppAction) } dbgprintf("action param blk after actionNewInst:\n"); cnfparamsPrint(&pblk, paramvals); - if(paramvals[cnfparamGetIdx(&pblk, "type")].bUsed == 0) { + typeIdx = cnfparamGetIdx(&pblk, "type"); + if(paramvals[typeIdx].bUsed == 0) { + errmsg.LogError(0, RS_RET_CONF_RQRD_PARAM_MISSING, "action type missing"); ABORT_FINALIZE(RS_RET_CONF_RQRD_PARAM_MISSING); // TODO: move this into rainerscript handlers } cnfModName = (uchar*)es_str2cstr(paramvals[cnfparamGetIdx(&pblk, ("type"))].val.d.estr, NULL); diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 1b44974c..22a90cb7 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -437,8 +437,8 @@ nvlstGetParam(struct nvlst *valnode, struct cnfparamdescr *param, { uchar *cstr; - dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d\n", - param->name, (int) param->type); + dbgprintf("XXXX: in nvlstGetParam, name '%s', type %d, valnode->bUsed %d\n", + param->name, (int) param->type, valnode->bUsed); valnode->bUsed = 1; val->bUsed = 1; switch(param->type) { diff --git a/runtime/rsyslog.h b/runtime/rsyslog.h index fc8578a8..293aabbf 100644 --- a/runtime/rsyslog.h +++ b/runtime/rsyslog.h @@ -367,6 +367,8 @@ enum rsRetVal_ /** return value. All methods return this if not specified oth RS_RET_CONFOBJ_UNSUPPORTED = -2210,/**< config objects (v6 conf) are not supported here */ RS_RET_MISSING_CNFPARAMS = -2211, /**< missing configuration parameters */ RS_RET_NO_LISTNERS = -2212, /**< module loaded, but no listeners are defined */ + RS_RET_INVLD_PROTOCOL = -2213, /**< invalid protocol specified in config file */ + RS_RET_CNF_INVLD_FRAMING = -2214, /**< invalid framing specified in config file */ /* 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 e68bddd4..cad8ae80 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -765,7 +765,7 @@ BEGINnewActInst struct cnfparamvals *pvals; int i; CODESTARTnewActInst - dbgprintf("XXXX: in newActInst (omfile)\n"); + DBGPRINTF("newActInst (omfile)\n"); pvals = nvlstGetParams(lst, &actpblk, NULL); if(pvals == NULL) { @@ -853,41 +853,7 @@ CODESTARTnewActInst pData->iCurrElt = -1; /* no current element */ } // TODO: add pData->iSizeLimit = 0; /* default value, use outchannels to configure! */ -#if 0 - switch(*p) { - case '$': - CODE_STD_STRING_REQUESTnewActInst(1) - /* rgerhards 2005-06-21: this is a special setting for output-channel - * definitions. In the long term, this setting will probably replace - * anything else, but for the time being we must co-exist with the - * traditional mode lines. - * rgerhards, 2007-07-24: output-channels will go away. We keep them - * for compatibility reasons, but seems to have been a bad idea. - */ - CHKiRet(cflineParseOutchannel(pData, p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS)); - pData->bDynamicName = 0; - break; - - case '?': /* This is much like a regular file handle, but we need to obtain - * a template name. rgerhards, 2007-07-03 - */ - CODE_STD_STRING_REQUESTnewActInst(2) - ++p; /* eat '?' */ - CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, - (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); - /* "filename" is actually a template name, we need this as string 1. So let's add it - * to the pOMSR. -- rgerhards, 2007-07-27 - */ - CHKiRet(OMSRsetEntry(*ppOMSR, 1, ustrdup(pData->f_fname), OMSR_NO_RQD_TPL_OPTS)); - pData->bDynamicName = 1; - pData->iCurrElt = -1; /* no current element */ - /* we now allocate the cache table */ - CHKmalloc(pData->dynCache = (dynaFileCacheEntry**) - calloc(cs.iDynaFileCacheSize, sizeof(dynaFileCacheEntry*))); - break; - } -#endif CODE_STD_FINALIZERnewActInst cnfparamvalsDestruct(pvals, &actpblk); ENDnewActInst diff --git a/tools/omfwd.c b/tools/omfwd.c index c39d1d67..8669a8de 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -4,13 +4,7 @@ * NOTE: read comments in module-template.h to understand how this file * works! * - * File begun on 2007-07-20 by RGerhards (extracted from syslogd.c) - * This file is under development and has not yet arrived at being fully - * self-contained and a real object. So far, it is mostly an excerpt - * of the "old" message code without any modifications. However, it - * helps to have things at the right place one we go to the meat of it. - * - * Copyright 2007, 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -28,6 +22,9 @@ * along with Rsyslog. If not, see . * * A copy of the GPL can be found in the file "COPYING" in this distribution. + * + * TODO v6 config: + * - permitted peer *list* */ #include "config.h" #include "rsyslog.h" @@ -62,9 +59,11 @@ #include "module-template.h" #include "glbl.h" #include "errmsg.h" +#include "unicode-helper.h" MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP +MODULE_CNFNAME("omfwd") /* internal structures */ @@ -77,25 +76,27 @@ DEFobjCurrIf(netstrm) DEFobjCurrIf(tcpclt) typedef struct _instanceData { + uchar *tplName; /* name of assigned template */ netstrms_t *pNS; /* netstream subsystem */ netstrm_t *pNetstrm; /* our output netstream */ uchar *pszStrmDrvr; uchar *pszStrmDrvrAuthMode; permittedPeers_t *pPermPeers; int iStrmDrvrMode; - char *f_hname; + char *target; int *pSockArray; /* sockets to use for UDP */ int bIsConnected; /* are we connected to remote host? 0 - no, 1 - yes, UDP means addr resolved */ struct addrinfo *f_addr; int compressionLevel; /* 0 - no compression, else level for zlib */ char *port; int protocol; - int iUDPRebindInterval; /* rebind interval */ - int iTCPRebindInterval; /* rebind interval */ + int iRebindInterval; /* rebind interval */ int nXmit; /* number of transmissions since last (re-)bind */ # define FORW_UDP 0 # define FORW_TCP 1 /* following fields for TCP-based delivery */ + TCPFRAMINGMODE tcp_framing; + int bResendLastOnRecon; /* should the last message be re-sent on a successful reconnect? */ tcpclt_t *pTCPClt; /* our tcpclt object */ uchar sndBuf[16*1024]; /* this is intensionally fixed -- see no good reason to make configurable */ unsigned offsSndBuf; /* next free spot in send buffer */ @@ -108,13 +109,35 @@ typedef struct configSettings_s { int iStrmDrvrMode; /* mode for stream driver, driver-dependent (0 mostly means plain tcp) */ int bResendLastOnRecon; /* should the last message be re-sent on a successful reconnect? */ uchar *pszStrmDrvrAuthMode; /* authentication mode to use */ - int iUDPRebindInterval; /* support for automatic re-binding (load balancers!). 0 - no rebind */ int iTCPRebindInterval; /* support for automatic re-binding (load balancers!). 0 - no rebind */ + int iUDPRebindInterval; /* support for automatic re-binding (load balancers!). 0 - no rebind */ permittedPeers_t *pPermPeers; } configSettings_t; SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "target", eCmdHdlrGetWord, 0 }, + { "port", eCmdHdlrGetWord, 0 }, + { "protocol", eCmdHdlrGetWord, 0 }, + { "tcp_framing", eCmdHdlrGetWord, 0 }, + { "ziplevel", eCmdHdlrInt, 0 }, + { "rebindinterval", eCmdHdlrInt, 0 }, + { "streamdriver", eCmdHdlrGetWord, 0 }, + { "streamdrivermode", eCmdHdlrInt, 0 }, + { "streamdriverauthmode", eCmdHdlrGetWord, 0 }, + { "streamdriverpermittedpeers", eCmdHdlrGetWord, 0 }, + { "resendlastmsgonreconnect", eCmdHdlrBinary, 0 }, +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + + BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars cs.pszTplName = NULL; /* name of the default template to use */ @@ -208,7 +231,7 @@ CODESTARTfreeInstance } free(pData->port); - free(pData->f_hname); + free(pData->target); free(pData->pszStrmDrvr); free(pData->pszStrmDrvrAuthMode); net.DestructPermittedPeers(&pData->pPermPeers); @@ -217,7 +240,7 @@ ENDfreeInstance BEGINdbgPrintInstInfo CODESTARTdbgPrintInstInfo - dbgprintf("%s", pData->f_hname); + dbgprintf("%s", pData->target); ENDdbgPrintInstInfo @@ -232,7 +255,7 @@ static rsRetVal UDPSend(instanceData *pData, char *msg, size_t len) unsigned lsent = 0; int bSendSuccess; - if(pData->iUDPRebindInterval && (pData->nXmit++ % pData->iUDPRebindInterval == 0)) { + if(pData->iRebindInterval && (pData->nXmit++ % pData->iRebindInterval == 0)) { dbgprintf("omfwd dropping UDP 'connection' (as configured)\n"); pData->nXmit = 1; /* else we have an addtl wrap at 2^31-1 */ CHKiRet(closeUDPSockets(pData)); @@ -309,7 +332,6 @@ TCPSendBuf(instanceData *pData, uchar *buf, unsigned len) ssize_t lenSend; alreadySent = 0; -dbgprintf("omfwd: XXXX: pData %p, pNetStrm %p\n", pData, pData->pNetstrm); netstrm.CheckConnection(pData->pNetstrm); /* hack for plain tcp syslog - see ptcp driver for details */ while(alreadySent != len) { lenSend = len - alreadySent; @@ -382,7 +404,7 @@ static rsRetVal TCPSendInit(void *pvData) if(pData->pNetstrm == NULL) { CHKiRet(netstrms.Construct(&pData->pNS)); /* the stream driver must be set before the object is finalized! */ - CHKiRet(netstrms.SetDrvrName(pData->pNS, cs.pszStrmDrvr)); + CHKiRet(netstrms.SetDrvrName(pData->pNS, pData->pszStrmDrvr)); CHKiRet(netstrms.ConstructFinalize(pData->pNS)); /* now create the actual stream and connect to the server */ @@ -398,7 +420,7 @@ static rsRetVal TCPSendInit(void *pvData) } /* params set, now connect */ CHKiRet(netstrm.Connect(pData->pNetstrm, glbl.GetDefPFFamily(), - (uchar*)getFwdPt(pData), (uchar*)pData->f_hname)); + (uchar*)getFwdPt(pData), (uchar*)pData->target)); } finalize_it: @@ -424,23 +446,23 @@ static rsRetVal doTryResume(instanceData *pData) FINALIZE; /* The remote address is not yet known and needs to be obtained */ - dbgprintf(" %s\n", pData->f_hname); + dbgprintf(" %s\n", pData->target); if(pData->protocol == FORW_UDP) { memset(&hints, 0, sizeof(hints)); /* port must be numeric, because config file syntax requires this */ hints.ai_flags = AI_NUMERICSERV; hints.ai_family = glbl.GetDefPFFamily(); hints.ai_socktype = SOCK_DGRAM; - if((iErr = (getaddrinfo(pData->f_hname, getFwdPt(pData), &hints, &res))) != 0) { + if((iErr = (getaddrinfo(pData->target, getFwdPt(pData), &hints, &res))) != 0) { dbgprintf("could not get addrinfo for hostname '%s':'%s': %d%s\n", - pData->f_hname, getFwdPt(pData), iErr, gai_strerror(iErr)); + pData->target, getFwdPt(pData), iErr, gai_strerror(iErr)); ABORT_FINALIZE(RS_RET_SUSPENDED); } - dbgprintf("%s found, resuming.\n", pData->f_hname); + dbgprintf("%s found, resuming.\n", pData->target); pData->f_addr = res; pData->bIsConnected = 1; if(pData->pSockArray == NULL) { - pData->pSockArray = net.create_udp_socket((uchar*)pData->f_hname, NULL, 0); + pData->pSockArray = net.create_udp_socket((uchar*)pData->target, NULL, 0); } } else { CHKiRet(TCPSendInit((void*)pData)); @@ -480,7 +502,7 @@ CODESTARTdoAction iMaxLine = glbl.GetMaxLine(); - dbgprintf(" %s:%s/%s\n", pData->f_hname, getFwdPt(pData), + dbgprintf(" %s:%s/%s\n", pData->target, getFwdPt(pData), pData->protocol == FORW_UDP ? "udp" : "tcp"); psz = (char*) ppString[0]; @@ -582,6 +604,184 @@ finalize_it: RETiRet; } + +/* initialize TCP structures (if necessary) after the instance has been + * created. + */ +static rsRetVal +initTCP(instanceData *pData) +{ + DEFiRet; + if(pData->protocol == FORW_TCP) { + /* create our tcpclt */ + CHKiRet(tcpclt.Construct(&pData->pTCPClt)); + CHKiRet(tcpclt.SetResendLastOnRecon(pData->pTCPClt, pData->bResendLastOnRecon)); + /* and set callbacks */ + CHKiRet(tcpclt.SetSendInit(pData->pTCPClt, TCPSendInit)); + CHKiRet(tcpclt.SetSendFrame(pData->pTCPClt, TCPSendFrame)); + CHKiRet(tcpclt.SetSendPrepRetry(pData->pTCPClt, TCPSendPrepRetry)); + CHKiRet(tcpclt.SetFraming(pData->pTCPClt, pData->tcp_framing)); + CHKiRet(tcpclt.SetRebindInterval(pData->pTCPClt, pData->iRebindInterval)); + pData->iStrmDrvrMode = cs.iStrmDrvrMode; + if(cs.pszStrmDrvr != NULL) + CHKmalloc(pData->pszStrmDrvr = (uchar*)strdup((char*)cs.pszStrmDrvr)); + if(cs.pszStrmDrvrAuthMode != NULL) + CHKmalloc(pData->pszStrmDrvrAuthMode = + (uchar*)strdup((char*)cs.pszStrmDrvrAuthMode)); + } +finalize_it: + RETiRet; +} + + +static inline void +setInstParamDefaults(instanceData *pData) +{ + pData->tplName = NULL; + pData->protocol = FORW_UDP; + pData->tcp_framing = TCP_FRAMING_OCTET_STUFFING; + pData->pszStrmDrvr = NULL; + pData->pszStrmDrvrAuthMode = NULL; + pData->iStrmDrvrMode = 0; + pData->iRebindInterval = 0; + pData->bResendLastOnRecon = 0; + pData->pPermPeers = NULL; + pData->compressionLevel = 0; +} + +BEGINnewActInst + struct cnfparamvals *pvals; + int i; + rsRetVal localRet; +CODESTARTnewActInst + DBGPRINTF("newActInst (omfwd)\n"); + + pvals = nvlstGetParams(lst, &actpblk, NULL); + if(pvals == NULL) { + errmsg.LogError(0, RS_RET_MISSING_CNFPARAMS, "omfwd: either the \"file\" or " + "\"dynfile\" parameter must be given"); + ABORT_FINALIZE(RS_RET_MISSING_CNFPARAMS); + } + + if(Debug) { + dbgprintf("action param blk in omfwd:\n"); + cnfparamsPrint(&actpblk, pvals); + } + + CHKiRet(createInstance(&pData)); + setInstParamDefaults(pData); + + for(i = 0 ; i < actpblk.nParams ; ++i) { + if(!pvals[i].bUsed) + continue; + if(!strcmp(actpblk.descr[i].name, "target")) { + pData->target = es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "port")) { + pData->port = es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "protocol")) { + if(!es_strcasebufcmp(pvals[i].val.d.estr, (uchar*)"udp", 3)) { + pData->protocol = FORW_UDP; + } else if(!es_strcasebufcmp(pvals[i].val.d.estr, (uchar*)"tcp", 3)) { + localRet = loadTCPSupport(); + if(localRet != RS_RET_OK) { + errmsg.LogError(0, localRet, "could not activate network stream modules for TCP " + "(internal error %d) - are modules missing?", localRet); + ABORT_FINALIZE(localRet); + } + pData->protocol = FORW_TCP; + } else { + uchar *str; + str = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_INVLD_PROTOCOL, + "omfwd: invalid protocol \"%s\"", str); + free(str); + ABORT_FINALIZE(RS_RET_INVLD_PROTOCOL); + } + } else if(!strcmp(actpblk.descr[i].name, "tcp_framing")) { + if(!es_strcasebufcmp(pvals[i].val.d.estr, (uchar*)"traditional", 11)) { + pData->tcp_framing = TCP_FRAMING_OCTET_STUFFING; + } else if(!es_strcasebufcmp(pvals[i].val.d.estr, (uchar*)"octet-counted", 13)) { + pData->tcp_framing = TCP_FRAMING_OCTET_COUNTING; + } else { + uchar *str; + str = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + errmsg.LogError(0, RS_RET_CNF_INVLD_FRAMING, + "omfwd: invalid framing \"%s\"", str); + free(str); + ABORT_FINALIZE(RS_RET_CNF_INVLD_FRAMING ); + } + } else if(!strcmp(actpblk.descr[i].name, "rebindinterval")) { + pData->iRebindInterval = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "streamdriver")) { + pData->pszStrmDrvr = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "streamdrivermode")) { + pData->iStrmDrvrMode = pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "streamdriverauthmode")) { + pData->pszStrmDrvrAuthMode = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "streamdriverpermittedpeers")) { + uchar *start, *str; + uchar save; + uchar *p; + int lenStr; + str = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + start = str; + lenStr = ustrlen(start); /* we need length after '\0' has been dropped... */ + while(lenStr > 0) { + p = start; + while(*p && *p != ',' && lenStr--) + p++; + if(*p == ',') { + *p = '\0'; + } + save = *(p+1); /* we always have this, at least the \0 byte at EOS */ + *(p+1) = '\0'; + if(*start == '\0') { + DBGPRINTF("omfwd: ignoring empty permitted peer\n"); + } else { + dbgprintf("omfwd: adding permitted peer: '%s'\n", start); + CHKiRet(net.AddPermittedPeer(&(pData->pPermPeers), start)); + } + start = p+1; + if(lenStr) + --lenStr; + *(p+1) = save; + } + free(str); + } else if(!strcmp(actpblk.descr[i].name, "ziplevel")) { +# ifdef USE_NETZIP + int complevel = pvals[i].val.d.n; + if(complevel >= 0 && complevel <= 10) { + pData->compressionLevel = complevel; + } else { + errmsg.LogError(0, NO_ERRCODE, "Invalid ziplevel %d specified in " + "forwardig action - NOT turning on compression.", + complevel); + } +# else + errmsg.LogError(0, NO_ERRCODE, "Compression requested, but rsyslogd is not compiled " + "with compression support - request ignored."); +# endif /* #ifdef USE_NETZIP */ + } else if(!strcmp(actpblk.descr[i].name, "resendlastmsgonreconnect")) { + pData->bResendLastOnRecon = (int) pvals[i].val.d.n; + } else if(!strcmp(actpblk.descr[i].name, "template")) { + pData->tplName = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else { + DBGPRINTF("omfwd: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + 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(initTCP(pData)); +CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + + BEGINparseSelectorAct uchar *q; int i; @@ -687,6 +887,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) /* JUST SKIP */; } + pData->tcp_framing = tcp_framing; pData->port = NULL; if(*p == ':') { /* process port */ uchar * tmp; @@ -714,30 +915,22 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) if(*p == ';' || *p == '#' || isspace(*p)) { uchar cTmp = *p; *p = '\0'; /* trick to obtain hostname (later)! */ - CHKmalloc(pData->f_hname = strdup((char*) q)); + CHKmalloc(pData->target = strdup((char*) q)); *p = cTmp; } else { - CHKmalloc(pData->f_hname = strdup((char*) q)); + CHKmalloc(pData->target = strdup((char*) q)); } /* copy over config data as needed */ - pData->iUDPRebindInterval = cs.iUDPRebindInterval; - pData->iTCPRebindInterval = cs.iTCPRebindInterval; + pData->iRebindInterval = (pData->protocol == FORW_TCP) ? + cs.iTCPRebindInterval : cs.iUDPRebindInterval; /* process template */ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (cs.pszTplName == NULL) ? (uchar*)"RSYSLOG_TraditionalForwardFormat" : cs.pszTplName)); if(pData->protocol == FORW_TCP) { - /* create our tcpclt */ - CHKiRet(tcpclt.Construct(&pData->pTCPClt)); - CHKiRet(tcpclt.SetResendLastOnRecon(pData->pTCPClt, cs.bResendLastOnRecon)); - /* and set callbacks */ - CHKiRet(tcpclt.SetSendInit(pData->pTCPClt, TCPSendInit)); - CHKiRet(tcpclt.SetSendFrame(pData->pTCPClt, TCPSendFrame)); - CHKiRet(tcpclt.SetSendPrepRetry(pData->pTCPClt, TCPSendPrepRetry)); - CHKiRet(tcpclt.SetFraming(pData->pTCPClt, tcp_framing)); - CHKiRet(tcpclt.SetRebindInterval(pData->pTCPClt, pData->iTCPRebindInterval)); + pData->bResendLastOnRecon = cs.bResendLastOnRecon; pData->iStrmDrvrMode = cs.iStrmDrvrMode; if(cs.pszStrmDrvr != NULL) CHKmalloc(pData->pszStrmDrvr = (uchar*)strdup((char*)cs.pszStrmDrvr)); @@ -749,7 +942,7 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) cs.pPermPeers = NULL; } } - + CHKiRet(initTCP(pData)); CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct @@ -780,7 +973,6 @@ CODESTARTmodExit objRelease(netstrm, LM_NETSTRMS_FILENAME); objRelease(netstrms, LM_NETSTRMS_FILENAME); objRelease(tcpclt, LM_TCPCLT_FILENAME); - freeConfigVars(); ENDmodExit @@ -788,6 +980,7 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES CODEqueryEtryPt_TXIF_OMOD_QUERIES /* we support the transactional interface! */ ENDqueryEtryPt -- cgit v1.2.3 From e61672c6932868d6b09ad0ae8453dc91c545742f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 17 Oct 2011 15:49:20 +0200 Subject: removed dependency on gcrypt for recently-enough GnuTLS see: http://bugzilla.adiscon.com/show_bug.cgi?id=289 --- ChangeLog | 2 ++ runtime/nsd_gtls.c | 6 +++++- tests/tcpflood.c | 6 +++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index f14971ae..22d194e1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ --------------------------------------------------------------------------- Version 5.9.4 [V5-DEVEL], 2011-0?-?? +- removed dependency on gcrypt for recently-enough GnuTLS + see: http://bugzilla.adiscon.com/show_bug.cgi?id=289 - bugfix: imuxsock did no longer ignore message-provided timestamp, if so configured (the *default*). Lead to no longer sub-second timestamps. closes: http://bugzilla.adiscon.com/show_bug.cgi?id=281 diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c index ca4b2928..9dda795d 100644 --- a/runtime/nsd_gtls.c +++ b/runtime/nsd_gtls.c @@ -29,7 +29,9 @@ #include #include #include -#include +#if GNUTLS_VERSION_NUMBER <= 0x020b00 +# include +#endif #include #include #include @@ -563,7 +565,9 @@ gtlsGlblInit(void) DEFiRet; /* gcry_control must be called first, so that the thread system is correctly set up */ + #if GNUTLS_VERSION_NUMBER <= 0x020b00 gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + #endif CHKgnutls(gnutls_global_init()); /* X509 stuff */ diff --git a/tests/tcpflood.c b/tests/tcpflood.c index 8485acbb..8a34f06f 100644 --- a/tests/tcpflood.c +++ b/tests/tcpflood.c @@ -91,8 +91,10 @@ #include #ifdef ENABLE_GNUTLS # include -# include +# if GNUTLS_VERSION_NUMBER <= 0x020b00 +# include GCRY_THREAD_OPTION_PTHREAD_IMPL; +# endif #endif #define EXIT_FAILURE 1 @@ -707,7 +709,9 @@ initTLS(void) int r; /* order of gcry_control and gnutls_global_init matters! */ + #if GNUTLS_VERSION_NUMBER <= 0x020b00 gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); + #endif gnutls_global_init(); /* set debug mode, if so required by the options */ if(tlsLogLevel > 0) { -- cgit v1.2.3 From 1c96bcba4f2c852ffe097816d9aabb7edc092770 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 21 Oct 2011 15:29:51 +0200 Subject: one further change to support gnutls without libgcrypt --- runtime/nsd_gtls.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/runtime/nsd_gtls.c b/runtime/nsd_gtls.c index 9dda795d..15340738 100644 --- a/runtime/nsd_gtls.c +++ b/runtime/nsd_gtls.c @@ -56,7 +56,9 @@ #define CRLFILE "crl.pem" +#if GNUTLS_VERSION_NUMBER <= 0x020b00 GCRY_THREAD_OPTION_PTHREAD_IMPL; +#endif MODULE_TYPE_LIB MODULE_TYPE_KEEP -- cgit v1.2.3 From 54cee2ce69c5bbd96aa51ac8636f4b029e2ceb75 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 29 Nov 2011 12:36:36 +0100 Subject: imuxsock: added capability to "annotate" messages with "trusted information", which contains some properties obtained from the system and as such sure to not be faked. This is inspired by the similiar idea introduced in systemd. --- ChangeLog | 4 ++ doc/imuxsock.html | 28 ++++++-- plugins/imuxsock/imuxsock.c | 163 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 184 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index fdf13e62..199446f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ --------------------------------------------------------------------------- Version 5.9.4 [V5-DEVEL], 2011-0?-?? +- imuxsock: added capability to "annotate" messages with "trusted + information", which contains some properties obtained from the system + and as such sure to not be faked. This is inspired by the similiar idea + introduced in systemd. - removed dependency on gcrypt for recently-enough GnuTLS see: http://bugzilla.adiscon.com/show_bug.cgi?id=289 - bugfix: imuxsock did no longer ignore message-provided timestamp, if diff --git a/doc/imuxsock.html b/doc/imuxsock.html index 58b3ae54..f80bc598 100644 --- a/doc/imuxsock.html +++ b/doc/imuxsock.html @@ -49,6 +49,15 @@ are places as quickly as possible into the processing queues. If you would like flow control, you need to enable it via the $SystemLogSocketFlowControl and $InputUnixListenSocketFlowControl 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 +are available. These require a recent enough Linux Kernel and access to the /proc file +system. In other words, this may not work on all platforms and may not work fully when +privileges are dropped (depending on how they are dropped). Note that trusted properties +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).

        Configuration Directives:

        • $InputUnixListenSocketIgnoreMsgTimestamp [on/off] @@ -115,7 +124,12 @@ shall be used inside messages taken from the next $AddUnixListenSocket so 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 +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 @@ -151,17 +165,21 @@ $InputUnixListenSocketHostName /var/run/sshd/dev/log

          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. +

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

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

          diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index e9dc5de2..5dbfcbf4 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -135,6 +136,7 @@ typedef struct lstn_s { sbool bParseHost; /* should parser parse host name? read-only after startup */ sbool bCreatePath; /* auto-creation of socket directory? */ sbool bUseCreds; /* pull original creator credentials from socket */ + sbool bAnnotate; /* annotate events with trusted properties */ sbool bWritePid; /* write original PID into tag */ sbool bUseSysTimeStamp; /* use timestamp from system (instead of from message) */ } lstn_t; @@ -159,6 +161,8 @@ static int bWritePid = 0; /* use credentials from recvmsg() and fixup PID in TA static int bWritePidSysSock = 0; /* use credentials from recvmsg() and fixup PID in TAG */ static int bUseSysTimeStamp = 1; /* use timestamp from system (rather than from message) */ static int bUseSysTimeStampSysSock = 1; /* same, for system log socket */ +static int bAnnotate = 0; /* annotate trusted properties */ +static int bAnnotateSysSock = 0; /* same, for system log socket */ #define DFLT_bCreatePath 0 static int bCreatePath = DFLT_bCreatePath; /* auto-create socket path? */ #define DFLT_ratelimitInterval 5 @@ -303,7 +307,8 @@ addLstnSocketName(void __attribute__((unused)) *pVal, uchar *pNewVal) listeners[nfd].flags = bIgnoreTimestamp ? IGNDATE : NOFLAG; listeners[nfd].bCreatePath = bCreatePath; listeners[nfd].sockName = pNewVal; - listeners[nfd].bUseCreds = (bWritePid || ratelimitInterval) ? 1 : 0; + listeners[nfd].bUseCreds = (bWritePid || ratelimitInterval || bAnnotate) ? 1 : 0; + listeners[nfd].bAnnotate = bAnnotate; listeners[nfd].bWritePid = bWritePid; listeners[nfd].bUseSysTimeStamp = bUseSysTimeStamp; nfd++; @@ -426,6 +431,7 @@ openLogSocket(lstn_t *pLstn) } # else /* HAVE_SCM_CREDENTIALS */ pLstn->bUseCreds = 0; + pLstn->bAnnotate = 0; # endif /* HAVE_SCM_CREDENTIALS */ finalize_it: @@ -508,6 +514,103 @@ fixPID(uchar *bufTAG, int *lenTag, struct ucred *cred) } +/* Get an "trusted property" from the system. Returns an empty string if the + * property can not be obtained. Inspired by similiar functionality inside + * journald. Currently works with Linux /proc filesystem, only. + */ +static rsRetVal +getTrustedProp(struct ucred *cred, char *propName, uchar *buf, size_t lenBuf, int *lenProp) +{ + int fd; + int i; + int lenRead; + char namebuf[1024]; + DEFiRet; + + if(snprintf(namebuf, sizeof(namebuf), "/proc/%lu/%s", (long unsigned) cred->pid, + propName) >= (int) sizeof(namebuf)) { + ABORT_FINALIZE(RS_RET_ERR); + } + + if((fd = open(namebuf, O_RDONLY)) == -1) { + DBGPRINTF("error reading '%s'\n", namebuf); + *lenProp = 0; + FINALIZE; + } + if((lenRead = read(fd, buf, lenBuf - 1)) == -1) { + DBGPRINTF("error reading file data for '%s'\n", namebuf); + *lenProp = 0; + close(fd); + FINALIZE; + } + + /* we strip after the first \n */ + for(i = 0 ; i < lenRead ; ++i) { + if(buf[i] == '\n') + break; + else if(iscntrl(buf[i])) + buf[i] = ' '; + } + buf[i] = '\0'; + *lenProp = i; + + close(fd); + +finalize_it: + RETiRet; +} + + +/* read the exe trusted property path (so far, /proc fs only) + */ +static rsRetVal +getTrustedExe(struct ucred *cred, uchar *buf, size_t lenBuf, int* lenProp) +{ + int lenRead; + char namebuf[1024]; + DEFiRet; + + if(snprintf(namebuf, sizeof(namebuf), "/proc/%lu/exe", (long unsigned) cred->pid) + >= (int) sizeof(namebuf)) { + ABORT_FINALIZE(RS_RET_ERR); + } + + if((lenRead = readlink(namebuf, (char*)buf, lenBuf - 1)) == -1) { + DBGPRINTF("error reading link '%s'\n", namebuf); + *lenProp = 0; + FINALIZE; + } + + buf[lenRead] = '\0'; + *lenProp = lenRead; + +finalize_it: + RETiRet; +} + + +/* copy a trusted property in escaped mode. That is, the property can contain + * any character and so it must be properly quoted AND escaped. + * It is assumed the output buffer is large enough. Returns the number of + * characters added. + */ +static inline int +copyescaped(uchar *dstbuf, uchar *inbuf, int inlen) +{ + int iDst, iSrc; + + *dstbuf = '"'; + for(iDst=1, iSrc=0 ; iSrc < inlen ; ++iDst, ++iSrc) { + if(inbuf[iSrc] == '"' || inbuf[iSrc] == '\\') { + dstbuf[iDst++] = '\\'; + } + dstbuf[iDst] = inbuf[iSrc]; + } + dstbuf[iDst++] = '"'; + return iDst; +} + + /* 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. @@ -527,6 +630,11 @@ SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred, struct tim struct syslogTime st; time_t tt; rs_ratelimit_state_t *ratelimiter = NULL; + int lenProp; + uchar propBuf[1024]; + uchar msgbuf[8192]; + uchar *pmsgbuf; + int toffs; /* offset for trusted properties */ DEFiRet; /* TODO: handle format errors?? */ @@ -564,6 +672,47 @@ SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred, struct tim FINALIZE; } + /* created trusted properties */ + if(cred != NULL && pLstn->bAnnotate) { + if((unsigned) (lenRcv + 4096) < sizeof(msgbuf)) { + pmsgbuf = msgbuf; + } 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); + } + /* 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 */ CHKiRet(msgConstructWithTime(&pMsg, &st, tt)); MsgSetRawMsg(pMsg, (char*)pRcv, lenRcv); @@ -694,14 +843,11 @@ static rsRetVal readSocket(lstn_t *pLstn) cred = NULL; ts = NULL; if(pLstn->bUseCreds || pLstn->bUseSysTimeStamp) { - dbgprintf("XXX: pre CM loop, length of control message %d\n", (int) msgh.msg_controllen); for(cm = CMSG_FIRSTHDR(&msgh); cm; cm = CMSG_NXTHDR(&msgh, cm)) { - dbgprintf("XXX: in CM loop, %d, %d\n", cm->cmsg_level, cm->cmsg_type); # if HAVE_SCM_CREDENTIALS if( pLstn->bUseCreds && cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_CREDENTIALS) { cred = (struct ucred*) CMSG_DATA(cm); - dbgprintf("XXX: got credentials pid %d\n", (int) cred->pid); break; } # endif /* HAVE_SCM_CREDENTIALS */ @@ -715,7 +861,6 @@ static rsRetVal readSocket(lstn_t *pLstn) } # endif /* HAVE_SO_TIMESTAMP */ } - dbgprintf("XXX: post CM loop\n"); } CHKiRet(SubmitMsg(pRcv, iRcvd, pLstn, cred, ts)); } else if(iRcvd < 0 && errno != EINTR) { @@ -827,8 +972,9 @@ CODESTARTwillRun listeners[0].ratelimitInterval = ratelimitIntervalSysSock; listeners[0].ratelimitBurst = ratelimitBurstSysSock; listeners[0].ratelimitSev = ratelimitSeveritySysSock; - listeners[0].bUseCreds = (bWritePidSysSock || ratelimitIntervalSysSock) ? 1 : 0; + listeners[0].bUseCreds = (bWritePidSysSock || ratelimitIntervalSysSock || bAnnotateSysSock) ? 1 : 0; listeners[0].bWritePid = bWritePidSysSock; + listeners[0].bAnnotate = bAnnotateSysSock; listeners[0].bUseSysTimeStamp = bUseSysTimeStampSysSock; sd_fds = sd_listen_fds(0); @@ -978,6 +1124,7 @@ CODEmodInit_QueryRegCFSLineHdlr listeners[0].fd = -1; listeners[0].bParseHost = 0; listeners[0].bUseCreds = 0; + listeners[0].bAnnotate = 0; listeners[0].bCreatePath = 0; listeners[0].bUseSysTimeStamp = 1; @@ -1007,6 +1154,8 @@ CODEmodInit_QueryRegCFSLineHdlr NULL, &pLogHostName, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketflowcontrol", 0, eCmdHdlrBinary, NULL, &bUseFlowCtl, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketannotate", 0, eCmdHdlrBinary, + NULL, &bAnnotate, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketcreatepath", 0, eCmdHdlrBinary, NULL, &bCreatePath, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputunixlistensocketusepidfromsystem", 0, eCmdHdlrBinary, @@ -1035,6 +1184,8 @@ CODEmodInit_QueryRegCFSLineHdlr setSystemLogFlowControl, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogusesystimestamp", 0, eCmdHdlrBinary, NULL, &bUseSysTimeStampSysSock, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogsocketannotate", 0, eCmdHdlrBinary, + NULL, &bAnnotateSysSock, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogusepidfromsystem", 0, eCmdHdlrBinary, NULL, &bWritePidSysSock, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"systemlogratelimitinterval", 0, eCmdHdlrInt, -- cgit v1.2.3 From e53752e168d1f3d19c605e0d7f1a0797785f6a8c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 29 Nov 2011 16:55:26 +0100 Subject: preparing for 5.9.4 --- ChangeLog | 2 +- configure.ac | 2 +- doc/manual.html | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 199446f8..42c26845 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 5.9.4 [V5-DEVEL], 2011-0?-?? +Version 5.9.4 [V5-DEVEL], 2011-11-29 - imuxsock: added capability to "annotate" messages with "trusted information", which contains some properties obtained from the system and as such sure to not be faked. This is inspired by the similiar idea diff --git a/configure.ac b/configure.ac index f1c83fa4..98beb121 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],[5.9.3],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.9.4],[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 a15c5a0b..fdeb2980 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 5.9.3 (stable branch) of rsyslog. +

          This documentation is for version 5.9.4 (stable 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 01c7c9ffc6771f73df9ee0bc18e30534d6c6974c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 16 Dec 2011 12:14:48 +0100 Subject: enhanced module loader to not rely on PATH_MAX --- ChangeLog | 3 +++ runtime/modules.c | 80 ++++++++++++++++++++++++++++++++----------------------- 2 files changed, 49 insertions(+), 34 deletions(-) diff --git a/ChangeLog b/ChangeLog index 42c26845..61210128 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,7 @@ --------------------------------------------------------------------------- +Version 5.9.5 [V5-DEVEL], 2011-11-29 +- enhanced module loader to not rely on PATH_MAX +--------------------------------------------------------------------------- Version 5.9.4 [V5-DEVEL], 2011-11-29 - imuxsock: added capability to "annotate" messages with "trusted information", which contains some properties obtained from the system diff --git a/runtime/modules.c b/runtime/modules.c index 4541bddf..6a32b2e8 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -767,7 +767,6 @@ Load(uchar *pModName) DEFiRet; size_t iPathLen, iModNameLen; - uchar szPath[PATH_MAX]; uchar *pModNameCmp; int bHasExtension; void *pModHdlr, *pModInit; @@ -775,13 +774,25 @@ Load(uchar *pModName) uchar *pModDirCurr, *pModDirNext; int iLoadCnt; struct dlhandle_s *pHandle = NULL; +# ifdef PATH_MAX + uchar pathBuf[PATH_MAX+1]; +# else + uchar pathBuf[4096]; +# endif + uchar *pPathBuf = pathBuf; + size_t lenPathBuf = sizeof(pathBuf); assert(pModName != NULL); dbgprintf("Requested to load module '%s'\n", pModName); + iModNameLen = strlen((char*)pModName); + /* overhead for a full path is potentially 1 byte for a slash, + * three bytes for ".so" and one byte for '\0'. + */ +# define PATHBUF_OVERHEAD 1 + iModNameLen + 3 + 1 + pthread_mutex_lock(&mutLoadUnload); - iModNameLen = strlen((char *) pModName); if(iModNameLen > 3 && !strcmp((char *) pModName + iModNameLen - 3, ".so")) { iModNameLen -= 3; bHasExtension = TRUE; @@ -802,13 +813,19 @@ Load(uchar *pModName) pModDirNext = NULL; pModHdlr = NULL; iLoadCnt = 0; - do { - /* now build our load module name */ + do { /* now build our load module name */ if(*pModName == '/' || *pModName == '.') { - *szPath = '\0'; /* we do not need to append the path - its already in the module name */ + if(lenPathBuf < PATHBUF_OVERHEAD) { + if(pPathBuf != pathBuf) /* already malloc()ed memory? */ + free(pPathBuf); + /* we always alloc enough memory for everything we potentiall need to add */ + lenPathBuf = PATHBUF_OVERHEAD; + CHKmalloc(pPathBuf = malloc(sizeof(char)*lenPathBuf)); + } + *pPathBuf = '\0'; /* we do not need to append the path - its already in the module name */ iPathLen = 0; } else { - *szPath = '\0'; + *pPathBuf = '\0'; iPathLen = strlen((char *)pModDirCurr); pModDirNext = (uchar *)strchr((char *)pModDirCurr, ':'); @@ -821,30 +838,27 @@ Load(uchar *pModName) continue; } break; - } else if(iPathLen > sizeof(szPath) - 1) { - errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', module path too long\n", pModName); - ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); + } else if(iPathLen > lenPathBuf - PATHBUF_OVERHEAD) { + if(pPathBuf != pathBuf) /* already malloc()ed memory? */ + free(pPathBuf); + /* we always alloc enough memory for everything we potentiall need to add */ + lenPathBuf = iPathLen + PATHBUF_OVERHEAD; + CHKmalloc(pPathBuf = malloc(sizeof(char)*lenPathBuf)); } - strncat((char *) szPath, (char *)pModDirCurr, iPathLen); - iPathLen = strlen((char*) szPath); + memcpy((char *) pPathBuf, (char *)pModDirCurr, iPathLen); + if((pPathBuf[iPathLen - 1] != '/')) { + /* we have space, made sure in previous check */ + pPathBuf[iPathLen++] = '/'; + } + pPathBuf[iPathLen] = '\0'; if(pModDirNext) pModDirCurr = pModDirNext + 1; - - if((szPath[iPathLen - 1] != '/')) { - if((iPathLen <= sizeof(szPath) - 2)) { - szPath[iPathLen++] = '/'; - szPath[iPathLen] = '\0'; - } else { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); - ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); - } - } } /* ... add actual name ... */ - strncat((char *) szPath, (char *) pModName, sizeof(szPath) - iPathLen - 1); + strncat((char *) pPathBuf, (char *) pModName, lenPathBuf - iPathLen - 1); /* now see if we have an extension and, if not, append ".so" */ if(!bHasExtension) { @@ -853,17 +867,12 @@ Load(uchar *pModName) * algo over time... -- rgerhards, 2008-03-05 */ /* ... so now add the extension */ - strncat((char *) szPath, ".so", sizeof(szPath) - strlen((char*) szPath) - 1); + strncat((char *) pPathBuf, ".so", lenPathBuf - strlen((char*) pPathBuf) - 1); iPathLen += 3; } - if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); - ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); - } - /* complete load path constructed, so ... GO! */ - dbgprintf("loading module '%s'\n", szPath); + dbgprintf("loading module '%s'\n", pPathBuf); /* see if we have this one already */ for (pHandle = pHandles; pHandle; pHandle = pHandle->next) { @@ -875,7 +884,7 @@ Load(uchar *pModName) /* not found, try to dynamically link it */ if (!pModHdlr) { - pModHdlr = dlopen((char *) szPath, RTLD_NOW); + pModHdlr = dlopen((char *) pPathBuf, RTLD_NOW); } iLoadCnt++; @@ -884,25 +893,28 @@ Load(uchar *pModName) if(!pModHdlr) { if(iLoadCnt) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", szPath, dlerror()); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", + pPathBuf, dlerror()); } else { - errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', ModDir was '%s'\n", szPath, + errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', ModDir was '%s'\n", pPathBuf, ((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir)); } ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_DLOPEN); } if(!(pModInit = dlsym(pModHdlr, "modInit"))) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_NO_INIT, "could not load module '%s', dlsym: %s\n", szPath, dlerror()); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_NO_INIT, "could not load module '%s', dlsym: %s\n", pPathBuf, dlerror()); dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_NO_INIT); } if((iRet = doModInit(pModInit, (uchar*) pModName, pModHdlr)) != RS_RET_OK) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_INIT_FAILED, "could not load module '%s', rsyslog error %d\n", szPath, iRet); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_INIT_FAILED, "could not load module '%s', rsyslog error %d\n", pPathBuf, iRet); dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_INIT_FAILED); } finalize_it: + if(pPathBuf != pathBuf) /* used malloc()ed memory? */ + free(pPathBuf); pthread_mutex_unlock(&mutLoadUnload); RETiRet; } -- cgit v1.2.3 From 7796eeb6960b2e1d1aeac77242a5ad93a64776cc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 16 Dec 2011 14:42:37 +0100 Subject: new stats counter "discarded" for queue object Tells how many messages have been discarded due to queue full condition. --- ChangeLog | 4 ++++ plugins/impstats/impstats.c | 2 +- runtime/queue.c | 5 +++++ runtime/queue.h | 1 + 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 61210128..6f228b80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ --------------------------------------------------------------------------- Version 5.9.5 [V5-DEVEL], 2011-11-29 +- new stats counter "discarded" for queue object. Tells how many messages + have been discarded due to queue full condition. +--------------------------------------------------------------------------- +Version 5.9.5 [V5-DEVEL], 2011-11-29 - enhanced module loader to not rely on PATH_MAX --------------------------------------------------------------------------- Version 5.9.4 [V5-DEVEL], 2011-11-29 diff --git a/plugins/impstats/impstats.c b/plugins/impstats/impstats.c index cfbbad76..dc2541b8 100644 --- a/plugins/impstats/impstats.c +++ b/plugins/impstats/impstats.c @@ -10,7 +10,7 @@ * of the "old" message code without any modifications. However, it * helps to have things at the right place one we go to the meat of it. * - * Copyright 2010 Rainer Gerhards and Adiscon GmbH. + * Copyright 2010-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * diff --git a/runtime/queue.c b/runtime/queue.c index d81c552b..1692db3a 100644 --- a/runtime/queue.c +++ b/runtime/queue.c @@ -1989,6 +1989,10 @@ qqueueStart(qqueue_t *pThis) /* this is the ConstructionFinalizer */ CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("full"), ctrType_IntCtr, &pThis->ctrFull)); + STATSCOUNTER_INIT(pThis->ctrDscrd, pThis->mutCtrDscrd); + CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("discarded"), + ctrType_IntCtr, &pThis->ctrDscrd)); + pThis->ctrMaxqsize = 0; CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("maxqsize"), ctrType_Int, &pThis->ctrMaxqsize)); @@ -2342,6 +2346,7 @@ doEnqSingleObj(qqueue_t *pThis, flowControl_t flowCtlType, void *pUsr) // TODO : handle enqOnly => discard! if(pthread_cond_timedwait(&pThis->notFull, pThis->mut, &t) != 0) { DBGOPRINT((obj_t*) pThis, "enqueueMsg: cond timeout, dropping message!\n"); + STATSCOUNTER_INC(pThis->ctrDscrd, pThis->mutCtrDscrd); objDestruct(pUsr); ABORT_FINALIZE(RS_RET_QUEUE_FULL); } diff --git a/runtime/queue.h b/runtime/queue.h index 97057180..70bb8895 100644 --- a/runtime/queue.h +++ b/runtime/queue.h @@ -169,6 +169,7 @@ struct queue_s { statsobj_t *statsobj; STATSCOUNTER_DEF(ctrEnqueued, mutCtrEnqueued); STATSCOUNTER_DEF(ctrFull, mutCtrFull); + STATSCOUNTER_DEF(ctrDscrd, mutCtrDscrd); int ctrMaxqsize; }; -- cgit v1.2.3 From a1b752b32ffb90bfdce4fd8dfdffac3ebbadc79e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 16 Dec 2011 15:12:24 +0100 Subject: more work on queue statistics counter --- ChangeLog | 4 ++-- doc/impstats.html | 4 +++- runtime/queue.c | 12 ++++++++---- runtime/queue.h | 3 ++- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6f228b80..b2c8bf44 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,7 @@ --------------------------------------------------------------------------- Version 5.9.5 [V5-DEVEL], 2011-11-29 -- new stats counter "discarded" for queue object. Tells how many messages - have been discarded due to queue full condition. +- new stats counters "discarded.nf" and "discarded.full" for queue object. + Tells how many messages have been discarded due to queue full condition. --------------------------------------------------------------------------- Version 5.9.5 [V5-DEVEL], 2011-11-29 - enhanced module loader to not rely on PATH_MAX diff --git a/doc/impstats.html b/doc/impstats.html index cede4874..260c1aa4 100644 --- a/doc/impstats.html +++ b/doc/impstats.html @@ -18,7 +18,9 @@ prepared to change your trending scripts when you upgrade to a newer rsyslog ver output is periodic, with the interval being configurable (default is 5 minutes). Be sure that your configuration records the counter messages (default is syslog.info).

          Note that loading this module has impact on rsyslog performance. Depending on -settings, this impact may be severe (for high-load environments). +settings, this impact may be noticable (for high-load environments). +

          The rsyslog website has an updated overview of available +rsyslog statistic counters.

          Configuration Directives:

            diff --git a/runtime/queue.c b/runtime/queue.c index 1692db3a..c8e6bb27 100644 --- a/runtime/queue.c +++ b/runtime/queue.c @@ -1355,6 +1355,7 @@ static int qqueueChkDiscardMsg(qqueue_t *pThis, int iQueueSize, void *pUsr) if(iRetLocal == RS_RET_OK && iSeverity >= pThis->iDiscardSeverity) { DBGOPRINT((obj_t*) pThis, "queue nearly full (%d entries), discarded severity %d message\n", iQueueSize, iSeverity); + STATSCOUNTER_INC(pThis->ctrNFDscrd, pThis->mutCtrNFDscrd); objDestruct(pUsr); ABORT_FINALIZE(RS_RET_QUEUE_FULL); } else { @@ -1989,9 +1990,12 @@ qqueueStart(qqueue_t *pThis) /* this is the ConstructionFinalizer */ CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("full"), ctrType_IntCtr, &pThis->ctrFull)); - STATSCOUNTER_INIT(pThis->ctrDscrd, pThis->mutCtrDscrd); - CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("discarded"), - ctrType_IntCtr, &pThis->ctrDscrd)); + STATSCOUNTER_INIT(pThis->ctrFDscrd, pThis->mutCtrFDscrd); + CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("discarded.full"), + ctrType_IntCtr, &pThis->ctrFDscrd)); + STATSCOUNTER_INIT(pThis->ctrNFDscrd, pThis->mutCtrNFDscrd); + CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("discarded.nf"), + ctrType_IntCtr, &pThis->ctrNFDscrd)); pThis->ctrMaxqsize = 0; CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("maxqsize"), @@ -2346,7 +2350,7 @@ doEnqSingleObj(qqueue_t *pThis, flowControl_t flowCtlType, void *pUsr) // TODO : handle enqOnly => discard! if(pthread_cond_timedwait(&pThis->notFull, pThis->mut, &t) != 0) { DBGOPRINT((obj_t*) pThis, "enqueueMsg: cond timeout, dropping message!\n"); - STATSCOUNTER_INC(pThis->ctrDscrd, pThis->mutCtrDscrd); + STATSCOUNTER_INC(pThis->ctrFDscrd, pThis->mutCtrFDscrd); objDestruct(pUsr); ABORT_FINALIZE(RS_RET_QUEUE_FULL); } diff --git a/runtime/queue.h b/runtime/queue.h index 70bb8895..06a58229 100644 --- a/runtime/queue.h +++ b/runtime/queue.h @@ -169,7 +169,8 @@ struct queue_s { statsobj_t *statsobj; STATSCOUNTER_DEF(ctrEnqueued, mutCtrEnqueued); STATSCOUNTER_DEF(ctrFull, mutCtrFull); - STATSCOUNTER_DEF(ctrDscrd, mutCtrDscrd); + STATSCOUNTER_DEF(ctrFDscrd, mutCtrFDscrd); + STATSCOUNTER_DEF(ctrNFDscrd, mutCtrNFDscrd); int ctrMaxqsize; }; -- cgit v1.2.3 From 955312ebf5d59e2ed0d35ba624070439b9fc5273 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 16 Dec 2011 18:51:49 +0100 Subject: experimental: added first stats counter to action object --- action.c | 49 +++++++++++++++++++++++++++++++++++++++++++------ action.h | 3 +++ runtime/queue.c | 2 +- 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/action.c b/action.c index af7723e7..45fa6cf7 100644 --- a/action.c +++ b/action.c @@ -112,6 +112,7 @@ #include "datetime.h" #include "unicode-helper.h" #include "atomic.h" +#include "statsobj.h" #define NO_TIME_PROVIDED 0 /* indicate we do not provide any cached time */ @@ -127,6 +128,7 @@ DEFobjCurrIf(obj) DEFobjCurrIf(datetime) DEFobjCurrIf(module) DEFobjCurrIf(errmsg) +DEFobjCurrIf(statsobj) static int iActExecOnceInterval = 0; /* execute action once every nn seconds */ static int iActExecEveryNthOccur = 0; /* execute action every n-th occurence (0,1=always) */ @@ -313,18 +315,38 @@ rsRetVal actionConstructFinalize(action_t *pThis) { DEFiRet; - uchar pszQName[64]; /* friendly name of our queue */ + uchar pszAName[64]; /* friendly name of our action */ ASSERT(pThis != NULL); - /* find a name for our queue */ + /* generate a friendly name for us action stats */ if(pThis->pszName == NULL) { - snprintf((char*) pszQName, sizeof(pszQName)/sizeof(uchar), "action %d queue", iActionNbr); + snprintf((char*) pszAName, sizeof(pszAName)/sizeof(uchar), "action %d", iActionNbr); } else { - ustrncpy(pszQName, pThis->pszName, sizeof(pszQName)); - pszQName[63] = '\0'; /* to be on the save side */ + ustrncpy(pszAName, pThis->pszName, sizeof(pszAName)); + pszAName[63] = '\0'; /* to be on the save side */ } + /* support statistics gathering */ + CHKiRet(statsobj.Construct(&pThis->statsobj)); + CHKiRet(statsobj.SetName(pThis->statsobj, pszAName)); + + STATSCOUNTER_INIT(pThis->ctrProcessed, pThis->mutCtrProcessed); + CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("processed"), + ctrType_IntCtr, &pThis->ctrProcessed)); + + CHKiRet(statsobj.ConstructFinalize(pThis->statsobj)); + + /* create our queue */ + + /* generate a friendly name for the queue */ + if(pThis->pszName == NULL) { + snprintf((char*) pszAName, sizeof(pszAName)/sizeof(uchar), "action %d queue", + iActionNbr); + } else { + ustrncpy(pszAName, pThis->pszName, sizeof(pszAName)); + pszAName[63] = '\0'; /* to be on the save side */ + } /* now check if we can run the action in "firehose mode" during stage one of * its processing (that is before messages are enqueued into the action q). * This is only possible if some features, which require strict sequence, are @@ -367,7 +389,7 @@ actionConstructFinalize(action_t *pThis) */ CHKiRet(qqueueConstruct(&pThis->pQueue, ActionQueType, 1, iActionQueueSize, (rsRetVal (*)(void*, batch_t*, int*))processBatchMain)); - obj.SetName((obj_t*) pThis->pQueue, pszQName); + obj.SetName((obj_t*) pThis->pQueue, pszAName); /* ... set some properties ... */ # define setQPROP(func, directive, data) \ @@ -1266,6 +1288,7 @@ doSubmitToActionQ(action_t *pAction, msg_t *pMsg) { DEFiRet; + STATSCOUNTER_INC(pAction->ctrProcessed, pAction->mutCtrProcessed); if(pAction->pQueue->qType == QUEUETYPE_DIRECT) iRet = qqueueEnqObjDirect(pAction->pQueue, (void*) MsgAddRef(pMsg)); else @@ -1542,6 +1565,17 @@ finalize_it: RETiRet; } +static inline void +countStatsBatchEnq(action_t *pAction, batch_t *pBatch) +{ + int i; + for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate) ; ++i) { + if(pBatch->pElem[i].bFilterOK) { + STATSCOUNTER_INC(pAction->ctrProcessed, pAction->mutCtrProcessed); + } + } +} + /* enqueue a batch in direct mode. We have put this into its own function just to avoid * cluttering the actual submit function. @@ -1585,6 +1619,7 @@ doQueueEnqObjDirectBatch(action_t *pAction, batch_t *pBatch) pAction->bExecWhenPrevSusp, pBatch->pElem[i].bPrevWasSuspended); } if(bNeedSubmit) { + countStatsBatchEnq(pAction, pBatch); iRet = qqueueEnqObjDirectBatch(pAction->pQueue, pBatch); } else { DBGPRINTF("no need to submit batch, all bFilterOK==0\n"); @@ -1599,6 +1634,7 @@ doQueueEnqObjDirectBatch(action_t *pAction, batch_t *pBatch) } } } else { + countStatsBatchEnq(pAction, pBatch); iRet = qqueueEnqObjDirectBatch(pAction->pQueue, pBatch); } @@ -1822,6 +1858,7 @@ rsRetVal actionClassInit(void) CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); + CHKiRet(objUse(statsobj, CORE_COMPONENT)); CHKiRet(regCfSysLineHdlr((uchar *)"actionname", 0, eCmdHdlrGetWord, NULL, &pszActionName, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszActionQFName, NULL)); diff --git a/action.h b/action.h index bae64d31..310ef114 100644 --- a/action.h +++ b/action.h @@ -89,6 +89,9 @@ struct action_s { pthread_mutex_t mutActExec; /* mutex to guard actual execution of doAction for single-threaded modules */ uchar *pszName; /* action name (for documentation) */ DEF_ATOMIC_HELPER_MUT(mutCAS); + /* for statistics subsystem */ + statsobj_t *statsobj; + STATSCOUNTER_DEF(ctrProcessed, mutCtrProcessed); }; diff --git a/runtime/queue.c b/runtime/queue.c index c8e6bb27..56d05571 100644 --- a/runtime/queue.c +++ b/runtime/queue.c @@ -12,7 +12,7 @@ * function names - this makes it really hard to read and does not provide much * benefit, at least I (now) think so... * - * Copyright 2008, 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2008-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * -- cgit v1.2.3 From be2383f2b80d4fb83abd2765e6467e8d7614ab49 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 16 Dec 2011 18:54:59 +0100 Subject: fixing memory leak in new stats code (delete statsobj) --- action.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/action.c b/action.c index 45fa6cf7..84b97e5c 100644 --- a/action.c +++ b/action.c @@ -265,6 +265,12 @@ rsRetVal actionDestruct(action_t *pThis) qqueueDestruct(&pThis->pQueue); } + /* destroy stats object, if we have one (may not always be + * be the case, e.g. if turned off) + */ + if(pThis->statsobj != NULL) + statsobj.Destruct(&pThis->statsobj); + if(pThis->pMod != NULL) pThis->pMod->freeInstance(pThis->pModData); -- cgit v1.2.3 From 5fe837bf7dbdcc245ee233feb1fbcc6d052a4898 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 Dec 2011 11:16:07 +0100 Subject: added instrumentation --- action.c | 48 ++++++++++++++++++++++++++++++++++++++++++--- action.h | 3 +++ doc/impstats.html | 4 +++- plugins/impstats/impstats.c | 2 +- runtime/queue.c | 11 ++++++++++- runtime/queue.h | 2 ++ 6 files changed, 64 insertions(+), 6 deletions(-) diff --git a/action.c b/action.c index 278625ce..49eb3663 100644 --- a/action.c +++ b/action.c @@ -112,6 +112,7 @@ #include "datetime.h" #include "unicode-helper.h" #include "atomic.h" +#include "statsobj.h" #define NO_TIME_PROVIDED 0 /* indicate we do not provide any cached time */ @@ -127,6 +128,7 @@ DEFobjCurrIf(obj) DEFobjCurrIf(datetime) DEFobjCurrIf(module) DEFobjCurrIf(errmsg) +DEFobjCurrIf(statsobj) static int iActExecOnceInterval = 0; /* execute action once every nn seconds */ static int iActExecEveryNthOccur = 0; /* execute action every n-th occurence (0,1=always) */ @@ -263,6 +265,12 @@ rsRetVal actionDestruct(action_t *pThis) qqueueDestruct(&pThis->pQueue); } + /* destroy stats object, if we have one (may not always be + * be the case, e.g. if turned off) + */ + if(pThis->statsobj != NULL) + statsobj.Destruct(&pThis->statsobj); + if(pThis->pMod != NULL) pThis->pMod->freeInstance(pThis->pModData); @@ -313,12 +321,31 @@ rsRetVal actionConstructFinalize(action_t *pThis) { DEFiRet; - uchar pszQName[64]; /* friendly name of our queue */ + uchar pszAName[64]; /* friendly name of our queue */ ASSERT(pThis != NULL); + /* generate a friendly name for us action stats */ + if(pThis->pszName == NULL) { + snprintf((char*) pszAName, sizeof(pszAName)/sizeof(uchar), "action %d", iActionNbr); + } else { + ustrncpy(pszAName, pThis->pszName, sizeof(pszAName)); + pszAName[63] = '\0'; /* to be on the save side */ + } + + /* support statistics gathering */ + CHKiRet(statsobj.Construct(&pThis->statsobj)); + CHKiRet(statsobj.SetName(pThis->statsobj, pszAName)); + + STATSCOUNTER_INIT(pThis->ctrProcessed, pThis->mutCtrProcessed); + CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("processed"), + ctrType_IntCtr, &pThis->ctrProcessed)); + + CHKiRet(statsobj.ConstructFinalize(pThis->statsobj)); + + /* create our queue */ /* find a name for our queue */ - snprintf((char*) pszQName, sizeof(pszQName)/sizeof(uchar), "action %d queue", iActionNbr); + snprintf((char*) pszAName, sizeof(pszAName)/sizeof(uchar), "action %d queue", iActionNbr); /* now check if we can run the action in "firehose mode" during stage one of * its processing (that is before messages are enqueued into the action q). @@ -362,7 +389,7 @@ actionConstructFinalize(action_t *pThis) */ CHKiRet(qqueueConstruct(&pThis->pQueue, ActionQueType, 1, iActionQueueSize, (rsRetVal (*)(void*, batch_t*, int*))processBatchMain)); - obj.SetName((obj_t*) pThis->pQueue, pszQName); + obj.SetName((obj_t*) pThis->pQueue, pszAName); /* ... set some properties ... */ # define setQPROP(func, directive, data) \ @@ -1261,6 +1288,7 @@ doSubmitToActionQ(action_t *pAction, msg_t *pMsg) { DEFiRet; + STATSCOUNTER_INC(pAction->ctrProcessed, pAction->mutCtrProcessed); if(pAction->pQueue->qType == QUEUETYPE_DIRECT) iRet = qqueueEnqObjDirect(pAction->pQueue, (void*) MsgAddRef(pMsg)); else @@ -1537,6 +1565,17 @@ finalize_it: RETiRet; } +static inline void +countStatsBatchEnq(action_t *pAction, batch_t *pBatch) +{ + int i; + for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate) ; ++i) { + if(pBatch->pElem[i].bFilterOK) { + STATSCOUNTER_INC(pAction->ctrProcessed, pAction->mutCtrProcessed); + } + } +} + /* enqueue a batch in direct mode. We have put this into its own function just to avoid * cluttering the actual submit function. @@ -1580,6 +1619,7 @@ doQueueEnqObjDirectBatch(action_t *pAction, batch_t *pBatch) pAction->bExecWhenPrevSusp, pBatch->pElem[i].bPrevWasSuspended); } if(bNeedSubmit) { + countStatsBatchEnq(pAction, pBatch); iRet = qqueueEnqObjDirectBatch(pAction->pQueue, pBatch); } else { DBGPRINTF("no need to submit batch, all bFilterOK==0\n"); @@ -1594,6 +1634,7 @@ doQueueEnqObjDirectBatch(action_t *pAction, batch_t *pBatch) } } } else { + countStatsBatchEnq(pAction, pBatch); iRet = qqueueEnqObjDirectBatch(pAction->pQueue, pBatch); } @@ -1817,6 +1858,7 @@ rsRetVal actionClassInit(void) CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(module, CORE_COMPONENT)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); + CHKiRet(objUse(statsobj, CORE_COMPONENT)); CHKiRet(regCfSysLineHdlr((uchar *)"actionname", 0, eCmdHdlrGetWord, NULL, &pszActionName, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"actionqueuefilename", 0, eCmdHdlrGetWord, NULL, &pszActionQFName, NULL)); diff --git a/action.h b/action.h index bae64d31..310ef114 100644 --- a/action.h +++ b/action.h @@ -89,6 +89,9 @@ struct action_s { pthread_mutex_t mutActExec; /* mutex to guard actual execution of doAction for single-threaded modules */ uchar *pszName; /* action name (for documentation) */ DEF_ATOMIC_HELPER_MUT(mutCAS); + /* for statistics subsystem */ + statsobj_t *statsobj; + STATSCOUNTER_DEF(ctrProcessed, mutCtrProcessed); }; diff --git a/doc/impstats.html b/doc/impstats.html index cede4874..260c1aa4 100644 --- a/doc/impstats.html +++ b/doc/impstats.html @@ -18,7 +18,9 @@ prepared to change your trending scripts when you upgrade to a newer rsyslog ver output is periodic, with the interval being configurable (default is 5 minutes). Be sure that your configuration records the counter messages (default is syslog.info).

            Note that loading this module has impact on rsyslog performance. Depending on -settings, this impact may be severe (for high-load environments). +settings, this impact may be noticable (for high-load environments). +

            The rsyslog website has an updated overview of available +rsyslog statistic counters.

            Configuration Directives:

              diff --git a/plugins/impstats/impstats.c b/plugins/impstats/impstats.c index cfbbad76..dc2541b8 100644 --- a/plugins/impstats/impstats.c +++ b/plugins/impstats/impstats.c @@ -10,7 +10,7 @@ * of the "old" message code without any modifications. However, it * helps to have things at the right place one we go to the meat of it. * - * Copyright 2010 Rainer Gerhards and Adiscon GmbH. + * Copyright 2010-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * diff --git a/runtime/queue.c b/runtime/queue.c index 9012abeb..e97d78e8 100644 --- a/runtime/queue.c +++ b/runtime/queue.c @@ -12,7 +12,7 @@ * function names - this makes it really hard to read and does not provide much * benefit, at least I (now) think so... * - * Copyright 2008, 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2008-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -1312,6 +1312,7 @@ static int qqueueChkDiscardMsg(qqueue_t *pThis, int iQueueSize, void *pUsr) if(iRetLocal == RS_RET_OK && iSeverity >= pThis->iDiscardSeverity) { DBGOPRINT((obj_t*) pThis, "queue nearly full (%d entries), discarded severity %d message\n", iQueueSize, iSeverity); + STATSCOUNTER_INC(pThis->ctrNFDscrd, pThis->mutCtrNFDscrd); objDestruct(pUsr); ABORT_FINALIZE(RS_RET_QUEUE_FULL); } else { @@ -1936,6 +1937,13 @@ qqueueStart(qqueue_t *pThis) /* this is the ConstructionFinalizer */ CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("full"), ctrType_IntCtr, &pThis->ctrFull)); + STATSCOUNTER_INIT(pThis->ctrFDscrd, pThis->mutCtrFDscrd); + CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("discarded.full"), + ctrType_IntCtr, &pThis->ctrFDscrd)); + STATSCOUNTER_INIT(pThis->ctrNFDscrd, pThis->mutCtrNFDscrd); + CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("discarded.nf"), + ctrType_IntCtr, &pThis->ctrNFDscrd)); + pThis->ctrMaxqsize = 0; CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("maxqsize"), ctrType_Int, &pThis->ctrMaxqsize)); @@ -2289,6 +2297,7 @@ doEnqSingleObj(qqueue_t *pThis, flowControl_t flowCtlType, void *pUsr) // TODO : handle enqOnly => discard! if(pthread_cond_timedwait(&pThis->notFull, pThis->mut, &t) != 0) { DBGOPRINT((obj_t*) pThis, "enqueueMsg: cond timeout, dropping message!\n"); + STATSCOUNTER_INC(pThis->ctrFDscrd, pThis->mutCtrFDscrd); objDestruct(pUsr); ABORT_FINALIZE(RS_RET_QUEUE_FULL); } diff --git a/runtime/queue.h b/runtime/queue.h index 97057180..06a58229 100644 --- a/runtime/queue.h +++ b/runtime/queue.h @@ -169,6 +169,8 @@ struct queue_s { statsobj_t *statsobj; STATSCOUNTER_DEF(ctrEnqueued, mutCtrEnqueued); STATSCOUNTER_DEF(ctrFull, mutCtrFull); + STATSCOUNTER_DEF(ctrFDscrd, mutCtrFDscrd); + STATSCOUNTER_DEF(ctrNFDscrd, mutCtrNFDscrd); int ctrMaxqsize; }; -- cgit v1.2.3 From 7837c523b8da7ac90c6efbb3de12855978ecaecf Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 Dec 2011 12:34:19 +0100 Subject: additional counter for lost messages due to failed actions added --- action.c | 5 +++++ action.h | 1 + 2 files changed, 6 insertions(+) diff --git a/action.c b/action.c index 49eb3663..66d7b55c 100644 --- a/action.c +++ b/action.c @@ -341,6 +341,10 @@ actionConstructFinalize(action_t *pThis) CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("processed"), ctrType_IntCtr, &pThis->ctrProcessed)); + STATSCOUNTER_INIT(pThis->ctrFail, pThis->mutCtrFail); + CHKiRet(statsobj.AddCounter(pThis->statsobj, UCHAR_CONSTANT("failed"), + ctrType_IntCtr, &pThis->ctrFail)); + CHKiRet(statsobj.ConstructFinalize(pThis->statsobj)); /* create our queue */ @@ -1099,6 +1103,7 @@ submitBatch(action_t *pAction, batch_t *pBatch, int nElem) && pBatch->pElem[i].state != BATCH_STATE_COMM ) { pBatch->pElem[i].state = BATCH_STATE_BAD; pBatch->pElem[i].bPrevWasSuspended = 1; + STATSCOUNTER_INC(pAction->ctrFail, pAction->mutCtrFail); } } bDone = 1; diff --git a/action.h b/action.h index 310ef114..7a283a4a 100644 --- a/action.h +++ b/action.h @@ -92,6 +92,7 @@ struct action_s { /* for statistics subsystem */ statsobj_t *statsobj; STATSCOUNTER_DEF(ctrProcessed, mutCtrProcessed); + STATSCOUNTER_DEF(ctrFail, mutCtrFail); }; -- cgit v1.2.3 From 58d1c9e21b2c31a1f1f6631275a6f90886321269 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 Dec 2011 12:46:13 +0100 Subject: flagged special branch version --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 5a77a8a6..99d7b203 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],[5.8.6],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.8.6-newstats1],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -- cgit v1.2.3 From 32203be41af9c682a4f81c629f08b0593d755f69 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 Dec 2011 14:16:32 +0100 Subject: better performance for action stats & cleanup: removing debug prints --- action.c | 9 ++++++--- runtime/msg.c | 4 ---- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/action.c b/action.c index 66d7b55c..7226e7d6 100644 --- a/action.c +++ b/action.c @@ -1617,14 +1617,16 @@ doQueueEnqObjDirectBatch(action_t *pAction, batch_t *pBatch) pBatch->pElem[i].bFilterOK = 0; bModifiedFilter = 1; } - if(pBatch->pElem[i].bFilterOK) + if(pBatch->pElem[i].bFilterOK) { + STATSCOUNTER_INC(pAction->ctrProcessed, pAction->mutCtrProcessed); bNeedSubmit = 1; + } DBGPRINTF("action %p[%d]: filterOK:%d state:%d execWhenPrev:%d prevWasSusp:%d\n", pAction, i, pBatch->pElem[i].bFilterOK, pBatch->pElem[i].state, pAction->bExecWhenPrevSusp, pBatch->pElem[i].bPrevWasSuspended); } if(bNeedSubmit) { - countStatsBatchEnq(pAction, pBatch); + /* note: stats were already computed above */ iRet = qqueueEnqObjDirectBatch(pAction->pQueue, pBatch); } else { DBGPRINTF("no need to submit batch, all bFilterOK==0\n"); @@ -1639,7 +1641,8 @@ doQueueEnqObjDirectBatch(action_t *pAction, batch_t *pBatch) } } } else { - countStatsBatchEnq(pAction, pBatch); + if(GatherStats) + countStatsBatchEnq(pAction, pBatch); iRet = qqueueEnqObjDirectBatch(pAction->pQueue, pBatch); } diff --git a/runtime/msg.c b/runtime/msg.c index 0744edd5..759554d8 100644 --- a/runtime/msg.c +++ b/runtime/msg.c @@ -1671,8 +1671,6 @@ void MsgSetTAG(msg_t *pMsg, uchar* pszBuf, size_t lenBuf) uchar *pBuf; assert(pMsg != NULL); -dbgprintf("MsgSetTAG in: len %d, pszBuf: %s\n", lenBuf, pszBuf); - freeTAG(pMsg); pMsg->iLenTAG = lenBuf; @@ -1691,8 +1689,6 @@ dbgprintf("MsgSetTAG in: len %d, pszBuf: %s\n", lenBuf, pszBuf); memcpy(pBuf, pszBuf, pMsg->iLenTAG); pBuf[pMsg->iLenTAG] = '\0'; /* this also works with truncation! */ - -dbgprintf("MsgSetTAG exit: pMsg->iLenTAG %d, pMsg->TAG.szBuf: %s\n", pMsg->iLenTAG, pMsg->TAG.szBuf); } -- cgit v1.2.3 From 5ba3fc7238c49f8317ba4d694091d8a191744ed5 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 19 Dec 2011 17:08:06 +0100 Subject: imudp: stats added --- plugins/imudp/imudp.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index a5002591..32cd89d2 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -51,6 +51,7 @@ #include "datetime.h" #include "prop.h" #include "ruleset.h" +#include "statsobj.h" #include "unicode-helper.h" MODULE_TYPE_INPUT @@ -66,6 +67,10 @@ DEFobjCurrIf(net) DEFobjCurrIf(datetime) DEFobjCurrIf(prop) DEFobjCurrIf(ruleset) +DEFobjCurrIf(statsobj) + +statsobj_t *modStats; +STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit) static int bDoACLCheck; /* are ACL checks neeed? Cached once immediately before listener startup */ static int iMaxLine; /* maximum UDP message size supported */ @@ -377,6 +382,7 @@ processSocket(thrdInfo_t *pThrd, int fd, struct sockaddr_storage *frominetPrev, pMsg->msgFlags |= NEEDS_ACLCHK_U; /* request ACL check after resolution */ CHKiRet(msgSetFromSockinfo(pMsg, &frominet)); CHKiRet(submitMsg(pMsg)); + STATSCOUNTER_INC(ctrSubmit, mutCtrSubmit); } } @@ -622,9 +628,12 @@ ENDafterRun BEGINmodExit CODESTARTmodExit + statsobj.Destruct(&modStats); + /* release what we no longer need */ objRelease(errmsg, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); + objRelease(statsobj, CORE_COMPONENT); objRelease(datetime, CORE_COMPONENT); objRelease(prop, CORE_COMPONENT); objRelease(ruleset, CORE_COMPONENT); @@ -662,6 +671,7 @@ CODESTARTmodInit CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(statsobj, CORE_COMPONENT)); CHKiRet(objUse(datetime, CORE_COMPONENT)); CHKiRet(objUse(prop, CORE_COMPONENT)); CHKiRet(objUse(ruleset, CORE_COMPONENT)); @@ -682,6 +692,13 @@ CODEmodInit_QueryRegCFSLineHdlr NULL, &iTimeRequery, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); + + /* support statistics gathering */ + CHKiRet(statsobj.Construct(&modStats)); + CHKiRet(statsobj.SetName(modStats, UCHAR_CONSTANT("imudp"))); + CHKiRet(statsobj.AddCounter(modStats, UCHAR_CONSTANT("submitted"), + ctrType_IntCtr, &ctrSubmit)); + CHKiRet(statsobj.ConstructFinalize(modStats)); ENDmodInit /* vim:set ai: */ -- cgit v1.2.3 From 8d2f6675c47c0b7b6d7c644004507d0a85a90cb4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 20 Dec 2011 18:17:45 +0100 Subject: bugfix: stats counter were not properly initialized on creation --- ChangeLog | 1 + runtime/statsobj.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 26d6762a..598a9036 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ --------------------------------------------------------------------------- Version 5.8.7 [V5-stable] 2011-??-?? +- bugfix: stats counter were not properly initialized on creation - bugfix: potential abort after reading invalid X.509 certificate closes: http://bugzilla.adiscon.com/show_bug.cgi?id=290 Thanks to Tomas Heinrich for the patch diff --git a/runtime/statsobj.c b/runtime/statsobj.c index e1a89cf4..131605e0 100644 --- a/runtime/statsobj.c +++ b/runtime/statsobj.c @@ -154,9 +154,11 @@ addCounter(statsobj_t *pThis, uchar *ctrName, statsCtrType_t ctrType, void *pCtr switch(ctrType) { case ctrType_IntCtr: ctr->val.pIntCtr = (intctr_t*) pCtr; + *(ctr->val.pIntCtr) = 0; break; case ctrType_Int: ctr->val.pInt = (int*) pCtr; + *(ctr->val.pInt) = 0; break; } addCtrToList(pThis, ctr); -- cgit v1.2.3 From 832d6e1e2c88455be6bb0929591715499602ad56 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 20 Dec 2011 18:19:14 +0100 Subject: imtcp: added stats counters also adds counters to other users of tcpsrv.c method, but these do not work if default submit method is overwritten (currently only the case for imdiag, what we don't consider a problem) --- tcps_sess.c | 1 + tcpsrv.c | 15 ++++++++++++++- tcpsrv.h | 3 +++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tcps_sess.c b/tcps_sess.c index 99af0cb8..0fd3e713 100644 --- a/tcps_sess.c +++ b/tcps_sess.c @@ -259,6 +259,7 @@ defaultDoSubmitMessage(tcps_sess_t *pThis, struct syslogTime *stTime, time_t ttG CHKiRet(MsgSetRcvFromIP(pMsg, pThis->fromHostIP)); MsgSetRuleset(pMsg, pThis->pLstnInfo->pRuleset); + STATSCOUNTER_INC(pThis->pLstnInfo->ctrSubmit, pThis->pLstnInfo->mutCtrSubmit); if(pMultiSub == NULL) { CHKiRet(submitMsg(pMsg)); } else { diff --git a/tcpsrv.c b/tcpsrv.c index 0b822511..ca9d4192 100644 --- a/tcpsrv.c +++ b/tcpsrv.c @@ -36,8 +36,8 @@ * * A copy of the GPL can be found in the file "COPYING" in this distribution. */ - #include "config.h" +#include #include #include #include @@ -90,6 +90,7 @@ DEFobjCurrIf(netstrm) DEFobjCurrIf(nssel) DEFobjCurrIf(nspoll) DEFobjCurrIf(prop) +DEFobjCurrIf(statsobj) /* add new listener port to listener port list @@ -99,6 +100,7 @@ static inline rsRetVal addNewLstnPort(tcpsrv_t *pThis, uchar *pszPort) { tcpLstnPortList_t *pEntry; + uchar statname[64]; DEFiRet; ISOBJ_TYPE_assert(pThis, tcpsrv); @@ -118,6 +120,15 @@ addNewLstnPort(tcpsrv_t *pThis, uchar *pszPort) pEntry->pNext = pThis->pLstnPorts; pThis->pLstnPorts = pEntry; + /* support statistics gathering */ + CHKiRet(statsobj.Construct(&(pEntry->stats))); + snprintf((char*)statname, sizeof(statname), "%s(%s)", pThis->pszInputName, pszPort); + statname[sizeof(statname)-1] = '\0'; /* just to be on the save side... */ + CHKiRet(statsobj.SetName(pEntry->stats, statname)); + CHKiRet(statsobj.AddCounter(pEntry->stats, UCHAR_CONSTANT("submitted"), + ctrType_IntCtr, &(pEntry->ctrSubmit))); + CHKiRet(statsobj.ConstructFinalize(pEntry->stats)); + finalize_it: RETiRet; } @@ -1068,6 +1079,7 @@ CODESTARTObjClassExit(tcpsrv) objRelease(tcps_sess, DONT_LOAD_LIB); objRelease(conf, CORE_COMPONENT); objRelease(prop, CORE_COMPONENT); + objRelease(statsobj, CORE_COMPONENT); objRelease(ruleset, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); objRelease(errmsg, CORE_COMPONENT); @@ -1094,6 +1106,7 @@ BEGINObjClassInit(tcpsrv, 1, OBJ_IS_LOADABLE_MODULE) /* class, version - CHANGE CHKiRet(objUse(conf, CORE_COMPONENT)); CHKiRet(objUse(glbl, CORE_COMPONENT)); CHKiRet(objUse(ruleset, CORE_COMPONENT)); + CHKiRet(objUse(statsobj, CORE_COMPONENT)); CHKiRet(objUse(prop, CORE_COMPONENT)); /* set our own handlers */ diff --git a/tcpsrv.h b/tcpsrv.h index 57bdf4b1..6dc79897 100644 --- a/tcpsrv.h +++ b/tcpsrv.h @@ -25,6 +25,7 @@ #include "obj.h" #include "prop.h" #include "tcps_sess.h" +#include "statsobj.h" /* support for framing anomalies */ typedef enum ETCPsyslogFramingAnomaly { @@ -40,6 +41,8 @@ struct tcpLstnPortList_s { prop_t *pInputName; tcpsrv_t *pSrv; /**< pointer to higher-level server instance */ ruleset_t *pRuleset; /**< associated ruleset */ + statsobj_t *stats; /**< associated stats object */ + STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit) tcpLstnPortList_t *pNext; /**< next port or NULL */ }; -- cgit v1.2.3 From d61eb8067b11bdee20e64c73345df2537275e03a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 21 Dec 2011 14:48:54 +0100 Subject: prepared milestone (version push) --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 99d7b203..a4bc7f88 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],[5.8.6-newstats1],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.8.6-newstats2],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -- cgit v1.2.3 From 7774a3e8744f447f262dfbb834af626a94acced6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 8 Jan 2012 17:41:08 +0100 Subject: cleanup of imudp to use better lstn data structure (part I) --- plugins/imudp/imudp.c | 128 +++++++++++++++++++++++--------------------------- 1 file changed, 60 insertions(+), 68 deletions(-) diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 32cd89d2..3fb60727 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -72,15 +72,20 @@ DEFobjCurrIf(statsobj) statsobj_t *modStats; STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit) +static struct cnfinfo_s { +int udpLstnSocks; /* Internet datagram sockets, first element is nbr of elements + * read-only after init(), but beware of restart! */ +ruleset_t *udpRulesets; /* ruleset to be used with sockets in question (entry 0 is empty) */ +} *lcnfinfo = NULL; /**< the structure contains information needed to configure the listeners */ +static int nLstn = 0; /**< number of listners */ + 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 * This shall prevent remote DoS when the "discard on disallowed sender" * message is configured to be logged on occurance of such a case. */ -static int *udpLstnSocks = NULL; /* Internet datagram sockets, first element is nbr of elements - * read-only after init(), but beware of restart! */ -static ruleset_t **udpRulesets = NULL; /* ruleset to be used with sockets in question (entry 0 is empty) */ + static uchar *pszBindAddr = NULL; /* IP to bind socket to */ static uchar *pRcvBuf = NULL; /* receive buffer (for a single packet). We use a global and alloc * it so that we can check available memory in willRun() and request @@ -195,9 +200,9 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal) DEFiRet; uchar *bindAddr; int *newSocks; - int *tmpSocks; int iSrc, iDst; - ruleset_t **tmpRulesets; + struct cnfinfo_s *newlcnfinfo; + int newnLstn; /* 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 @@ -215,48 +220,34 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal) newSocks = net.create_udp_socket(bindAddr, (pNewVal == NULL || *pNewVal == '\0') ? (uchar*) "514" : pNewVal, 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] = pBindRuleset; + if(lcnfinfo == NULL) { + /* esay, src and dest are equal */ + nLstn = newSocks[0]; + CHKmalloc(lcnfinfo = (struct cnfinfo_s*) MALLOC(sizeof(struct cnfinfo_s) * nLstn)); + for(iDst = 0, iSrc=1 ; iDst < nLstn ; ++iDst, ++iSrc) { + lcnfinfo[iDst].udpLstnSocks = newSocks[iSrc]; + lcnfinfo[iDst].udpRulesets = 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] = pBindRuleset; - } - tmpSocks[0] = udpLstnSocks[0] + newSocks[0]; - free(newSocks); - free(udpLstnSocks); - udpLstnSocks = tmpSocks; - free(udpRulesets); - udpRulesets = tmpRulesets; + newnLstn = nLstn + newSocks[0]; + CHKmalloc(newlcnfinfo = (struct cnfinfo_s*) MALLOC(sizeof(struct cnfinfo_s) * newnLstn)); + /* ready to copy */ + iDst = 0; + memcpy(newlcnfinfo, lcnfinfo, nLstn * sizeof(struct cnfinfo_s)); + for(iSrc = 1 ; iSrc <= newSocks[0] ; ++iSrc, ++iDst) { + lcnfinfo[iDst].udpLstnSocks = newSocks[iSrc]; + lcnfinfo[iDst].udpRulesets = pBindRuleset; } + free(lcnfinfo); + lcnfinfo = newlcnfinfo; + nLstn = newnLstn; } } finalize_it: free(pNewVal); /* in any case, this is no longer needed */ + free(newSocks); RETiRet; } @@ -299,8 +290,7 @@ finalize_it: * on scheduling order. -- rgerhards, 2008-10-02 */ static inline rsRetVal -processSocket(thrdInfo_t *pThrd, int fd, struct sockaddr_storage *frominetPrev, int *pbIsPermitted, - ruleset_t *pRuleset) +processSocket(thrdInfo_t *pThrd, int idxLstn, struct sockaddr_storage *frominetPrev, int *pbIsPermitted) { DEFiRet; int iNbrTimeUsed; @@ -320,7 +310,7 @@ processSocket(thrdInfo_t *pThrd, int fd, struct sockaddr_storage *frominetPrev, if(pThrd->bShallStop == TRUE) ABORT_FINALIZE(RS_RET_FORCE_TERM); socklen = sizeof(struct sockaddr_storage); - lenRcvBuf = recvfrom(fd, (char*) pRcvBuf, iMaxLine, 0, (struct sockaddr *)&frominet, &socklen); + lenRcvBuf = recvfrom(lcnfinfo[idxLstn].udpLstnSocks, (char*) pRcvBuf, iMaxLine, 0, (struct sockaddr *)&frominet, &socklen); if(lenRcvBuf < 0) { if(errno != EINTR && errno != EAGAIN) { rs_strerror_r(errno, errStr, sizeof(errStr)); @@ -365,7 +355,7 @@ processSocket(thrdInfo_t *pThrd, int fd, struct sockaddr_storage *frominetPrev, *pbIsPermitted = 1; /* no check -> everything permitted */ } - DBGPRINTF("recv(%d,%d),acl:%d,msg:%s\n", fd, (int) lenRcvBuf, *pbIsPermitted, pRcvBuf); + DBGPRINTF("recv(%d,%d),acl:%d,msg:%s\n", lcnfinfo[idxLstn].udpLstnSocks, (int) lenRcvBuf, *pbIsPermitted, pRcvBuf); if(*pbIsPermitted != 0) { if((iTimeRequery == 0) || (iNbrTimeUsed++ % iTimeRequery) == 0) { @@ -375,7 +365,7 @@ processSocket(thrdInfo_t *pThrd, int fd, struct sockaddr_storage *frominetPrev, CHKiRet(msgConstructWithTime(&pMsg, &stTime, ttGenTime)); MsgSetRawMsg(pMsg, (char*)pRcvBuf, lenRcvBuf); MsgSetInputName(pMsg, pInputName); - MsgSetRuleset(pMsg, pRuleset); + MsgSetRuleset(pMsg, lcnfinfo[idxLstn].udpRulesets); MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY); pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME | NEEDS_DNSRESOL; if(*pbIsPermitted == 2) @@ -436,7 +426,8 @@ static void set_thread_schedparam(void) * interface. ./configure settings control which one is used. * rgerhards, 2009-09-09 */ -#if defined(HAVE_EPOLL_CREATE1) || defined(HAVE_EPOLL_CREATE) +//#if defined(HAVE_EPOLL_CREATE1) || defined(HAVE_EPOLL_CREATE) +#if 0 #define NUM_EPOLL_EVENTS 10 rsRetVal rcvMainLoop(thrdInfo_t *pThrd) { @@ -457,7 +448,7 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) bIsPermitted = 0; memset(&frominetPrev, 0, sizeof(frominetPrev)); - CHKmalloc(udpEPollEvt = calloc(udpLstnSocks[0], sizeof(struct epoll_event))); + CHKmalloc(udpEPollEvt = calloc(nLstn, sizeof(struct epoll_event))); #if defined(EPOLL_CLOEXEC) && defined(HAVE_EPOLL_CREATE1) DBGPRINTF("imudp uses epoll_create1()\n"); @@ -477,14 +468,14 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) /* fill the epoll set - we need to do this only once, as the set * can not change dyamically. */ - for (i = 0; i < *udpLstnSocks; i++) { - if (udpLstnSocks[i+1] != -1) { + for (i = 0; i < nLstn ; i++) { + if (lcnfinfo[i].udpLstnSocks != -1) { udpEPollEvt[i].events = EPOLLIN | EPOLLET; - udpEPollEvt[i].data.u64 = i+1; - if(epoll_ctl(efd, EPOLL_CTL_ADD, udpLstnSocks[i+1], &(udpEPollEvt[i])) < 0) { + udpEPollEvt[i].data.u64 = i; + if(epoll_ctl(efd, EPOLL_CTL_ADD, lcnfinfo[i].udpLstnSocks, &(udpEPollEvt[i])) < 0) { rs_strerror_r(errno, errStr, sizeof(errStr)); errmsg.LogError(errno, NO_ERRCODE, "epoll_ctrl failed on fd %d with %s\n", - udpLstnSocks[i+1], errStr); + lcnfinfo[i].udpLstnSocks, errStr); } } } @@ -498,8 +489,7 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) break; /* terminate input! */ for(i = 0 ; i < nfds ; ++i) { - processSocket(pThrd, udpLstnSocks[currEvt[i].data.u64], &frominetPrev, &bIsPermitted, - udpRulesets[currEvt[i].data.u64]); + processSocket(pThrd, (int)currEvt[i].data.u64, &frominetPrev, &bIsPermitted); } } @@ -540,12 +530,12 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) FD_ZERO(&readfds); /* Add the UDP listen sockets to the list of read descriptors. */ - for (i = 0; i < *udpLstnSocks; i++) { - if (udpLstnSocks[i+1] != -1) { + for (i = 0; i < nLstn ; i++) { + if (lcnfinfo[i].udpLstnSocks != -1) { if(Debug) - net.debugListenInfo(udpLstnSocks[i+1], "UDP"); - FD_SET(udpLstnSocks[i+1], &readfds); - if(udpLstnSocks[i+1]>maxfds) maxfds=udpLstnSocks[i+1]; + net.debugListenInfo(lcnfinfo[i].udpLstnSocks, "UDP"); + FD_SET(lcnfinfo[i].udpLstnSocks, &readfds); + if(lcnfinfo[i].udpLstnSocks>maxfds) maxfds=lcnfinfo[i].udpLstnSocks; } } if(Debug) { @@ -561,10 +551,9 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) if(glbl.GetGlobalInputTermState() == 1) break; /* terminate input! */ - for(i = 0; nfds && i < *udpLstnSocks; i++) { - if(FD_ISSET(udpLstnSocks[i+1], &readfds)) { - processSocket(pThrd, udpLstnSocks[i+1], &frominetPrev, &bIsPermitted, - udpRulesets[i+1]); + for(i = 0; nfds && i < nLstn ; i++) { + if(FD_ISSET(lcnfinfo[i].udpLstnSocks, &readfds)) { + processSocket(pThrd, i, &frominetPrev, &bIsPermitted); --nfds; /* indicate we have processed one descriptor */ } } @@ -597,7 +586,7 @@ CODESTARTwillRun net.HasRestrictions(UCHAR_CONSTANT("UDP"), &bDoACLCheck); /* UDP */ /* if we could not set up any listners, there is no point in running... */ - if(udpLstnSocks == NULL) + if(nLstn == 0) ABORT_FINALIZE(RS_RET_NO_RUN); iMaxLine = glbl.GetMaxLine(); @@ -611,12 +600,15 @@ BEGINafterRun CODESTARTafterRun /* do cleanup here */ net.clearAllowedSenders((uchar*)"UDP"); - if(udpLstnSocks != NULL) { - net.closeUDPListenSockets(udpLstnSocks); - udpLstnSocks = NULL; - free(udpRulesets); - udpRulesets = NULL; +#warning UDP listen socks must be cloesed! also select must be supported! +#if 0 + if(lcnfinfo.udpLstnSocks != NULL) { + net.closeUDPListenSockets(lcnfinfo.udpLstnSocks); + lcnfinfo.udpLstnSocks = NULL; + free(lcnfinfo.udpRulesets); + lcnfinfo.udpRulesets = NULL; } +#endif if(pRcvBuf != NULL) { free(pRcvBuf); pRcvBuf = NULL; -- cgit v1.2.3 From 6ea4cb7f5383f8c367be810fdc66650eeb9cc787 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sun, 8 Jan 2012 17:42:55 +0100 Subject: nit fixed (testing aid removed) --- plugins/imudp/imudp.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 3fb60727..6a6ab498 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -426,8 +426,7 @@ static void set_thread_schedparam(void) * interface. ./configure settings control which one is used. * rgerhards, 2009-09-09 */ -//#if defined(HAVE_EPOLL_CREATE1) || defined(HAVE_EPOLL_CREATE) -#if 0 +#if defined(HAVE_EPOLL_CREATE1) || defined(HAVE_EPOLL_CREATE) #define NUM_EPOLL_EVENTS 10 rsRetVal rcvMainLoop(thrdInfo_t *pThrd) { -- cgit v1.2.3 From 5438784b3ff566dc9efd863151ff782e2b9f4e45 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 9 Jan 2012 09:01:44 +0100 Subject: imudp refactor: fixed socket leak --- plugins/imudp/imudp.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 6a6ab498..f5a8a08d 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -596,18 +596,14 @@ ENDwillRun BEGINafterRun + int i; CODESTARTafterRun /* do cleanup here */ net.clearAllowedSenders((uchar*)"UDP"); -#warning UDP listen socks must be cloesed! also select must be supported! -#if 0 - if(lcnfinfo.udpLstnSocks != NULL) { - net.closeUDPListenSockets(lcnfinfo.udpLstnSocks); - lcnfinfo.udpLstnSocks = NULL; - free(lcnfinfo.udpRulesets); - lcnfinfo.udpRulesets = NULL; - } -#endif + for (i = 0; i < nLstn ; i++) + close(lcnfinfo[i].udpLstnSocks); + free(lcnfinfo); + lcnfinfo = NULL; if(pRcvBuf != NULL) { free(pRcvBuf); pRcvBuf = NULL; -- cgit v1.2.3 From c1ac395b0b6010938827225739d1861c2b1fa63a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 9 Jan 2012 09:36:15 +0100 Subject: imudp refactor: regression fix --- plugins/imudp/imudp.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index f5a8a08d..7068af0b 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -233,11 +233,11 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal) newnLstn = nLstn + newSocks[0]; CHKmalloc(newlcnfinfo = (struct cnfinfo_s*) MALLOC(sizeof(struct cnfinfo_s) * newnLstn)); /* ready to copy */ - iDst = 0; + iDst = nLstn; memcpy(newlcnfinfo, lcnfinfo, nLstn * sizeof(struct cnfinfo_s)); for(iSrc = 1 ; iSrc <= newSocks[0] ; ++iSrc, ++iDst) { - lcnfinfo[iDst].udpLstnSocks = newSocks[iSrc]; - lcnfinfo[iDst].udpRulesets = pBindRuleset; + newlcnfinfo[iDst].udpLstnSocks = newSocks[iSrc]; + newlcnfinfo[iDst].udpRulesets = pBindRuleset; } free(lcnfinfo); lcnfinfo = newlcnfinfo; -- cgit v1.2.3 From c0b3c93a8b16d4b7aaf912405fce77a4be365f0a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 9 Jan 2012 09:43:01 +0100 Subject: imudp refactor: field renaming (new names more more sense) --- plugins/imudp/imudp.c | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 7068af0b..0e6c6614 100644 --- a/plugins/imudp/imudp.c +++ b/plugins/imudp/imudp.c @@ -73,9 +73,8 @@ statsobj_t *modStats; STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit) static struct cnfinfo_s { -int udpLstnSocks; /* Internet datagram sockets, first element is nbr of elements - * read-only after init(), but beware of restart! */ -ruleset_t *udpRulesets; /* ruleset to be used with sockets in question (entry 0 is empty) */ + int sock; /* socket */ + ruleset_t *pRuleset; /* bound ruleset */ } *lcnfinfo = NULL; /**< the structure contains information needed to configure the listeners */ static int nLstn = 0; /**< number of listners */ @@ -225,8 +224,8 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal) nLstn = newSocks[0]; CHKmalloc(lcnfinfo = (struct cnfinfo_s*) MALLOC(sizeof(struct cnfinfo_s) * nLstn)); for(iDst = 0, iSrc=1 ; iDst < nLstn ; ++iDst, ++iSrc) { - lcnfinfo[iDst].udpLstnSocks = newSocks[iSrc]; - lcnfinfo[iDst].udpRulesets = pBindRuleset; + lcnfinfo[iDst].sock = newSocks[iSrc]; + lcnfinfo[iDst].pRuleset = pBindRuleset; } } else { /* we need to add them */ @@ -236,8 +235,8 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal) iDst = nLstn; memcpy(newlcnfinfo, lcnfinfo, nLstn * sizeof(struct cnfinfo_s)); for(iSrc = 1 ; iSrc <= newSocks[0] ; ++iSrc, ++iDst) { - newlcnfinfo[iDst].udpLstnSocks = newSocks[iSrc]; - newlcnfinfo[iDst].udpRulesets = pBindRuleset; + newlcnfinfo[iDst].sock = newSocks[iSrc]; + newlcnfinfo[iDst].pRuleset = pBindRuleset; } free(lcnfinfo); lcnfinfo = newlcnfinfo; @@ -310,7 +309,7 @@ processSocket(thrdInfo_t *pThrd, int idxLstn, struct sockaddr_storage *frominetP if(pThrd->bShallStop == TRUE) ABORT_FINALIZE(RS_RET_FORCE_TERM); socklen = sizeof(struct sockaddr_storage); - lenRcvBuf = recvfrom(lcnfinfo[idxLstn].udpLstnSocks, (char*) pRcvBuf, iMaxLine, 0, (struct sockaddr *)&frominet, &socklen); + lenRcvBuf = recvfrom(lcnfinfo[idxLstn].sock, (char*) pRcvBuf, iMaxLine, 0, (struct sockaddr *)&frominet, &socklen); if(lenRcvBuf < 0) { if(errno != EINTR && errno != EAGAIN) { rs_strerror_r(errno, errStr, sizeof(errStr)); @@ -355,7 +354,7 @@ processSocket(thrdInfo_t *pThrd, int idxLstn, struct sockaddr_storage *frominetP *pbIsPermitted = 1; /* no check -> everything permitted */ } - DBGPRINTF("recv(%d,%d),acl:%d,msg:%s\n", lcnfinfo[idxLstn].udpLstnSocks, (int) lenRcvBuf, *pbIsPermitted, pRcvBuf); + DBGPRINTF("recv(%d,%d),acl:%d,msg:%s\n", lcnfinfo[idxLstn].sock, (int) lenRcvBuf, *pbIsPermitted, pRcvBuf); if(*pbIsPermitted != 0) { if((iTimeRequery == 0) || (iNbrTimeUsed++ % iTimeRequery) == 0) { @@ -365,7 +364,7 @@ processSocket(thrdInfo_t *pThrd, int idxLstn, struct sockaddr_storage *frominetP CHKiRet(msgConstructWithTime(&pMsg, &stTime, ttGenTime)); MsgSetRawMsg(pMsg, (char*)pRcvBuf, lenRcvBuf); MsgSetInputName(pMsg, pInputName); - MsgSetRuleset(pMsg, lcnfinfo[idxLstn].udpRulesets); + MsgSetRuleset(pMsg, lcnfinfo[idxLstn].pRuleset); MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY); pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME | NEEDS_DNSRESOL; if(*pbIsPermitted == 2) @@ -468,13 +467,13 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) * can not change dyamically. */ for (i = 0; i < nLstn ; i++) { - if (lcnfinfo[i].udpLstnSocks != -1) { + if (lcnfinfo[i].sock != -1) { udpEPollEvt[i].events = EPOLLIN | EPOLLET; udpEPollEvt[i].data.u64 = i; - if(epoll_ctl(efd, EPOLL_CTL_ADD, lcnfinfo[i].udpLstnSocks, &(udpEPollEvt[i])) < 0) { + if(epoll_ctl(efd, EPOLL_CTL_ADD, lcnfinfo[i].sock, &(udpEPollEvt[i])) < 0) { rs_strerror_r(errno, errStr, sizeof(errStr)); errmsg.LogError(errno, NO_ERRCODE, "epoll_ctrl failed on fd %d with %s\n", - lcnfinfo[i].udpLstnSocks, errStr); + lcnfinfo[i].sock, errStr); } } } @@ -530,11 +529,11 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) /* Add the UDP listen sockets to the list of read descriptors. */ for (i = 0; i < nLstn ; i++) { - if (lcnfinfo[i].udpLstnSocks != -1) { + if (lcnfinfo[i].sock != -1) { if(Debug) - net.debugListenInfo(lcnfinfo[i].udpLstnSocks, "UDP"); - FD_SET(lcnfinfo[i].udpLstnSocks, &readfds); - if(lcnfinfo[i].udpLstnSocks>maxfds) maxfds=lcnfinfo[i].udpLstnSocks; + net.debugListenInfo(lcnfinfo[i].sock, "UDP"); + FD_SET(lcnfinfo[i].sock, &readfds); + if(lcnfinfo[i].sock>maxfds) maxfds=lcnfinfo[i].sock; } } if(Debug) { @@ -551,7 +550,7 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) break; /* terminate input! */ for(i = 0; nfds && i < nLstn ; i++) { - if(FD_ISSET(lcnfinfo[i].udpLstnSocks, &readfds)) { + if(FD_ISSET(lcnfinfo[i].sock, &readfds)) { processSocket(pThrd, i, &frominetPrev, &bIsPermitted); --nfds; /* indicate we have processed one descriptor */ } @@ -564,7 +563,7 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) #endif /* #if HAVE_EPOLL_CREATE1 */ /* This function is called to gather input. - * Note that udpLstnSocks must be non-NULL because otherwise we would not have + * Note that sock must be non-NULL because otherwise we would not have * indicated that we want to run (or we have a programming error ;)). -- rgerhards, 2008-10-02 */ BEGINrunInput @@ -601,7 +600,7 @@ CODESTARTafterRun /* do cleanup here */ net.clearAllowedSenders((uchar*)"UDP"); for (i = 0; i < nLstn ; i++) - close(lcnfinfo[i].udpLstnSocks); + close(lcnfinfo[i].sock); free(lcnfinfo); lcnfinfo = NULL; if(pRcvBuf != NULL) { -- cgit v1.2.3 From 355b6818b8ff08cd7e0d72f790bcc98504924e48 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 9 Jan 2012 11:55:57 +0100 Subject: imudp: added per-listner stats settings & more refactoring --- plugins/imudp/imudp.c | 154 ++++++++++++++++++++++++++------------------------ 1 file changed, 80 insertions(+), 74 deletions(-) diff --git a/plugins/imudp/imudp.c b/plugins/imudp/imudp.c index 0e6c6614..0db6bf9a 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-2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * @@ -26,6 +26,7 @@ * A copy of the GPL can be found in the file "COPYING" in this distribution. */ #include "config.h" +#include #include #include #include @@ -69,14 +70,14 @@ DEFobjCurrIf(prop) DEFobjCurrIf(ruleset) DEFobjCurrIf(statsobj) -statsobj_t *modStats; -STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit) -static struct cnfinfo_s { +static struct lstn_s { + struct lstn_s *next; int sock; /* socket */ ruleset_t *pRuleset; /* bound ruleset */ -} *lcnfinfo = NULL; /**< the structure contains information needed to configure the listeners */ -static int nLstn = 0; /**< number of listners */ + statsobj_t *stats; /* listener stats */ + STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit) +} *lcnfRoot = NULL, *lcnfLast = NULL; static int bDoACLCheck; /* are ACL checks neeed? Cached once immediately before listener startup */ static int iMaxLine; /* maximum UDP message size supported */ @@ -199,9 +200,11 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal) DEFiRet; uchar *bindAddr; int *newSocks; - int iSrc, iDst; - struct cnfinfo_s *newlcnfinfo; - int newnLstn; + int iSrc; + struct lstn_s *newlcnfinfo; + uchar *bindName; + uchar *port; + uchar statname[64]; /* 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 @@ -212,35 +215,37 @@ static rsRetVal addListner(void __attribute__((unused)) *pVal, uchar *pNewVal) bindAddr = NULL; else bindAddr = pszBindAddr; + bindName = (bindAddr == NULL) ? (uchar*)"*" : bindAddr; - DBGPRINTF("Trying to open syslog UDP ports at %s:%s.\n", - (bindAddr == NULL) ? (uchar*)"*" : bindAddr, pNewVal); + DBGPRINTF("Trying to open syslog UDP ports at %s:%s.\n", bindName, pNewVal); - newSocks = net.create_udp_socket(bindAddr, (pNewVal == NULL || *pNewVal == '\0') ? (uchar*) "514" : pNewVal, 1); + port = (pNewVal == NULL || *pNewVal == '\0') ? (uchar*) "514" : pNewVal; + newSocks = net.create_udp_socket(bindAddr, port, 1); if(newSocks != NULL) { /* we now need to add the new sockets to the existing set */ - if(lcnfinfo == NULL) { - /* esay, src and dest are equal */ - nLstn = newSocks[0]; - CHKmalloc(lcnfinfo = (struct cnfinfo_s*) MALLOC(sizeof(struct cnfinfo_s) * nLstn)); - for(iDst = 0, iSrc=1 ; iDst < nLstn ; ++iDst, ++iSrc) { - lcnfinfo[iDst].sock = newSocks[iSrc]; - lcnfinfo[iDst].pRuleset = pBindRuleset; - } - } else { - /* we need to add them */ - newnLstn = nLstn + newSocks[0]; - CHKmalloc(newlcnfinfo = (struct cnfinfo_s*) MALLOC(sizeof(struct cnfinfo_s) * newnLstn)); - /* ready to copy */ - iDst = nLstn; - memcpy(newlcnfinfo, lcnfinfo, nLstn * sizeof(struct cnfinfo_s)); - for(iSrc = 1 ; iSrc <= newSocks[0] ; ++iSrc, ++iDst) { - newlcnfinfo[iDst].sock = newSocks[iSrc]; - newlcnfinfo[iDst].pRuleset = pBindRuleset; - } - free(lcnfinfo); - lcnfinfo = newlcnfinfo; - nLstn = newnLstn; + /* ready to copy */ + for(iSrc = 1 ; iSrc <= newSocks[0] ; ++iSrc) { + CHKmalloc(newlcnfinfo = (struct lstn_s*) MALLOC(sizeof(struct lstn_s))); + newlcnfinfo->next = NULL; + newlcnfinfo->sock = newSocks[iSrc]; + newlcnfinfo->pRuleset = pBindRuleset; + /* support statistics gathering */ + CHKiRet(statsobj.Construct(&(newlcnfinfo->stats))); + snprintf((char*)statname, sizeof(statname), "imudp(%s:%s)", bindName, port); + statname[sizeof(statname)-1] = '\0'; /* just to be on the save side... */ + CHKiRet(statsobj.SetName(newlcnfinfo->stats, statname)); + CHKiRet(statsobj.AddCounter(newlcnfinfo->stats, UCHAR_CONSTANT("submitted"), + ctrType_IntCtr, &(newlcnfinfo->ctrSubmit))); + CHKiRet(statsobj.ConstructFinalize(newlcnfinfo->stats)); + /* link to list. Order must be preserved to take care for + * conflicting matches. + */ + if(lcnfRoot == NULL) + lcnfRoot = newlcnfinfo; + if(lcnfLast == NULL) + lcnfLast = newlcnfinfo; + else + lcnfLast->next = newlcnfinfo; } } @@ -289,7 +294,7 @@ finalize_it: * on scheduling order. -- rgerhards, 2008-10-02 */ static inline rsRetVal -processSocket(thrdInfo_t *pThrd, int idxLstn, struct sockaddr_storage *frominetPrev, int *pbIsPermitted) +processSocket(thrdInfo_t *pThrd, struct lstn_s *lstn, struct sockaddr_storage *frominetPrev, int *pbIsPermitted) { DEFiRet; int iNbrTimeUsed; @@ -309,7 +314,7 @@ processSocket(thrdInfo_t *pThrd, int idxLstn, struct sockaddr_storage *frominetP if(pThrd->bShallStop == TRUE) ABORT_FINALIZE(RS_RET_FORCE_TERM); socklen = sizeof(struct sockaddr_storage); - lenRcvBuf = recvfrom(lcnfinfo[idxLstn].sock, (char*) pRcvBuf, iMaxLine, 0, (struct sockaddr *)&frominet, &socklen); + lenRcvBuf = recvfrom(lstn->sock, (char*) pRcvBuf, iMaxLine, 0, (struct sockaddr *)&frominet, &socklen); if(lenRcvBuf < 0) { if(errno != EINTR && errno != EAGAIN) { rs_strerror_r(errno, errStr, sizeof(errStr)); @@ -354,7 +359,7 @@ processSocket(thrdInfo_t *pThrd, int idxLstn, struct sockaddr_storage *frominetP *pbIsPermitted = 1; /* no check -> everything permitted */ } - DBGPRINTF("recv(%d,%d),acl:%d,msg:%s\n", lcnfinfo[idxLstn].sock, (int) lenRcvBuf, *pbIsPermitted, pRcvBuf); + DBGPRINTF("recv(%d,%d),acl:%d,msg:%s\n", lstn->sock, (int) lenRcvBuf, *pbIsPermitted, pRcvBuf); if(*pbIsPermitted != 0) { if((iTimeRequery == 0) || (iNbrTimeUsed++ % iTimeRequery) == 0) { @@ -364,14 +369,14 @@ processSocket(thrdInfo_t *pThrd, int idxLstn, struct sockaddr_storage *frominetP CHKiRet(msgConstructWithTime(&pMsg, &stTime, ttGenTime)); MsgSetRawMsg(pMsg, (char*)pRcvBuf, lenRcvBuf); MsgSetInputName(pMsg, pInputName); - MsgSetRuleset(pMsg, lcnfinfo[idxLstn].pRuleset); + MsgSetRuleset(pMsg, lstn->pRuleset); MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY); pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME | NEEDS_DNSRESOL; if(*pbIsPermitted == 2) pMsg->msgFlags |= NEEDS_ACLCHK_U; /* request ACL check after resolution */ CHKiRet(msgSetFromSockinfo(pMsg, &frominet)); CHKiRet(submitMsg(pMsg)); - STATSCOUNTER_INC(ctrSubmit, mutCtrSubmit); + STATSCOUNTER_INC(lstn->ctrSubmit, lstn->mutCtrSubmit); } } @@ -438,6 +443,8 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) struct epoll_event *udpEPollEvt = NULL; struct epoll_event currEvt[NUM_EPOLL_EVENTS]; char errStr[1024]; + struct lstn_s *lstn; + int nLstn; /* start "name caching" algo by making sure the previous system indicator * is invalidated. @@ -446,6 +453,10 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) bIsPermitted = 0; memset(&frominetPrev, 0, sizeof(frominetPrev)); + /* count num listeners -- do it here in order to avoid inconsistency */ + nLstn = 0; + for(lstn = lcnfRoot ; lstn != NULL ; lstn = lstn->next) + ++nLstn; CHKmalloc(udpEPollEvt = calloc(nLstn, sizeof(struct epoll_event))); #if defined(EPOLL_CLOEXEC) && defined(HAVE_EPOLL_CREATE1) @@ -466,16 +477,18 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) /* fill the epoll set - we need to do this only once, as the set * can not change dyamically. */ - for (i = 0; i < nLstn ; i++) { - if (lcnfinfo[i].sock != -1) { + i = 0; + for(lstn = lcnfRoot ; lstn != NULL ; lstn = lstn->next) { + if(lstn->sock != -1) { udpEPollEvt[i].events = EPOLLIN | EPOLLET; - udpEPollEvt[i].data.u64 = i; - if(epoll_ctl(efd, EPOLL_CTL_ADD, lcnfinfo[i].sock, &(udpEPollEvt[i])) < 0) { + udpEPollEvt[i].data.u64 = (long long unsigned) lstn; + if(epoll_ctl(efd, EPOLL_CTL_ADD, lstn->sock, &(udpEPollEvt[i])) < 0) { rs_strerror_r(errno, errStr, sizeof(errStr)); errmsg.LogError(errno, NO_ERRCODE, "epoll_ctrl failed on fd %d with %s\n", - lcnfinfo[i].sock, errStr); + lstn->sock, errStr); } } + i++; } while(1) { @@ -487,7 +500,7 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) break; /* terminate input! */ for(i = 0 ; i < nfds ; ++i) { - processSocket(pThrd, (int)currEvt[i].data.u64, &frominetPrev, &bIsPermitted); + processSocket(pThrd, (struct lstn_s*)currEvt[i].data.u64, &frominetPrev, &bIsPermitted); } } @@ -504,10 +517,10 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) DEFiRet; int maxfds; int nfds; - int i; fd_set readfds; struct sockaddr_storage frominetPrev; int bIsPermitted; + struct lstn_s *lstn; /* start "name caching" algo by making sure the previous system indicator * is invalidated. @@ -518,22 +531,18 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) DBGPRINTF("imudp uses select()\n"); while(1) { - /* Add the Unix Domain Sockets to the list of read - * descriptors. - * rgerhards 2005-08-01: we must now check if there are - * any local sockets to listen to at all. If the -o option - * is given without -a, we do not need to listen at all.. + /* Add the Unix Domain Sockets to the list of read descriptors. */ maxfds = 0; FD_ZERO(&readfds); /* Add the UDP listen sockets to the list of read descriptors. */ - for (i = 0; i < nLstn ; i++) { - if (lcnfinfo[i].sock != -1) { + for(lstn = lcnfRoot ; lstn != NULL ; lstn = lstn->next) { + if (lstn->sock != -1) { if(Debug) - net.debugListenInfo(lcnfinfo[i].sock, "UDP"); - FD_SET(lcnfinfo[i].sock, &readfds); - if(lcnfinfo[i].sock>maxfds) maxfds=lcnfinfo[i].sock; + net.debugListenInfo(lstn->sock, "UDP"); + FD_SET(lstn->sock, &readfds); + if(lstn->sock>maxfds) maxfds=lstn->sock; } } if(Debug) { @@ -549,9 +558,9 @@ rsRetVal rcvMainLoop(thrdInfo_t *pThrd) if(glbl.GetGlobalInputTermState() == 1) break; /* terminate input! */ - for(i = 0; nfds && i < nLstn ; i++) { - if(FD_ISSET(lcnfinfo[i].sock, &readfds)) { - processSocket(pThrd, i, &frominetPrev, &bIsPermitted); + for(lstn = lcnfRoot ; nfds && lstn != NULL ; lstn = lstn->next) { + if(FD_ISSET(lstn->sock, &readfds)) { + processSocket(pThrd, lstn, &frominetPrev, &bIsPermitted); --nfds; /* indicate we have processed one descriptor */ } } @@ -584,8 +593,10 @@ CODESTARTwillRun net.HasRestrictions(UCHAR_CONSTANT("UDP"), &bDoACLCheck); /* UDP */ /* if we could not set up any listners, there is no point in running... */ - if(nLstn == 0) + if(lcnfRoot == NULL) { + DBGPRINTF("imudp: no listeners configured, will not run\n"); ABORT_FINALIZE(RS_RET_NO_RUN); + } iMaxLine = glbl.GetMaxLine(); @@ -595,14 +606,18 @@ ENDwillRun BEGINafterRun - int i; + struct lstn_s *lstn, *lstnDel; CODESTARTafterRun /* do cleanup here */ net.clearAllowedSenders((uchar*)"UDP"); - for (i = 0; i < nLstn ; i++) - close(lcnfinfo[i].sock); - free(lcnfinfo); - lcnfinfo = NULL; + for(lstn = lcnfRoot ; lstn != NULL ; ) { + statsobj.Destruct(&(lstn->stats)); + close(lstn->sock); + lstnDel = lstn; + lstn = lstn->next; + free(lstnDel); + } + lcnfRoot = lcnfLast = NULL; if(pRcvBuf != NULL) { free(pRcvBuf); pRcvBuf = NULL; @@ -614,8 +629,6 @@ ENDafterRun BEGINmodExit CODESTARTmodExit - statsobj.Destruct(&modStats); - /* release what we no longer need */ objRelease(errmsg, CORE_COMPONENT); objRelease(glbl, CORE_COMPONENT); @@ -678,13 +691,6 @@ CODEmodInit_QueryRegCFSLineHdlr NULL, &iTimeRequery, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); - - /* support statistics gathering */ - CHKiRet(statsobj.Construct(&modStats)); - CHKiRet(statsobj.SetName(modStats, UCHAR_CONSTANT("imudp"))); - CHKiRet(statsobj.AddCounter(modStats, UCHAR_CONSTANT("submitted"), - ctrType_IntCtr, &ctrSubmit)); - CHKiRet(statsobj.ConstructFinalize(modStats)); ENDmodInit /* vim:set ai: */ -- cgit v1.2.3 From 785e107502f58808152b3134915fd3c986b1ed27 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 9 Jan 2012 12:39:02 +0100 Subject: push version number --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index a4bc7f88..dd305221 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],[5.8.6-newstats2],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.8.6-newstats3],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -- cgit v1.2.3 From 6766b6f3e7cf0331eea40403bae8145ac1fd805c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 9 Jan 2012 13:47:54 +0100 Subject: Merge v5-stable-newstats & manual ChangeLog update --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 641d6bea..ad6de170 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ --------------------------------------------------------------------------- Version 5.9.5 [V5-DEVEL], 2011-11-29 +- new stats counters for imudp and imtcp - new stats counters "discarded.nf" and "discarded.full" for queue object. Tells how many messages have been discarded due to queue full condition. --------------------------------------------------------------------------- -- cgit v1.2.3 From 4ccbb80ca13104d088e1c7c4916d4b57af642650 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 9 Jan 2012 15:59:01 +0100 Subject: removed imtemplate/omtemplate template modules, as this was waste of time The actual input/output modules are better copy templates. Instead, the now-removed modules cost time for maintenance AND often caused confusion on what their role was. --- ChangeLog | 4 + Makefile.am | 10 - configure.ac | 46 +--- plugins/imtemplate/Makefile.am | 6 - plugins/imtemplate/imtemplate.c | 467 ---------------------------------------- plugins/omtemplate/Makefile.am | 8 - plugins/omtemplate/omtemplate.c | 234 -------------------- 7 files changed, 5 insertions(+), 770 deletions(-) delete mode 100644 plugins/imtemplate/Makefile.am delete mode 100644 plugins/imtemplate/imtemplate.c delete mode 100644 plugins/omtemplate/Makefile.am delete mode 100644 plugins/omtemplate/omtemplate.c diff --git a/ChangeLog b/ChangeLog index 110745ac..b42a8004 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ --------------------------------------------------------------------------- Version 6.3.7 [DEVEL] 2011-0?-?? +- removed imtemplate/omtemplate template modules, as this was waste of time + The actual input/output modules are better copy templates. Instead, the + now-removed modules cost time for maintenance AND often caused confusion + on what their role was. - added a couple of new stats objects - improved support for new v6 config system. Now also supported by - omfwd diff --git a/Makefile.am b/Makefile.am index 7bf9dd0e..49ece3a8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -116,10 +116,6 @@ if ENABLE_SMCUSTBINDCDR SUBDIRS += plugins/sm_cust_bindcdr endif -if ENABLE_IMTEMPLATE -SUBDIRS += plugins/imtemplate -endif - if ENABLE_OMSTDOUT SUBDIRS += plugins/omstdout endif @@ -164,10 +160,6 @@ if ENABLE_OMHDFS SUBDIRS += plugins/omhdfs endif -if ENABLE_OMTEMPLATE -SUBDIRS += plugins/omtemplate -endif - if ENABLE_MMSNMPTRAPD SUBDIRS += plugins/mmsnmptrapd endif @@ -250,8 +242,6 @@ DISTCHECK_CONFIGURE_FLAGS= --enable-gssapi_krb5 \ --enable-pmaixforwardedfrom \ --enable-pmcisconames \ --enable-pmsnare \ - --enable-imtemplate \ - --enable-omtemplate \ --enable-mmsnmptrapd \ --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index 40f5bc8f..89177fc3 100644 --- a/configure.ac +++ b/configure.ac @@ -1130,46 +1130,6 @@ AC_ARG_ENABLE(smcustbindcdr, AM_CONDITIONAL(ENABLE_SMCUSTBINDCDR, test x$enable_smcustbindcdr = xyes) -# settings for the template input module; copy and modify this code -# if you intend to add your own module. Be sure to replace imtemplate -# by the actual name of your module. -AC_ARG_ENABLE(imtemplate, - [AS_HELP_STRING([--enable-imtemplate],[Compiles imtemplate template module @<:@default=no@:>@])], - [case "${enableval}" in - yes) enable_imtemplate="yes" ;; - no) enable_imtemplate="no" ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-imtemplate) ;; - esac], - [enable_imtemplate=no] -) -# -# you may want to do some library checks here - see snmp, mysql, pgsql modules -# for samples -# -AM_CONDITIONAL(ENABLE_IMTEMPLATE, test x$enable_imtemplate = xyes) -# end of copy template - be sure to search for imtemplate to find everything! - - -# settings for the template output module; copy and modify this code -# if you intend to add your own module. Be sure to replace omtemplate -# by the actual name of your module. -AC_ARG_ENABLE(omtemplate, - [AS_HELP_STRING([--enable-omtemplate],[Compiles omtemplate template module @<:@default=no@:>@])], - [case "${enableval}" in - yes) enable_omtemplate="yes" ;; - no) enable_omtemplate="no" ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-omtemplate) ;; - esac], - [enable_omtemplate=no] -) -# -# you may want to do some library checks here - see snmp, mysql, pgsql modules -# for samples -# -AM_CONDITIONAL(ENABLE_OMTEMPLATE, test x$enable_omtemplate = xyes) -# end of copy template - be sure to search for omtemplate to find everything! - - # settings for mmsnmptrapd message modification module AC_ARG_ENABLE(mmsnmptrapd, [AS_HELP_STRING([--enable-mmsnmptrapd],[Compiles mmsnmptrapd module @<:@default=no@:>@])], @@ -1216,7 +1176,7 @@ AC_ARG_ENABLE(ommongodb, # for samples # AM_CONDITIONAL(ENABLE_OMMONGODB, test x$enable_ommongodb = xyes) -# end of copy template - be sure to search for omtemplate to find everything! +# end of mongodb code AC_CONFIG_FILES([Makefile \ @@ -1231,8 +1191,6 @@ AC_CONFIG_FILES([Makefile \ plugins/imuxsock/Makefile \ plugins/immark/Makefile \ plugins/imklog/Makefile \ - plugins/imtemplate/Makefile \ - plugins/omtemplate/Makefile \ plugins/omhdfs/Makefile \ plugins/omprog/Makefile \ plugins/omstdout/Makefile \ @@ -1290,7 +1248,6 @@ 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 " input template module will be compiled: $enable_imtemplate" echo echo "---{ output plugins }---" echo " Mail support enabled: $enable_mail" @@ -1302,7 +1259,6 @@ echo " omruleset module will be compiled: $enable_omruleset" echo " omdbalerting module will be compiled: $enable_omdbalerting" echo " omudpspoof module will be compiled: $enable_omudpspoof" echo " omuxsock module will be compiled: $enable_omuxsock" -echo " output template module will be compiled: $enable_omtemplate" echo echo "---{ parser modules }---" echo " pmrfc3164sd module will be compiled: $enable_pmrfc3164sd" diff --git a/plugins/imtemplate/Makefile.am b/plugins/imtemplate/Makefile.am deleted file mode 100644 index 1825b5bc..00000000 --- a/plugins/imtemplate/Makefile.am +++ /dev/null @@ -1,6 +0,0 @@ -pkglib_LTLIBRARIES = imtemplate.la - -imtemplate_la_SOURCES = imtemplate.c -imtemplate_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) -imtemplate_la_LDFLAGS = -module -avoid-version -imtemplate_la_LIBADD = diff --git a/plugins/imtemplate/imtemplate.c b/plugins/imtemplate/imtemplate.c deleted file mode 100644 index 8d8b8ac4..00000000 --- a/plugins/imtemplate/imtemplate.c +++ /dev/null @@ -1,467 +0,0 @@ -/* imtemplate.c - * - * This is NOT a real input module but a (copy)-template to create one. Please - * do NOT edit this file directly. Rather, copy it, together with the rest of - * the directory, to a new location ./plugins/im, then replace - * all references to imtemplate in Makefile.am to im. Be sure to - * fix the copyright notices to gain proper credit ;) Any derived version, - * however, needs to be placed under GPLv3 (see GPLv3 for details). If you - * do not like that policy, do not use this template or any of the header - * files. The rsyslog project greatly appreciates module contributions, so - * please consider contributing your work - even if you may think it only - * server a single very special purpose. It has turned out that at least some - * folks have similiar special purposes ;) - * - * IMPORTANT - * The comments in this file are actually the interface specification. I decided - * not to put it into a separate file as it is much simpler to keep it up to - * date when it is part of the actual template module. - * - * NAMING - * All input modules shall be named im. While this is not a hard - * requirement, it helps keeping track of things. - * - * Global variables and functions should have a prefix - use as somewhat - * longer one to prevent conflicts with rsyslog itself and other modules - * (OK, hopefully I'll have some more precise advise in the future...). - * - * INCLUDE MODULE IN THE MAIN MAKE SCRIPT - * If the module shall be provided as part of rsyslog (or simply as a build aid, - * you need to add it to the main autoconf files). To do so, you need to edit - * Makefile.am and configure.ac in the main directory. Search for imtemplate - * and copy/modify the relevant code for your plugin. - * - * DEBUGGING - * While you develop your code, you may want to add - * --enable-debug --enable-rtinst - * to your ./configure settings. These enable extra run-time checks, which cost - * a lot of performance but can help detect some of the most frequently made - * bugs. These settings will also provide you with a nice stack dump if something - * goes really wrong. - * - * MORE SAMPLES - * Remember that rsyslog ships with a number of input modules (./plugins/im*). It - * is always a good idea to have a look at them before starting your own. imudp - * may be a good, relatively trivial, sample. - * - * -------------------------------------------------------------------------------- - * - * This template was cretead on 2008-02-01 by Rainer Gerhards. - * - * Copyright 2008 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of rsyslog. - * - * Rsyslog is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Rsyslog is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Rsyslog. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - */ -#include "config.h" /* this is for autotools and always must be the first include */ -#include -#include -#include -#include -#include /* do NOT remove: will soon be done by the module generation macros */ -#include "rsyslog.h" /* error codes etc... */ -#include "cfsysline.h" /* access to config file objects */ -#include "module-template.h" /* generic module interface code - very important, read it! */ -#include "srUtils.h" /* some utility functions */ -#include "debug.h" /* some debug helper functions */ - -MODULE_TYPE_INPUT /* must be present for input modules, do not remove */ -MODULE_TYPE_NOKEEP -MODULE_CNFNAME("imtemplate") - -/* defines */ - -/* Module static data */ -DEF_IMOD_STATIC_DATA /* must be present, starts static data */ - -/* Here, define whatever static data is needed. Is it suggested that static variables only are - * used (not externally visible). If you need externally visible variables, make sure you use a - * prefix in order not to conflict with other modules or rsyslogd itself (also see comment - * at file header). - */ -/* static int imtemplateWhateverVar = 0; */ - -/* config settings */ -struct modConfData_s { - EMPTY_STRUCT; -}; - - -#if 0 /* can be used to integrate into new config system */ -BEGINbeginCnfLoad -CODESTARTbeginCnfLoad -ENDbeginCnfLoad - - -BEGINendCnfLoad -CODESTARTendCnfLoad -ENDendCnfLoad - - -BEGINcheckCnf -CODESTARTcheckCnf -ENDcheckCnf - - -BEGINactivateCnf -CODESTARTactivateCnf -ENDactivateCnf - - -BEGINfreeCnf -CODESTARTfreeCnf -ENDfreeCnf -#endif - - -/* You may add any functions that you feel are useful for your needs. No specific restrictions - * apply, but we suggest that you use the "iRet" call order, which enables you to use debug - * support for your own functions and which also makes it easy to communicate exceptions back - * to the upstream caller (rsyslog framework, for example. - * - * The function below is a sample of how one of your functions may look like. Again, the sample - * below is *not* needed to be present in order to meet the interface requirements. - * - * Be sure to use static functions (suggested) or prefixes to prevent name conflicts -- see file - * header for more information. - */ -static rsRetVal /* rsRetVal is our generic error-reporting return type */ -imtemplateMyFunc(int iMyParam) -{ - DEFiRet; /* define iRet, the return code and other plumbing */ - /* define your local variables here */ - - /* code whatever you need to code here. The "iRet" system can be helpful: - * - * CHKiRet(function(param1, param2, ...)); - * calls a function and checks if it returns RS_RET_OK. If so, work - * proceeds. If some other code is returned, the function is aborted - * and control transferred to finalize_it (which you need to define) - * - * CHKiRet_Hdlr(function(param1, param2, ...)) - * much like CHKiRet, but allows you to specify your own code that is - * executed if the function does not return RS_RET_OK, e.g.: - * CHKiRet_Hdlr(function(a, b)) { - * ... some error handling here ... - * } - * control is not transferred to finalize_it, except if you use one - * of the relevant macros (described below) - * - * FINALIZE - * immediately transfers control to finalize_it, using the current - * value of iRet, e.g. - * if(bDone) - * FINALIZE; - * - * ABORT_FINALIZE(retcode) - * just like FINALIZE, except that iRet is set to the provided error - * code before control is transferred, e.g. - * if((ptr = MALLOC(20)) == NULL) - * ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); - * - * In order for all this to work, you need to define finalize_it, e.g. - * - * finalize_it: - * RETiRet; - * - * RETiRet does some housekeeping and then does a "return iRet" to transfer - * control back to the caller. There shall only be one function exit and - * it shall be via RETiRet, preferrably at the end of the function code. - * - */ - -finalize_it: - /* clean up anything that needs to be cleaned up if processing did not - * go well, for example: - */ - if(iRet != RS_RET_OK) { - /* cleanup, e.g. - * free(somePtr); - */ - } - - RETiRet; -} - - -/* 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 - * in the middle of what it was doing. The cancel cleanup handler below should take - * care of any locked mutexes and such, things that really need to be cleaned up - * before processing continues. In general, many plugins do not need to provide - * any code at all here. - * - * IMPORTANT: the calling interface of this function can NOT be modified. It actually is - * called by pthreads. The provided argument is currently not being used. - */ -/* ------------------------------------------------------------------------------------------ * - * DO NOT TOUCH the following code - it will soon be part of the module generation macros! */ -static void -inputModuleCleanup(void *arg) -{ - BEGINfunc -/* END no-touch zone * - * ------------------------------------------------------------------------------------------ */ - - - - /* your code here */ - - - -/* ------------------------------------------------------------------------------------------ * - * DO NOT TOUCH the following code - it will soon be part of the module generation macros! */ - ENDfunc -} -/* END no-touch zone * - * ------------------------------------------------------------------------------------------ */ - - -/* This function is called by the framework to gather the input. The module stays - * most of its lifetime inside this function. It MUST NEVER exit this function. Doing - * so would end module processing and rsyslog would NOT reschedule the module. If - * you exit from this function, you violate the interface specification! - * - * So how is it terminated? When it is time to terminate, rsyslog actually cancels - * the threads. This may sound scary, but is not. There is a cancel cleanup handler - * defined (the function directly above). See comments there for specifics. - * - * runInput is always called on a single thread. If the module neees multiple threads, - * it is free to create them. HOWEVER, it must make sure that any threads created - * are killed and joined in the cancel cleanup handler. - */ -BEGINrunInput - /* define any local variables you need here */ -CODESTARTrunInput - /* ------------------------------------------------------------------------------------------ * - * DO NOT TOUCH the following code - it will soon be part of the module generation macros! */ - pthread_cleanup_push(inputModuleCleanup, NULL); - while(1) { /* endless loop - do NOT break; out of it! */ - /* END no-touch zone * - * ------------------------------------------------------------------------------------------ */ - - /* your code here */ - - /* All rsyslog objects (see other modules, e.g. msg.c) are available - * to your here. Some useful things are: - * - * errmsg.LogError(NO_ERRCODE, format-string, ... params ...); - * logs an error message as syslogd, just as printf, e.g. - * errmsg.LogError(NO_ERRCODE, "Error %d occured during %s", 1, "test"); - * - * To submit the message to the queue engine, we must create the message - * object and fill it with data. If it contains a syslog message that must - * be parsed, we can add a flag that requests parsing. Otherwise, we must - * fill the properties ourselves. That is appropriate if the message - * does not need to be parsed, for example when reading text (log) files. In that way, - * we can set the message properties as of our liking. This is how it works: - * - msg_t *pMsg; - CHKiRet(msgConstruct(&pMsg)); - MsgSetRawMsg(pMsg, msg); - MsgSetHOSTNAME(pMsg, LocalHostName); - MsgSetTAG(pMsg, "rsyslogd:"); - pMsg->iFacility = LOG_FAC(pri); - pMsg->iSeverity = LOG_PRI(pri); - flags |= INTERNAL_MSG; - logmsg(pMsg, flags); / * some time, CHKiRet() will work here, too [today NOT!] * / - * - * NOTE: for up-to-date usage samples, see the other provided input modules. - * A good starting point is probably imuxsock. - * - * This example probably does not set all message properties (but the ones - * that are of practical importance). If you need all, check msg.h. Use - * method access functions whereever possible, unfortunately not all structure - * members are currently exposed in that clean way - so you sometimes need - * to access them directly (it goes without saying that we will fix that - * over time ;)). - */ - - /* ------------------------------------------------------------------------------------------ * - * DO NOT TOUCH the following code - it will soon be part of the module generation macros! */ - } - /*NOTREACHED*/ - - pthread_cleanup_pop(0); /* just for completeness, but never called... */ - RETiRet; /* use it to make sure the housekeeping is done! */ -ENDrunInput - /* END no-touch zone * - * ------------------------------------------------------------------------------------------ */ - - -/* The function is called by rsyslog before runInput() is called. It is a last chance - * to set up anything specific. Most importantly, it can be used to tell rsyslog if the - * input shall run or not. The idea is that if some config settings (or similiar things) - * are not OK, the input can tell rsyslog it will not execute. To do so, return - * RS_RET_NO_RUN or a specific error code. If RS_RET_OK is returned, rsyslog will - * proceed and call the runInput() entry point. If you do not return anything - * specific, RS_RET_OK is automatically returned (as in all functions). - */ -BEGINwillRun - /* place any variables needed here */ -CODESTARTwillRun - - /* ... your code here ... */ - - /* Just to give you an idea, here are some samples (from the actual imudp module: - * - if(udpLstnSocks == NULL) - ABORT_FINALIZE(RS_RET_NO_RUN); - - if((pRcvBuf = MALLOC(glbl.GetMaxLine * sizeof(char))) == NULL) { - ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); - } - * - */ -finalize_it: -ENDwillRun - - -/* This function is called by the framework after runInput() has been terminated. It - * shall free any resources and prepare the module for unload. - * - * So it is important that runInput() keeps track of what needs to be cleaned up. - * Objects to think about are files (must be closed), network connections, threads (must - * be stopped and joined) and memory (must be freed). Of course, there are a myriad - * of other things, so use your own judgement what you need to do. - * - * Another important chore of this function is to persist whatever state the module - * needs to persist. Unfortunately, there is currently no standard way of doing that. - * Future version of the module interface will probably support it, but that doesn't - * help you right at the moment. In general, it is suggested that anything that needs - * to be persisted is saved in a file, whose name and location is passed in by a - * module-specific config directive. - */ -BEGINafterRun - /* place any variables needed here */ -CODESTARTafterRun - - /* ... do cleanup here ... */ - - /* if you have a string config variable, remember to free its content: - * - if(pszStr != NULL) { - free(pszStr); - pszStr = NULL; - } - */ -ENDafterRun - - -/* The following entry points are defined in module-template.h. - * In general, they need to be present, but you do NOT need to provide - * any code here. - */ -BEGINmodExit -CODESTARTmodExit -ENDmodExit - - -BEGINqueryEtryPt -CODESTARTqueryEtryPt -CODEqueryEtryPt_STD_IMOD_QUERIES -ENDqueryEtryPt - - -/* The following function shall reset all configuration variables to their - * default values. The code provided in modInit() below registers it to be - * called on "$ResetConfigVariables". You may also call it from other places, - * 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) -{ - DEFiRet; - - /* if you have string variables in you config settings, you need to do this: - if(pszStr != NULL) { - free(pszStr); - pszStr = NULL; - } - * Note that it is vitally important that the pointer is set to NULL, because - * otherwise the framework handler will try to free it a second time when - * a new value is set! - */ - - - /* ... your code here ... */ - - - 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 - * complexity of processing is depending on the actual module. However, only - * thing absolutely necessary should be done here. Actual app-level processing - * is to be performed in runInput(). A good sample of what to do here may be to - * set some variable defaults. The most important thing probably is registration - * of config command handlers. - */ -BEGINmodInit() -CODESTARTmodInit - *ipIFVersProvided = 1; /* interface spec version this module is written to (currently always 1) */ -CODEmodInit_QueryRegCFSLineHdlr - /* register config file handlers - * For details, see cfsysline.c/.h. The config file is automatically handled. In general, - * a pointer to a variable receiving the value and the config directive is to be supplied. - * A custom function pointer can only be provided, which then is called when the config - * directive appears. Limit this to cases where it is absolutely necessary. The - * STD_LOADABLE_MODULE_ID is a value that identifies the module. It is use to automatically - * unregister the module's config file handlers upon module unload. Do NOT use any other - * value for this parameter! Available Syntaxes (supported types) can be seen in cfsysline.h, - * the ecslCmdHdrlType enum has all that are currently defined. - * - * Config file directives should always be along the lines of - * - * $InputObjObjName - * - * An example would be $InputImtemplateRetriesMax. This is currently not enforced, - * but when we get to our new config file format and reader, this becomes quite - * important. - * - * Please note that config directives must be provided in lower case. The engine - * makes the mapping (what currently means case-insensitive comparison). The dollar - * sign is NOT part of the directive and thus not specified. - * - * Some samples: - * - * A hypothetical integer variable: - * CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputimtemplatemessagenumber", 0, eCmdHdlrInt, - NULL, &intVariable, STD_LOADABLE_MODULE_ID)); - * - * and a hypothetical string variable: - * CHKiRet(omsdRegCFSLineHdlr((uchar *)"inputimtemplatemessagetext", 0, eCmdHdlrGetWord, - * NULL, &pszBindAddr, STD_LOADABLE_MODULE_ID)); - */ - - /* whenever config variables exist, they should be resettable via $ResetConfigVariables. - * The following line adds our handler for that. Note that if you do not have any config - * variables at all (unlikely, I think...), you can remove this handler. - */ - CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, - resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjGlobal)); - - /* ... do whatever else you need to do, but keep it brief ... */ - -ENDmodInit -/* - * vim:set ai: - */ diff --git a/plugins/omtemplate/Makefile.am b/plugins/omtemplate/Makefile.am deleted file mode 100644 index e816c7c6..00000000 --- a/plugins/omtemplate/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -pkglib_LTLIBRARIES = omtemplate.la - -omtemplate_la_SOURCES = omtemplate.c -omtemplate_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) -omtemplate_la_LDFLAGS = -module -avoid-version -omtemplate_la_LIBADD = - -EXTRA_DIST = diff --git a/plugins/omtemplate/omtemplate.c b/plugins/omtemplate/omtemplate.c deleted file mode 100644 index 09320a72..00000000 --- a/plugins/omtemplate/omtemplate.c +++ /dev/null @@ -1,234 +0,0 @@ -/* omtemplate.c - * This is a template for an output module. It implements a very - * simple single-threaded output, just as thought of by the output - * plugin interface. - * - * NOTE: read comments in module-template.h for more specifics! - * - * File begun on 2009-03-16 by RGerhards - * - * Copyright 2009 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of rsyslog. - * - * Rsyslog is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Rsyslog is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Rsyslog. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - */ -#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" - -MODULE_TYPE_OUTPUT -MODULE_TYPE_NOKEEP -MODULE_CNFNAME("omtemplate") - -static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); - -/* internal structures - */ -DEF_OMOD_STATIC_DATA -DEFobjCurrIf(errmsg) - -typedef struct _instanceData { - /* here you need to define all action-specific data. A record of type - * instanceData will be handed over to each instance of the action. Keep - * in mind that there may be several invocations of the same type of action - * inside rsyslog.conf, and this is what keeps them apart. Do NOT use - * static data for this! - */ - unsigned iSrvPort; /* sample: server port */ -} instanceData; - -/* config variables - * For the configuration interface, we need to keep track of some settings. This - * is done in global variables, inside a struct. It works as follows: when configuration statements - * are entered, the config file handler (or custom function) sets the global - * variable here. When the action then actually is instantiated, this handler - * copies over to instanceData whatever configuration settings (from the global - * variables) apply. The global variables are NEVER used inside an action - * instance (at least this is how it is supposed to work ;) - */ -typedef struct configSettings_s { - int iSrvPort; /* sample: server port */ -} configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ - -BEGINinitConfVars /* (re)set config variables to default values */ -CODESTARTinitConfVars - resetConfigVariables(NULL, NULL); -ENDinitConfVars - - -BEGINcreateInstance -CODESTARTcreateInstance -ENDcreateInstance - - -BEGINisCompatibleWithFeature -CODESTARTisCompatibleWithFeature - /* use this to specify if select features are supported by this - * plugin. If not, the framework will handle that. Currently, only - * RepeatedMsgReduction ("last message repeated n times") is optional. - */ - if(eFeat == sFEATURERepeatedMsgReduction) - iRet = RS_RET_OK; -ENDisCompatibleWithFeature - - -BEGINfreeInstance -CODESTARTfreeInstance - /* this is a cleanup callback. All dynamically-allocated resources - * in instance data must be cleaned up here. Prime examples are - * malloc()ed memory, file & database handles and the like. - */ -ENDfreeInstance - - -BEGINdbgPrintInstInfo -CODESTARTdbgPrintInstInfo - /* permits to spit out some debug info */ -ENDdbgPrintInstInfo - - -BEGINtryResume -CODESTARTtryResume - /* this is called when an action has been suspended and the - * rsyslog core tries to resume it. The action must then - * retry (if possible) and report RS_RET_OK if it succeeded - * or RS_RET_SUSPENDED otherwise. - * Note that no data can be written in this callback, as it is - * not present. Prime examples of what can be retried are - * reconnects to remote hosts, reconnects to database, - * opening of files and the like. - * If there is no retry-type of operation, the action may - * return RS_RET_OK, so that it will get called on its doAction - * entry point (where it receives data), retries there, and - * immediately returns RS_RET_SUSPENDED if that does not work - * out. This disables some optimizations in the core's retry logic, - * but is a valid and expected behaviour. Note that it is also OK - * for the retry entry point to return OK but the immediately following - * doAction call to fail. In real life, for example, a buggy com line - * may cause such behaviour. - * Note that there is no guarantee that the core will very quickly - * call doAction after the retry succeeded. Today, it does, but that may - * not always be the case. - */ -ENDtryResume - -BEGINdoAction -CODESTARTdoAction - /* this is where you receive the message and need to carry out the - * action. Data is provided in ppString[i] where 0 <= i <= num of strings - * requested. - * Return RS_RET_OK if all goes well, RS_RET_SUSPENDED if the action can - * currently not complete, or an error code or RS_RET_DISABLED. The later - * two should only be returned if there is no hope that the action can be - * restored unless an rsyslog restart (prime example is an invalid config). - * Error code or RS_RET_DISABLED permanently disables the action, up to - * the next restart. - */ -ENDdoAction - - -BEGINparseSelectorAct -CODESTARTparseSelectorAct -CODE_STD_STRING_REQUESTparseSelectorAct(1) - /* first check if this config line is actually for us - * This is a clumpsy interface. We receive the action-part of the selector line - * and need to look at the first characters. If they match our signature - * ":omtemplate:", then we need to instantiate an action. It is recommended that - * newer actions just watch for the template and all other parameters are passed in - * via $-config-lines, this will hopefully be compatbile with future config syntaxes. - * If we do not detect our signature, we must return with RS_RET_CONFLINE_UNPROCESSED - * and NOT do anything else. - */ - if(strncmp((char*) p, ":omtemplate:", sizeof(":omtemplate:") - 1)) { - ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); - } - - /* ok, if we reach this point, we have something for us */ - p += sizeof(":omtemplate:") - 1; /* eat indicator sequence (-1 because of '\0'!) */ - CHKiRet(createInstance(&pData)); - - /* check if a non-standard template is to be applied */ - if(*(p-1) == ';') - --p; - /* if we have, call rsyslog runtime to get us template. Note that StdFmt below is - * the standard name. Currently, we may need to patch tools/syslogd.c if we need - * to add a new standard template. - */ - CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_RQD_TPL_OPT_SQL, (uchar*) " StdFmt")); - - /* if we reach this point, all went well, and we can copy over to instanceData - * those configuration elements that we need. - */ - pData->iSrvPort = (unsigned) cs.iSrvPort; /* set configured port */ - -CODE_STD_FINALIZERparseSelectorAct -ENDparseSelectorAct - - -BEGINmodExit -CODESTARTmodExit -ENDmodExit - - -BEGINqueryEtryPt -CODESTARTqueryEtryPt -CODEqueryEtryPt_STD_OMOD_QUERIES -ENDqueryEtryPt - - -/* Reset config variables for this module to default values. - */ -static rsRetVal -resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) -{ - DEFiRet; - cs.iSrvPort = 0; /* zero is the default port */ - RETiRet; -} - - -BEGINmodInit() -CODESTARTmodInit -SCOPINGmodInit - *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ -CODEmodInit_QueryRegCFSLineHdlr - CHKiRet(objUse(errmsg, CORE_COMPONENT)); - /* register our config handlers */ - /* confguration parameters MUST always be specified in lower case! */ - CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomtemplteserverport", 0, eCmdHdlrInt, NULL, &cs.iSrvPort, STD_LOADABLE_MODULE_ID, eConfObjAction)); - /* "resetconfigvariables" should be provided. Notat that it is a chained directive */ - CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID, eConfObjAction)); -ENDmodInit - -/* vi:set ai: - */ -- cgit v1.2.3 From e1e6ef71f4572de404d63a53f43c53c1b2b56803 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 9 Jan 2012 18:44:05 +0100 Subject: finally cleaning up the syslog-ng rsyslog comparison this page should be removed from the doc set over time -- it really does not belong here. --- doc/rsyslog_ng_comparison.html | 235 +++++++++++++++++++++-------------------- 1 file changed, 123 insertions(+), 112 deletions(-) diff --git a/doc/rsyslog_ng_comparison.html b/doc/rsyslog_ng_comparison.html index 7d12a4a7..44c895f7 100644 --- a/doc/rsyslog_ng_comparison.html +++ b/doc/rsyslog_ng_comparison.html @@ -4,24 +4,45 @@ back

              rsyslog vs. syslog-ng

              Written by Rainer Gerhards -(2008-05-06)

              -

              Warning: this comparison is a little outdated, take it with a grain -of salt and be sure to check the links at the bottom (both syslog-ng as well as -rsyslog features are missing, but our priority is on creating great software not -continously updating this comparison ;)). -

              We have often been asked about a comparison sheet between -rsyslog and syslog-ng. Unfortunately, I do not know much about -syslog-ng, I did not even use it once. Also, there seems to be no -comprehensive feature sheet available for syslog-ng (that recently -changed, see below). So I started this -comparison, but it probably is not complete. For sure, I miss some -syslog-ng features. This is not an attempt to let rsyslog shine more -than it should. I just used the rsyslog -feature sheet as a starting point, simply because it was -available. If you would like to add anything to the chart, or correct -it, please simply drop -me a line. I would love to see a real honest and up-to-date -comparison sheet, so please don't be shy ;)

              +(2008-05-06), slightly updated 2012-01-09

              +

              This comparison page is rooted nearly 5 years in the past and has become severely +outdated since then. It was unmaintained for several years and contained false +information on both syslog-ng and rsyslog as technology had advanced so much. +

              This page was initially written because so many people asked about a comparison when +rsyslog was in its infancy. So I tried to create one, but it was hard to maintain as both +projects grew and added feature after feature. I have to admit we did not try hard to keep +it current -- there were many other priorities. I even had forgetten about this page, when I +saw that Peter Czanik blogged about its +incorrectness (it must be noted +that Peter is wrong on RELP -- it is well alive). I now remember +that he asked me some time ago about this page, what I somehow lost... I guess he must have been +rather grumpy about that :-( +

              Visiting this page after so many years is interesting, because it shows how much has changed since then. +Obviously, one of my main goals in regard to syslog-ng is reached: in 2007, I blogged that +the +world needs another syslogd in order to have healthy competition and a greate feature +set in the free editions. In my opinion, the timeline clearly tells that rsyslog's competition +has driven more syslog-ng features from the commercial to the free edition. Also, I found +it interesting to see that syslog-ng has adapted rsyslog's licensing scheme, modular design and +multi-threadedness. On the other hand, the Balabit folks have obviously done a quicker and +better move on log normalization with what they call patterndb (it is very roughly equivalent +to what rsyslog has just recently introduced with the help of liblognorm). + +

              To that account, I think the projects are closer together than 5 years ago. I should now +go ahead and create a new feature comparison. Given previous experience, I think this does not +work out. In the future, we will probably focus on some top features, as Balabit does. However, +that requires some time and I have to admit I do not like to drop this page that has a lot of +inbound links. So I think I do the useful thing by providing these notes and removing the +syslog-ng information. So it can't be wrong on syslog-ng any more. Note that it still contains +some incorrect information about rsyslog (it's the state it had 5 years ago!). The core idea is +to start with updating the rsyslog feature sheet and from there +on work to a complete comparision. Of course, feel free to read on if you like to get some sense +of history (and inspiration on what you can still do -- but more ;)). +

              +Thanks,
              +Rainer Gerhards +

              + @@ -37,50 +58,50 @@ comparison sheet, so please don't be shy ;)

              - + - + - + - + - + - + - + - + @@ -89,8 +110,7 @@ optional inputEventReporter or MonitorWare Agent (both commercial software, both fund rsyslog development) - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -277,47 +296,47 @@ program name blocks for easy multi-host support - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + loadable modules - + - + @@ -417,7 +436,7 @@ plugins - + - + - + - + - + - + - + - + - + - + - - + + - + - + - + @@ -510,24 +528,23 @@ selector/filter condition - + - + - + - + - + - + - + - + - + - + - - + +
              UNIX domain socket yesyes
              UDP yesyes
              TCP yesyes
              RELP yesno
              RFC 3195/BEEP yes (via im3195)no
              kernel log yesyes
              file yesyes
              mark message generator as an optional input yesno (?)
              via separate Windows agent, paid -edition only

              @@ -100,83 +120,82 @@ Network (Protocol) Support

              support for (plain) tcp based syslog yesyes
              support for GSS-API yesno
              ability to limit the allowed network senders (syslog ACLs) yesyes (?)
              support for syslog-transport-tls based framing on syslog/tcp connections yesno (?)
              udp syslog yesyes
              syslog over RELP
              truly reliable message delivery (Why is plain tcp syslog not reliable?)
              yesno
              on the wire (zlib) message compression yesno (?)
              support for receiving messages via reliable RFC 3195 delivery yesno
              support for TLS/SSL-protected syslog natively (since 3.19.0)
              via stunnel
              via stunnel
              -paid edition natively
              support for IETF's new syslog-protocol draft yesno
              support for IETF's new syslog-transport-tls draft yes
              (since 3.19.0 - world's first implementation)
              no
              support for IPv6 yesyes
              native ability to send SNMP traps yesno
              ability to preserve the original hostname in NAT environments and relay chains yesyes

              @@ -187,81 +206,81 @@ hostname in NAT environments and relay chains
              Filtering for syslog facility and priority yesyes
              Filtering for hostname yesyes
              Filtering for application yesyes
              Filtering for message contents yesyes
              Filtering for sending IP address yesyes
              ability to filter on any other message field not mentioned above (including substrings and the like) yesno
              support for complex filters, using full boolean algebra with and/or/not operators and parenthesis yesyes
              Support for reusable filters: specify a filter once and use it in multiple selector lines noyes
              support for arbritrary complex arithmetic and string expressions inside filters yesno
              ability to use regular expressions in filters yesyes
              support for discarding messages based on filters yesyes
              ability to filter out messages based on sequence of appearing yes (starting with 3.21.3)no
              powerful BSD-style hostname and program name blocks for easy multi-host support yesno
              MySQL yes (native ommysql, omlibdbi)yes (via libdibi)
              PostgreSQL yes (native ompgsql, omlibdbi)yes (via libdibi)
              Oracle yes (omlibdbi)yes (via libdibi)
              SQLite yes (omlibdbi)yes (via libdibi)
              Microsoft SQL (Open TDS) yes (omlibdbi)no (?)
              Sybase (Open TDS) yes (omlibdbi)no (?)
              Firebird/Interbase yes (omlibdbi)no (?)
              Ingres yes (omlibdbi)no (?)
              mSQL yes (omlibdbi)no (?)

              @@ -328,26 +347,26 @@ program name blocks for easy multi-host support
              support for on-demand on-disk spooling of messages yespaid edition only
              ability to limit disk space used by spool files yesyes
              each action can use its own, independant set of spool files yesno
              different sets of spool files can be placed on different disk yesno
              ability to process spooled @@ -356,18 +375,18 @@ during off-peak hours, during peak hours they are enqueued only) yes
              (can independently be configured for the main queue and each action queue)
              no
              ability to configure backup syslog/database servers yesno
              Professional Support yesyes

              @@ -378,20 +397,20 @@ syslog/database servers
              config file format compatible to legacy syslogd but uglyclean but not backwards compatible
              ability to include config file from within other config files yesno
              ability to include all config files existing in a specific directory yesno

              @@ -403,13 +422,13 @@ existing in a specific directory
              yesno
              Support for third-party input plugins yesno
              Support for third-party output plugins yesno

              @@ -430,79 +449,78 @@ plugins
              ability to generate file names and directories (log targets) dynamically yesyes
              control of log output format, including ability to present channel and priority as visible log data yesyes
              native ability to send mail messages yes (ommail, introduced in 3.17.0)no (only via piped external process)
              good timestamp format control; at a minimum, ISO 8601/RFC 3339 second-resolution UTC zone yesyes
              ability to reformat message contents and work with substrings yesI think yes
              support for log files larger than 2gb yesyes
              support for log file size limitation and automatic rollover command execution yesyes
              support for running multiple syslogd instances on a single machine yes? (but I think yes)
              ability to execute shell scripts on received messagesyes yes
              ability to pipe messages to a continously running programnoyes
              massively multi-threaded for tomorrow's multi-core machines yesno (only multithreaded with -database destinations)
              ability to control repeated line reduction ("last message repeated n times") on a per selector-line basis yesyes (?)
              supports multiple actions per selector/filter condition yesyes
              phpLogCon
              [also works with php-syslog-ng]
              -php-syslog-ng
              using text files as input source yesyes
              rate-limiting output actions yesyes
              discard low-priority messages under system stress yesno (?)
              flow control @@ -535,40 +552,39 @@ system stress yes (advanced, with multiple ways to slow down inputs depending on individual input capabilities, based on watermarks)yes (limited? -"stops accepting messages")
              rewriting messages yesyes (at least I think so...)
              output data into various formats yesyes (looks somewhat limited to me)
              ability to control "message repeated n times" generation yesno (?)
              license GPLv3 (GPLv2 for v2 branch)GPL (paid edition is closed source)
              supported platforms Linux, BSD, anecdotical seen on Solaris; compilation and basic testing done on HP UXmany popular *nixes
              DNS cachenoyes
              @@ -585,11 +601,6 @@ that vast experience and sometimes even on the code.

              argument why it is good to have another strong syslogd besides syslog-ng
              . You may want to read it at my blog at "Why does the world need another syslogd?".

              -

              Balabit, the vendor of syslog-ng, has just recently done a -feature sheet. I have not yet been able to fully work through it. In -the mean time, you may want to read it in parallel. It is available at -Balabit's -site.

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

              -- cgit v1.2.3 From e25dc05e9127537cf2ddbae30b15300f601fbff0 Mon Sep 17 00:00:00 2001 From: Tomas Heinrich Date: Tue, 10 Jan 2012 17:07:55 +0100 Subject: added canned template for ultra-exact sysklogd file format the point is that LF will be translated to SP Signed-off-by: Rainer Gerhards --- doc/rsyslog_conf_templates.html | 4 ++++ tools/syslogd.c | 3 +++ 2 files changed, 7 insertions(+) diff --git a/doc/rsyslog_conf_templates.html b/doc/rsyslog_conf_templates.html index 6c68b801..5790ba8a 100644 --- a/doc/rsyslog_conf_templates.html +++ b/doc/rsyslog_conf_templates.html @@ -118,6 +118,10 @@ with high-precision timestamps and timezone information useful if you send messages to other syslogd's or rsyslogd below version 3.12.5. +
            • RSYSLOG_SysklogdFileFormat +- sysklogd compatible log file format. If used with options: $SpaceLFOnReceive on; +$EscapeControlCharactersOnReceive off; $DropTrailingLFOnReception off, +the log format will conform to sysklogd log format.
            • RSYSLOG_ForwardFormat - a new high-precision forwarding format very similar to the traditional one, but with high-precision timestamps and timezone diff --git a/tools/syslogd.c b/tools/syslogd.c index 64b23566..4a5cbf60 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -381,6 +381,7 @@ static uchar template_TraditionalForwardFormat[] = "\"<%PRI%>%TIMESTAMP% %HOSTNA static uchar template_StdUsrMsgFmt[] = "\" %syslogtag%%msg%\n\r\""; static uchar template_StdDBFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-mysql%', '%timegenerated:::date-mysql%', %iut%, '%syslogtag%')\",SQL"; static uchar template_StdPgSQLFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-pgsql%', '%timegenerated:::date-pgsql%', %iut%, '%syslogtag%')\",STDSQL"; +static uchar template_SysklogdFileFormat[] = "\"%TIMESTAMP% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg%\n\""; /* end template */ @@ -2836,6 +2837,8 @@ static rsRetVal mainThread() tplAddLine(" StdUsrMsgFmt", &pTmp); pTmp = template_StdDBFmt; tplAddLine(" StdDBFmt", &pTmp); + pTmp = template_SysklogdFileFormat; + tplAddLine("RSYSLOG_SysklogdFileFormat", &pTmp); pTmp = template_StdPgSQLFmt; tplLastStaticInit(tplAddLine(" StdPgSQLFmt", &pTmp)); -- cgit v1.2.3 From a2e69cffff21ad433e61b45f91a2be4d5ebc5c72 Mon Sep 17 00:00:00 2001 From: Tomas Heinrich Date: Tue, 10 Jan 2012 17:14:16 +0100 Subject: added $SpaceLFOnReceive config directive Signed-off-by: Rainer Gerhards --- dirty.h | 1 + doc/rsyslog_conf_global.html | 1 + runtime/parser.c | 6 +++++- tools/syslogd.c | 9 +++++++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/dirty.h b/dirty.h index 0153cb69..a93eca8f 100644 --- a/dirty.h +++ b/dirty.h @@ -54,6 +54,7 @@ extern int bReduceRepeatMsgs; extern int bDropTrailingLF; extern uchar cCCEscapeChar; extern int bEscapeCCOnRcv; +extern int bSpaceLFOnRcv; #ifdef USE_NETZIP /* config param: minimum message size to try compression. The smaller * the message, the less likely is any compression gain. We check for diff --git a/doc/rsyslog_conf_global.html b/doc/rsyslog_conf_global.html index d5a27541..f5269490 100644 --- a/doc/rsyslog_conf_global.html +++ b/doc/rsyslog_conf_global.html @@ -130,6 +130,7 @@ our paper on using multiple rule sets in rsyslog$DropTrailingLFOnReception
            • $DynaFileCacheSize
            • $EscapeControlCharactersOnReceive
            • +
            • $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
            • diff --git a/runtime/parser.c b/runtime/parser.c index 466066e7..57b7bf8f 100644 --- a/runtime/parser.c +++ b/runtime/parser.c @@ -202,9 +202,13 @@ sanitizeMessage(msg_t *pMsg) int bNeedSanitize = 0; for(iSrc = 0 ; iSrc < lenMsg ; iSrc++) { if(iscntrl(pszMsg[iSrc])) { + if(bSpaceLFOnRcv && pszMsg[iSrc] == '\n') + pszMsg[iSrc] = ' '; + else if(pszMsg[iSrc] == '\0' || bEscapeCCOnRcv) { bNeedSanitize = 1; - break; + if (!bSpaceLFOnRcv) + break; } } } diff --git a/tools/syslogd.c b/tools/syslogd.c index 4a5cbf60..b696c55f 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -259,6 +259,7 @@ static int bDebugPrintCfSysLineHandlerList = 1;/* output cfsyslinehandler list i static int bDebugPrintModuleList = 1;/* output module list in debug mode? */ uchar cCCEscapeChar = '\\';/* character to be used to start an escape sequence for control chars */ int bEscapeCCOnRcv = 1; /* escape control characters on reception: 0 - no, 1 - yes */ +int bSpaceLFOnRcv = 0; /* replace newlines with spaces on reception: 0 - no, 1 - yes */ static int bErrMsgToStderr = 1; /* print error messages to stderr (in addition to everything else)? */ int bReduceRepeatMsgs; /* reduce repeated message - 0 - no, 1 - yes */ int bActExecWhenPrevSusp; /* execute action only when previous one was suspended? */ @@ -343,6 +344,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a bDebugPrintCfSysLineHandlerList = 1; bDebugPrintModuleList = 1; bEscapeCCOnRcv = 1; /* default is to escape control characters */ + bSpaceLFOnRcv = 0; bReduceRepeatMsgs = 0; free(pszMainMsgQFName); pszMainMsgQFName = NULL; @@ -810,6 +812,9 @@ parseAndSubmitMessage(uchar *hname, uchar *hnameIP, uchar *msg, int len, int fla /* log an error? Very questionable... rgerhards, 2006-11-30 */ /* decided: we do not log an error, it won't help... rger, 2007-06-21 */ ++pData; + } else if (bSpaceLFOnRcv && *pData == '\n') { + *(pMsg + iMsg++) = ' '; + ++pData; } else if(bEscapeCCOnRcv && iscntrl((int) *pData)) { /* we are configured to escape control characters. Please note * that this most probably break non-western character sets like @@ -2115,6 +2120,9 @@ static void dbgPrintInitInfo(void) DBGPRINTF("Control characters are %sreplaced upon reception.\n", bEscapeCCOnRcv? "" : "not "); + DBGPRINTF("Newlines are %sreplaced upon reception.\n", + bSpaceLFOnRcv? "" : "not "); + if(bEscapeCCOnRcv) DBGPRINTF("Control character escape sequence prefix is '%c'.\n", cCCEscapeChar); @@ -2728,6 +2736,7 @@ static rsRetVal loadBuildInModules(void) CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt, setActionResumeInterval, NULL, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"controlcharacterescapeprefix", 0, eCmdHdlrGetChar, NULL, &cCCEscapeChar, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscapeCCOnRcv, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"spacelfonreceive", 0, eCmdHdlrBinary, NULL, &bSpaceLFOnRcv, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"droptrailinglfonreception", 0, eCmdHdlrBinary, NULL, &bDropTrailingLF, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_TEMPLATE, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler, conf.doNameLine, (void*)DIR_OUTCHANNEL, NULL)); -- cgit v1.2.3 From d4024e98d0a7cef5830c71992513bbef0e342874 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 10 Jan 2012 18:04:18 +0100 Subject: part of merge, but forgot to add to merge set --- runtime/parser.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/runtime/parser.c b/runtime/parser.c index ffaaac25..300db1e0 100644 --- a/runtime/parser.c +++ b/runtime/parser.c @@ -60,6 +60,7 @@ DEFobjCurrIf(ruleset) /* config data */ static uchar cCCEscapeChar = '#';/* character to be used to start an escape sequence for control chars */ static int bEscapeCCOnRcv = 1; /* escape control characters on reception: 0 - no, 1 - yes */ +static int bSpaceLFOnRcv = 0; /* replace newlines with spaces on reception: 0 - no, 1 - yes */ static int bEscape8BitChars = 0; /* escape characters > 127 on reception: 0 - no, 1 - yes */ static int bEscapeTab = 1; /* escape tab control character when doing CC escapes: 0 - no, 1 - yes */ static int bDropTrailingLF = 1; /* drop trailing LF's on reception? */ @@ -649,6 +650,7 @@ resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unus { cCCEscapeChar = '#'; bEscapeCCOnRcv = 1; /* default is to escape control characters */ + bSpaceLFOnRcv = 0; bEscape8BitChars = 0; /* default is to escape control characters */ bEscapeTab = 1; /* default is to escape control characters */ bDropTrailingLF = 1; /* default is to drop trailing LF's on reception */ @@ -702,6 +704,7 @@ BEGINObjClassInit(parser, 1, OBJ_IS_CORE_MODULE) /* class, version */ CHKiRet(regCfSysLineHdlr((uchar *)"controlcharacterescapeprefix", 0, eCmdHdlrGetChar, NULL, &cCCEscapeChar, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"droptrailinglfonreception", 0, eCmdHdlrBinary, NULL, &bDropTrailingLF, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscapeCCOnRcv, NULL)); + CHKiRet(regCfSysLineHdlr((uchar *)"spacelfonreceive", 0, eCmdHdlrBinary, NULL, &bSpaceLFOnRcv, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"escape8bitcharactersonreceive", 0, eCmdHdlrBinary, NULL, &bEscape8BitChars, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"escapecontrolcharactertab", 0, eCmdHdlrBinary, NULL, &bEscapeTab, NULL)); CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, NULL)); -- cgit v1.2.3 From 6b72037d669d7aa6672cb23d5190606ed7c3dd8d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 12 Jan 2012 04:05:34 +0100 Subject: regression fix: imuxsock-received messages were malformed probably caused by a recent merge, was not present in 5.9.4 --- plugins/imuxsock/imuxsock.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 0fb3492d..14d8b594 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -713,7 +713,6 @@ SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred, struct tim lenRcv = toffs + 1; } - /* we now create our own message object and submit it to the queue */ CHKiRet(msgConstructWithTime(&pMsg, &st, tt)); MsgSetRawMsg(pMsg, (char*)pRcv, lenRcv); @@ -734,8 +733,6 @@ SubmitMsg(uchar *pRcv, int lenRcv, lstn_t *pLstn, struct ucred *cred, struct tim * datestamp or not .. and advance the parse pointer accordingly. */ datetime.ParseTIMESTAMP3164(&dummyTS, &parse, &lenMsg); - parse += 16; /* just skip timestamp */ - lenMsg -= 16; } else { if(datetime.ParseTIMESTAMP3164(&(pMsg->tTIMESTAMP), &parse, &lenMsg) != RS_RET_OK) { DBGPRINTF("we have a problem, invalid timestamp in msg!\n"); @@ -1018,7 +1015,6 @@ CODESTARTafterRun /* Clean-up files. */ for(i = startIndexUxLocalSockets; i < nfd; i++) if (listeners[i].sockName && listeners[i].fd != -1) { - /* If systemd passed us a socket it is systemd's job to clean it up. * Do not unlink it -- we will get same socket (node) from systemd * e.g. on restart again. -- cgit v1.2.3 From 45ba66d14acd1910869c8e5c3fb1255150eeb629 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 14 Jan 2012 18:13:26 +0100 Subject: omfwd refactor: simplifying code also remove code introduced by commit 6e97513eea1a6e282365eb01d972e0657cb36baa --- tools/omfwd.c | 30 +++++++++--------------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/tools/omfwd.c b/tools/omfwd.c index 10cce0e2..0156fbfc 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -131,22 +131,6 @@ pData->bIsConnected = 0; // TODO: remove this variable altogether } -/* get the syslog forward port from selector_t. The passed in - * struct must be one that is setup for forwarding. - * rgerhards, 2007-06-28 - * We may change the implementation to try to lookup the port - * if it is unspecified. So far, we use the IANA default auf 514. - */ -static char *getFwdPt(instanceData *pData) -{ - assert(pData != NULL); - if(pData->port == NULL) - return("514"); - else - return(pData->port); -} - - /* destruct the TCP helper objects * This, for example, is needed after something went wrong. * This function is void because it "can not" fail. @@ -345,7 +329,7 @@ static rsRetVal TCPSendInit(void *pvData) } /* params set, now connect */ CHKiRet(netstrm.Connect(pData->pNetstrm, glbl.GetDefPFFamily(), - (uchar*)getFwdPt(pData), (uchar*)pData->f_hname)); + (uchar*)pData->port, (uchar*)pData->f_hname)); } finalize_it: @@ -378,9 +362,9 @@ static rsRetVal doTryResume(instanceData *pData) hints.ai_flags = AI_NUMERICSERV; hints.ai_family = glbl.GetDefPFFamily(); hints.ai_socktype = SOCK_DGRAM; - if((iErr = (getaddrinfo(pData->f_hname, getFwdPt(pData), &hints, &res))) != 0) { + if((iErr = (getaddrinfo(pData->f_hname, pData->port, &hints, &res))) != 0) { dbgprintf("could not get addrinfo for hostname '%s':'%s': %d%s\n", - pData->f_hname, getFwdPt(pData), iErr, gai_strerror(iErr)); + pData->f_hname, pData->port, iErr, gai_strerror(iErr)); ABORT_FINALIZE(RS_RET_SUSPENDED); } dbgprintf("%s found, resuming.\n", pData->f_hname); @@ -420,7 +404,7 @@ CODESTARTdoAction iMaxLine = glbl.GetMaxLine(); - dbgprintf(" %s:%s/%s\n", pData->f_hname, getFwdPt(pData), + dbgprintf(" %s:%s/%s\n", pData->f_hname, pData->port, pData->protocol == FORW_UDP ? "udp" : "tcp"); psz = (char*) ppString[0]; @@ -630,12 +614,16 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) if(pData->port == NULL) { errmsg.LogError(0, NO_ERRCODE, "Could not get memory to store syslog forwarding port, " "using default port, results may not be what you intend\n"); - /* we leave f_forw.port set to NULL, this is then handled by getFwdPt(). */ + /* we leave f_forw.port set to NULL, this is then handled below */ } else { memcpy(pData->port, tmp, i); *(pData->port + i) = '\0'; } } + /* check if no port is set. If so, we use the IANA-assigned port of 514 */ + if(pData->port == NULL) { + CHKmalloc(pData->port = strdup("514")); + } /* now skip to template */ while(*p && *p != ';' && *p != '#' && !isspace((int) *p)) -- cgit v1.2.3 From ac64c118ea9ea69edfc1ab698d5413fa3485fc94 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 14 Jan 2012 18:22:16 +0100 Subject: omfwd refactor: simplification at the same time, remove commits - 8c3ab2e26f1bae46ff34fc1d0a10a69c4db78127 - 009738a0ac6ba0dccf403f9e396095f44e4f9ac6 --- tools/omfwd.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/tools/omfwd.c b/tools/omfwd.c index 0156fbfc..46c13dc9 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -396,9 +396,12 @@ CODESTARTtryResume ENDtryResume BEGINdoAction - char *psz = NULL; /* temporary buffering */ + char *psz; /* temporary buffering */ register unsigned l; int iMaxLine; +# ifdef USE_NETZIP + Bytef *out = NULL; /* for compression */ +# endif CODESTARTdoAction CHKiRet(doTryResume(pData)); @@ -422,7 +425,6 @@ CODESTARTdoAction * rgerhards, 2006-11-30 */ if(pData->compressionLevel && (l > CONF_MIN_SIZE_FOR_COMPRESS)) { - Bytef *out; uLongf destLen = iMaxLine + iMaxLine/100 +12; /* recommended value from zlib doc */ uLong srcLen = l; int ret; @@ -443,14 +445,11 @@ CODESTARTdoAction * rgerhards, 2006-11-30 */ dbgprintf("Compression failed, sending uncompressed message\n"); - free(out); } else if(destLen+1 < l) { /* only use compression if there is a gain in using it! */ dbgprintf("there is gain in compression, so we do it\n"); psz = (char*) out; l = destLen + 1; /* take care for the "z" at message start! */ - } else { - free(out); } ++destLen; } @@ -472,10 +471,8 @@ CODESTARTdoAction } finalize_it: # ifdef USE_NETZIP - if((psz != NULL) && (psz != (char*) ppString[0])) { - /* we need to free temporary buffer, alloced above - Naoya Nakazawa, 2010-01-11 */ - free(psz); - } + if(out != NULL) + free(out); # endif ENDdoAction -- cgit v1.2.3 From 38afe62f33db10a31ed2e4a6c6c10bc3995d860d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 14 Jan 2012 18:25:23 +0100 Subject: omfwd license change to ASL 2.0 after careful consideration of contributor history. David Lang gave permission to license under ASL 2.0, other patches have been replaced by refactored code. --- tools/omfwd.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-) diff --git a/tools/omfwd.c b/tools/omfwd.c index 46c13dc9..acc2f6f6 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -4,30 +4,26 @@ * NOTE: read comments in module-template.h to understand how this file * works! * - * File begun on 2007-07-20 by RGerhards (extracted from syslogd.c) - * This file is under development and has not yet arrived at being fully - * self-contained and a real object. So far, it is mostly an excerpt - * of the "old" message code without any modifications. However, it - * helps to have things at the right place one we go to the meat of it. + * File begun on 2007-07-20 by RGerhards (extracted from syslogd.c, which + * at the time of rsyslog fork from sysklogd was under BSD license) * - * Copyright 2007, 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2012 Adiscon GmbH. * * This file is part of rsyslog. * - * Rsyslog is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Rsyslog is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Rsyslog. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * -or- + * see COPYING.ASL20 in the source distribution + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "config.h" #include "rsyslog.h" -- cgit v1.2.3 From a468063315c3ce5eccc702080bebeb79158ad6b7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 14 Jan 2012 18:27:24 +0100 Subject: cosmetic: cleanup of ChangeLog --- ChangeLog | 2 -- 1 file changed, 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4cf7dc19..ef742100 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,8 +3,6 @@ Version 5.9.5 [V5-DEVEL], 2011-11-29 - new stats counters for imudp and imtcp - new stats counters "discarded.nf" and "discarded.full" for queue object. Tells how many messages have been discarded due to queue full condition. ---------------------------------------------------------------------------- -Version 5.9.5 [V5-DEVEL], 2011-11-29 - enhanced module loader to not rely on PATH_MAX --------------------------------------------------------------------------- Version 5.9.4 [V5-DEVEL], 2011-11-29 -- cgit v1.2.3 From d5a18a93ae585c25d67ec200b308f08c6bd6d5b2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Sat, 14 Jan 2012 18:29:33 +0100 Subject: omfwd refactor: even more simplification (small one ;)) --- tools/omfwd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/omfwd.c b/tools/omfwd.c index acc2f6f6..b456db17 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -467,8 +467,7 @@ CODESTARTdoAction } finalize_it: # ifdef USE_NETZIP - if(out != NULL) - free(out); + free(out); /* is NULL if it was never used... */ # endif ENDdoAction -- cgit v1.2.3 From 167192666ba8905b83210ab7c5f00cc6be9f7147 Mon Sep 17 00:00:00 2001 From: Peng Haitao Date: Fri, 6 Jan 2012 14:48:18 +0800 Subject: fix error of not define HAVE_SETSID [add list to the CC list] When HAVE_SETSID is not defined, rsyslogd will use ioctl() make itself to daemon, but this can not make rsyslogd process become the process group leader of a new process group. In RHEL6.1, the status is as follows: # uname -a Linux RHEL6U1GA-Intel64-199 2.6.32-131.0.15.el6.x86_64 #1 SMP Tue May 10 15:42:40 EDT 2011 x86_64 x86_64 x86_64 GNU/Linux # /etc/init.d/rsyslog restart Shutting down system logger: [ OK ] Starting system logger: [ OK ] # ps axo pgrp,ppid,pid,comm | grep rsyslog 6290 1 6301 rsyslogd When we send SIGTERM signal to 6290, rsyslogd will die:( So I think we should call setpgid() before ioctl(). Signed-off-by: Peng Haitao --- tools/syslogd.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/syslogd.c b/tools/syslogd.c index 6879bafa..65770404 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -460,8 +460,15 @@ void untty(void) #else { int i; + pid_t pid; if(!Debug) { + pid = getpid(); + if (setpgid(pid, pid) < 0) { + perror("setpgid"); + exit(1); + } + i = open(_PATH_TTY, O_RDWR|O_CLOEXEC); if (i >= 0) { # if !defined(__hpux) -- cgit v1.2.3 From 76c4d6b951453078ab53bf612caf0b8ec9d54bb8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 16 Jan 2012 17:58:57 +0100 Subject: $IMUXSockRateLimitInterval DEFAULT CHANGED, was 5, now 0 The new default turns off rate limiting. This was chosen as people experienced problems with rate-limiting activated by default. Now it needs an explicit opt-in by setting this parameter. Thanks to Chris Gaffney for suggesting to make it opt-in; thanks to many unnamed others who already had complained at the time Chris made the suggestion ;-) --- ChangeLog | 9 +++++++++ doc/imuxsock.html | 5 ++++- plugins/imuxsock/imuxsock.c | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7639ca95..ad3f85f2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,13 @@ --------------------------------------------------------------------------- +Version 5.9.6 [V5-DEVEL], 2012-??-?? +- $IMUXSockRateLimitInterval DEFAULT CHANGED, was 5, now 0 + The new default turns off rate limiting. This was chosen as people + experienced problems with rate-limiting activated by default. Now it + needs an explicit opt-in by setting this parameter. + Thanks to Chris Gaffney for suggesting to make it opt-in; thanks to + many unnamed others who already had complained at the time Chris made + the suggestion ;-) +--------------------------------------------------------------------------- Version 5.9.5 [V5-DEVEL], 2011-11-29 - new stats counters for imudp and imtcp - new stats counters "discarded.nf" and "discarded.full" for queue object. diff --git a/doc/imuxsock.html b/doc/imuxsock.html index f80bc598..734ae889 100644 --- a/doc/imuxsock.html +++ b/doc/imuxsock.html @@ -65,7 +65,10 @@ you must turn it on (via $SystemLogSocketAnnotate and $InputUnixListenSocketAnno
            • $InputUnixListenSocketFlowControl [on/off] - specifies if flow control should be applied to the next socket.
            • $IMUXSockRateLimitInterval [number] - specifies the rate-limiting -interval in seconds. Default value is 5 seconds. Set it to 0 to turn rate limiting off. +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 burst in number of messages. Default is 200. diff --git a/plugins/imuxsock/imuxsock.c b/plugins/imuxsock/imuxsock.c index 14d8b594..403173e1 100644 --- a/plugins/imuxsock/imuxsock.c +++ b/plugins/imuxsock/imuxsock.c @@ -165,7 +165,7 @@ static int bAnnotate = 0; /* annotate trusted properties */ static int bAnnotateSysSock = 0; /* same, for system log socket */ #define DFLT_bCreatePath 0 static int bCreatePath = DFLT_bCreatePath; /* auto-create socket path? */ -#define DFLT_ratelimitInterval 5 +#define DFLT_ratelimitInterval 0 static int ratelimitInterval = DFLT_ratelimitInterval; /* interval in seconds, 0 = off */ static int ratelimitIntervalSysSock = DFLT_ratelimitInterval; #define DFLT_ratelimitBurst 200 -- cgit v1.2.3 From 052b1c75945106c6336fd0c172fbaa129248334c Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Mon, 15 Aug 2011 22:22:05 +1000 Subject: add JSON escaping option Following the path taken by the two SQL formatting options, which escape single quotes with double quotes (amongst other things), this patch adds a JSON quoting option. JSON is the opposite to the SQL options, requiring double quotes to be quoted within a string. This patch provides a formatting option implementing this requirement, while piggy-backing on the existing code as much as possible. Signed-off-by: Nathan Scott --- action.c | 2 +- template.c | 90 +++++++++++++++++++++++++++++++++++++++----------------------- template.h | 9 ++++--- 3 files changed, 63 insertions(+), 38 deletions(-) diff --git a/action.c b/action.c index 278625ce..6796cf14 100644 --- a/action.c +++ b/action.c @@ -1743,7 +1743,7 @@ addAction(action_t **ppAction, modInfo_t *pMod, void *pModData, omodStringReques } /* check required template options */ if( (iTplOpts & OMSR_RQD_TPL_OPT_SQL) - && (pAction->ppTpl[i]->optFormatForSQL == 0)) { + && (pAction->ppTpl[i]->optFormatEscape == 0)) { errno = 0; errmsg.LogError(0, RS_RET_RQD_TPLOPT_MISSING, "Action disabled. To use this action, you have to specify " "the SQL or stdSQL option in your template!\n"); diff --git a/template.c b/template.c index 2038c6c1..54ca95af 100644 --- a/template.c +++ b/template.c @@ -53,7 +53,12 @@ static struct template *tplRoot = NULL; /* the root of the template list */ static struct template *tplLast = NULL; /* points to the last element of the template list */ static struct template *tplLastStatic = NULL; /* last static element of the template list */ - +enum { + NO_ESCAPE = 0, + SQL_ESCAPE, + STDSQL_ESCAPE, + JSON_ESCAPE, +}; /* helper to tplToString and strgen's, extends buffer */ #define ALLOC_INC 128 @@ -123,10 +128,12 @@ rsRetVal tplToString(struct template *pTpl, msg_t *pMsg, uchar **ppBuf, size_t * * but they are handled in this way because of legacy (don't break any * existing thing). */ - if(pTpl->optFormatForSQL == 1) - doSQLEscape(&pVal, &iLenVal, &bMustBeFreed, 1); - else if(pTpl->optFormatForSQL == 2) - doSQLEscape(&pVal, &iLenVal, &bMustBeFreed, 0); + if(pTpl->optFormatEscape == SQL_ESCAPE) + doEscape(&pVal, &iLenVal, &bMustBeFreed, SQL_ESCAPE); + else if(pTpl->optFormatEscape == JSON_ESCAPE) + doEscape(&pVal, &iLenVal, &bMustBeFreed, JSON_ESCAPE); + else if(pTpl->optFormatEscape == STDSQL_ESCAPE) + doEscape(&pVal, &iLenVal, &bMustBeFreed, STDSQL_ESCAPE); } /* got source, now copy over */ if(iLenVal > 0) { /* may be zero depending on property */ @@ -213,27 +220,29 @@ finalize_it: } -/* Helper to doSQLEscape. This is called if doSQLEscape +/* Helper to doEscape. This is called if doEscape * runs out of memory allocating the escaped string. * Then we are in trouble. We can * NOT simply return the unmodified string because this * may cause SQL injection. But we also can not simply * abort the run, this would be a DoS. I think an appropriate - * measure is to remove the dangerous \' characters. We + * measure is to remove the dangerous \' characters (SQL). We * replace them by \", which will break the message and * signatures eventually present - but this is the * best thing we can do now (or does anybody * have a better idea?). rgerhards 2004-11-23 - * added support for "escapeMode" (so doSQLEscape for details). - * if mode = 1, then backslashes are changed to slashes. + * added support for escape mode (see doEscape for details). + * if mode = SQL_ESCAPE, then backslashes are changed to slashes. * rgerhards 2005-09-22 */ -static void doSQLEmergencyEscape(register uchar *p, int escapeMode) +static void doEmergencyEscape(register uchar *p, int mode) { while(*p) { - if(*p == '\'') + if((mode == SQL_ESCAPE||mode == STDSQL_ESCAPE) && *p == '\'') *p = '"'; - else if((escapeMode == 1) && (*p == '\\')) + else if((mode == JSON_ESCAPE) && *p == '"') + *p = '\''; + else if((mode == SQL_ESCAPE) && *p == '\\') *p = '/'; ++p; } @@ -258,14 +267,16 @@ static void doSQLEmergencyEscape(register uchar *p, int escapeMode) * smartness depends on config settings. So we add a new option to this * function that allows the caller to select if they want to standard or * "smart" encoding ;) - * new parameter escapeMode is 0 - standard sql, 1 - "smart" engines + * -- + * Parameter "mode" is STDSQL_ESCAPE, SQL_ESCAPE "smart" SQL engines, or + * JSON_ESCAPE for everyone requiring escaped JSON (e.g. ElasticSearch). * 2005-09-22 rgerhards */ rsRetVal -doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode) +doEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int mode) { DEFiRet; - uchar *p; + uchar *p = NULL; int iLen; cstr_t *pStrB = NULL; uchar *pszGenerated; @@ -276,26 +287,32 @@ doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeM assert(pbMustBeFreed != NULL); /* first check if we need to do anything at all... */ - if(escapeMode == 0) + if(mode == STDSQL_ESCAPE) for(p = *pp ; *p && *p != '\'' ; ++p) ; - else + else if(mode == SQL_ESCAPE) for(p = *pp ; *p && *p != '\'' && *p != '\\' ; ++p) ; + else if(mode == JSON_ESCAPE) + for(p = *pp ; *p && *p != '"' ; ++p) + ; /* when we get out of the loop, we are either at the - * string terminator or the first \'. */ - if(*p == '\0') + * string terminator or the first character to escape */ + if(p && *p == '\0') FINALIZE; /* nothing to do in this case! */ p = *pp; iLen = *pLen; CHKiRet(cstrConstruct(&pStrB)); - + while(*p) { - if(*p == '\'') { - CHKiRet(cstrAppendChar(pStrB, (escapeMode == 0) ? '\'' : '\\')); + if((mode == SQL_ESCAPE || mode == STDSQL_ESCAPE) && *p == '\'') { + CHKiRet(cstrAppendChar(pStrB, (mode == STDSQL_ESCAPE) ? '\'' : '\\')); + iLen++; /* reflect the extra character */ + } else if((mode == SQL_ESCAPE) && *p == '\\') { + CHKiRet(cstrAppendChar(pStrB, '\\')); iLen++; /* reflect the extra character */ - } else if((escapeMode == 1) && (*p == '\\')) { + } else if((mode == JSON_ESCAPE) && *p == '"') { CHKiRet(cstrAppendChar(pStrB, '\\')); iLen++; /* reflect the extra character */ } @@ -314,7 +331,7 @@ doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeM finalize_it: if(iRet != RS_RET_OK) { - doSQLEmergencyEscape(*pp, escapeMode); + doEmergencyEscape(*pp, mode); if(pStrB != NULL) cstrDestruct(&pStrB); } @@ -883,11 +900,14 @@ tplAddTplMod(struct template *pTpl, uchar** ppRestOfConfLine) * acknowledged implementing the option. -- rgerhards, 2011-03-21 */ if(lenMod > 6 && !strcasecmp((char*) szMod + lenMod - 7, ",stdsql")) { - pTpl->optFormatForSQL = 2; - DBGPRINTF("strgen suports the stdsql option\n"); + pTpl->optFormatEscape = STDSQL_ESCAPE; + DBGPRINTF("strgen supports the stdsql option\n"); } else if(lenMod > 3 && !strcasecmp((char*) szMod+ lenMod - 4, ",sql")) { - pTpl->optFormatForSQL = 1; - DBGPRINTF("strgen suports the sql option\n"); + pTpl->optFormatEscape = SQL_ESCAPE; + DBGPRINTF("strgen supports the sql option\n"); + } else if(lenMod > 4 && !strcasecmp((char*) szMod+ lenMod - 4, ",json")) { + pTpl->optFormatEscape = JSON_ESCAPE; + DBGPRINTF("strgen supports the json option\n"); } finalize_it: @@ -1015,11 +1035,13 @@ struct template *tplAddLine(char* pName, uchar** ppRestOfConfLine) * it anyhow... ;) rgerhards 2004-11-22 */ if(!strcmp(optBuf, "stdsql")) { - pTpl->optFormatForSQL = 2; + pTpl->optFormatEscape = STDSQL_ESCAPE; + } else if(!strcmp(optBuf, "json")) { + pTpl->optFormatEscape = JSON_ESCAPE; } else if(!strcmp(optBuf, "sql")) { - pTpl->optFormatForSQL = 1; + pTpl->optFormatEscape = SQL_ESCAPE; } else if(!strcmp(optBuf, "nosql")) { - pTpl->optFormatForSQL = 0; + pTpl->optFormatEscape = NO_ESCAPE; } else { dbgprintf("Invalid option '%s' ignored.\n", optBuf); } @@ -1180,9 +1202,11 @@ void tplPrintList(void) pTpl = tplRoot; while(pTpl != NULL) { dbgprintf("Template: Name='%s' ", pTpl->pszName == NULL? "NULL" : pTpl->pszName); - if(pTpl->optFormatForSQL == 1) + if(pTpl->optFormatEscape == SQL_ESCAPE) dbgprintf("[SQL-Format (MySQL)] "); - else if(pTpl->optFormatForSQL == 2) + else if(pTpl->optFormatEscape == JSON_ESCAPE) + dbgprintf("[JSON-Escaped Format] "); + else if(pTpl->optFormatEscape == STDSQL_ESCAPE) dbgprintf("[SQL-Format (standard SQL)] "); dbgprintf("\n"); pTpe = pTpl->pEntryRoot; diff --git a/template.h b/template.h index f7ac2e08..b5598b6d 100644 --- a/template.h +++ b/template.h @@ -36,9 +36,10 @@ struct template { int tpenElements; /* number of elements in templateEntry list */ struct templateEntry *pEntryRoot; struct templateEntry *pEntryLast; - char optFormatForSQL; /* in text fields, 0 - do not escape, - * 1 - escape quotes by double quotes, - * 2 - escape "the MySQL way" + char optFormatEscape; /* in text fields, 0 - do not escape, + * 1 - escape "the MySQL way" + * 2 - escape quotes by double quotes, + * 3 - escape double quotes for JSON. */ /* following are options. All are 0/1 defined (either on or off). * we use chars because they are faster than bit fields and smaller @@ -130,7 +131,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 doSQLEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode); +rsRetVal doEscape(uchar **pp, size_t *pLen, unsigned short *pbMustBeFreed, int escapeMode); rsRetVal templateInit(); -- cgit v1.2.3 From f8019d52f83884acb5e8f8755fe976d1592b4ccb Mon Sep 17 00:00:00 2001 From: Nathan Scott Date: Mon, 15 Aug 2011 22:22:13 +1000 Subject: add elasticsearch output module Add support for sending events to elasticsearch - a distributed, RESTful, search engine built on Lucene (www.elasticsearch.org). The output module is enabled via a configure option, and uses libcurl to send the messages from rsyslog to elasticsearch. This patch makes use of the earlier JSON quoting patch to ensure valid JSON strings are sent to the server. Signed-off-by: Nathan Scott --- Makefile.am | 5 + configure.ac | 36 ++++ plugins/omelasticsearch/Makefile.am | 8 + plugins/omelasticsearch/omelasticsearch.c | 271 ++++++++++++++++++++++++++++++ tools/syslogd.c | 3 + 5 files changed, 323 insertions(+) create mode 100644 plugins/omelasticsearch/Makefile.am create mode 100644 plugins/omelasticsearch/omelasticsearch.c diff --git a/Makefile.am b/Makefile.am index de4777b2..fd348a67 100644 --- a/Makefile.am +++ b/Makefile.am @@ -168,6 +168,10 @@ if ENABLE_OMTEMPLATE SUBDIRS += plugins/omtemplate endif +if ENABLE_ELASTICSEARCH +SUBDIRS += plugins/omelasticsearch +endif + if ENABLE_MMSNMPTRAPD SUBDIRS += plugins/mmsnmptrapd endif @@ -244,5 +248,6 @@ DISTCHECK_CONFIGURE_FLAGS= --enable-gssapi_krb5 \ --enable-imtemplate \ --enable-omtemplate \ --enable-mmsnmptrapd \ + --enable-elasticsearch \ --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) ACLOCAL_AMFLAGS = -I m4 diff --git a/configure.ac b/configure.ac index 6fbc84a6..099b78b9 100644 --- a/configure.ac +++ b/configure.ac @@ -669,6 +669,40 @@ AC_SUBST(SNMP_CFLAGS) AC_SUBST(SNMP_LIBS) +# elasticsearch support +AC_ARG_ENABLE(elasticsearch, + [AS_HELP_STRING([--enable-elasticsearch],[Enable elasticsearch output module @<:@default=no@:>@])], + [case "${enableval}" in + yes) enable_elasticsearch="yes" ;; + no) enable_elasticsearch="no" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-elasticsearch) ;; + esac], + [enable_elasticsearch=no] +) +if test "x$enable_elasticsearch" = "xyes"; then + AC_CHECK_PROG( + [HAVE_CURL_CONFIG], + [curl-config], + [yes],,, + ) + if test "x${HAVE_CURL_CONFIG}" != "xyes"; then + AC_MSG_FAILURE([curl-config not found in PATH]) + fi + AC_CHECK_LIB( + [curl], + [curl_global_init], + [CURL_CFLAGS="`curl-config --cflags`" + CURL_LIBS="`curl-config --libs`" + ], + [AC_MSG_FAILURE([curl library is missing])], + [`curl-config --libs --cflags`] + ) +fi +AM_CONDITIONAL(ENABLE_ELASTICSEARCH, test x$enable_elasticsearch = xyes) +AC_SUBST(CURL_CFLAGS) +AC_SUBST(CURL_LIBS) + + # GnuTLS support AC_ARG_ENABLE(gnutls, [AS_HELP_STRING([--enable-gnutls],[Enable GNU TLS support @<:@default=no@:>@])], @@ -1205,6 +1239,7 @@ AC_CONFIG_FILES([Makefile \ plugins/omsnmp/Makefile \ plugins/omoracle/Makefile \ plugins/omudpspoof/Makefile \ + plugins/omelasticsearch/Makefile \ plugins/sm_cust_bindcdr/Makefile \ plugins/mmsnmptrapd/Makefile \ plugins/cust1/Makefile \ @@ -1239,6 +1274,7 @@ echo " Mail support enabled: $enable_mail" echo " omprog module will be compiled: $enable_omprog" echo " omstdout module will be compiled: $enable_omstdout" echo " omhdfs module will be compiled: $enable_omhdfs" +echo " omelasticsearch module will be compiled: $enable_elasticsearch" echo " omruleset module will be compiled: $enable_omruleset" echo " omdbalerting module will be compiled: $enable_omdbalerting" echo " omudpspoof module will be compiled: $enable_omudpspoof" diff --git a/plugins/omelasticsearch/Makefile.am b/plugins/omelasticsearch/Makefile.am new file mode 100644 index 00000000..a574c72f --- /dev/null +++ b/plugins/omelasticsearch/Makefile.am @@ -0,0 +1,8 @@ +pkglib_LTLIBRARIES = omelasticsearch.la + +omelasticsearch_la_SOURCES = omelasticsearch.c +omelasticsearch_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) +omelasticsearch_la_LDFLAGS = -module -avoid-version +omelasticsearch_la_LIBADD = $(CURL_LIBS) + +EXTRA_DIST = diff --git a/plugins/omelasticsearch/omelasticsearch.c b/plugins/omelasticsearch/omelasticsearch.c new file mode 100644 index 00000000..ce2e0c1f --- /dev/null +++ b/plugins/omelasticsearch/omelasticsearch.c @@ -0,0 +1,271 @@ +/* omelasticsearch.c + * This is the http://www.elasticsearch.org/ output module. + * + * NOTE: read comments in module-template.h for more specifics! + * + * Copyright 2011 Nathan Scott. + * Copyright 2009 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of rsyslog. + * + * Rsyslog is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Rsyslog is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Rsyslog. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + */ +#include "config.h" +#include "rsyslog.h" +#include +#include +#include +#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 "statsobj.h" +#include "cfsysline.h" + +MODULE_TYPE_OUTPUT +MODULE_TYPE_NOKEEP + +/* internal structures */ +DEF_OMOD_STATIC_DATA +DEFobjCurrIf(errmsg) +DEFobjCurrIf(statsobj) + +statsobj_t *indexStats; +STATSCOUNTER_DEF(indexConFail, mutIndexConFail) +STATSCOUNTER_DEF(indexSubmit, mutIndexSubmit) +STATSCOUNTER_DEF(indexFailed, mutIndexFailed) +STATSCOUNTER_DEF(indexSuccess, mutIndexSuccess) + +/* REST API for elasticsearch hits this URL: + * http://:// + */ +typedef struct curl_slist HEADER; +typedef struct _instanceData { + CURL *curlHandle; /* libcurl session handle */ + HEADER *postHeader; /* json POST request info */ +} instanceData; + +/* config variables */ +static int restPort = 9200; +static char *hostName = "localhost"; +static char *searchIndex = "system"; +static char *searchType = "events"; + +BEGINcreateInstance +CODESTARTcreateInstance +ENDcreateInstance + +BEGINisCompatibleWithFeature +CODESTARTisCompatibleWithFeature + if(eFeat == sFEATURERepeatedMsgReduction) + iRet = RS_RET_OK; +ENDisCompatibleWithFeature + +BEGINfreeInstance +CODESTARTfreeInstance + if (pData->postHeader) { + curl_slist_free_all(pData->postHeader); + pData->postHeader = NULL; + } + if (pData->curlHandle) { + curl_easy_cleanup(pData->curlHandle); + pData->curlHandle = NULL; + } +ENDfreeInstance + +BEGINdbgPrintInstInfo +CODESTARTdbgPrintInstInfo +ENDdbgPrintInstInfo + +BEGINtryResume +CODESTARTtryResume +ENDtryResume + +rsRetVal +curlPost(instanceData *instance, uchar *message) +{ + CURLcode code; + CURL *curl = instance->curlHandle; + int length = strlen((char *)message); + + curl_easy_setopt(curl, CURLOPT_WRITEDATA, (char *)message); + curl_easy_setopt(curl, CURLOPT_POSTFIELDS, (char *)message); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, length); + code = curl_easy_perform(curl); + switch (code) { + case CURLE_COULDNT_RESOLVE_HOST: + case CURLE_COULDNT_RESOLVE_PROXY: + case CURLE_COULDNT_CONNECT: + case CURLE_WRITE_ERROR: + STATSCOUNTER_INC(indexConFail, mutIndexConFail); + return RS_RET_SUSPENDED; + default: + STATSCOUNTER_INC(indexSubmit, mutIndexSubmit); + return RS_RET_OK; + } +} + +BEGINdoAction +CODESTARTdoAction + CHKiRet(curlPost(pData, ppString[0])); +finalize_it: +ENDdoAction + +/* elasticsearch POST result string ... useful for debugging */ +size_t +curlResult(void *ptr, size_t size, size_t nmemb, void *userdata) +{ + unsigned int i; + char *p = (char *)ptr; + char *jsonData = (char *)userdata; + static char ok[] = "{\"ok\":true,"; + + ASSERT(size == 1); + + if (size == 1 && + nmemb > sizeof(ok)-1 && + strncmp(p, ok, sizeof(ok)-1) == 0) { + STATSCOUNTER_INC(indexSuccess, mutIndexSuccess); + } else { + STATSCOUNTER_INC(indexFailed, mutIndexFailed); + if (Debug) { + DBGPRINTF("omelasticsearch request: %s\n", jsonData); + DBGPRINTF("omelasticsearch result: "); + for (i = 0; i < nmemb; i++) + DBGPRINTF("%c", p[i]); + DBGPRINTF("\n"); + } + } + return size * nmemb; +} + +static rsRetVal +curlSetup(instanceData *instance) +{ + char restURL[2048]; /* libcurl makes a copy, using the stack here is OK */ + HEADER *header; + CURL *handle; + + handle = curl_easy_init(); + if (handle == NULL) { + return RS_RET_OBJ_CREATION_FAILED; + } + + snprintf(restURL, sizeof(restURL)-1, "http://%s:%d/%s/%s", + hostName, restPort, searchIndex, searchType); + header = curl_slist_append(NULL, "Content-Type: text/json; charset=utf-8"); + + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, curlResult); + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, header); + curl_easy_setopt(handle, CURLOPT_URL, restURL); + curl_easy_setopt(handle, CURLOPT_POST, 1); + + instance->curlHandle = handle; + instance->postHeader = header; + + DBGPRINTF("omelasticsearch setup, using REST URL: %s\n", restURL); + return RS_RET_OK; +} + +BEGINparseSelectorAct +CODESTARTparseSelectorAct +CODE_STD_STRING_REQUESTparseSelectorAct(1) + if(strncmp((char*) p, ":omelasticsearch:", sizeof(":omelasticsearch:") - 1)) { + ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); + } + p += sizeof(":omelasticsearch:") - 1; /* eat indicator sequence (-1 because of '\0'!) */ + CHKiRet(createInstance(&pData)); + + /* check if a non-standard template is to be applied */ + if(*(p-1) == ';') + --p; + CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (uchar*) " StdJSONFmt")); + + /* all good, we can now initialise our private data */ + CHKiRet(curlSetup(pData)); +CODE_STD_FINALIZERparseSelectorAct +ENDparseSelectorAct + +BEGINmodExit +CODESTARTmodExit + curl_global_cleanup(); + statsobj.Destruct(&indexStats); + objRelease(errmsg, CORE_COMPONENT); + objRelease(statsobj, CORE_COMPONENT); +ENDmodExit + +BEGINqueryEtryPt +CODESTARTqueryEtryPt +CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES +ENDqueryEtryPt + +static rsRetVal +resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) +{ + DEFiRet; + restPort = 9200; + hostName = "localhost"; + searchIndex = "system"; + searchType = "events"; + RETiRet; +} + +BEGINmodInit() +CODESTARTmodInit + *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ +CODEmodInit_QueryRegCFSLineHdlr + CHKiRet(objUse(errmsg, CORE_COMPONENT)); + CHKiRet(objUse(statsobj, CORE_COMPONENT)); + + /* register config file handlers */ + CHKiRet(omsdRegCFSLineHdlr((uchar *)"elasticsearchindex", 0, eCmdHdlrGetWord, NULL, &searchIndex, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"elasticsearchtype", 0, eCmdHdlrGetWord, NULL, &searchType, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"elasticsearchhost", 0, eCmdHdlrGetWord, NULL, &hostName, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"elasticsearchport", 0, eCmdHdlrInt, NULL, &restPort, STD_LOADABLE_MODULE_ID)); + CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); + + if (curl_global_init(CURL_GLOBAL_ALL) != 0) { + errmsg.LogError(0, RS_RET_OBJ_CREATION_FAILED, "CURL fail. -elasticsearch indexing disabled"); + ABORT_FINALIZE(RS_RET_OBJ_CREATION_FAILED); + } + + /* support statistics gathering */ + CHKiRet(statsobj.Construct(&indexStats)); + CHKiRet(statsobj.SetName(indexStats, (uchar *)"elasticsearch")); + CHKiRet(statsobj.AddCounter(indexStats, (uchar *)"connfail", + ctrType_IntCtr, &indexConFail)); + CHKiRet(statsobj.AddCounter(indexStats, (uchar *)"submits", + ctrType_IntCtr, &indexSubmit)); + CHKiRet(statsobj.AddCounter(indexStats, (uchar *)"failed", + ctrType_IntCtr, &indexFailed)); + CHKiRet(statsobj.AddCounter(indexStats, (uchar *)"success", + ctrType_IntCtr, &indexSuccess)); + CHKiRet(statsobj.ConstructFinalize(indexStats)); +ENDmodInit + +/* vi:set ai: + */ diff --git a/tools/syslogd.c b/tools/syslogd.c index 0b7bbc96..bec2f9a7 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -334,6 +334,7 @@ static uchar template_WallFmt[] = "\"\r\n\7Message from syslogd@%HOSTNAME% at %t static uchar template_StdUsrMsgFmt[] = "\" %syslogtag%%msg%\n\r\""; static uchar template_StdDBFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-mysql%', '%timegenerated:::date-mysql%', %iut%, '%syslogtag%')\",SQL"; static uchar template_StdPgSQLFmt[] = "\"insert into SystemEvents (Message, Facility, FromHost, Priority, DeviceReportedTime, ReceivedAt, InfoUnitID, SysLogTag) values ('%msg%', %syslogfacility%, '%HOSTNAME%', %syslogpriority%, '%timereported:::date-pgsql%', '%timegenerated:::date-pgsql%', %iut%, '%syslogtag%')\",STDSQL"; +static uchar template_StdJSONFmt[] = "\"{\\\"message\\\":\\\"%msg%\\\",\\\"fromhost\\\":\\\"%HOSTNAME%\\\",\\\"facility\\\":\\\"%syslogfacility-text%\\\",\\\"priority\\\":\\\"%syslogpriority-text%\\\",\\\"timereported\\\":\\\"%timereported:::date-rfc3339%\\\",\\\"timegenerated\\\":\\\"%timegenerated:::date-rfc3339%\\\"}\",JSON"; static uchar template_spoofadr[] = "\"%fromhost-ip%\""; /* end templates */ @@ -2173,6 +2174,8 @@ static rsRetVal mainThread() tplAddLine(" StdDBFmt", &pTmp); pTmp = template_StdPgSQLFmt; tplAddLine(" StdPgSQLFmt", &pTmp); + pTmp = template_StdJSONFmt; + tplAddLine(" StdJSONFmt", &pTmp); pTmp = template_spoofadr; tplLastStaticInit(tplAddLine("RSYSLOG_omudpspoofDfltSourceTpl", &pTmp)); -- cgit v1.2.3 From 9911dacf59e898bae2c8c6619b85348bf54ddc23 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 17 Jan 2012 10:42:04 +0100 Subject: elasticsearch: move to asl 2.0 email conversation Nathan/Rainer 2012-01-16&17 --- plugins/omelasticsearch/omelasticsearch.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/plugins/omelasticsearch/omelasticsearch.c b/plugins/omelasticsearch/omelasticsearch.c index ce2e0c1f..3bec1838 100644 --- a/plugins/omelasticsearch/omelasticsearch.c +++ b/plugins/omelasticsearch/omelasticsearch.c @@ -8,20 +8,19 @@ * * 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. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * -or- + * see COPYING.ASL20 in the source distribution + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ #include "config.h" #include "rsyslog.h" -- cgit v1.2.3 From 19a09944b477819c74b16c9861f1e7db085b4170 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 18 Jan 2012 10:57:55 +0100 Subject: imptcp: added basic stats counters --- plugins/imptcp/imptcp.c | 42 ++++++++++++++++++++++++++++++++---------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 65fe703c..951b24e4 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -65,6 +65,7 @@ #include "datetime.h" #include "ruleset.h" #include "msg.h" +#include "statsobj.h" #include "net.h" /* for permittedPeers, may be removed when this is removed */ /* the define is from tcpsrv.h, we need to find a new (but easier!!!) abstraction layer some time ... */ @@ -82,7 +83,7 @@ DEFobjCurrIf(prop) DEFobjCurrIf(datetime) DEFobjCurrIf(errmsg) DEFobjCurrIf(ruleset) - +DEFobjCurrIf(statsobj) /* config settings */ @@ -123,7 +124,8 @@ struct ptcpsrv_s { * includes support for doubly-linked list. */ struct ptcpsess_s { - ptcpsrv_t *pSrv; /* our server */ +// ptcpsrv_t *pSrv; /* our server TODO: check remove! */ + ptcplstn_t *pLstn; /* our listener */ ptcpsess_t *prev, *next; int sock; epolld_t *epd; @@ -151,6 +153,8 @@ struct ptcplstn_s { ptcplstn_t *prev, *next; int sock; epolld_t *epd; + statsobj_t *stats; /* listener stats */ + STATSCOUNTER_DEF(ctrSubmit, mutCtrSubmit) }; @@ -492,22 +496,25 @@ static rsRetVal doSubmitMsg(ptcpsess_t *pThis, struct syslogTime *stTime, time_t ttGenTime, multi_submit_t *pMultiSub) { msg_t *pMsg; + ptcpsrv_t *pSrv; DEFiRet; if(pThis->iMsg == 0) { DBGPRINTF("discarding zero-sized message\n"); FINALIZE; } + pSrv = pThis->pLstn->pSrv; /* we now create our own message object and submit it to the queue */ CHKiRet(msgConstructWithTime(&pMsg, stTime, ttGenTime)); MsgSetRawMsg(pMsg, (char*)pThis->pMsg, pThis->iMsg); - MsgSetInputName(pMsg, pThis->pSrv->pInputName); + MsgSetInputName(pMsg, pSrv->pInputName); MsgSetFlowControlType(pMsg, eFLOWCTL_LIGHT_DELAY); pMsg->msgFlags = NEEDS_PARSING | PARSE_HOSTNAME; MsgSetRcvFrom(pMsg, pThis->peerName); CHKiRet(MsgSetRcvFromIP(pMsg, pThis->peerIP)); - MsgSetRuleset(pMsg, pThis->pSrv->pRuleset); + MsgSetRuleset(pMsg, pSrv->pRuleset); + STATSCOUNTER_INC(pThis->pLstn->ctrSubmit, pThis->pLstn->mutCtrSubmit); if(pMultiSub == NULL) { CHKiRet(submitMsg(pMsg)); @@ -589,7 +596,8 @@ processDataRcvd(ptcpsess_t *pThis, char c, struct syslogTime *stTime, time_t ttG } if(( (c == '\n') - || ((pThis->pSrv->iAddtlFrameDelim != TCPSRV_NO_ADDTL_DELIMITER) && (c == pThis->pSrv->iAddtlFrameDelim)) + || ((pThis->pLstn->pSrv->iAddtlFrameDelim != TCPSRV_NO_ADDTL_DELIMITER) + && (c == pThis->pLstn->pSrv->iAddtlFrameDelim)) ) && pThis->eFraming == TCP_FRAMING_OCTET_STUFFING) { /* record delimiter? */ doSubmitMsg(pThis, stTime, ttGenTime, pMultiSub); pThis->inputState = eAtStrtFram; @@ -751,10 +759,19 @@ addLstn(ptcpsrv_t *pSrv, int sock) { DEFiRet; ptcplstn_t *pLstn; + uchar statname[64]; CHKmalloc(pLstn = malloc(sizeof(ptcplstn_t))); pLstn->pSrv = pSrv; pLstn->sock = sock; + /* support statistics gathering */ + CHKiRet(statsobj.Construct(&(pLstn->stats))); + snprintf((char*)statname, sizeof(statname), "imptcp(%s)", pSrv->port); + statname[sizeof(statname)-1] = '\0'; /* just to be on the save side... */ + CHKiRet(statsobj.SetName(pLstn->stats, statname)); + CHKiRet(statsobj.AddCounter(pLstn->stats, UCHAR_CONSTANT("submitted"), + ctrType_IntCtr, &(pLstn->ctrSubmit))); + CHKiRet(statsobj.ConstructFinalize(pLstn->stats)); /* add to start of server's listener list */ pLstn->prev = NULL; @@ -773,14 +790,15 @@ finalize_it: /* add a session to the server */ static rsRetVal -addSess(ptcpsrv_t *pSrv, int sock, prop_t *peerName, prop_t *peerIP) +addSess(ptcplstn_t *pLstn, int sock, prop_t *peerName, prop_t *peerIP) { DEFiRet; ptcpsess_t *pSess = NULL; + ptcpsrv_t *pSrv = pLstn->pSrv; CHKmalloc(pSess = malloc(sizeof(ptcpsess_t))); CHKmalloc(pSess->pMsg = malloc(iMaxLine * sizeof(uchar))); - pSess->pSrv = pSrv; + pSess->pLstn = pLstn; pSess->sock = sock; pSess->inputState = eAtStrtFram; pSess->iMsg = 0; @@ -824,7 +842,7 @@ closeSess(ptcpsess_t *pSess) pSess->next->prev = pSess->prev; if(pSess->prev == NULL) { /* need to update root! */ - pSess->pSrv->pSess = pSess->next; + pSess->pLstn->pSrv->pSess = pSess->next; } else { pSess->prev->next = pSess->next; } @@ -949,7 +967,7 @@ lstnActivity(ptcplstn_t *pLstn) if(localRet == RS_RET_NO_MORE_DATA) break; CHKiRet(localRet); - CHKiRet(addSess(pLstn->pSrv, newSock, peerName, peerIP)); + CHKiRet(addSess(pLstn, newSock, peerName, peerIP)); } finalize_it: @@ -979,7 +997,7 @@ sessActivity(ptcpsess_t *pSess) CHKiRet(DataRcvd(pSess, rcvBuf, lenRcv)); } else if (lenRcv == 0) { /* session was closed, do clean-up */ - if(pSess->pSrv->bEmitMsgOnClose) { + if(pSess->pLstn->pSrv->bEmitMsgOnClose) { uchar *peerName; int lenPeer; prop.GetString(pSess->peerName, &peerName, &lenPeer); @@ -1085,6 +1103,8 @@ shutdownSrv(ptcpsrv_t *pSrv) pLstn = pSrv->pLstn; while(pLstn != NULL) { close(pLstn->sock); + statsobj.Destruct(&(pLstn->stats)); + /* now unlink listner */ lstnDel = pLstn; pLstn = pLstn->next; DBGPRINTF("imptcp shutdown listen socket %d\n", lstnDel->sock); @@ -1132,6 +1152,7 @@ CODESTARTmodExit /* release objects we used */ objRelease(glbl, CORE_COMPONENT); + objRelease(statsobj, CORE_COMPONENT); objRelease(prop, CORE_COMPONENT); objRelease(net, LM_NET_FILENAME); objRelease(datetime, CORE_COMPONENT); @@ -1167,6 +1188,7 @@ CODEmodInit_QueryRegCFSLineHdlr initConfigSettings(); /* request objects we use */ CHKiRet(objUse(glbl, CORE_COMPONENT)); + CHKiRet(objUse(statsobj, CORE_COMPONENT)); CHKiRet(objUse(prop, CORE_COMPONENT)); CHKiRet(objUse(net, LM_NET_FILENAME)); CHKiRet(objUse(errmsg, CORE_COMPONENT)); -- cgit v1.2.3 From b41fc354ede3baec9740cb7e6a2f609824269836 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 18 Jan 2012 12:31:01 +0100 Subject: imptcp: added additional information to stats record --- plugins/imptcp/imptcp.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/plugins/imptcp/imptcp.c b/plugins/imptcp/imptcp.c index 951b24e4..103da210 100644 --- a/plugins/imptcp/imptcp.c +++ b/plugins/imptcp/imptcp.c @@ -192,7 +192,7 @@ static char rcvBuf[128*1024]; /* forward definitions */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); -static rsRetVal addLstn(ptcpsrv_t *pSrv, int sock); +static rsRetVal addLstn(ptcpsrv_t *pSrv, int sock, int isIPv6); /* some simple constructors/destructors */ @@ -237,6 +237,7 @@ startupSrv(ptcpsrv_t *pSrv) int sockflags; struct addrinfo hints, *res = NULL, *r; uchar *lstnIP; + int isIPv6 = 0; lstnIP = pSrv->lstnIP == NULL ? UCHAR_CONSTANT("") : pSrv->lstnIP; @@ -269,8 +270,9 @@ startupSrv(ptcpsrv_t *pSrv) continue; } -#ifdef IPV6_V6ONLY if(r->ai_family == AF_INET6) { + isIPv6 = 1; +#ifdef IPV6_V6ONLY int iOn = 1; if(setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&iOn, sizeof (iOn)) < 0) { @@ -278,8 +280,8 @@ startupSrv(ptcpsrv_t *pSrv) sock = -1; continue; } - } #endif + } if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)) < 0 ) { DBGPRINTF("error %d setting tcp socket option\n", errno); close(sock); @@ -341,7 +343,7 @@ startupSrv(ptcpsrv_t *pSrv) /* if we reach this point, we were able to obtain a valid socket, so we can * create our listener object. -- rgerhards, 2010-08-10 */ - CHKiRet(addLstn(pSrv, sock)); + CHKiRet(addLstn(pSrv, sock, isIPv6)); ++numSocks; } @@ -755,7 +757,7 @@ finalize_it: /* add a listener to the server */ static rsRetVal -addLstn(ptcpsrv_t *pSrv, int sock) +addLstn(ptcpsrv_t *pSrv, int sock, int isIPv6) { DEFiRet; ptcplstn_t *pLstn; @@ -766,7 +768,9 @@ addLstn(ptcpsrv_t *pSrv, int sock) pLstn->sock = sock; /* support statistics gathering */ CHKiRet(statsobj.Construct(&(pLstn->stats))); - snprintf((char*)statname, sizeof(statname), "imptcp(%s)", pSrv->port); + snprintf((char*)statname, sizeof(statname), "imptcp(%s/%s/%s)", + (pSrv->lstnIP == NULL) ? "*" : (char*)pSrv->lstnIP, pSrv->port, + isIPv6 ? "IPv6" : "IPv4"); statname[sizeof(statname)-1] = '\0'; /* just to be on the save side... */ CHKiRet(statsobj.SetName(pLstn->stats, statname)); CHKiRet(statsobj.AddCounter(pLstn->stats, UCHAR_CONSTANT("submitted"), -- cgit v1.2.3 From 535d6cf0b8fe2423eee3fd670bc1e944b231e827 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 19 Jan 2012 14:48:40 +0100 Subject: v6.1/2 scoping support removed from plugins --- plugins/mmnormalize/mmnormalize.c | 5 ++--- plugins/mmsnmptrapd/mmsnmptrapd.c | 5 ++--- plugins/omlibdbi/omlibdbi.c | 5 ++--- plugins/ommail/ommail.c | 5 ++--- plugins/ommysql/ommysql.c | 5 ++--- plugins/ompgsql/ompgsql.c | 5 ++--- plugins/omprog/omprog.c | 5 ++--- plugins/omrelp/omrelp.c | 5 ++--- plugins/omruleset/omruleset.c | 5 ++--- plugins/omstdout/omstdout.c | 5 ++--- plugins/omtesting/omtesting.c | 5 ++--- plugins/omudpspoof/omudpspoof.c | 5 ++--- plugins/omuxsock/omuxsock.c | 4 ++-- runtime/module-template.h | 37 +++---------------------------------- tools/omdiscard.c | 11 ----------- tools/omfile.c | 5 ++--- tools/omfwd.c | 5 ++--- tools/ompipe.c | 5 ++--- tools/omshell.c | 5 ++--- tools/omusrmsg.c | 4 ++-- 20 files changed, 39 insertions(+), 97 deletions(-) diff --git a/plugins/mmnormalize/mmnormalize.c b/plugins/mmnormalize/mmnormalize.c index fd898a3b..7b92d820 100644 --- a/plugins/mmnormalize/mmnormalize.c +++ b/plugins/mmnormalize/mmnormalize.c @@ -69,8 +69,7 @@ typedef struct configSettings_s { uchar *rulebase; /**< name of normalization rulebase to use */ sbool bUseRawMsg; /**< use %rawmsg% instead of %msg% */ } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -238,7 +237,7 @@ BEGINmodInit() unsigned long opts; int bMsgPassingSupported; CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr diff --git a/plugins/mmsnmptrapd/mmsnmptrapd.c b/plugins/mmsnmptrapd/mmsnmptrapd.c index cfc30a95..b1ac2f64 100644 --- a/plugins/mmsnmptrapd/mmsnmptrapd.c +++ b/plugins/mmsnmptrapd/mmsnmptrapd.c @@ -77,8 +77,7 @@ typedef struct configSettings_s { uchar *pszTagName; /**< name of tag start value that indicates snmptrapd initiated message */ uchar *pszSeverityMapping; /**< severitystring to numerical code mapping for snmptrapd string */ } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -386,7 +385,7 @@ BEGINmodInit() unsigned long opts; int bMsgPassingSupported; CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr diff --git a/plugins/omlibdbi/omlibdbi.c b/plugins/omlibdbi/omlibdbi.c index 4bca5263..44e635c1 100644 --- a/plugins/omlibdbi/omlibdbi.c +++ b/plugins/omlibdbi/omlibdbi.c @@ -78,8 +78,7 @@ typedef struct configSettings_s { uchar *pwd; /* password for connect */ uchar *dbName; /* database to use */ } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -361,7 +360,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a BEGINmodInit() CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); diff --git a/plugins/ommail/ommail.c b/plugins/ommail/ommail.c index 73bccd15..d70fa30a 100644 --- a/plugins/ommail/ommail.c +++ b/plugins/ommail/ommail.c @@ -98,8 +98,7 @@ typedef struct configSettings_s { uchar *pszSubject; int bEnableBody; /* should a mail body be generated? (set to 0 eg for SMS gateways) */ } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -706,7 +705,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a BEGINmodInit() CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr /* tell which objects we need */ diff --git a/plugins/ommysql/ommysql.c b/plugins/ommysql/ommysql.c index d5fa7c71..50ebf3a3 100644 --- a/plugins/ommysql/ommysql.c +++ b/plugins/ommysql/ommysql.c @@ -73,8 +73,7 @@ typedef struct configSettings_s { uchar *pszMySQLConfigFile; /* MySQL Client Configuration File */ uchar *pszMySQLConfigSection; /* MySQL Client Configuration Section */ } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -356,7 +355,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a BEGINmodInit() CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); diff --git a/plugins/ompgsql/ompgsql.c b/plugins/ompgsql/ompgsql.c index 46e929dd..2c10d881 100644 --- a/plugins/ompgsql/ompgsql.c +++ b/plugins/ompgsql/ompgsql.c @@ -69,8 +69,7 @@ typedef struct _instanceData { typedef struct configSettings_s { EMPTY_STRUCT } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -368,7 +367,7 @@ ENDqueryEtryPt BEGINmodInit() CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); diff --git a/plugins/omprog/omprog.c b/plugins/omprog/omprog.c index 9b2ad934..1f6bb62f 100644 --- a/plugins/omprog/omprog.c +++ b/plugins/omprog/omprog.c @@ -62,8 +62,7 @@ typedef struct _instanceData { typedef struct configSettings_s { uchar *szBinary; /* name of binary to call */ } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -349,7 +348,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a BEGINmodInit() CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c index 804a2da4..ca64daf2 100644 --- a/plugins/omrelp/omrelp.c +++ b/plugins/omrelp/omrelp.c @@ -68,8 +68,7 @@ typedef struct _instanceData { typedef struct configSettings_s { EMPTY_STRUCT } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -347,7 +346,7 @@ ENDqueryEtryPt BEGINmodInit() CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr /* create our relp engine */ diff --git a/plugins/omruleset/omruleset.c b/plugins/omruleset/omruleset.c index ccc82d72..67aee97e 100644 --- a/plugins/omruleset/omruleset.c +++ b/plugins/omruleset/omruleset.c @@ -74,8 +74,7 @@ typedef struct configSettings_s { ruleset_t *pRuleset; /* ruleset to enqueue message to (NULL = Default, not recommended) */ uchar *pszRulesetName; } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -215,7 +214,7 @@ BEGINmodInit() unsigned long opts; int bMsgPassingSupported; /* does core support template passing as an array? */ CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr /* check if the rsyslog core supports parameter passing code */ diff --git a/plugins/omstdout/omstdout.c b/plugins/omstdout/omstdout.c index f8564a01..fb95e951 100644 --- a/plugins/omstdout/omstdout.c +++ b/plugins/omstdout/omstdout.c @@ -64,8 +64,7 @@ typedef struct configSettings_s { int bUseArrayInterface; /* shall action use array instead of string template interface? */ int bEnsureLFEnding; /* shall action use array instead of string template interface? */ } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -197,7 +196,7 @@ BEGINmodInit() unsigned long opts; int bArrayPassingSupported; /* does core support template passing as an array? */ CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr /* check if the rsyslog core supports parameter passing code */ diff --git a/plugins/omtesting/omtesting.c b/plugins/omtesting/omtesting.c index 466aab3f..ff290c94 100644 --- a/plugins/omtesting/omtesting.c +++ b/plugins/omtesting/omtesting.c @@ -79,8 +79,7 @@ typedef struct _instanceData { typedef struct configSettings_s { int bEchoStdout; /* echo non-failed messages to stdout */ } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -319,7 +318,7 @@ ENDqueryEtryPt BEGINmodInit() CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomtestingechostdout", 0, eCmdHdlrBinary, NULL, diff --git a/plugins/omudpspoof/omudpspoof.c b/plugins/omudpspoof/omudpspoof.c index 762f83c5..506fca77 100644 --- a/plugins/omudpspoof/omudpspoof.c +++ b/plugins/omudpspoof/omudpspoof.c @@ -115,8 +115,7 @@ typedef struct configSettings_s { int iSourcePortStart; int iSourcePortEnd; } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -485,7 +484,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a BEGINmodInit() CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(glbl, CORE_COMPONENT)); diff --git a/plugins/omuxsock/omuxsock.c b/plugins/omuxsock/omuxsock.c index f6b18111..cf27c93c 100644 --- a/plugins/omuxsock/omuxsock.c +++ b/plugins/omuxsock/omuxsock.c @@ -69,8 +69,7 @@ typedef struct configSettings_s { uchar *tplName; /* name of the default template to use */ uchar *sockName; /* name of the default template to use */ } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -307,6 +306,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a BEGINmodInit() CODESTARTmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(glbl, CORE_COMPONENT)); diff --git a/runtime/module-template.h b/runtime/module-template.h index b98890ae..75bf7312 100644 --- a/runtime/module-template.h +++ b/runtime/module-template.h @@ -375,38 +375,7 @@ static rsRetVal tryResume(instanceData __attribute__((unused)) *pData)\ } -/* Config scoping system. - * save current config scope and start a new one. Note that we do NOT implement a - * stack. Exactly one scope can be saved. - * We assume standard naming conventions (local confgSettings_t holds all - * config settings and MUST have been defined before this macro is being used!). - * Note that initConfVars() must be defined locally as well. - */ -#define SCOPING_SUPPORT \ -static rsRetVal initConfVars(void);\ -static configSettings_t cs; /* our current config settings */ \ -static configSettings_t cs_save; /* our saved (scope!) config settings */ \ -static rsRetVal __attribute__((unused)) newScope(void) \ -{ \ - DEFiRet; \ - memcpy(&cs_save, &cs, sizeof(cs)); \ - iRet = initConfVars(); \ - RETiRet; \ -} \ -static rsRetVal __attribute__((unused)) restoreScope(void) \ -{ \ - DEFiRet; \ - memcpy(&cs, &cs_save, sizeof(cs)); \ - RETiRet; \ -} -/* initConfVars() - * 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, - * the engine periodically tries to resume the module. If that succeeds, normal - * processing continues. If not, the module will not be called unless a - * tryResume() call succeeds. - * Returns RS_RET_OK, if resumption succeeded, RS_RET_SUSPENDED otherwise - * rgerhard, 2007-08-02 +/* initConfVars() - initialize pre-v6.3-config variables */ #define BEGINinitConfVars \ static rsRetVal initConfVars(void)\ @@ -634,8 +603,8 @@ rsRetVal modInit##uniqName(int iIFVersRequested __attribute__((unused)), int *ip /* now get the obj interface so that we can access other objects */ \ CHKiRet(pObjGetObjInterface(&obj)); -/* do those initializations necessary for scoping */ -#define SCOPINGmodInit \ +/* do those initializations necessary for legacy config variables */ +#define INITLegCnfVars \ initConfVars(); #define ENDmodInit \ diff --git a/tools/omdiscard.c b/tools/omdiscard.c index 5b64d3ff..182c4b63 100644 --- a/tools/omdiscard.c +++ b/tools/omdiscard.c @@ -47,16 +47,6 @@ typedef struct _instanceData { EMPTY_STRUCT } instanceData; -typedef struct configSettings_s { - EMPTY_STRUCT -} configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ - -BEGINinitConfVars /* (re)set config variables to default values */ -CODESTARTinitConfVars -ENDinitConfVars - /* we do not need a createInstance()! BEGINcreateInstance CODESTARTcreateInstance @@ -124,7 +114,6 @@ ENDqueryEtryPt BEGINmodInit(Discard) CODESTARTmodInit -SCOPINGmodInit *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr ENDmodInit diff --git a/tools/omfile.c b/tools/omfile.c index e618b817..c7f1b896 100644 --- a/tools/omfile.c +++ b/tools/omfile.c @@ -177,10 +177,9 @@ typedef struct configSettings_s { int bUseAsyncWriter; /* should we enable asynchronous writing? */ EMPTY_STRUCT } configSettings_t; +static configSettings_t cs; uchar *pszFileDfltTplName; /* name of the default template to use */ -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ - /* tables for interfacing with the v6 config system */ /* action (instance) parameters */ static struct cnfparamdescr actpdescr[] = { @@ -1010,7 +1009,7 @@ BEGINmodInit(File) CODESTARTmodInit *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr -SCOPINGmodInit +INITLegCnfVars CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(objUse(strm, CORE_COMPONENT)); diff --git a/tools/omfwd.c b/tools/omfwd.c index da8f9e22..96458941 100644 --- a/tools/omfwd.c +++ b/tools/omfwd.c @@ -112,8 +112,7 @@ typedef struct configSettings_s { int iUDPRebindInterval; /* support for automatic re-binding (load balancers!). 0 - no rebind */ permittedPeers_t *pPermPeers; } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; /* tables for interfacing with the v6 config system */ /* action (instance) parameters */ @@ -987,7 +986,7 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a BEGINmodInit(Fwd) CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(glbl, CORE_COMPONENT)); diff --git a/tools/ompipe.c b/tools/ompipe.c index 7400bb18..1eb0dbce 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -78,8 +78,7 @@ typedef struct _instanceData { typedef struct configSettings_s { EMPTY_STRUCT } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -250,7 +249,7 @@ ENDqueryEtryPt BEGINmodInit(Pipe) CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); diff --git a/tools/omshell.c b/tools/omshell.c index 648d28a4..130d89d8 100644 --- a/tools/omshell.c +++ b/tools/omshell.c @@ -60,8 +60,7 @@ typedef struct _instanceData { typedef struct configSettings_s { EMPTY_STRUCT /* remove this when data members are added */ } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -148,7 +147,7 @@ ENDqueryEtryPt BEGINmodInit(Shell) CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); diff --git a/tools/omusrmsg.c b/tools/omusrmsg.c index 6d6b267a..f8e40594 100644 --- a/tools/omusrmsg.c +++ b/tools/omusrmsg.c @@ -91,7 +91,7 @@ typedef struct configSettings_s { EMPTY_STRUCT } configSettings_t; -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; /* tables for interfacing with the v6 config system */ @@ -442,7 +442,7 @@ ENDqueryEtryPt BEGINmodInit(UsrMsg) CODESTARTmodInit -SCOPINGmodInit +INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); -- cgit v1.2.3 From 7ed586df12b8d2f6f70f21ab08bd99c71850ba6c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 19 Jan 2012 14:58:36 +0100 Subject: refactor: removing v6.1 scoping code --- runtime/cfsysline.c | 30 +++++-------- runtime/conf.c | 122 +--------------------------------------------------- 2 files changed, 12 insertions(+), 140 deletions(-) diff --git a/runtime/cfsysline.c b/runtime/cfsysline.c index 870c5faf..7814e86a 100644 --- a/runtime/cfsysline.c +++ b/runtime/cfsysline.c @@ -937,25 +937,17 @@ rsRetVal processCfSysLineCommand(uchar *pCmdName, uchar **p) llCookieCmdHdlr = NULL; bWasOnceOK = 0; while((iRetLL = llGetNextElt(&pCmd->llCmdHdlrs, &llCookieCmdHdlr, (void*)&pCmdHdlr)) == RS_RET_OK) { - /* check if handler is valid in current scope */ - if(pCmdHdlr->eConfObjType == eConfObjAlways || - (bConfStrictScoping == 0 && currConfObj == eConfObjGlobal) || - pCmdHdlr->eConfObjType == currConfObj) { - /* for the time being, we ignore errors during handlers. The - * reason is that handlers are independent. An error in one - * handler does not necessarily mean that another one will - * fail, too. Later, we might add a config variable to control - * this behaviour (but I am not sure if that is really - * necessary). -- rgerhards, 2007-07-31 - */ - pHdlrP = *p; - if((iRet = cslchCallHdlr(pCmdHdlr, &pHdlrP)) == RS_RET_OK) { - bWasOnceOK = 1; - pOKp = pHdlrP; - } - } else { - errmsg.LogError(0, RS_RET_CONF_INVLD_SCOPE, "config command invalid for current scope"); - bHadScopingErr = 1; + /* for the time being, we ignore errors during handlers. The + * reason is that handlers are independent. An error in one + * handler does not necessarily mean that another one will + * fail, too. Later, we might add a config variable to control + * this behaviour (but I am not sure if that is really + * necessary). -- rgerhards, 2007-07-31 + */ + pHdlrP = *p; + if((iRet = cslchCallHdlr(pCmdHdlr, &pHdlrP)) == RS_RET_OK) { + bWasOnceOK = 1; + pOKp = pHdlrP; } } diff --git a/runtime/conf.c b/runtime/conf.c index 7849598e..f5e064ff 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -82,7 +82,6 @@ DEFobjCurrIf(net) DEFobjCurrIf(rule) DEFobjCurrIf(ruleset) -ecslConfObjType currConfObj = eConfObjGlobal; /* to support scoping - which config object is currently active? */ int bConfStrictScoping = 0; /* force strict scoping during config processing? */ @@ -740,8 +739,6 @@ rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) /* advance our config parser state: we now only accept an $End as valid, * no more action statments. */ - if(currConfObj == eConfObjAction) - currConfObj = eConfObjActionWaitEnd; if((iRet = addAction(&pAction, pMod, pModData, pOMSR, NULL, NULL, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { /* now check if the module is compatible with select features */ @@ -812,129 +809,12 @@ finalize_it: ENDobjQueryInterface(conf) -/* switch to a new action scope. This means that we switch the current - * mode to action, but it also means we need to clear all scope variables, - * so that we have a new environment. - * rgerhards, 2010-07-23 - */ -static inline rsRetVal -setActionScope(void) -{ - DEFiRet; - cfgmodules_etry_t *node; - - currConfObj = eConfObjAction; - DBGPRINTF("entering action scope\n"); - CHKiRet(actionNewScope()); - - /* now tell each action to start the scope */ - node = NULL; - while((node = module.GetNxtCnfType(loadConf, node, eMOD_OUT)) != NULL) { - DBGPRINTF("NO LONGER SUPPORTED beginning scope on module %s\n", node->pMod->pszName); - } - -finalize_it: - RETiRet; -} - - -/* switch back from action scope. - * rgerhards, 2010-07-27 - */ -static inline rsRetVal -unsetActionScope(void) -{ - DEFiRet; - cfgmodules_etry_t *node; - - currConfObj = eConfObjAction; - DBGPRINTF("exiting action scope\n"); - CHKiRet(actionRestoreScope()); - - /* now tell each action to restore the scope */ - node = NULL; - while((node = module.GetNxtCnfType(loadConf, node, eMOD_OUT)) != NULL) { - DBGPRINTF("NO LONGER SUPPORTED exiting scope on module %s\n", node->pMod->pszName); - } - -finalize_it: - RETiRet; -} - - -/* This method is called by our own handlers to begin a new config - * object ($Begin statement). This also implies a new scope. - * rgerhards, 2010-07-23 - */ -static rsRetVal -beginConfObj(void __attribute__((unused)) *pVal, uchar *pszName) -{ - DEFiRet; - - if(currConfObj != eConfObjGlobal) { - errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "not in global scope - can not nest $Begin"); - ABORT_FINALIZE(RS_RET_CONF_NOT_GLBL); - } - - if(!strcasecmp((char*)pszName, "action")) { - setActionScope(); - } else { - errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $Begin", pszName); - ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ); - } - -finalize_it: - free(pszName); /* no longer needed */ - RETiRet; -} - - -/* This method is called to end a config scope and switch - * back to global scope. - * rgerhards, 2010-07-23 - */ -static rsRetVal -endConfObj(void __attribute__((unused)) *pVal, uchar *pszName) -{ - DEFiRet; - - if(currConfObj == eConfObjGlobal) { - errmsg.LogError(0, RS_RET_CONF_NOT_GLBL, "already in global scope - dangling $End"); - ABORT_FINALIZE(RS_RET_CONF_IN_GLBL); - } - - if(!strcasecmp((char*)pszName, "action")) { - if(currConfObj == eConfObjAction) { - errmsg.LogError(0, RS_RET_CONF_END_NO_ACT, "$End action but not action specified"); - /* this is a warning, we continue processing in that case (unscope) */ - } else if(currConfObj != eConfObjActionWaitEnd) { - errmsg.LogError(0, RS_RET_CONF_INVLD_END, "$End not for active config object - " - "nesting error?"); - ABORT_FINALIZE(RS_RET_CONF_INVLD_END); - } - currConfObj = eConfObjGlobal; - CHKiRet(unsetActionScope()); - } else { - errmsg.LogError(0, RS_RET_INVLD_CONF_OBJ, "invalid config object \"%s\" in $End", pszName); - ABORT_FINALIZE(RS_RET_INVLD_CONF_OBJ); - } - -finalize_it: - free(pszName); /* no longer needed */ - RETiRet; -} - - -/* Reset config variables to default values. Note that - * when we are inside an scope, we simply reset this to global. - * However, $ResetConfigVariables is a global directive, and as such - * will not be honored inside a scope! +/* Reset config variables to default values. * rgerhards, 2010-07-23 */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { - currConfObj = eConfObjGlobal; bConfStrictScoping = 0; return RS_RET_OK; } -- cgit v1.2.3 From 6db75eb0d2613ab423edfc88222f7a28556a8d03 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 19 Jan 2012 15:07:25 +0100 Subject: cleanup: different text escape types made more portable --- template.c | 10 ---------- template.h | 10 +++++----- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/template.c b/template.c index 12d27ff3..ca1688f7 100644 --- a/template.c +++ b/template.c @@ -50,16 +50,6 @@ DEFobjCurrIf(regexp) static int bFirstRegexpErrmsg = 1; /**< did we already do a "can't load regexp" error message? */ #endif -#warning check this merge -#if 1 -enum { - NO_ESCAPE = 0, - SQL_ESCAPE, - STDSQL_ESCAPE, - JSON_ESCAPE, -}; -#endif - /* helper to tplToString and strgen's, extends buffer */ #define ALLOC_INC 128 rsRetVal diff --git a/template.h b/template.h index 40dbe448..d394809b 100644 --- a/template.h +++ b/template.h @@ -37,11 +37,11 @@ struct template { int tpenElements; /* number of elements in templateEntry list */ struct templateEntry *pEntryRoot; struct templateEntry *pEntryLast; - char optFormatEscape; /* in text fields, 0 - do not escape, - * 1 - escape "the MySQL way" - * 2 - escape quotes by double quotes, - * 3 - escape double quotes for JSON. - */ + char optFormatEscape; /* in text fields, */ +# define NO_ESCAPE 0 /* 0 - do not escape, */ +# define SQL_ESCAPE 1 /* 1 - escape "the MySQL way" */ +# define STDSQL_ESCAPE 2 /* 2 - escape quotes by double quotes, */ +# define JSON_ESCAPE 3 /* 3 - escape double quotes for JSON. */ /* following are options. All are 0/1 defined (either on or off). * we use chars because they are faster than bit fields and smaller * than short... -- cgit v1.2.3 From 4124fa03f6ce58893642342a48eee5fe0cf5d478 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 19 Jan 2012 15:12:06 +0100 Subject: omshell: light cleanup --- tools/omshell.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/tools/omshell.c b/tools/omshell.c index 130d89d8..ac62fa62 100644 --- a/tools/omshell.c +++ b/tools/omshell.c @@ -1,6 +1,13 @@ /* omshell.c * This is the implementation of the build-in shell output module. * + * ************* DO NOT EXTEND THIS MODULE ************** + * This is pure legacy, omprog has much better and more + * secure functionality than this module. It is NOT + * recommended to base new work on it! + * 2012-01-19 rgerhards + * ****************************************************** + * * NOTE: read comments in module-template.h to understand how this file * works! * @@ -56,16 +63,6 @@ typedef struct _instanceData { uchar progName[MAXFNAME]; /* program to execute */ } instanceData; - -typedef struct configSettings_s { - EMPTY_STRUCT /* remove this when data members are added */ -} configSettings_t; -static configSettings_t cs; - -BEGINinitConfVars /* (re)set config variables to default values */ -CODESTARTinitConfVars -ENDinitConfVars - BEGINcreateInstance CODESTARTcreateInstance ENDcreateInstance @@ -147,7 +144,6 @@ ENDqueryEtryPt BEGINmodInit(Shell) CODESTARTmodInit -INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); -- cgit v1.2.3 From 3fe63651667d3b74c2f9c97824cb9ed65913a99e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 19 Jan 2012 15:24:16 +0100 Subject: refactor: remove very old sync.[ch] system for "abstracting" mutex access This was a bad idea that never was used much. --- action.c | 10 +++++----- action.h | 3 +-- runtime/Makefile.am | 2 -- runtime/sync.c | 55 ----------------------------------------------------- runtime/sync.h | 48 ---------------------------------------------- tools/syslogd.c | 4 ++-- 6 files changed, 8 insertions(+), 114 deletions(-) delete mode 100644 runtime/sync.c delete mode 100644 runtime/sync.h diff --git a/action.c b/action.c index a098eaae..b2620f6e 100644 --- a/action.c +++ b/action.c @@ -305,7 +305,7 @@ rsRetVal actionDestruct(action_t *pThis) if(pThis->f_pMsg != NULL) msgDestruct(&pThis->f_pMsg); - SYNC_OBJ_TOOL_EXIT(pThis); + pthread_mutex_destroy(&pThis->mutAction); pthread_mutex_destroy(&pThis->mutActExec); d_free(pThis->pszName); d_free(pThis->ppTpl); @@ -344,8 +344,8 @@ rsRetVal actionConstruct(action_t **ppThis) pThis->bRepMsgHasMsg = 0; pThis->tLastOccur = datetime.GetTime(NULL); /* done once per action on startup only */ pthread_mutex_init(&pThis->mutActExec, NULL); + pthread_mutex_init(&pThis->mutAction, NULL); INIT_ATOMIC_HELPER_MUT(pThis->mutCAS); - SYNC_OBJ_TOOL_INIT(pThis); /* indicate we have a new action */ ++iActionNbr; @@ -1800,10 +1800,10 @@ doSubmitToActionQComplexBatch(action_t *pAction, batch_t *pBatch) { DEFiRet; - LockObj(pAction); - pthread_cleanup_push(mutexCancelCleanup, pAction->Sync_mut); + d_pthread_mutex_lock(&pAction->mutAction); + pthread_cleanup_push(mutexCancelCleanup, &pAction->mutAction); iRet = helperSubmitToActionQComplexBatch(pAction, pBatch); - UnlockObj(pAction); + d_pthread_mutex_unlock(&pAction->mutAction); pthread_cleanup_pop(0); /* remove mutex cleanup handler */ RETiRet; diff --git a/action.h b/action.h index fbfee37a..4da0be24 100644 --- a/action.h +++ b/action.h @@ -26,7 +26,6 @@ #define ACTION_H_INCLUDED 1 #include "syslogd-types.h" -#include "sync.h" #include "queue.h" /* external data - this is to be removed when we change the action @@ -85,7 +84,7 @@ struct action_s { * processed - it is also used to detect duplicates. */ qqueue_t *pQueue; /* action queue */ - SYNC_OBJ_TOOL; /* required for mutex support */ + pthread_mutex_t mutAction; /* primary action mutex */ pthread_mutex_t mutActExec; /* mutex to guard actual execution of doAction for single-threaded modules */ uchar *pszName; /* action name (for documentation) */ DEF_ATOMIC_HELPER_MUT(mutCAS); diff --git a/runtime/Makefile.am b/runtime/Makefile.am index ac4f4279..e504b1fd 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -53,8 +53,6 @@ librsyslog_la_SOURCES = \ apc.h \ statsobj.c \ statsobj.h \ - sync.c \ - sync.h \ stream.c \ stream.h \ var.c \ diff --git a/runtime/sync.c b/runtime/sync.c deleted file mode 100644 index 46b5ce4c..00000000 --- a/runtime/sync.c +++ /dev/null @@ -1,55 +0,0 @@ -/* synrchonization-related stuff. In theory, that should - * help porting to something different from pthreads. - * - * Copyright 2007-2012 Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * -or- - * see COPYING.ASL20 in the source distribution - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "config.h" - -#include - -#include "rsyslog.h" -#include "sync.h" -#include "debug.h" - - -void -SyncObjInit(pthread_mutex_t **mut) -{ - *mut = (pthread_mutex_t *) MALLOC(sizeof (pthread_mutex_t)); - pthread_mutex_init(*mut, NULL); -} - - -/* This function destroys the mutex and also sets the mutex object - * to NULL. While the later is not strictly necessary, it is a good - * aid when debugging problems. As this function is not exepected to - * be called quite frequently, the additional overhead can well be - * accepted. If this changes over time, setting to NULL may be - * reconsidered. - rgerhards, 2007-11-12 - */ -void -SyncObjExit(pthread_mutex_t **mut) -{ - if(*mut != NULL) { - pthread_mutex_destroy(*mut); - free(*mut); - *mut = NULL; - } -} diff --git a/runtime/sync.h b/runtime/sync.h deleted file mode 100644 index a2c8f122..00000000 --- a/runtime/sync.h +++ /dev/null @@ -1,48 +0,0 @@ -/* Definitions syncrhonization-related stuff. In theory, that should - * help porting to something different from pthreads. - * - * Copyright 2007-2012 Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * -or- - * see COPYING.ASL20 in the source distribution - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef INCLUDED_SYNC_H -#define INCLUDED_SYNC_H - -#include - -/* SYNC_OBJ_TOOL definition must be placed in object to be synced! - * SYNC_OBJ_TOOL_INIT must be called upon of object construction and - * SUNC_OBJ_TOOL_EXIT must be called upon object destruction - */ -#define SYNC_OBJ_TOOL pthread_mutex_t *Sync_mut -#define SYNC_OBJ_TOOL_INIT(x) SyncObjInit(&((x)->Sync_mut)) -#define SYNC_OBJ_TOOL_EXIT(x) SyncObjExit(&((x)->Sync_mut)) - -/* If we run in non-debug (release) mode, we use inline code for the mutex - * operations. If we run in debug mode, we use functions, because they - * are better to trace in the stackframe. - */ -#define LockObj(x) d_pthread_mutex_lock((x)->Sync_mut) -#define UnlockObj(x) d_pthread_mutex_unlock((x)->Sync_mut) - -void SyncObjInit(pthread_mutex_t **mut); -void SyncObjExit(pthread_mutex_t **mut); -extern void lockObj(pthread_mutex_t *mut); -extern void unlockObj(pthread_mutex_t *mut); - -#endif /* #ifndef INCLUDED_SYNC_H */ diff --git a/tools/syslogd.c b/tools/syslogd.c index 4cfbd377..2e7a1e23 100644 --- a/tools/syslogd.c +++ b/tools/syslogd.c @@ -695,7 +695,7 @@ DEFFUNC_llExecFunc(flushRptdMsgsActions) assert(pAction != NULL); BEGINfunc - LockObj(pAction); + d_pthread_mutex_lock(&pAction->mutAction); /* TODO: time() performance: the call below could be moved to * the beginn of the llExec(). This makes it slightly less correct, but * in an acceptable way. -- rgerhards, 2008-09-16 @@ -707,7 +707,7 @@ DEFFUNC_llExecFunc(flushRptdMsgsActions) actionWriteToAction(pAction); BACKOFF(pAction); } - UnlockObj(pAction); + d_pthread_mutex_unlock(&pAction->mutAction); ENDfunc return RS_RET_OK; /* we ignore errors, we can not do anything either way */ -- cgit v1.2.3 From 46605923a27acdb7a061e0135e977bfac9b8a6c5 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 19 Jan 2012 15:37:56 +0100 Subject: refactor: removing dead apc code another concept that did not prove valuable enough to be kept active. For the last couple of releases, the dead code was kept inside the project as we thought we could probably reuse it. Doesn't look so... --- action.c | 1 - runtime/Makefile.am | 2 - runtime/apc.c | 402 ---------------------------------------------------- runtime/apc.h | 56 -------- runtime/obj.c | 2 - runtime/stream.h | 3 - 6 files changed, 466 deletions(-) delete mode 100644 runtime/apc.c delete mode 100644 runtime/apc.h diff --git a/action.c b/action.c index b2620f6e..d12d182a 100644 --- a/action.c +++ b/action.c @@ -103,7 +103,6 @@ #include "template.h" #include "action.h" #include "modules.h" -#include "sync.h" #include "cfsysline.h" #include "srUtils.h" #include "errmsg.h" diff --git a/runtime/Makefile.am b/runtime/Makefile.am index e504b1fd..67e235a0 100644 --- a/runtime/Makefile.am +++ b/runtime/Makefile.am @@ -49,8 +49,6 @@ librsyslog_la_SOURCES = \ obj.h \ modules.c \ modules.h \ - apc.c \ - apc.h \ statsobj.c \ statsobj.h \ stream.c \ diff --git a/runtime/apc.c b/runtime/apc.c deleted file mode 100644 index 3c6b7ec4..00000000 --- a/runtime/apc.c +++ /dev/null @@ -1,402 +0,0 @@ -/* apc.c - asynchronous procedure call support - * - * An asynchronous procedure call (APC) is a procedure call (guess what) that is potentially run - * asynchronously to its main thread. It can be scheduled to occur at a caller-provided time. - * As long as the procedure has not been called, the APC entry may be modified by the caller - * or deleted. It is the caller's purpose to make sure proper synchronization is in place. - * The APC object only case about APC's own control structures (which *are* properly - * guarded by synchronization primitives). - * - * Module begun 2009-06-15 by Rainer Gerhards - * - * Copyright 2009 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ - -#include "config.h" -#include -#include -#include -#include - -#include "rsyslog.h" -#include "obj.h" -#include "apc.h" -#include "srUtils.h" -#include "datetime.h" - -/* static data */ -DEFobjStaticHelpers -DEFobjCurrIf(datetime) - -/* following is a used to implement a monotonically increasing id for the apcs. That - * ID can be used to cancel an apc request. Note that the ID is generated with modulo - * arithmetic, so at some point, it will wrap. Howerver, this happens at 2^32-1 at - * earliest, so this is not considered a problem. - */ -apc_id_t apcID = 0; - -/* private data structures */ - -/* the apc list and its entries - * This is a doubly-linked list as we need to be able to do inserts - * and deletes right in the middle of the list. It is inspired by the - * Unix callout mechanism. - * Note that we support two generic caller-provided parameters as - * experience shows that at most two are often used. This causes very - * little overhead, but simplifies caller code in cases where exactly - * two parameters are needed. We hope this is a useful optimizaton. - * rgerhards, 2009-06-15 - */ -typedef struct apc_list_s { - struct apc_list_s *pNext; - struct apc_list_s *pPrev; - apc_id_t id; - apc_t *pApc; /* pointer to the APC object to be scheduled */ -} apc_list_t; - -apc_list_t *apcListRoot = NULL; -apc_list_t *apcListTail = NULL; -pthread_mutex_t listMutex; /* needs to be locked for all list operations */ - - -/* destructor for the apc object */ -BEGINobjDestruct(apc) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDestruct(apc) -ENDobjDestruct(apc) - - -/* ------------------------------ APC list handling functions ------------------------------ */ - -/* Function that handles changes to the list root. Most importantly, this function - * needs to schedule a new timer. It is OK to call this function with an empty list. - */ -static rsRetVal -listRootChanged(void) -{ - DEFiRet; - - if(apcListRoot == NULL) - FINALIZE; - - // TODO: implement! - -finalize_it: - RETiRet; -} - - -/* insert an apc entry into the APC list. The same entry MUST NOT already be present! - */ -static rsRetVal -insertApc(apc_t *pThis, apc_id_t *pID) -{ - apc_list_t *pCurr; - apc_list_t *pNew; - DEFiRet; - - CHKmalloc(pNew = (apc_list_t*) calloc(1, sizeof(apc_list_t))); - pNew->pApc = pThis; - pNew->id = *pID = apcID++; -dbgprintf("insert apc %p, id %ld\n", pThis, pNew->id); - - /* find right list location */ - if(apcListRoot == NULL) { - /* no need to search, list is empty */ - apcListRoot = pNew; - apcListTail = pNew; - CHKiRet(listRootChanged()); - } else { - for(pCurr = apcListRoot ; pCurr != NULL ; pCurr = pCurr->pNext) { - if(pCurr->pApc->ttExec > pThis->ttExec) - break; - } - - if(pCurr == NULL) { - /* insert at tail */ - pNew->pPrev = apcListTail; - apcListTail->pNext = pNew; - apcListTail = pNew; - } else { - if(pCurr == apcListRoot) { - /* new first entry */ - pCurr->pPrev = pNew; - pNew->pNext = pCurr; - apcListRoot = pNew; - CHKiRet(listRootChanged()); - } else { - /* in the middle of the list */ - pCurr->pPrev = pNew; - pNew->pNext = pCurr; - } - } - } - - -finalize_it: - RETiRet; -} - - -/* Delete an apc entry from the APC list. It is OK if the entry is not found, - * in this case we assume it already has been processed. - */ -static rsRetVal -deleteApc(apc_id_t id) -{ - apc_list_t *pCurr; - DEFiRet; - -dbgprintf("trying to delete apc %ld\n", id); - for(pCurr = apcListRoot ; pCurr != NULL ; pCurr = pCurr->pNext) { - if(pCurr->id == id) { -RUNLOG_STR("apc id found, now deleting!\n"); - if(pCurr == apcListRoot) { - apcListRoot = pCurr->pNext; - CHKiRet(listRootChanged()); - } else { - pCurr->pPrev->pNext = pCurr->pNext; - } - if(pCurr->pNext == NULL) { - apcListTail = pCurr->pPrev; - } else { - pCurr->pNext->pPrev = pCurr->pPrev; - } - free(pCurr); - pCurr = NULL; - break; - } - } - -finalize_it: - RETiRet; -} - - -/* unlist all elements up to the current timestamp. Return this as a seperate list - * to the caller. Returns an empty (NULL ptr) list if there are no such elements. - * The caller must handle that gracefully. The list is returned in the parameter. - */ -static rsRetVal -unlistCurrent(apc_list_t **ppList) -{ - apc_list_t *pCurr; - time_t tCurr; - DEFiRet; - assert(ppList != NULL); - - datetime.GetTime(&tCurr); - - if(apcListRoot == NULL || apcListRoot->pApc->ttExec > tCurr) { - *ppList = NULL; - FINALIZE; - } - - *ppList = apcListRoot; - /* now search up to which entry we need to execute */ - for(pCurr = apcListRoot ; pCurr != NULL && pCurr->pApc->ttExec <= tCurr ; pCurr = pCurr->pNext) { - /*JUST SKIP TO LAST ELEMENT*/; - } - - if(pCurr == NULL) { - /* all elements can be unlisted */ - apcListRoot = NULL; - apcListTail = NULL; - } else { - /* need to set a new root */ - pCurr->pPrev->pNext = NULL; /* terminate newly unlisted list */ - pCurr->pPrev = NULL; /* we are the new root */ - apcListRoot = pCurr; - } - -finalize_it: - RETiRet; -} - - -/* ------------------------------ END APC list handling functions ------------------------------ */ - - -/* execute all list elements that are currently scheduled for execution. We do this in two phases. - * In the first phase, we look the list mutex and move everything from the head of the queue to - * the current timestamp to a new to-be-executed list. Then we unlock the mutex and do the actual - * exec (which may take some time). - * Note that the caller is responsible for proper - * caller-level synchronization. The caller may schedule another Apc, this module must - * ensure that (and it does so by not locking the list mutex while we call the Apc). - * Note: this function "consumes" the apc_t, so it is no longer existing after this - * function returns. - */ -// TODO make static and associated with our own pthread-based timer -rsRetVal -execScheduled(void) -{ - apc_list_t *pExecList; - apc_list_t *pCurr; - apc_list_t *pNext; - DEFiRet; - - d_pthread_mutex_lock(&listMutex); - iRet = unlistCurrent(&pExecList); - d_pthread_mutex_unlock(&listMutex); - CHKiRet(iRet); - - if(pExecList != NULL) { - DBGPRINTF("running apc scheduler - we have %s to execute\n", - pExecList == NULL ? "nothing" : "something"); - } - - for(pCurr = pExecList ; pCurr != NULL ; pCurr = pNext) { -dbgprintf("executing apc list entry %p, apc %p\n", pCurr, pCurr->pApc); - pNext = pCurr->pNext; - pCurr->pApc->pProc(pCurr->pApc->param1, pCurr->pApc->param2); - apcDestruct(&pCurr->pApc); - free(pCurr); - } - -finalize_it: - RETiRet; -} - - -/* Standard-Constructor - */ -BEGINobjConstruct(apc) /* be sure to specify the object type also in END macro! */ -ENDobjConstruct(apc) - - -/* ConstructionFinalizer - * Note that we use a non-standard calling interface: pID returns the current APC - * id. This is the only way to handle the situation without the need for extra - * locking. - * rgerhards, 2008-01-09 - */ -static rsRetVal -apcConstructFinalize(apc_t *pThis, apc_id_t *pID) -{ - DEFiRet; - ISOBJ_TYPE_assert(pThis, apc); - assert(pID != NULL); - d_pthread_mutex_lock(&listMutex); - insertApc(pThis, pID); - d_pthread_mutex_unlock(&listMutex); - RETiRet; -} - - -/* some set methods */ -static rsRetVal -SetProcedure(apc_t *pThis, void (*pProc)(void*, void*)) -{ - ISOBJ_TYPE_assert(pThis, apc); - pThis->pProc = pProc; - return RS_RET_OK; -} -static rsRetVal -SetParam1(apc_t *pThis, void *param1) -{ - ISOBJ_TYPE_assert(pThis, apc); - pThis->param1 = param1; - return RS_RET_OK; -} -static rsRetVal -SetParam2(apc_t *pThis, void *param2) -{ - ISOBJ_TYPE_assert(pThis, apc); - pThis->param1 = param2; - return RS_RET_OK; -} - - -/* cancel an Apc request, ID is provided. It is OK if the ID can not be found, this may - * happen if the Apc was executed in the mean time. So it is safe to call CancelApc() at - * any time. - */ -static rsRetVal -CancelApc(apc_id_t id) -{ - BEGINfunc - d_pthread_mutex_lock(&listMutex); - deleteApc(id); - d_pthread_mutex_unlock(&listMutex); - ENDfunc - return RS_RET_OK; -} - - -/* debugprint for the apc object */ -BEGINobjDebugPrint(apc) /* be sure to specify the object type also in END and CODESTART macros! */ -CODESTARTobjDebugPrint(apc) - dbgoprint((obj_t*) pThis, "APC module, currently no state info available\n"); -ENDobjDebugPrint(apc) - - -/* queryInterface function - */ -BEGINobjQueryInterface(apc) -CODESTARTobjQueryInterface(apc) - if(pIf->ifVersion != apcCURR_IF_VERSION) { /* check for current version, increment on each change */ - ABORT_FINALIZE(RS_RET_INTERFACE_NOT_SUPPORTED); - } - - /* ok, we have the right interface, so let's fill it - * Please note that we may also do some backwards-compatibility - * work here (if we can support an older interface version - that, - * of course, also affects the "if" above). - */ - pIf->Construct = apcConstruct; - pIf->ConstructFinalize = apcConstructFinalize; - pIf->Destruct = apcDestruct; - pIf->DebugPrint = apcDebugPrint; - pIf->CancelApc = CancelApc; - pIf->SetProcedure = SetProcedure; - pIf->SetParam1 = SetParam1; - pIf->SetParam2 = SetParam2; -finalize_it: -ENDobjQueryInterface(apc) - - -/* Exit the apc class. - * rgerhards, 2009-04-06 - */ -BEGINObjClassExit(apc, OBJ_IS_CORE_MODULE) /* class, version */ - objRelease(datetime, CORE_COMPONENT); - pthread_mutex_destroy(&listMutex); -ENDObjClassExit(apc) - - -/* Initialize the apc class. Must be called as the very first method - * before anything else is called inside this class. - * rgerhards, 2008-02-19 - */ -BEGINObjClassInit(apc, 1, OBJ_IS_CORE_MODULE) /* class, version */ - /* request objects we use */ - CHKiRet(objUse(datetime, CORE_COMPONENT)); - - /* set our own handlers */ - OBJSetMethodHandler(objMethod_DEBUGPRINT, apcDebugPrint); - OBJSetMethodHandler(objMethod_CONSTRUCTION_FINALIZER, apcConstructFinalize); - - /* do other initializations */ - pthread_mutex_init(&listMutex, NULL); -ENDObjClassInit(apc) - -/* vi:set ai: - */ diff --git a/runtime/apc.h b/runtime/apc.h deleted file mode 100644 index 7c679b97..00000000 --- a/runtime/apc.h +++ /dev/null @@ -1,56 +0,0 @@ -/* The apc object. - * - * See apc.c for more information. - * - * Copyright 2009 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of the rsyslog runtime library. - * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. - */ -#ifndef INCLUDED_APC_H -#define INCLUDED_APC_H - -/* the apc object */ -typedef struct apc_s { - BEGINobjInstance; /* Data to implement generic object - MUST be the first data element! */ - time_t ttExec; /* when to call procedure (so far seconds...) */ - void (*pProc)(void*, void*); /* which procedure to call */ - void *param1; /* user-supplied parameters */ - void *param2; /* user-supplied parameters */ -} apc_t; - -typedef unsigned long apc_id_t; /* monotonically incrementing apc ID */ - -/* interfaces */ -BEGINinterface(apc) /* name must also be changed in ENDinterface macro! */ - INTERFACEObjDebugPrint(apc); - rsRetVal (*Construct)(apc_t **ppThis); - rsRetVal (*ConstructFinalize)(apc_t *pThis, apc_id_t *); - rsRetVal (*Destruct)(apc_t **ppThis); - rsRetVal (*SetProcedure)(apc_t *pThis, void (*pProc)(void*, void*)); - rsRetVal (*SetParam1)(apc_t *pThis, void *); - rsRetVal (*SetParam2)(apc_t *pThis, void *); - rsRetVal (*CancelApc)(apc_id_t); -ENDinterface(apc) -#define apcCURR_IF_VERSION 1 /* increment whenever you change the interface structure! */ - - -/* prototypes */ -PROTOTYPEObj(apc); - -#endif /* #ifndef INCLUDED_APC_H */ diff --git a/runtime/obj.c b/runtime/obj.c index 680f50fb..93fbd281 100644 --- a/runtime/obj.c +++ b/runtime/obj.c @@ -87,7 +87,6 @@ #include "errmsg.h" #include "cfsysline.h" #include "unicode-helper.h" -#include "apc.h" #include "datetime.h" /* static data */ @@ -1331,7 +1330,6 @@ objClassInit(modInfo_t *pModInfo) /* init classes we use (limit to as few as possible!) */ CHKiRet(errmsgClassInit(pModInfo)); CHKiRet(datetimeClassInit(pModInfo)); - CHKiRet(apcClassInit(pModInfo)); CHKiRet(cfsyslineInit()); CHKiRet(varClassInit(pModInfo)); CHKiRet(moduleClassInit(pModInfo)); diff --git a/runtime/stream.h b/runtime/stream.h index 60c68cb2..a01929f2 100644 --- a/runtime/stream.h +++ b/runtime/stream.h @@ -70,7 +70,6 @@ #include "glbl.h" #include "stream.h" #include "zlibw.h" -#include "apc.h" /* stream types */ typedef enum { @@ -126,7 +125,6 @@ typedef struct strm_s { sbool bStopWriter; /* shall writer thread terminate? */ sbool bDoTimedWait; /* instruct writer thread to do a times wait to support flush timeouts */ int iFlushInterval; /* flush in which interval - 0, no flushing */ - apc_id_t apcID; /* id of current Apc request (used for cancelling) */ pthread_mutex_t mut;/* mutex for flush in async mode */ pthread_cond_t notFull; pthread_cond_t notEmpty; @@ -139,7 +137,6 @@ typedef struct strm_s { size_t lenBuf; } asyncBuf[STREAM_ASYNC_NUMBUFS]; pthread_t writerThreadID; - int apcRequested; /* is an apc Requested? */ /* support for omfile size-limiting commands, special counters, NOT persisted! */ off_t iSizeLimit; /* file size limit, 0 = no limit */ uchar *pszSizeLimitCmd; /* command to carry out when size limit is reached */ -- cgit v1.2.3 From b68af9a016c229259ccb259c33e6598a3a77ea35 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 19 Jan 2012 15:41:49 +0100 Subject: cosmetic: remove compiler warnings --- plugins/ompgsql/ompgsql.c | 2 +- plugins/omrelp/omrelp.c | 2 +- tools/ompipe.c | 2 +- tools/omusrmsg.c | 3 +-- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/plugins/ompgsql/ompgsql.c b/plugins/ompgsql/ompgsql.c index 2c10d881..11f346f6 100644 --- a/plugins/ompgsql/ompgsql.c +++ b/plugins/ompgsql/ompgsql.c @@ -69,7 +69,7 @@ typedef struct _instanceData { typedef struct configSettings_s { EMPTY_STRUCT } configSettings_t; -static configSettings_t cs; +static configSettings_t __attribute__((unused)) cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars diff --git a/plugins/omrelp/omrelp.c b/plugins/omrelp/omrelp.c index ca64daf2..39ffe7fb 100644 --- a/plugins/omrelp/omrelp.c +++ b/plugins/omrelp/omrelp.c @@ -68,7 +68,7 @@ typedef struct _instanceData { typedef struct configSettings_s { EMPTY_STRUCT } configSettings_t; -static configSettings_t cs; +static configSettings_t __attribute__((unused)) cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars diff --git a/tools/ompipe.c b/tools/ompipe.c index 1eb0dbce..3d887e14 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -78,7 +78,7 @@ typedef struct _instanceData { typedef struct configSettings_s { EMPTY_STRUCT } configSettings_t; -static configSettings_t cs; +static configSettings_t __attribute__((unused)) cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars diff --git a/tools/omusrmsg.c b/tools/omusrmsg.c index f8e40594..ee2bc59f 100644 --- a/tools/omusrmsg.c +++ b/tools/omusrmsg.c @@ -90,8 +90,7 @@ typedef struct _instanceData { typedef struct configSettings_s { EMPTY_STRUCT } configSettings_t; - -static configSettings_t cs; +static configSettings_t __attribute__((unused)) cs; /* tables for interfacing with the v6 config system */ -- cgit v1.2.3 From 01405d78f4a8c090d5abe37380d60cff252efdc6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 23 Jan 2012 18:05:07 +0100 Subject: refactored imklog linux driver, now combined with BSD driver The Linux driver no longer supports outdated kernel symbol resolution, which was disabled by default for very long. Also overall cleanup, resulting in much smaller code. Linux and BSD are now covered by a single small driver. --- ChangeLog | 5 + configure.ac | 1 + plugins/imklog/Makefile.am | 3 +- plugins/imklog/bsd.c | 244 ++++++++----- plugins/imklog/imklog.c | 9 +- plugins/imklog/ksym.c | 832 --------------------------------------------- plugins/imklog/ksym_mod.c | 485 -------------------------- plugins/imklog/ksyms.h | 37 -- plugins/imklog/linux.c | 623 --------------------------------- 9 files changed, 176 insertions(+), 2063 deletions(-) delete mode 100644 plugins/imklog/ksym.c delete mode 100644 plugins/imklog/ksym_mod.c delete mode 100644 plugins/imklog/ksyms.h delete mode 100644 plugins/imklog/linux.c diff --git a/ChangeLog b/ChangeLog index 4b49ecbf..fe8ae053 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ --------------------------------------------------------------------------- Version 5.9.6 [V5-DEVEL], 2012-??-?? +- refactored imklog linux driver, now combined with BSD driver + The Linux driver no longer supports outdated kernel symbol resolution, + which was disabled by default for very long. Also overall cleanup, + resulting in much smaller code. Linux and BSD are now covered by a + single small driver. - $IMUXSockRateLimitInterval DEFAULT CHANGED, was 5, now 0 The new default turns off rate limiting. This was chosen as people experienced problems with rate-limiting activated by default. Now it diff --git a/configure.ac b/configure.ac index 011905a6..32029409 100644 --- a/configure.ac +++ b/configure.ac @@ -37,6 +37,7 @@ PKG_PROG_PKG_CONFIG case "${host}" in *-*-linux*) + AC_DEFINE([OS_LINUX], [1], [Indicator for a Linux OS]) os_type="linux" ;; *-*-*darwin*|*-*-freebsd*|*-*-netbsd*|*-*-openbsd*) diff --git a/plugins/imklog/Makefile.am b/plugins/imklog/Makefile.am index 5d4d0465..7d0d37c9 100644 --- a/plugins/imklog/Makefile.am +++ b/plugins/imklog/Makefile.am @@ -1,5 +1,4 @@ pkglib_LTLIBRARIES = imklog.la - imklog_la_SOURCES = imklog.c imklog.h # select klog "driver" @@ -8,7 +7,7 @@ imklog_la_SOURCES += bsd.c endif if ENABLE_IMKLOG_LINUX -imklog_la_SOURCES += linux.c module.h ksym.c ksyms.h ksym_mod.c +imklog_la_SOURCES += bsd.c endif imklog_la_CPPFLAGS = -I$(top_srcdir) $(PTHREADS_CFLAGS) $(RSRT_CFLAGS) diff --git a/plugins/imklog/bsd.c b/plugins/imklog/bsd.c index 930bbd11..eaf8e5ca 100644 --- a/plugins/imklog/bsd.c +++ b/plugins/imklog/bsd.c @@ -1,69 +1,30 @@ -/* klog for BSD, based on the FreeBSD syslogd implementation. +/* combined imklog driver for BSD and Linux * * This contains OS-specific functionality to read the BSD - * kernel log. For a general overview, see head comment in - * imklog.c. + * or Linux kernel log. For a general overview, see head comment in + * imklog.c. This started out as the BSD-specific drivers, but it + * turned out that on modern Linux the implementation details + * are very small, and so we use a single driver for both OS's with + * a little help of conditional compilation. * - * Copyright (C) 2008 by Rainer Gerhards for the modifications of - * the original FreeBSD sources. - * - * I would like to express my gratitude to those folks which - * layed an important foundation for rsyslog to build on. + * Copyright 2008-2012 Adiscon GmbH * * This file is part of rsyslog. * - * Rsyslog is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Rsyslog is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Rsyslog. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * - * This file is based on earlier work included in the FreeBSD sources. We - * integrated it into the rsyslog project. The copyright below applies, and - * I also reproduce the original license under which we aquired the code: - * - * Copyright (c) 1983, 1988, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * If you would like to use the code under the BSD license, you should - * aquire your own copy of BSD's syslogd, from which we have taken it. The - * code in this file is modified and may only be used under the terms of - * the GPLv3+ as specified above. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * -or- + * see COPYING.ASL20 in the source distribution + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - #ifdef HAVE_CONFIG_H # include "config.h" #endif @@ -72,18 +33,124 @@ #include #include #include +#include +#ifdef OS_LINUX +# include +#endif #include "rsyslog.h" -#include "imklog.h" +#include "srUtils.h" #include "debug.h" +#include "imklog.h" /* globals */ -static int fklog = -1; /* /dev/klog */ +static int fklog = -1; /* kernel log fd */ #ifndef _PATH_KLOG -# define _PATH_KLOG "/dev/klog" +# ifdef OS_LINUX +# define _PATH_KLOG "/proc/kmsg" +# else +# define _PATH_KLOG "/dev/klog" +# endif #endif + +#ifdef OS_LINUX +/* submit a message to imklog Syslog() API. In this function, we check if + * a kernel timestamp is present and, if so, extract and strip it. + * Note: this is an extra processing step. We should revisit the whole + * idea in v6 and remove all that old stuff that we do not longer need + * (like symbol resolution). <-- TODO + * Note that this is heavily Linux specific and thus is not compiled or + * used for BSD. + * Special thanks to Lennart Poettering for suggesting on how to convert + * the kernel timestamp to a realtime timestamp. This method depends on + * the fact the the kernel timestamp is written using the monotonic clock. + * Shall that change (very unlikely), this code must be changed as well. Note + * that due to the way we generate the delta, we are unable to write the + * absolutely correct timestamp (system call overhead of the clock calls + * prevents us from doing so). However, the difference is very minor. + * rgerhards, 2011-06-24 + */ +static void +submitSyslog(int pri, uchar *buf) +{ + long secs; + long nsecs; + long secOffs; + long nsecOffs; + unsigned i; + unsigned bufsize; + struct timespec monotonic, realtime; + struct timeval tv; + struct timeval *tp = NULL; + + if(buf[3] != '[') + goto done; + DBGPRINTF("imklog: kernel timestamp detected, extracting it\n"); + + /* we now try to parse the timestamp. iff it parses, we assume + * it is a timestamp. Otherwise we know for sure it is no ts ;) + */ + i = 4; /* first digit after '[' */ + secs = 0; + while(buf[i] && isdigit(buf[i])) { + secs = secs * 10 + buf[i] - '0'; + ++i; + } + if(buf[i] != '.') { + DBGPRINTF("no dot --> no kernel timestamp\n"); + goto done; /* no TS! */ + } + + ++i; /* skip dot */ + nsecs = 0; + while(buf[i] && isdigit(buf[i])) { + nsecs = nsecs * 10 + buf[i] - '0'; + ++i; + } + if(buf[i] != ']') { + DBGPRINTF("no trailing ']' --> no kernel timestamp\n"); + goto done; /* no TS! */ + } + ++i; /* skip ']' */ + + /* we have a timestamp */ + DBGPRINTF("kernel timestamp is %ld %ld\n", secs, nsecs); + bufsize= strlen((char*)buf); + memcpy(buf+3, buf+i, bufsize - i + 1); + + clock_gettime(CLOCK_MONOTONIC, &monotonic); + clock_gettime(CLOCK_REALTIME, &realtime); + secOffs = realtime.tv_sec - monotonic.tv_sec; + nsecOffs = realtime.tv_nsec - monotonic.tv_nsec; + if(nsecOffs < 0) { + secOffs--; + nsecOffs += 1000000000l; + } + + nsecs +=nsecOffs; + if(nsecs > 999999999l) { + secs++; + nsecs -= 1000000000l; + } + secs += secOffs; + tv.tv_sec = secs; + tv.tv_usec = nsecs / 1000; + tp = &tv; + +done: + Syslog(pri, buf, tp); +} +#else /* now comes the BSD "code" (just a shim) */ +static void +submitSyslog(int pri, uchar *buf) +{ + Syslog(pri, buf, NULL); +} +#endif /* #ifdef LINUX */ + + static uchar *GetPath(void) { return pszPath ? pszPath : (uchar*) _PATH_KLOG; @@ -95,23 +162,36 @@ static uchar *GetPath(void) rsRetVal klogWillRun(void) { + char errmsg[2048]; + int r; DEFiRet; fklog = open((char*)GetPath(), O_RDONLY, 0); if (fklog < 0) { - dbgprintf("can't open %s (%d)\n", GetPath(), errno); - iRet = RS_RET_ERR; // TODO: better error code + imklogLogIntMsg(RS_RET_ERR_OPEN_KLOG, "imklog: cannot open kernel log(%s): %s.", + GetPath(), rs_strerror_r(errno, errmsg, sizeof(errmsg))); + ABORT_FINALIZE(RS_RET_ERR_OPEN_KLOG); + } + +# ifdef OS_LINUX + /* Set level of kernel console messaging.. */ + if(console_log_level != -1) { + r = klogctl(8, NULL, console_log_level); + if(r != 0) { + imklogLogIntMsg(LOG_WARNING, "imklog: cannot set console log level: %s", + rs_strerror_r(errno, errmsg, sizeof(errmsg))); + /* make sure we do not try to re-set! */ + console_log_level = -1; + } } +# endif /* #ifdef OS_LINUX */ +finalize_it: RETiRet; } -/* Read /dev/klog while data are available, split into lines. - * Contrary to standard BSD syslogd, we do a blocking read. We can - * afford this as imklog is running on its own threads. So if we have - * a single file, it really doesn't matter if we wait inside a 1-file - * select or the read() directly. +/* Read kernel log while data are available, split into lines. */ static void readklog(void) @@ -119,13 +199,14 @@ readklog(void) char *p, *q; int len, i; int iMaxLine; - uchar bufRcv[4096+1]; + uchar bufRcv[128*1024+1]; + char errmsg[2048]; uchar *pRcv = NULL; /* receive buffer */ iMaxLine = klog_getMaxLine(); - /* we optimize performance: if iMaxLine is below 4K (which it is in almost all - * cases, we use a fixed buffer on the stack. Only if it is higher, heap memory + /* we optimize performance: if iMaxLine is below our fixed size buffer (which + * usually is sufficiently large), we use this buffer. if it is higher, heap memory * is used. We could use alloca() to achive a similar aspect, but there are so * many issues with alloca() that I do not want to take that route. * rgerhards, 2008-09-02 @@ -139,15 +220,15 @@ readklog(void) len = 0; for (;;) { - dbgprintf("----------imklog(BSD) waiting for kernel log line\n"); + dbgprintf("imklog(BSD/Linux) waiting for kernel log line\n"); i = read(fklog, pRcv + len, iMaxLine - len); if (i > 0) { pRcv[i + len] = '\0'; } else { if (i < 0 && errno != EINTR && errno != EAGAIN) { imklogLogIntMsg(LOG_ERR, - "imklog error %d reading kernel log - shutting down imklog", - errno); + "imklog: error reading kernel log - shutting down: %s", + rs_strerror_r(errno, errmsg, sizeof(errmsg))); fklog = -1; } break; @@ -155,18 +236,18 @@ readklog(void) for (p = (char*)pRcv; (q = strchr(p, '\n')) != NULL; p = q + 1) { *q = '\0'; - Syslog(LOG_INFO, (uchar*) p, NULL); + submitSyslog(LOG_INFO, (uchar*) p); } len = strlen(p); if (len >= iMaxLine - 1) { - Syslog(LOG_INFO, (uchar*)p, NULL); + submitSyslog(LOG_INFO, (uchar*)p); len = 0; } - if (len > 0) + if(len > 0) memmove(pRcv, p, len + 1); } if (len > 0) - Syslog(LOG_INFO, pRcv, NULL); + submitSyslog(LOG_INFO, pRcv); if(pRcv != NULL && (size_t) iMaxLine >= sizeof(bufRcv) - 1) free(pRcv); @@ -181,6 +262,11 @@ rsRetVal klogAfterRun(void) DEFiRet; if(fklog != -1) close(fklog); +# ifdef OS_LINUX + /* Turn on logging of messages to console, but only if a log level was speficied */ + if(console_log_level != -1) + klogctl(7, NULL, 0); +# endif RETiRet; } diff --git a/plugins/imklog/imklog.c b/plugins/imklog/imklog.c index cb28e68e..40249273 100644 --- a/plugins/imklog/imklog.c +++ b/plugins/imklog/imklog.c @@ -200,15 +200,14 @@ rsRetVal Syslog(int priority, uchar *pMsg, struct timeval *tp) DEFiRet; /* then check if we have two PRIs. This can happen in case of systemd, - * in which case the second PRI is the rigth one. - * TODO: added kernel timestamp support to this PoC. -- rgerhards, 2011-03-18 + * in which case the second PRI is the right one. */ - if(pMsg[3] == '<') { /* could be a pri... */ - uchar *pMsgTmp = pMsg + 3; + if(pMsg[3] == '<' || (pMsg[3] == ' ' && pMsg[4] == '<')) { /* could be a pri... */ + uchar *pMsgTmp = pMsg + ((pMsg[3] == '<') ? 3 : 4); localRet = parsePRI(&pMsgTmp, &pri); if(localRet == RS_RET_OK && pri >= 8 && pri <= 192) { /* *this* is our PRI */ - DBGPRINTF("imklog detected secondary PRI in klog msg\n"); + DBGPRINTF("imklog detected secondary PRI(%d) in klog msg\n", pri); pMsg = pMsgTmp; priority = pri; } diff --git a/plugins/imklog/ksym.c b/plugins/imklog/ksym.c deleted file mode 100644 index ebaec011..00000000 --- a/plugins/imklog/ksym.c +++ /dev/null @@ -1,832 +0,0 @@ -/* ksym.c - functions for kernel address->symbol translation - * Copyright (c) 1995, 1996 Dr. G.W. Wettstein - * Copyright (c) 1996 Enjellic Systems Development - * Copyright (c) 1998-2007 Martin Schulze - * Copyright (C) 2007-2008 Rainer Gerhards - * - * 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. -*/ - -/* - * This file contains functions which handle the translation of kernel - * numeric addresses into symbols for the klogd utility. - * - * Sat Oct 28 09:00:14 CDT 1995: Dr. Wettstein - * Initial Version. - * - * Fri Nov 24 12:50:52 CST 1995: Dr. Wettstein - * Added VERBOSE_DEBUGGING define to make debugging output more - * manageable. - * - * Added support for verification of the loaded kernel symbols. If - * no version information can be be found in the mapfile a warning - * message is issued but translation will still take place. This - * will be the default case if kernel versions < 1.3.43 are used. - * - * If the symbols in the mapfile are of the same version as the kernel - * that is running an informative message is issued. If the symbols - * in the mapfile do not match the current kernel version a warning - * message is issued and translation is disabled. - * - * Wed Dec 6 16:14:11 CST 1995: Dr. Wettstein - * Added /boot/System.map to the list of symbol maps to search for. - * Also made this map the first item in the search list. I am open - * to CONSTRUCTIVE suggestions for any additions or corrections to - * the list of symbol maps to search for. Be forewarned that the - * list in use is the consensus agreement between myself, Linus and - * some package distributers. It is a given that no list will suit - * everyone's taste. If you have rabid concerns about the list - * please feel free to edit the system_maps array and compile your - * own binaries. - * - * Added support for searching of the list of symbol maps. This - * allows support for access to multiple symbol maps. The theory - * behind this is that a production kernel may have a system map in - * /boot/System.map. If a test kernel is booted this system map - * would be skipped in favor of one found in /usr/src/linux. - * - * Thu Jan 18 11:18:31 CST 1996: Dr. Wettstein - * Added patch from beta-testers to allow for reading of both - * ELF and a.out map files. - * - * Wed Aug 21 09:15:49 CDT 1996: Dr. Wettstein - * Reloading of kernel module symbols is now turned on by the - * SetParanoiaLevel function. The default behavior is to NOT reload - * the kernel module symbols when a protection fault is detected. - * - * Added support for freeing of the current kernel module symbols. - * This was necessary to support reloading of the kernel module symbols. - * - * When a matching static symbol table is loaded the kernel version - * number is printed. - * - * Mon Jun 9 17:12:42 CST 1997: Martin Schulze - * Added #1 and #2 to some error messages in order to being able - * to divide them (ulmo@Q.Net) - * - * Fri Jun 13 10:50:23 CST 1997: Martin Schulze - * Changed definition of LookupSymbol to non-static because it is - * used in klogd.c, too. - * - * Fri Jan 9 23:00:08 CET 1998: Martin Schulze - * Fixed bug that caused klogd to die if there is no System.map available. - * - * Sun 29 Mar 18:14:07 BST 1998: Mark Simon Phillips - * Switched to fgets() as gets() is not buffer overrun secure. - * - * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze - * Modified loop for detecting the correct system map. Now it won't - * stop if a file has been found but doesn't contain the correct map. - * Special thanks go go Mark Simon Phillips for the hint. - * - * Mon Oct 12 00:42:30 CEST 1998: Martin Schulze - * Modified CheckVersion() - * . Use shift to decode the kernel version - * . Compare integers of kernel version - * . extract major.minor.patch from utsname.release via sscanf() - * The reason lays in possible use of kernel flavours which - * modify utsname.release but no the Version_ symbol. - * - * Sun Feb 21 22:27:49 EST 1999: Keith Owens - * Fixed bug that caused klogd to die if there is no sym_array available. - * - * Tue Sep 12 23:48:12 CEST 2000: Martin Schulze - * Close symbol file in InitKsyms() when an error occurred. - */ - - -/* Includes. */ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include "imklog.h" -#include "ksyms.h" -#include "module.h" -#include "debug.h" - - -int num_syms = 0; -static int i_am_paranoid = 0; -static char vstring[12]; -static struct sym_table *sym_array = (struct sym_table *) 0; - -static char *system_maps[] = -{ - "/boot/System.map", - "/System.map", - NULL -}; - - -/* Function prototypes. */ -static char *FindSymbolFile(void); -static int AddSymbol(unsigned long, char*); -static void FreeSymbols(void); -static int CheckVersion(char *); -static int CheckMapVersion(char *); - - -/************************************************************************* - * Function: InitKsyms - * - * Purpose: This function is responsible for initializing and loading - * the data tables used by the kernel address translations. - * - * Arguements: (char *) mapfile - * - * mapfile:-> A pointer to a complete path - * specification of the file containing - * the kernel map to use. - * - * Return: int - * - * A boolean style context is returned. The return value will - * be true if initialization was successful. False if not. - **************************************************************************/ -extern int InitKsyms(char *mapfile) -{ - auto char type, - sym[512]; - - auto int version = 0; - - auto unsigned long int address; - - auto FILE *sym_file; - - BEGINfunc - - /* Check and make sure that we are starting with a clean slate. */ - if ( num_syms > 0 ) - FreeSymbols(); - - - /* Search for and open the file containing the kernel symbols. */ - if ( mapfile != NULL ) { - if ( (sym_file = fopen(mapfile, "r")) == NULL ) - { - imklogLogIntMsg(LOG_WARNING, "Cannot open map file: %s.", mapfile); - return(0); - } - } else { - if ( (mapfile = FindSymbolFile()) == NULL ) { - imklogLogIntMsg(LOG_WARNING, "Cannot find map file."); - dbgprintf("Cannot find map file.\n"); - return(0); - } - - if ( (sym_file = fopen(mapfile, "r")) == NULL ) { - imklogLogIntMsg(LOG_WARNING, "Cannot open map file."); - dbgprintf("Cannot open map file.\n"); - return(0); - } - } - - - /* Read the kernel symbol table file and add entries for each - * line. I suspect that the use of fscanf is not really in vogue - * but it was quick and dirty and IMHO suitable for fixed format - * data such as this. If anybody doesn't agree with this please - * e-mail me a diff containing a parser with suitable political - * correctness -- GW. - */ - while ( !feof(sym_file) ) { - if ( fscanf(sym_file, "%lx %c %s\n", &address, &type, sym) != 3 ) { - imklogLogIntMsg(LOG_ERR, "Error in symbol table input (#1)."); - fclose(sym_file); - return(0); - } - if(dbgPrintSymbols) - dbgprintf("Address: %lx, Type: %c, Symbol: %s\n", address, type, sym); - - if ( AddSymbol(address, sym) == 0 ) { - imklogLogIntMsg(LOG_ERR, "Error adding symbol - %s.", sym); - fclose(sym_file); - return(0); - } - - if ( version == 0 ) - version = CheckVersion(sym); - } - - - imklogLogIntMsg(LOG_INFO, "Loaded %d symbols from %s.", num_syms, mapfile); - switch(version) { - case -1: - imklogLogIntMsg(LOG_WARNING, "Symbols do not match kernel version."); - num_syms = 0; - break; - - case 0: - imklogLogIntMsg(LOG_WARNING, "Cannot verify that symbols match kernel version."); - break; - - case 1: - imklogLogIntMsg(LOG_INFO, "Symbols match kernel version %s.", vstring); - break; - } - - fclose(sym_file); - ENDfunc - return(1); -} - - -extern void DeinitKsyms(void) -{ - FreeSymbols(); -} - - -/************************************************************************** - * Function: FindSymbolFile - * - * Purpose: This function is responsible for encapsulating the search - * for a valid symbol file. Encapsulating the search for - * the map file in this function allows an intelligent search - * process to be implemented. - * - * The list of symbol files will be searched until either a - * symbol file is found whose version matches the currently - * executing kernel or the end of the list is encountered. If - * the end of the list is encountered the first available - * symbol file is returned to the caller. - * - * This strategy allows klogd to locate valid symbol files - * for both a production and an experimental kernel. For - * example a map for a production kernel could be installed - * in /boot. If an experimental kernel is loaded the map - * in /boot will be skipped and the map in /usr/src/linux would - * be used if its version number matches the executing kernel. - * - * Arguements: None specified. - * - * Return: char * - * - * If a valid system map cannot be located a null pointer - * is returned to the caller. - * - * If the search is succesful a pointer is returned to the - * caller which points to the name of the file containing - * the symbol table to be used. - **************************************************************************/ -static char *FindSymbolFile(void) -{ - auto char *file = NULL, - **mf = system_maps; - auto struct utsname utsname; - static char mysymfile[100]; - auto FILE *sym_file = NULL; - BEGINfunc - - if(uname(&utsname) < 0) { - imklogLogIntMsg(LOG_ERR, "Cannot get kernel version information."); - return(0); - } - - dbgprintf("Searching for symbol map.\n"); - - for(mf = system_maps; *mf != NULL && file == NULL; ++mf) { - snprintf(mysymfile, sizeof(mysymfile), "%s-%s", *mf, utsname.release); - dbgprintf("Trying %s.\n", mysymfile); - if((sym_file = fopen(mysymfile, "r")) != NULL) { - if(CheckMapVersion(mysymfile) == 1) - file = mysymfile; - fclose(sym_file); - } - if(sym_file == NULL || file == NULL) { - sprintf (mysymfile, "%s", *mf); - dbgprintf("Trying %s.\n", mysymfile); - if((sym_file = fopen(mysymfile, "r")) != NULL ) { - if (CheckMapVersion(mysymfile) == 1) - file = mysymfile; - fclose(sym_file); - } - } - } - - /* At this stage of the game we are at the end of the symbol tables. */ - dbgprintf("End of search list encountered.\n"); - ENDfunc - return(file); -} - - -/************************************************************************** - * Function: CheckVersion - * - * Purpose: This function is responsible for determining whether or - * the system map being loaded matches the version of the - * currently running kernel. - * - * The kernel version is checked by examing a variable which - * is of the form: _Version_66347 (a.out) or Version_66437 (ELF). - * - * The suffix of this variable is the current kernel version - * of the kernel encoded in base 256. For example the - * above variable would be decoded as: - * - * (66347 = 1*65536 + 3*256 + 43 = 1.3.43) - * - * (Insert appropriate deities here) help us if Linus ever - * needs more than 255 patch levels to get a kernel out the - * door... :-) - * - * Arguements: (char *) version - * - * version:-> A pointer to the string which - * is to be decoded as a kernel - * version variable. - * - * Return: int - * - * -1:-> The currently running kernel version does - * not match this version string. - * - * 0:-> The string is not a kernel version variable. - * - * 1:-> The executing kernel is of the same version - * as the version string. - **************************************************************************/ -static int CheckVersion(char *version) -{ - auto int vnum, - major, - minor, - patch; - int kvnum; - auto struct utsname utsname; - - static char *prefix = { "Version_" }; - - - /* Early return if there is no hope. */ - if ( strncmp(version, prefix, strlen(prefix)) == 0 /* ELF */ || - (*version == '_' && - strncmp(++version, prefix, strlen(prefix)) == 0 ) /* a.out */ ) - ; - else - return(0); - - - /* Since the symbol looks like a kernel version we can start - * things out by decoding the version string into its component - * parts. - */ - vnum = atoi(version + strlen(prefix)); - patch = vnum & 0x000000FF; - minor = (vnum >> 8) & 0x000000FF; - major = (vnum >> 16) & 0x000000FF; - dbgprintf("Version string = %s, Major = %d, Minor = %d, Patch = %d.\n", version + - strlen(prefix), major, minor, patch); - sprintf(vstring, "%d.%d.%d", major, minor, patch); - - /* We should now have the version string in the vstring variable in - * the same format that it is stored in by the kernel. We now - * ask the kernel for its version information and compare the two - * values to determine if our system map matches the kernel - * version level. - */ - if ( uname(&utsname) < 0 ) { - imklogLogIntMsg(LOG_ERR, "Cannot get kernel version information."); - return(0); - } - dbgprintf("Comparing kernel %s with symbol table %s.\n", utsname.release, vstring); - - if ( sscanf (utsname.release, "%d.%d.%d", &major, &minor, &patch) < 3 ) { - imklogLogIntMsg(LOG_ERR, "Kernel send bogus release string `%s'.", utsname.release); - return(0); - } - - /* Compute the version code from data sent by the kernel */ - kvnum = (major << 16) | (minor << 8) | patch; - - /* Failure. */ - if ( vnum != kvnum ) - return(-1); - - /* Success. */ - return(1); -} - - -/************************************************************************** - * Function: CheckMapVersion - * - * Purpose: This function is responsible for determining whether or - * the system map being loaded matches the version of the - * currently running kernel. It uses CheckVersion as - * backend. - * - * Arguements: (char *) fname - * - * fname:-> A pointer to the string which - * references the system map file to - * be used. - * - * Return: int - * - * -1:-> The currently running kernel version does - * not match the version in the given file. - * - * 0:-> No system map file or no version information. - * - * 1:-> The executing kernel is of the same version - * as the version of the map file. - **************************************************************************/ -static int CheckMapVersion(char *fname) -{ - int version; - FILE *sym_file; - auto unsigned long int address; - auto char type, - sym[512]; - - if ( (sym_file = fopen(fname, "r")) != NULL ) { - /* - * At this point a map file was successfully opened. We - * now need to search this file and look for version - * information. - */ - imklogLogIntMsg(LOG_INFO, "Inspecting %s", fname); - - version = 0; - while ( !feof(sym_file) && (version == 0) ) { - if ( fscanf(sym_file, "%lx %c %s\n", &address, &type, sym) != 3 ) { - imklogLogIntMsg(LOG_ERR, "Error in symbol table input (#2)."); - fclose(sym_file); - return(0); - } - if(dbgPrintSymbols) - dbgprintf("Address: %lx, Type: %c, Symbol: %s\n", address, type, sym); - version = CheckVersion(sym); - } - fclose(sym_file); - - switch ( version ) { - case -1: - imklogLogIntMsg(LOG_ERR, "Symbol table has incorrect version number.\n"); - break; - case 0: - dbgprintf("No version information found.\n"); - break; - case 1: - dbgprintf("Found table with matching version number.\n"); - break; - } - - return(version); - } - - return(0); -} - - -/************************************************************************** - * Function: AddSymbol - * - * Purpose: This function is responsible for adding a symbol name - * and its address to the symbol table. - * - * Arguements: (unsigned long) address, (char *) symbol - * - * Return: int - * - * A boolean value is assumed. True if the addition is - * successful. False if not. - **************************************************************************/ -static int AddSymbol(unsigned long address, char *symbol) -{ - /* Allocate the the symbol table entry. */ - sym_array = (struct sym_table *) realloc(sym_array, (num_syms+1) * - sizeof(struct sym_table)); - if ( sym_array == (struct sym_table *) 0 ) - return(0); - - /* Then the space for the symbol. */ - sym_array[num_syms].name = (char *) MALLOC(strlen(symbol)*sizeof(char) + 1); - if ( sym_array[num_syms].name == NULL ) - return(0); - - sym_array[num_syms].value = address; - strcpy(sym_array[num_syms].name, symbol); - ++num_syms; - return(1); -} - - -/************************************************************************** - * Function: LookupSymbol - * - * Purpose: Find the symbol which is related to the given kernel - * address. - * - * Arguements: (long int) value, (struct symbol *) sym - * - * value:-> The address to be located. - * - * sym:-> A pointer to a structure which will be - * loaded with the symbol's parameters. - * - * Return: (char *) - * - * If a match cannot be found a diagnostic string is printed. - * If a match is found the pointer to the symbolic name most - * closely matching the address is returned. - **************************************************************************/ -char * LookupSymbol(unsigned long value, struct symbol *sym) -{ - auto int lp; - - auto char *last; - auto char *name; - - struct symbol ksym, msym; - - if (!sym_array) - return(NULL); - - last = sym_array[0].name; - ksym.offset = 0; - ksym.size = 0; - if ( value < sym_array[0].value ) - return(NULL); - - for(lp = 0; lp <= num_syms; ++lp) { - if ( sym_array[lp].value > value ) { - ksym.offset = value - sym_array[lp-1].value; - ksym.size = sym_array[lp].value - \ - sym_array[lp-1].value; - break; - } - last = sym_array[lp].name; - } - - name = LookupModuleSymbol(value, &msym); - - if ( ksym.offset == 0 && msym.offset == 0 ) { - return(NULL); - } - - if ( ksym.offset == 0 || msym.offset < 0 || - (ksym.offset > 0 && ksym.offset < msym.offset) ) { - sym->offset = ksym.offset; - sym->size = ksym.size; - return(last); - } else { - sym->offset = msym.offset; - sym->size = msym.size; - return(name); - } - - - return(NULL); -} - -/************************************************************************** - * Function: FreeSymbols - * - * Purpose: This function is responsible for freeing all memory which - * has been allocated to hold the static symbol table. It - * also initializes the symbol count and in general prepares - * for a re-read of a static symbol table. - * - * Arguements: void - * - * Return: void - **************************************************************************/ -static void FreeSymbols(void) -{ - auto int lp; - - /* Free each piece of memory allocated for symbol names. */ - for(lp= 0; lp < num_syms; ++lp) - free(sym_array[lp].name); - - /* Whack the entire array and initialize everything. */ - free(sym_array); - sym_array = (struct sym_table *) 0; - num_syms = 0; - - return; -} - - -/************************************************************************** - * Function: LogExpanded - * - * Purpose: This function is responsible for logging a kernel message - * line after all potential numeric kernel addresses have - * been resolved symolically. - * - * Arguements: (char *) line, (char *) el - * - * line:-> A pointer to the buffer containing the kernel - * message to be expanded and logged. - * - * el:-> A pointer to the buffer into which the expanded - * kernel line will be written. - * - * Return: void - **************************************************************************/ -extern char *ExpandKadds(char *line, char *el) -{ - auto char *kp, - *sl = line, - *elp = el, - *symbol; - char num[15]; - auto unsigned long int value; - auto struct symbol sym; - - sym.offset = 0; - sym.size = 0; - - /* - * This is as handy a place to put this as anyplace. - * - * Since the insertion of kernel modules can occur in a somewhat - * dynamic fashion we need some mechanism to insure that the - * kernel symbol tables get read just prior to when they are - * needed. - * - * To accomplish this we look for the Oops string and use its - * presence as a signal to load the module symbols. - * - * This is not the best solution of course, especially if the - * kernel is rapidly going out to lunch. What really needs to - * be done is to somehow generate a callback from the - * kernel whenever a module is loaded or unloaded. I am - * open for patches. - */ - if ( i_am_paranoid && - (strstr(line, "Oops:") != NULL) && !InitMsyms() ) - imklogLogIntMsg(LOG_WARNING, "Cannot load kernel module symbols.\n"); - - - /* - * Early return if there do not appear to be any kernel - * messages in this line. - */ - if ( (num_syms == 0) || - (kp = strstr(line, "[<")) == NULL ) { -#ifdef __sparc__ - if (num_syms) { - /* On SPARC, register dumps do not have the [< >] characters in it. - */ - static struct sparc_tests { - char *str; - int len; - } tests[] = { { "PC: ", 4 }, - { " o7: ", 5 }, - { " ret_pc: ", 9 }, - { " i7: ", 5 }, - { "Caller[", 7 } - }; - int i, j, ndigits; - char *kp2; - for (i = 0; i < 5; i++) { - kp = strstr(line, tests[i].str); - if (!kp) continue; - kp2 = kp + tests[i].len; - if (!isxdigit(*kp2)) continue; - for (ndigits = 1; isxdigit(kp2[ndigits]); ndigits++); - if (ndigits != 8 && ndigits != 16) continue; - /* On sparc64, all kernel addresses are in first 4GB */ - if (ndigits == 16) { - if (strncmp (kp2, "00000000", 8)) continue; - kp2 += 8; - } - if (!i) { - char *kp3; - if (ndigits == 16 && kp > line && kp[-1L] != 'T') continue; - kp3 = kp2 + 8; - if (ndigits == 16) { - if (strncmp (kp3, " TNPC: 00000000", 15) || !isxdigit(kp3[15])) - continue; - kp3 += 15; - } else { - if (strncmp (kp3, " NPC: ", 6) || !isxdigit(kp3[6])) - continue; - kp3 += 6; - } - for (j = 0; isxdigit(kp3[j]); j++); - if (j != 8) continue; - strncpy(elp, line, kp2 + 8 - line); - elp += kp2 + 8 - line; - value = strtol(kp2, (char **) 0, 16); - if ( (symbol = LookupSymbol(value, &sym)) ) { - if (sym.size) - elp += sprintf(elp, " (%s+%d/%d)", symbol, sym.offset, sym.size); - else - elp += sprintf(elp, " (%s)", symbol); - } - strncpy(elp, kp2 + 8, kp3 - kp2); - elp += kp3 - kp2; - value = strtol(kp3, (char **) 0, 16); - if ( (symbol = LookupSymbol(value, &sym)) ) { - if (sym.size) - elp += sprintf(elp, " (%s+%d/%d)", symbol, sym.offset, sym.size); - else - elp += sprintf(elp, " (%s)", symbol); - } - strcpy(elp, kp3 + 8); - } else { - strncpy(elp, line, kp2 + 8 - line); - elp += kp2 + 8 - line; - value = strtol(kp2, (char **) 0, 16); - if ( (symbol = LookupSymbol(value, &sym)) ) { - if (sym.size) - elp += sprintf(elp, " (%s+%d/%d)", symbol, sym.offset, sym.size); - else - elp += sprintf(elp, " (%s)", symbol); - } - strcpy(elp, kp2 + 8); - } - return el; - } - } -#endif - strcpy(el, line); - return(el); - } - - /* Loop through and expand all kernel messages. */ - do { - while ( sl < kp+1 ) - *elp++ = *sl++; - - /* Now poised at a kernel delimiter. */ - if ( (kp = strstr(sl, ">]")) == NULL ) { - strcpy(el, sl); - return(el); - } - strncpy(num,sl+1,kp-sl-1); - num[kp-sl-1] = '\0'; - value = strtoul(num, (char **) 0, 16); - if ( (symbol = LookupSymbol(value, &sym)) == NULL ) - symbol = sl; - - strcat(elp, symbol); - elp += strlen(symbol); - dbgprintf("Symbol: %s = %lx = %s, %x/%d\n", sl+1, value, - (sym.size==0) ? symbol+1 : symbol, sym.offset, sym.size); - - value = 2; - if ( sym.size != 0 ) { - --value; - ++kp; - elp += sprintf(elp, "+0x%x/0x%02x", sym.offset, sym.size); - } - strncat(elp, kp, value); - elp += value; - sl = kp + value; - if ( (kp = strstr(sl, "[<")) == NULL ) - strcat(elp, sl); - } - while ( kp != NULL); - - dbgprintf("Expanded line: %s\n", el); - return(el); -} - - -/************************************************************************** - * Function: SetParanoiaLevel - * - * Purpose: This function is an interface function for setting the - * mode of loadable module symbol lookups. Probably overkill - * but it does slay another global variable. - * - * Arguements: (int) level - * - * level:-> The amount of paranoia which is to be - * present when resolving kernel exceptions. - * Return: void - **************************************************************************/ -extern void SetParanoiaLevel(int level) -{ - i_am_paranoid = level; - return; -} - diff --git a/plugins/imklog/ksym_mod.c b/plugins/imklog/ksym_mod.c deleted file mode 100644 index 82978892..00000000 --- a/plugins/imklog/ksym_mod.c +++ /dev/null @@ -1,485 +0,0 @@ -/* ksym_mod.c - functions for building symbol lookup tables for klogd - * Copyright (c) 1995, 1996 Dr. G.W. Wettstein - * Copyright (c) 1996 Enjellic Systems Development - * Copyright (c) 1998-2007 Martin Schulze - * Copyright (C) 2007-2009 Rainer Gerhards - * - * 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. -*/ - -/* - * This file implements functions which are useful for building - * a symbol lookup table based on the in kernel symbol table - * maintained by the Linux kernel. - * - * Proper logging of kernel panics generated by loadable modules - * tends to be difficult. Since the modules are loaded dynamically - * their addresses are not known at kernel load time. A general - * protection fault (Oops) cannot be properly deciphered with - * classic methods using the static symbol map produced at link time. - * - * One solution to this problem is to have klogd attempt to translate - * addresses from module when the fault occurs. By referencing the - * the kernel symbol table proper resolution of these symbols is made - * possible. - * - * At least that is the plan. - * - * Wed Aug 21 09:20:09 CDT 1996: Dr. Wettstein - * The situation where no module support has been compiled into a - * kernel is now detected. An informative message is output indicating - * that the kernel has no loadable module support whenever kernel - * module symbols are loaded. - * - * An informative message is printed indicating the number of kernel - * modules and the number of symbols loaded from these modules. - * - * Sun Jun 15 16:23:29 MET DST 1997: Michael Alan Dorman - * Some more glibc patches made by . - * - * Sat Jan 10 15:00:18 CET 1998: Martin Schulze - * Fixed problem with klogd not being able to be built on a kernel - * newer than 2.1.18. It was caused by modified structures - * inside the kernel that were included. I have worked in a - * patch from Alessandro Suardi . - * - * Sun Jan 25 20:57:34 CET 1998: Martin Schulze - * Another patch for Linux/alpha by Christopher C Chimelis - * . - * - * Thu Mar 19 23:39:29 CET 1998: Manuel Rodrigues - * Changed lseek() to llseek() in order to support > 2GB address - * space which provided by kernels > 2.1.70. - * - * Mon Apr 13 18:18:45 CEST 1998: Martin Schulze - * Removed as it's no longer part of recent glibc - * versions. Added prototyp for llseek() which has been - * forgotton in from glibc. Added more log - * information if problems occurred while reading a system map - * file, by submission from Mark Simon Phillips . - * - * Sun Jan 3 18:38:03 CET 1999: Martin Schulze - * Corrected return value of AddModule if /dev/kmem can't be - * loaded. This will prevent klogd from segfaulting if /dev/kmem - * is not available. Patch from Topi Miettinen . - * - * Tue Sep 12 23:11:13 CEST 2000: Martin Schulze - * Changed llseek() to lseek64() in order to skip a libc warning. - */ - -/* Includes. */ -#include "config.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if !defined(__GLIBC__) -#include -#include -#else /* __GLIBC__ */ -#include "module.h" -#endif /* __GLIBC__ */ -#include -#include -#include - -#include "rsyslog.h" -#include "imklog.h" -#include "ksyms.h" -#include "debug.h" - -#define KSYMS "/proc/kallsyms" - -static int num_modules = 0; -struct Module *sym_array_modules = (struct Module *) NULL; - -static int have_modules = 0; - - -/* Function prototypes. */ -static void FreeModules(void); -static int AddSymbol(const char *); -struct Module *AddModule(const char *); -static int symsort(const void *, const void *); - -/* Imported from ksym.c */ -extern int num_syms; - - -/************************************************************************** - * Function: InitMsyms - * - * Purpose: This function is responsible for building a symbol - * table which can be used to resolve addresses for - * loadable modules. - * - * Arguements: Void - * - * Return: A boolean return value is assumed. - * - * A false value indicates that something went wrong. - * - * True if loading is successful. - **************************************************************************/ -extern int InitMsyms(void) -{ - - auto int rtn, - tmp; - FILE *ksyms; - char buf[128]; - char *p; - - /* Initialize the kernel module symbol table. */ - FreeModules(); - - ksyms = fopen(KSYMS, "r"); - - if ( ksyms == NULL ) { - if ( errno == ENOENT ) - imklogLogIntMsg(LOG_INFO, "No module symbols loaded - " - "kernel modules not enabled.\n"); - else - imklogLogIntMsg(LOG_ERR, "Error loading kernel symbols " \ - "- %s\n", strerror(errno)); - return(0); - } - - dbgprintf("Loading kernel module symbols - Source: %s\n", KSYMS); - - while ( fgets(buf, sizeof(buf), ksyms) != NULL ) { - if (num_syms > 0 && index(buf, '[') == NULL) - continue; - - p = index(buf, ' '); - - if ( p == NULL ) - continue; - - if ( buf[strlen(buf)-1] == '\n' ) - buf[strlen(buf)-1] = '\0'; - /* overlong lines will be ignored above */ - - AddSymbol(buf); - } - - if(ksyms != NULL) - fclose(ksyms); - - have_modules = 1; - - /* Sort the symbol tables in each module. */ - for (rtn = tmp = 0; tmp < num_modules; ++tmp) { - rtn += sym_array_modules[tmp].num_syms; - if ( sym_array_modules[tmp].num_syms < 2 ) - continue; - qsort(sym_array_modules[tmp].sym_array, \ - sym_array_modules[tmp].num_syms, \ - sizeof(struct sym_table), symsort); - } - - if ( rtn == 0 ) - imklogLogIntMsg(LOG_INFO, "No module symbols loaded."); - else - imklogLogIntMsg(LOG_INFO, "Loaded %d %s from %d module%s", rtn, \ - (rtn == 1) ? "symbol" : "symbols", \ - num_modules, (num_modules == 1) ? "." : "s."); - - return(1); -} - - -static int symsort(const void *p1, const void *p2) -{ - auto const struct sym_table *sym1 = p1, - *sym2 = p2; - - if ( sym1->value < sym2->value ) - return(-1); - if ( sym1->value == sym2->value ) - return(0); - return(1); -} - - -extern void DeinitMsyms(void) -{ - FreeModules(); -} - - -/************************************************************************** - * Function: FreeModules - * - * Purpose: This function is used to free all memory which has been - * allocated for the modules and their symbols. - * - * Arguements: None specified. - * - * Return: void - **************************************************************************/ -static void FreeModules() -{ - auto int nmods, - nsyms; - auto struct Module *mp; - - /* Check to see if the module symbol tables need to be cleared. */ - have_modules = 0; - if ( num_modules == 0 ) - return; - - if ( sym_array_modules == NULL ) - return; - - for (nmods = 0; nmods < num_modules; ++nmods) { - mp = &sym_array_modules[nmods]; - if ( mp->num_syms == 0 ) - continue; - - for (nsyms= 0; nsyms < mp->num_syms; ++nsyms) - free(mp->sym_array[nsyms].name); - free(mp->sym_array); - if ( mp->name != NULL ) - free(mp->name); - } - - free(sym_array_modules); - sym_array_modules = (struct Module *) NULL; - num_modules = 0; - return; -} - - -/************************************************************************** - * Function: AddModule - * - * Purpose: This function is responsible for adding a module to - * the list of currently loaded modules. - * - * Arguments: (const char *) module - * - * module:-> The name of the module. - * - * Return: struct Module * - **************************************************************************/ - -struct Module *AddModule(module) - const char *module; -{ - struct Module *mp; - - if ( num_modules == 0 ) { - sym_array_modules = (struct Module *)MALLOC(sizeof(struct Module)); - - if ( sym_array_modules == NULL ) - { - imklogLogIntMsg(LOG_WARNING, "Cannot allocate Module array.\n"); - return NULL; - } - mp = sym_array_modules; - } else { - /* Allocate space for the module. */ - mp = (struct Module *) \ - realloc(sym_array_modules, \ - (num_modules+1) * sizeof(struct Module)); - - if ( mp == NULL ) - { - imklogLogIntMsg(LOG_WARNING, "Cannot allocate Module array.\n"); - return NULL; - } - - sym_array_modules = mp; - mp = &sym_array_modules[num_modules]; - } - - num_modules++; - mp->sym_array = NULL; - mp->num_syms = 0; - - if ( module != NULL ) - mp->name = strdup(module); - else - mp->name = NULL; - - return mp; -} - - -/************************************************************************** - * Function: AddSymbol - * - * Purpose: This function is responsible for adding a symbol name - * and its address to the symbol table. - * - * Arguements: const char * - * - * Return: int - * - * A boolean value is assumed. True if the addition is - * successful. False if not. - **************************************************************************/ -static int AddSymbol(line) - const char *line; -{ - char *module; - unsigned long address; - char *p; - static char *lastmodule = NULL; - struct Module *mp; - - module = index(line, '['); - - if ( module != NULL ) { - p = index(module, ']'); - if ( p != NULL ) - *p = '\0'; - p = module++; - while ( isspace(*(--p)) ) - /*SKIP*/; - *(++p) = '\0'; - } - - p = index(line, ' '); - - if ( p == NULL ) - return(0); - - *p = '\0'; - - address = strtoul(line, (char **) 0, 16); - - p += 3; - - if ( num_modules == 0 || - ( lastmodule == NULL && module != NULL ) || - ( module == NULL && lastmodule != NULL) || - ( module != NULL && strcmp(module, lastmodule))) { - mp = AddModule(module); - - if ( mp == NULL ) - return(0); - } else - mp = &sym_array_modules[num_modules-1]; - - lastmodule = mp->name; - - /* Allocate space for the symbol table entry. */ - mp->sym_array = (struct sym_table *) realloc(mp->sym_array, \ - (mp->num_syms+1) * sizeof(struct sym_table)); - - if ( mp->sym_array == (struct sym_table *) NULL ) - return(0); - - mp->sym_array[mp->num_syms].name = strdup(p); - if ( mp->sym_array[mp->num_syms].name == (char *) NULL ) - return(0); - - /* Stuff interesting information into the module. */ - mp->sym_array[mp->num_syms].value = address; - ++mp->num_syms; - - return(1); -} - - - -/************************************************************************** - * Function: LookupModuleSymbol - * - * Purpose: Find the symbol which is related to the given address from - * a kernel module. - * - * Arguements: (long int) value, (struct symbol *) sym - * - * value:-> The address to be located. - * - * sym:-> A pointer to a structure which will be - * loaded with the symbol's parameters. - * - * Return: (char *) - * - * If a match cannot be found a diagnostic string is printed. - * If a match is found the pointer to the symbolic name most - * closely matching the address is returned. - * - * TODO: We are using int values for the offset, but longs for the value - * values. This may create some trouble in the future (on 64 Bit OS?). - * Anyhow, I have not changed this, because we do not seem to have any - * issue and my understanding of this code is limited (and I don't see - * need to invest more time to dig much deeper). - * rgerhards, 2009-04-17 - **************************************************************************/ -extern char * LookupModuleSymbol(value, sym) - unsigned long value; - struct symbol *sym; -{ - int nmod, nsym; - struct sym_table *last; - struct Module *mp; - static char ret[100]; - - sym->size = 0; - sym->offset = 0; - if ( num_modules == 0 ) - return((char *) 0); - - for (nmod = 0; nmod < num_modules; ++nmod) { - mp = &sym_array_modules[nmod]; - - /* Run through the list of symbols in this module and - * see if the address can be resolved. - */ - for(nsym = 1, last = &mp->sym_array[0]; - nsym < mp->num_syms; - ++nsym) { - if ( mp->sym_array[nsym].value > value ) - { - if ( sym->size == 0 || - (int) (value - last->value) < sym->offset || - ( (sym->offset == (int) (value - last->value)) && - (int) (mp->sym_array[nsym].value-last->value) < sym->size ) ) - { - sym->offset = value - last->value; - sym->size = mp->sym_array[nsym].value - last->value; - ret[sizeof(ret)-1] = '\0'; - if ( mp->name == NULL ) - snprintf(ret, sizeof(ret)-1, - "%s", last->name); - else - snprintf(ret, sizeof(ret)-1, - "%s:%s", mp->name, last->name); - } - break; - } - last = &mp->sym_array[nsym]; - } - } - - if ( sym->size > 0 ) - return(ret); - - /* It has been a hopeless exercise. */ - return(NULL); -} diff --git a/plugins/imklog/ksyms.h b/plugins/imklog/ksyms.h deleted file mode 100644 index a168947b..00000000 --- a/plugins/imklog/ksyms.h +++ /dev/null @@ -1,37 +0,0 @@ -/* ksym.h - Definitions for symbol table utilities. - * Copyright (c) 1995, 1996 Dr. G.W. Wettstein - * Copyright (c) 1996 Enjellic Systems Development - * Copyright (c) 2004-7 Martin Schulze - * Copyright (c) 2007-2009 Rainer Gerhards - * - * 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. - */ - -/* Variables, structures and type definitions static to this module. */ - -struct symbol -{ - uchar *name; - int size; - int offset; -}; - - -/* Function prototypes. */ -extern char * LookupSymbol(unsigned long, struct symbol *); -extern char * LookupModuleSymbol(unsigned long int, struct symbol *); diff --git a/plugins/imklog/linux.c b/plugins/imklog/linux.c deleted file mode 100644 index b44619f5..00000000 --- a/plugins/imklog/linux.c +++ /dev/null @@ -1,623 +0,0 @@ -/* klog for linux, based on the FreeBSD syslogd implementation. - * - * This contains OS-specific functionality to read the BSD - * kernel log. For a general overview, see head comment in - * imklog.c. - * - * This file heavily borrows from the klogd daemon provided by - * the sysklogd project. Many thanks for this piece of software. - * - * 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 "rsyslog.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include "cfsysline.h" -#include "template.h" -#include "msg.h" -#include "module-template.h" -#include "imklog.h" -#include "unicode-helper.h" - - -/* Includes. */ -#include -#include -#include -#include - -#if HAVE_TIME_H -# include -#endif - -#include -#include -#include "ksyms.h" - -#define __LIBRARY__ -#include - - -#if !defined(__GLIBC__) -# define __NR_ksyslog __NR_syslog -_syscall3(int,ksyslog,int, type, char *, buf, int, len); -#else -#include -#define ksyslog klogctl -#endif - - - -#ifndef _PATH_KLOG -#define _PATH_KLOG "/proc/kmsg" -#endif - -#define LOG_BUFFER_SIZE 4096 -#define LOG_LINE_LENGTH 1000 - -static int kmsg; -static char log_buffer[LOG_BUFFER_SIZE]; - -static enum LOGSRC {none, proc, kernel} logsrc; - - -/* Function prototypes. */ -extern int ksyslog(int type, char *buf, int len); - - -static uchar *GetPath(void) -{ - return pszPath ? pszPath : UCHAR_CONSTANT(_PATH_KLOG); -} - -static void CloseLogSrc(void) -{ - /* Turn on logging of messages to console, but only if a log level was speficied */ - if(console_log_level != -1) - ksyslog(7, NULL, 0); - - /* Shutdown the log sources. */ - switch(logsrc) { - case kernel: - ksyslog(0, NULL, 0); - imklogLogIntMsg(LOG_INFO, "Kernel logging (ksyslog) stopped."); - break; - case proc: - close(kmsg); - imklogLogIntMsg(LOG_INFO, "Kernel logging (proc) stopped."); - break; - case none: - break; - } - - return; -} - - -static enum LOGSRC GetKernelLogSrc(void) -{ - auto struct stat sb; - - /* Set level of kernel console messaging.. */ - if ( (console_log_level != -1) && - (ksyslog(8, NULL, console_log_level) < 0) && - (errno == EINVAL) ) - { - /* - * An invalid arguement error probably indicates that - * a pre-0.14 kernel is being run. At this point we - * issue an error message and simply shut-off console - * logging completely. - */ - imklogLogIntMsg(LOG_WARNING, "Cannot set console log level - disabling " - "console output."); - } - - /* - * First do a stat to determine whether or not the proc based - * file system is available to get kernel messages from. - */ - if ( use_syscall || - ((stat((char*)GetPath(), &sb) < 0) && (errno == ENOENT)) ) - { - /* Initialize kernel logging. */ - ksyslog(1, NULL, 0); - imklogLogIntMsg(LOG_INFO, "imklog %s, log source = ksyslog " - "started.", VERSION); - return(kernel); - } - - if ( (kmsg = open((char*)GetPath(), O_RDONLY|O_CLOEXEC)) < 0 ) - { - imklogLogIntMsg(LOG_ERR, "imklog: Cannot open proc file system, %d.\n", errno); - ksyslog(7, NULL, 0); - return(none); - } - - imklogLogIntMsg(LOG_INFO, "imklog %s, log source = %s started.", VERSION, GetPath()); - return(proc); -} - - -/* Copy characters from ptr to line until a char in the delim - * string is encountered or until min( space, len ) chars have - * been copied. - * - * Returns the actual number of chars copied. - */ -static int copyin( uchar *line, int space, - const char *ptr, int len, - const char *delim ) -{ - auto int i; - auto int count; - - count = len < space ? len : space; - - for(i=0; i no kernel timestamp\n"); - goto done; /* no TS! */ - } - - ++i; /* skip dot */ - nsecs = 0; - while(buf[i] && isdigit(buf[i])) { - nsecs = nsecs * 10 + buf[i] - '0'; - ++i; - } - if(buf[i] != ']') { - DBGPRINTF("no trailing ']' --> no kernel timestamp\n"); - goto done; /* no TS! */ - } - ++i; /* skip ']' */ - - /* we have a timestamp */ - DBGPRINTF("kernel timestamp is %ld %ld\n", secs, nsecs); - bufsize= strlen((char*)buf); - memcpy(buf+3, buf+i, bufsize - i + 1); - - clock_gettime(CLOCK_MONOTONIC, &monotonic); - clock_gettime(CLOCK_REALTIME, &realtime); - secOffs = realtime.tv_sec - monotonic.tv_sec; - nsecOffs = realtime.tv_nsec - monotonic.tv_nsec; - if(nsecOffs < 0) { - secOffs--; - nsecOffs += 1000000000l; - } - - nsecs +=nsecOffs; - if(nsecs > 999999999l) { - secs++; - nsecs -= 1000000000l; - } - secs += secOffs; - tv.tv_sec = secs; - tv.tv_usec = nsecs / 1000; - tp = &tv; - -done: - Syslog(pri, buf, tp); -} - - -/* - * Messages are separated by "\n". Messages longer than - * LOG_LINE_LENGTH are broken up. - * - * Kernel symbols show up in the input buffer as : "[]", - * where "aaaaaa" is the address. These are replaced with - * "[symbolname+offset/size]" in the output line - symbolname, - * offset, and size come from the kernel symbol table. - * - * If a kernel symbol happens to fall at the end of a message close - * in length to LOG_LINE_LENGTH, the symbol will not be expanded. - * (This should never happen, since the kernel should never generate - * messages that long. - * - * To preserve the original addresses, lines containing kernel symbols - * are output twice. Once with the symbols converted and again with the - * original text. Just in case somebody wants to run their own Oops - * analysis on the syslog, e.g. ksymoops. - */ -static void LogLine(char *ptr, int len) -{ - enum parse_state_enum { - PARSING_TEXT, - PARSING_SYMSTART, /* at < */ - PARSING_SYMBOL, - PARSING_SYMEND /* at ] */ - }; - - static uchar line_buff[LOG_LINE_LENGTH]; - - static uchar *line =line_buff; - static enum parse_state_enum parse_state = PARSING_TEXT; - static int space = sizeof(line_buff)-1; - - static uchar *sym_start; /* points at the '<' of a symbol */ - - auto int delta = 0; /* number of chars copied */ - auto int symbols_expanded = 0; /* 1 if symbols were expanded */ - auto int skip_symbol_lookup = 0; /* skip symbol lookup on this pass */ - auto char *save_ptr = ptr; /* save start of input line */ - auto int save_len = len; /* save length at start of input line */ - - while( len > 0 ) - { - if( space == 0 ) /* line buffer is full */ - { - /* - ** Line too long. Start a new line. - */ - *line = 0; /* force null terminator */ - - //dbgprintf("Line buffer full:\n"); - //dbgprintf("\tLine: %s\n", line); - - submitSyslog(LOG_INFO, line_buff); - line = line_buff; - space = sizeof(line_buff)-1; - parse_state = PARSING_TEXT; - symbols_expanded = 0; - skip_symbol_lookup = 0; - save_ptr = ptr; - save_len = len; - } - - switch( parse_state ) - { - case PARSING_TEXT: - delta = copyin(line, space, ptr, len, "\n[" ); - line += delta; - ptr += delta; - space -= delta; - len -= delta; - - if( space == 0 || len == 0 ) { - break; /* full line_buff or end of input buffer */ - } - - if( *ptr == '\0' ) /* zero byte */ { - ptr++; /* skip zero byte */ - space -= 1; - len -= 1; - break; - } - - if( *ptr == '\n' ) /* newline */ { - ptr++; /* skip newline */ - space -= 1; - len -= 1; - - *line = 0; /* force null terminator */ - submitSyslog(LOG_INFO, line_buff); - line = line_buff; - space = sizeof(line_buff)-1; - if (symbols_twice) { - if (symbols_expanded) { - /* reprint this line without symbol lookup */ - symbols_expanded = 0; - skip_symbol_lookup = 1; - ptr = save_ptr; - len = save_len; - } else { - skip_symbol_lookup = 0; - save_ptr = ptr; - save_len = len; - } - } - break; - } - if( *ptr == '[' ) /* possible kernel symbol */ { - *line++ = *ptr++; - space -= 1; - len -= 1; - if (!skip_symbol_lookup) - parse_state = PARSING_SYMSTART; /* at < */ - break; - } - /* Now that line_buff is no longer fed to *printf as format - * string, '%'s are no longer "dangerous". - */ - break; - - case PARSING_SYMSTART: - if( *ptr != '<' ) { - parse_state = PARSING_TEXT; /* not a symbol */ - break; - } - - /* - ** Save this character for now. If this turns out to - ** be a valid symbol, this char will be replaced later. - ** If not, we'll just leave it there. - */ - - sym_start = line; /* this will point at the '<' */ - - *line++ = *ptr++; - space -= 1; - len -= 1; - parse_state = PARSING_SYMBOL; /* symbol... */ - break; - - case PARSING_SYMBOL: - delta = copyin( line, space, ptr, len, ">\n[" ); - line += delta; - ptr += delta; - space -= delta; - len -= delta; - if( space == 0 || len == 0 ) - { - break; /* full line_buff or end of input buffer */ - } - if( *ptr != '>' ) - { - parse_state = PARSING_TEXT; - break; - } - - *line++ = *ptr++; /* copy the '>' */ - space -= 1; - len -= 1; - - parse_state = PARSING_SYMEND; - - break; - - case PARSING_SYMEND: - if( *ptr != ']' ) - { - parse_state = PARSING_TEXT; /* not a symbol */ - break; - } - - /* - ** It's really a symbol! Replace address with the - ** symbol text. - */ - { - auto int sym_space; - - unsigned long value; - auto struct symbol sym; - auto char *symbol; - - *(line-1) = 0; /* null terminate the address string */ - value = strtoul((char*)(sym_start+1), (char **) 0, 16); - *(line-1) = '>'; /* put back delim */ - - if ( !symbol_lookup || (symbol = LookupSymbol(value, &sym)) == (char *)0 ) - { - parse_state = PARSING_TEXT; - break; - } - - /* - ** verify there is room in the line buffer - */ - sym_space = space + ( line - sym_start ); - if( (unsigned) sym_space < strlen(symbol) + 30 ) /*(30 should be overkill)*/ - { - parse_state = PARSING_TEXT; /* not enough space */ - break; - } - - // TODO: sprintf!!!! - delta = sprintf( (char*) sym_start, "%s+%d/%d]", - symbol, sym.offset, sym.size ); - - space = sym_space + delta; - line = sym_start + delta; - symbols_expanded = 1; - } - ptr++; - len--; - parse_state = PARSING_TEXT; - break; - - default: /* Can't get here! */ - parse_state = PARSING_TEXT; - - } - } - - return; -} - - -static void LogKernelLine(void) -{ - auto int rdcnt; - - /* - * Zero-fill the log buffer. This should cure a multitude of - * problems with klogd logging the tail end of the message buffer - * which will contain old messages. Then read the kernel log - * messages into this fresh buffer. - */ - memset(log_buffer, '\0', sizeof(log_buffer)); - if ( (rdcnt = ksyslog(2, log_buffer, sizeof(log_buffer)-1)) < 0 ) - { - if(errno == EINTR) - return; - imklogLogIntMsg(LOG_ERR, "imklog Error return from sys_sycall: %d\n", errno); - } - else - LogLine(log_buffer, rdcnt); - return; -} - - -static void LogProcLine(void) -{ - auto int rdcnt; - - /* - * Zero-fill the log buffer. This should cure a multitude of - * problems with klogd logging the tail end of the message buffer - * which will contain old messages. Then read the kernel messages - * from the message pseudo-file into this fresh buffer. - */ - memset(log_buffer, '\0', sizeof(log_buffer)); - if ( (rdcnt = read(kmsg, log_buffer, sizeof(log_buffer)-1)) < 0 ) { - if ( errno == EINTR ) - return; - imklogLogIntMsg(LOG_ERR, "Cannot read proc file system: %d - %s.", errno, strerror(errno)); - } else { - LogLine(log_buffer, rdcnt); - } - - return; -} - - -/* to be called in the module's WillRun entry point - * rgerhards, 2008-04-09 - */ -rsRetVal klogLogKMsg(void) -{ - DEFiRet; - switch(logsrc) { - case kernel: - LogKernelLine(); - break; - case proc: - LogProcLine(); - break; - case none: - /* TODO: We need to handle this case here somewhat more intelligent - * This is now at least partly done - code should never reach this point - * as willRun() already checked for the "none" status -- rgerhards, 2007-12-17 - */ - pause(); - break; - } - RETiRet; -} - - -/* to be called in the module's WillRun entry point - * rgerhards, 2008-04-09 - */ -rsRetVal klogWillRun(void) -{ - DEFiRet; - /* Initialize this module. If that fails, we tell the engine we don't like to run */ - /* Determine where kernel logging information is to come from. */ - logsrc = GetKernelLogSrc(); - if(logsrc == none) { - iRet = RS_RET_NO_KERNEL_LOGSRC; - } else { - if (symbol_lookup) { - symbol_lookup = (InitKsyms(symfile) == 1); - symbol_lookup |= InitMsyms(); - if (symbol_lookup == 0) { - imklogLogIntMsg(LOG_WARNING, "cannot find any symbols, turning off symbol lookups"); - } - } - } - - RETiRet; -} - - -/* to be called in the module's AfterRun entry point - * rgerhards, 2008-04-09 - */ -rsRetVal klogAfterRun(void) -{ - DEFiRet; - /* cleanup here */ - if(logsrc != none) - CloseLogSrc(); - - DeinitKsyms(); - DeinitMsyms(); - - RETiRet; -} - - -/* provide the (system-specific) default facility for internal messages - * rgerhards, 2008-04-14 - */ -int -klogFacilIntMsg(void) -{ - return LOG_KERN; -} - - -/* vi:set ai: - */ -- cgit v1.2.3 From cca05921dcfab557a4743a56c78683e4c1113e2a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 23 Jan 2012 18:06:26 +0100 Subject: imklog: forgot to remove one file; now done --- plugins/imklog/module.h | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 plugins/imklog/module.h diff --git a/plugins/imklog/module.h b/plugins/imklog/module.h deleted file mode 100644 index 38a26fea..00000000 --- a/plugins/imklog/module.h +++ /dev/null @@ -1,35 +0,0 @@ -/* module.h - Miscellaneous module definitions - * Copyright (c) 1996 Richard Henderson - * Copyright (c) 2004-7 Martin Schulze - * Copyright (c) 2007-2008 Rainer Gerhards - * - * 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. - */ -struct sym_table -{ - unsigned long value; - char *name; -}; - -struct Module -{ - struct sym_table *sym_array; - int num_syms; - - char *name; -}; -- cgit v1.2.3 From c129ddcc637875442dbf9e0869f5eafbd08199ae Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 27 Jan 2012 11:08:58 +0100 Subject: bugfix: action stats did invalidly contain already-discarded messages --- action.c | 7 ++++--- configure.ac | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/action.c b/action.c index 7226e7d6..f16146c1 100644 --- a/action.c +++ b/action.c @@ -1575,7 +1575,8 @@ countStatsBatchEnq(action_t *pAction, batch_t *pBatch) { int i; for(i = 0 ; i < batchNumMsgs(pBatch) && !*(pBatch->pbShutdownImmediate) ; ++i) { - if(pBatch->pElem[i].bFilterOK) { + if( pBatch->pElem[i].bFilterOK + && pBatch->pElem[i].state != BATCH_STATE_DISC) { STATSCOUNTER_INC(pAction->ctrProcessed, pAction->mutCtrProcessed); } } @@ -1617,7 +1618,7 @@ doQueueEnqObjDirectBatch(action_t *pAction, batch_t *pBatch) pBatch->pElem[i].bFilterOK = 0; bModifiedFilter = 1; } - if(pBatch->pElem[i].bFilterOK) { + if(pBatch->pElem[i].bFilterOK && pBatch->pElem[i].state != BATCH_STATE_DISC) { STATSCOUNTER_INC(pAction->ctrProcessed, pAction->mutCtrProcessed); bNeedSubmit = 1; } @@ -1629,7 +1630,7 @@ doQueueEnqObjDirectBatch(action_t *pAction, batch_t *pBatch) /* note: stats were already computed above */ iRet = qqueueEnqObjDirectBatch(pAction->pQueue, pBatch); } else { - DBGPRINTF("no need to submit batch, all bFilterOK==0\n"); + DBGPRINTF("no need to submit batch, all bFilterOK==0 or discarded\n"); } if(bModifiedFilter) { for(i = 0 ; i < batchNumMsgs(pBatch) ; ++i) { diff --git a/configure.ac b/configure.ac index 0e9240e5..c6d775af 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],[5.8.6-newstats5],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.8.6-newstats6],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -- cgit v1.2.3 From 2227515764469d475d42d05ca7384cb227a8dce5 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 27 Jan 2012 11:42:17 +0100 Subject: preparing for 5.9.6 --- ChangeLog | 10 +++------- configure.ac | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ChangeLog b/ChangeLog index 87a7cac8..be4f97c8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ --------------------------------------------------------------------------- -Version 5.9.6 [V5-DEVEL], 2012-??-?? +Version 5.9.5 [V5-DEVEL], 2012-01-27 +- improved impstats subsystem, added many new counters +- enhanced module loader to not rely on PATH_MAX - refactored imklog linux driver, now combined with BSD driver The Linux driver no longer supports outdated kernel symbol resolution, which was disabled by default for very long. Also overall cleanup, @@ -13,12 +15,6 @@ Version 5.9.6 [V5-DEVEL], 2012-??-?? many unnamed others who already had complained at the time Chris made the suggestion ;-) --------------------------------------------------------------------------- -Version 5.9.5 [V5-DEVEL], 2011-11-29 -- new stats counters for imudp and imtcp -- new stats counters "discarded.nf" and "discarded.full" for queue object. - Tells how many messages have been discarded due to queue full condition. -- enhanced module loader to not rely on PATH_MAX ---------------------------------------------------------------------------- Version 5.9.4 [V5-DEVEL], 2011-11-29 - imuxsock: added capability to "annotate" messages with "trusted information", which contains some properties obtained from the system diff --git a/configure.ac b/configure.ac index 32029409..ccb2c47a 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],[5.9.4],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.9.5],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -- cgit v1.2.3 From 532d6994dffd733e8850d3c743a7b791f8d388b1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 27 Jan 2012 12:05:40 +0100 Subject: ompipe: support for v6 config system added --- tools/ompipe.c | 71 +++++++++++++++++++++++++++++++++++++++++++++++++------- tools/omusrmsg.c | 1 - 2 files changed, 63 insertions(+), 9 deletions(-) diff --git a/tools/ompipe.c b/tools/ompipe.c index 3d887e14..dfaa3cb8 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -70,9 +70,10 @@ DEFobjCurrIf(errmsg) typedef struct _instanceData { - uchar f_fname[MAXFNAME];/* pipe or template name (display only) */ - short fd; /* pipe descriptor for (current) pipe */ - sbool bHadError; /* did we already have/report an error on this pipe? */ + uchar *f_fname; /* pipe or template name (display only) */ + uchar *tplName; /* format template to use */ + short fd; /* pipe descriptor for (current) pipe */ + sbool bHadError; /* did we already have/report an error on this pipe? */ } instanceData; typedef struct configSettings_s { @@ -80,6 +81,18 @@ typedef struct configSettings_s { } configSettings_t; static configSettings_t __attribute__((unused)) cs; +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "pipe", eCmdHdlrString, CNFPARAM_REQUIRED }, + { "template", eCmdHdlrGetWord, 0 } +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars ENDinitConfVars @@ -170,6 +183,7 @@ finalize_it: BEGINcreateInstance CODESTARTcreateInstance + pData->f_fname = NULL; pData->fd = -1; pData->bHadError = 0; ENDcreateInstance @@ -177,6 +191,7 @@ ENDcreateInstance BEGINfreeInstance CODESTARTfreeInstance + free(pData->f_fname); if(pData->fd != -1) close(pData->fd); ENDfreeInstance @@ -193,6 +208,49 @@ CODESTARTdoAction ENDdoAction +static inline void +setInstParamDefaults(instanceData *pData) +{ + pData->tplName = NULL; +} + +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, "pipe")) { + pData->f_fname = (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 { + dbgprintf("ompipe: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + + if(pData->tplName == NULL) { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, (uchar*) "RSYSLOG_FileFormat", + OMSR_NO_RQD_TPL_OPTS)); + } else { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, + (uchar*) strdup((char*) pData->tplName), + OMSR_NO_RQD_TPL_OPTS)); + } +CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + BEGINparseSelectorAct CODESTARTparseSelectorAct /* yes, the if below is redundant, but I need it now. Will go away as @@ -212,12 +270,8 @@ CODESTARTparseSelectorAct } CODE_STD_STRING_REQUESTparseSelectorAct(1) + CHKmalloc(pData->f_fname = malloc(512)); ++p; - /* rgerhards 2004-11-17: from now, we need to have different - * processing, because after the first comma, the template name - * to use is specified. So we need to scan for the first coma first - * and then look at the rest of the line. - */ CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); @@ -244,6 +298,7 @@ CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES CODEqueryEtryPt_doHUP CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES ENDqueryEtryPt diff --git a/tools/omusrmsg.c b/tools/omusrmsg.c index ee2bc59f..e57d7ef9 100644 --- a/tools/omusrmsg.c +++ b/tools/omusrmsg.c @@ -380,7 +380,6 @@ CODE_STD_FINALIZERnewActInst ENDnewActInst - BEGINparseSelectorAct es_str_t *usrs; int bHadWarning; -- cgit v1.2.3 From 6ff5f6d239ec7489e9f55cdfb665ce1e84e3865b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 27 Jan 2012 12:06:14 +0100 Subject: ompipe: cosmetic, rename var --- tools/ompipe.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tools/ompipe.c b/tools/ompipe.c index dfaa3cb8..30cb9bfc 100644 --- a/tools/ompipe.c +++ b/tools/ompipe.c @@ -70,7 +70,7 @@ DEFobjCurrIf(errmsg) typedef struct _instanceData { - uchar *f_fname; /* pipe or template name (display only) */ + uchar *pipe; /* pipe or template name (display only) */ uchar *tplName; /* format template to use */ short fd; /* pipe descriptor for (current) pipe */ sbool bHadError; /* did we already have/report an error on this pipe? */ @@ -107,7 +107,7 @@ ENDisCompatibleWithFeature BEGINdbgPrintInstInfo CODESTARTdbgPrintInstInfo - dbgprintf("pipe %s", pData->f_fname); + dbgprintf("pipe %s", pData->pipe); if (pData->fd == -1) dbgprintf(" (unused)"); ENDdbgPrintInstInfo @@ -123,17 +123,17 @@ static inline rsRetVal preparePipe(instanceData *pData) { DEFiRet; - pData->fd = open((char*) pData->f_fname, O_RDWR|O_NONBLOCK|O_CLOEXEC); + pData->fd = open((char*) pData->pipe, O_RDWR|O_NONBLOCK|O_CLOEXEC); if(pData->fd < 0 ) { pData->fd = -1; if(!pData->bHadError) { char errStr[1024]; rs_strerror_r(errno, errStr, sizeof(errStr)); errmsg.LogError(0, RS_RET_NO_FILE_ACCESS, "Could no open output pipe '%s': %s", - pData->f_fname, errStr); + pData->pipe, errStr); pData->bHadError = 1; } - DBGPRINTF("Error opening log pipe: %s\n", pData->f_fname); + DBGPRINTF("Error opening log pipe: %s\n", pData->pipe); } RETiRet; } @@ -173,7 +173,7 @@ static rsRetVal writePipe(uchar **ppString, instanceData *pData) pData->fd = -1; /* tell that fd is no longer open! */ iRet = RS_RET_SUSPENDED; errno = e; - errmsg.LogError(0, NO_ERRCODE, "%s", pData->f_fname); + errmsg.LogError(0, NO_ERRCODE, "%s", pData->pipe); } finalize_it: @@ -183,7 +183,7 @@ finalize_it: BEGINcreateInstance CODESTARTcreateInstance - pData->f_fname = NULL; + pData->pipe = NULL; pData->fd = -1; pData->bHadError = 0; ENDcreateInstance @@ -191,7 +191,7 @@ ENDcreateInstance BEGINfreeInstance CODESTARTfreeInstance - free(pData->f_fname); + free(pData->pipe); if(pData->fd != -1) close(pData->fd); ENDfreeInstance @@ -203,7 +203,7 @@ ENDtryResume BEGINdoAction CODESTARTdoAction - DBGPRINTF(" (%s)\n", pData->f_fname); + DBGPRINTF(" (%s)\n", pData->pipe); iRet = writePipe(ppString, pData); ENDdoAction @@ -230,7 +230,7 @@ CODESTARTnewActInst if(!pvals[i].bUsed) continue; if(!strcmp(actpblk.descr[i].name, "pipe")) { - pData->f_fname = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + pData->pipe = (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 { @@ -270,9 +270,9 @@ CODESTARTparseSelectorAct } CODE_STD_STRING_REQUESTparseSelectorAct(1) - CHKmalloc(pData->f_fname = malloc(512)); + CHKmalloc(pData->pipe = malloc(512)); ++p; - CHKiRet(cflineParseFileName(p, (uchar*) pData->f_fname, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, + CHKiRet(cflineParseFileName(p, (uchar*) pData->pipe, *ppOMSR, 0, OMSR_NO_RQD_TPL_OPTS, (pszFileDfltTplName == NULL) ? (uchar*)"RSYSLOG_FileFormat" : pszFileDfltTplName)); CODE_STD_FINALIZERparseSelectorAct -- cgit v1.2.3 From 52380b313f772f0a604db497dbc9b2d201617388 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 27 Jan 2012 12:11:26 +0100 Subject: cleanup: remove omdbalerting someone claimed to write a module with this functionality, if a template were provided. And indeed, it was provided but never anything happend (at least nothing was contributed back...). Removing this silly template now. If someone really intends to take up on it, get a copy from older git versions. --- Makefile.am | 4 - configure.ac | 16 ---- plugins/omdbalerting/Makefile.am | 8 -- plugins/omdbalerting/omdbalerting.c | 146 ------------------------------------ 4 files changed, 174 deletions(-) delete mode 100644 plugins/omdbalerting/Makefile.am delete mode 100644 plugins/omdbalerting/omdbalerting.c diff --git a/Makefile.am b/Makefile.am index 9c77807d..585756c8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -146,10 +146,6 @@ if ENABLE_OMRULESET SUBDIRS += plugins/omruleset endif -if ENABLE_OMDBALERTING -SUBDIRS += plugins/omdbalerting -endif - if ENABLE_OMUDPSPOOF SUBDIRS += plugins/omudpspoof endif diff --git a/configure.ac b/configure.ac index 7aa735e4..e19e351d 100644 --- a/configure.ac +++ b/configure.ac @@ -1088,20 +1088,6 @@ AC_ARG_ENABLE(omruleset, AM_CONDITIONAL(ENABLE_OMRULESET, test x$enable_omruleset = xyes) -# settings for omdbalerting -AC_ARG_ENABLE(omdbalerting, - [AS_HELP_STRING([--enable-omdbalerting],[Compiles omdbalerting module @<:@default=no@:>@])], - [case "${enableval}" in - yes) enable_omdbalerting="yes" ;; - no) enable_omdbalerting="no" ;; - *) AC_MSG_ERROR(bad value ${enableval} for --enable-omdbalerting) ;; - esac], - [enable_omdbalerting=no] -) -AM_CONDITIONAL(ENABLE_OMDBALERTING, test x$enable_omdbalerting = xyes) - - - # building the GUI (mostly for diagnostic reasons) AC_ARG_ENABLE(gui, [AS_HELP_STRING([--enable-gui],[Enable GUI programs @<:@default=no@:>@])], @@ -1235,7 +1221,6 @@ AC_CONFIG_FILES([Makefile \ plugins/pmsnare/Makefile \ plugins/pmaixforwardedfrom/Makefile \ plugins/omruleset/Makefile \ - plugins/omdbalerting/Makefile \ plugins/omuxsock/Makefile \ plugins/imfile/Makefile \ plugins/imsolaris/Makefile \ @@ -1293,7 +1278,6 @@ echo " omstdout module will be compiled: $enable_omstdout" echo " omhdfs module will be compiled: $enable_omhdfs" echo " omelasticsearch module will be compiled: $enable_elasticsearch" echo " omruleset module will be compiled: $enable_omruleset" -echo " omdbalerting module will be compiled: $enable_omdbalerting" echo " omudpspoof module will be compiled: $enable_omudpspoof" echo " omuxsock module will be compiled: $enable_omuxsock" echo diff --git a/plugins/omdbalerting/Makefile.am b/plugins/omdbalerting/Makefile.am deleted file mode 100644 index becf29b0..00000000 --- a/plugins/omdbalerting/Makefile.am +++ /dev/null @@ -1,8 +0,0 @@ -pkglib_LTLIBRARIES = omdbalerting.la - -omdbalerting_la_SOURCES = omdbalerting.c -omdbalerting_la_CPPFLAGS = $(RSRT_CFLAGS) $(PTHREADS_CFLAGS) -omdbalerting_la_LDFLAGS = -module -avoid-version -omdbalerting_la_LIBADD = - -EXTRA_DIST = diff --git a/plugins/omdbalerting/omdbalerting.c b/plugins/omdbalerting/omdbalerting.c deleted file mode 100644 index ec9cf346..00000000 --- a/plugins/omdbalerting/omdbalerting.c +++ /dev/null @@ -1,146 +0,0 @@ -/* omdbalerting.c - * generate alerts based on database contents - so far a skeleton - * left for implementation by somebody else (skeleton created on request). - * - * NOTE: read comments in module-template.h for more specifics! - * - * File begun on 2009-11-17 by RGerhards - * - * Copyright 2009 Rainer Gerhards and Adiscon GmbH. - * - * This file is part of rsyslog. - * - * Rsyslog is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Rsyslog is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Rsyslog. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - */ -#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" - -MODULE_TYPE_OUTPUT -MODULE_TYPE_NOKEEP -MODULE_CNFNAME("omdbalerting") - -/* internal structures - */ -DEF_OMOD_STATIC_DATA - -/* config variables */ - - -typedef struct _instanceData { -} instanceData; - -BEGINcreateInstance -CODESTARTcreateInstance -ENDcreateInstance - - -BEGINisCompatibleWithFeature -CODESTARTisCompatibleWithFeature - if(eFeat == sFEATURERepeatedMsgReduction) - iRet = RS_RET_OK; -ENDisCompatibleWithFeature - - -BEGINfreeInstance -CODESTARTfreeInstance -ENDfreeInstance - - -BEGINdbgPrintInstInfo -CODESTARTdbgPrintInstInfo -ENDdbgPrintInstInfo - - -BEGINtryResume -CODESTARTtryResume -ENDtryResume - -BEGINdoAction -CODESTARTdoAction -ENDdoAction - - -BEGINparseSelectorAct -CODESTARTparseSelectorAct -CODE_STD_STRING_REQUESTparseSelectorAct(1) - /* first check if this config line is actually for us */ - if(strncmp((char*) p, ":omdbalerting:", sizeof(":dbalerting:") - 1)) { - ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); - } - - /* ok, if we reach this point, we have something for us */ - p += sizeof(":omdbalerting:") - 1; /* eat indicator sequence (-1 because of '\0'!) */ - CHKiRet(createInstance(&pData)); - - /* check if a non-standard template is to be applied */ - if(*(p-1) == ';') - --p; - /* we request the standard interface via template, others may be more useful - * here. - */ - CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, 0, (uchar*) "RSYSLOG_FileFormat")); -CODE_STD_FINALIZERparseSelectorAct -ENDparseSelectorAct - - -BEGINmodExit -CODESTARTmodExit -ENDmodExit - - -BEGINqueryEtryPt -CODESTARTqueryEtryPt -CODEqueryEtryPt_STD_OMOD_QUERIES -ENDqueryEtryPt - - - -/* Reset config variables for this module to default values. - */ -static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) -{ - DEFiRet; - RETiRet; -} - - -BEGINmodInit() -CODESTARTmodInit - *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ -CODEmodInit_QueryRegCFSLineHdlr - // SAMPLE! CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomdbalertingensurelfending", 0, eCmdHdlrBinary, NULL, - // &bEnsureLFEnding, 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 99a48039fba51cad2ee6a18a756079fbccab32a2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 27 Jan 2012 12:43:48 +0100 Subject: omprog: added support for v6 config system --- ChangeLog | 1 - plugins/omprog/omprog.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index cab970f9..c9ddd5b6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,7 +9,6 @@ Version 6.3.7 [DEVEL] 2011-0?-?? on what their role was. - added a couple of new stats objects - improved support for new v6 config system. Now also supported by - - omfwd - bugfix: facility local was not correctly interpreted in legacy filters Was only accepted if it was the first PRI in a multi-filter PRI. Thanks to forum user Mark for bringing this to our attention. diff --git a/plugins/omprog/omprog.c b/plugins/omprog/omprog.c index 1f6bb62f..03252fd5 100644 --- a/plugins/omprog/omprog.c +++ b/plugins/omprog/omprog.c @@ -54,6 +54,7 @@ DEFobjCurrIf(errmsg) typedef struct _instanceData { uchar *szBinary; /* name of binary to call */ + uchar *tplName; /* assigned output template */ pid_t pid; /* pid of currently running process */ int fdPipe; /* file descriptor to write to */ int bIsRunning; /* is binary currently running? 0-no, 1-yes */ @@ -64,6 +65,19 @@ typedef struct configSettings_s { } configSettings_t; static configSettings_t cs; + +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "binary", eCmdHdlrString, CNFPARAM_REQUIRED }, + { "template", eCmdHdlrGetWord, 0 } +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars cs.szBinary = NULL; /* name of binary to call */ @@ -298,6 +312,51 @@ CODESTARTdoAction ENDdoAction +static inline void +setInstParamDefaults(instanceData *pData) +{ + pData->szBinary = NULL; + pData->fdPipe = -1; + pData->bIsRunning = 0; +} + +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, "binary")) { + pData->szBinary = (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 { + dbgprintf("omprog: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + + if(pData->tplName == NULL) { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, (uchar*) "RSYSLOG_FileFormat", + OMSR_NO_RQD_TPL_OPTS)); + } else { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, + (uchar*) strdup((char*) pData->tplName), + OMSR_NO_RQD_TPL_OPTS)); + } +CODE_STD_FINALIZERnewActInst + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + BEGINparseSelectorAct CODESTARTparseSelectorAct CODE_STD_STRING_REQUESTparseSelectorAct(1) @@ -308,6 +367,12 @@ CODE_STD_STRING_REQUESTparseSelectorAct(1) /* ok, if we reach this point, we have something for us */ p += sizeof(":omprog:") - 1; /* eat indicator sequence (-1 because of '\0'!) */ + if(cs.szBinary == NULL) { + errmsg.LogError(0, RS_RET_CONF_RQRD_PARAM_MISSING, + "no binary to execute specified"); + ABORT_FINALIZE(RS_RET_CONF_RQRD_PARAM_MISSING); + } + CHKiRet(createInstance(&pData)); CHKmalloc(pData->szBinary = (uchar*) strdup((char*)cs.szBinary)); @@ -331,6 +396,8 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES ENDqueryEtryPt -- cgit v1.2.3 From cb843f8b788644ea441e9f122468f442ef3d9a0b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 27 Jan 2012 14:29:48 +0100 Subject: bugfix: rsyslog aborted during startup if there is an error in loading an action and legacy configuration mode is used --- ChangeLog | 2 ++ runtime/conf.c | 6 +----- runtime/rsconf.c | 34 ++++++++++++++++------------------ runtime/ruleset.c | 2 +- 4 files changed, 20 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9cbe3841..9ff14b1f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,8 @@ Version 6.3.7 [DEVEL] 2011-0?-?? - imported refactored v5.9.6 imklog linux driver, now combined with BSD driver +- bugfix: rsyslog aborted during startup if there is an error in loading + an action and legacy configuration mode is used - bugfix: bsd klog driver did no longer compile - removed imtemplate/omtemplate template modules, as this was waste of time The actual input/output modules are better copy templates. Instead, the diff --git a/runtime/conf.c b/runtime/conf.c index 24f64b9f..37774902 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -736,9 +736,6 @@ rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) iRet = RS_RET_OK; } if(iRet == RS_RET_OK || iRet == RS_RET_SUSPENDED) { - /* advance our config parser state: we now only accept an $End as valid, - * no more action statments. - */ if((iRet = addAction(&pAction, pMod, pModData, pOMSR, NULL, NULL, (iRet == RS_RET_SUSPENDED)? 1 : 0)) == RS_RET_OK) { /* now check if the module is compatible with select features */ @@ -752,8 +749,7 @@ rsRetVal cflineDoAction(rsconf_t *conf, uchar **p, action_t **ppAction) conf->actions.nbrActions++; /* one more active action! */ } break; - } - else if(iRet != RS_RET_CONFLINE_UNPROCESSED) { + } else if(iRet != RS_RET_CONFLINE_UNPROCESSED) { /* In this case, the module would have handled the config * line, but some error occured while doing so. This error should * already by reported by the module. We do not try any other diff --git a/runtime/rsconf.c b/runtime/rsconf.c index 8d8891a5..ed61e65e 100644 --- a/runtime/rsconf.c +++ b/runtime/rsconf.c @@ -2,27 +2,24 @@ * * Module begun 2011-04-19 by Rainer Gerhards * - * Copyright 2011 by Rainer Gerhards and Adiscon GmbH. + * Copyright 2011-2012 Adiscon GmbH. * * This file is part of the rsyslog runtime library. * - * The rsyslog runtime library 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. - * - * The rsyslog runtime library 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 the rsyslog runtime library. If not, see . - * - * A copy of the GPL can be found in the file "COPYING" in this distribution. - * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * -or- + * see COPYING.ASL20 in the source distribution + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ - #include "config.h" #include #include @@ -241,7 +238,7 @@ cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) } else { dbgprintf("legacy action line:%s\n", actlst->data.legActLine); str = (uchar*) actlst->data.legActLine; - iRet = cflineDoAction(loadConf, &str, &pAction); + CHKiRet(cflineDoAction(loadConf, &str, &pAction)); iRet = llAppend(&(pRule)->llActList, NULL, (void*) pAction); } for( cflst = actlst->syslines @@ -250,6 +247,7 @@ cnfDoActlst(struct cnfactlst *actlst, rule_t *pRule) } actlst = actlst->next; } +finalize_it: RETiRet; } diff --git a/runtime/ruleset.c b/runtime/ruleset.c index ceab08d1..00d96714 100644 --- a/runtime/ruleset.c +++ b/runtime/ruleset.c @@ -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\n"); + dbgprintf("selector line successfully processed, %d actions\n", iActionCnt); } finalize_it: -- cgit v1.2.3 From be01fe3c551b3acafebb093c6ccbc34190245405 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 31 Jan 2012 15:17:23 +0100 Subject: preparing for 6.3.7 --- ChangeLog | 75 +++++++++++++++++++++++++-------------------------------- configure.ac | 2 +- doc/manual.html | 2 +- 3 files changed, 35 insertions(+), 44 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9ff14b1f..737a9e9e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 6.3.7 [DEVEL] 2011-0?-?? +Version 6.3.7 [DEVEL] 2012-01-31 - imported refactored v5.9.6 imklog linux driver, now combined with BSD driver - bugfix: rsyslog aborted during startup if there is an error in loading @@ -10,49 +10,15 @@ Version 6.3.7 [DEVEL] 2011-0?-?? now-removed modules cost time for maintenance AND often caused confusion on what their role was. - added a couple of new stats objects -- improved support for new v6 config system. Now also supported by +- improved support for new v6 config system. The build-in output modules + now all support the new config language - bugfix: facility local was not correctly interpreted in legacy filters Was only accepted if it was the first PRI in a multi-filter PRI. Thanks to forum user Mark for bringing this to our attention. - bugfix: potential abort after reading invalid X.509 certificate closes: http://bugzilla.adiscon.com/show_bug.cgi?id=290 Thanks to Tomas Heinrich for the patch ---------------------------------------------------------------------------- -Version 6.2.1 [v6-stable], 2012-01-?? -- change plugin config interface to be compatible with pre-v6.2 system - The functionality was already removed (because it is superseeded by the - v6.3+ config language), but code was still present. I have now removed - those parts that affect interface. Full removal will happen in v6.3, in - order to limit potential regressions. However, it was considered useful - enough to do the interface change in v6-stable; this also eases merging - branches! -- re-licensed larger parts of the codebase under the Apache license 2.0 -- bugfix: omprog made rsyslog abort on startup if not binary to - execute was configured ---------------------------------------------------------------------------- -Version 6.2.0 [v6-stable], 2012-01-09 -- bugfix (kind of): removed numerical part from pri-text - see v6 compatibility document for reasons -- bugfix: race condition when extracting program name, APPNAME, structured - data and PROCID (RFC5424 fields) could lead to invalid characters e.g. - in dynamic file names or during forwarding (general malfunction of these - fields in templates, mostly under heavy load) -- bugfix: imuxsock did no longer ignore message-provided timestamp, if - so configured (the *default*). Lead to no longer sub-second timestamps. - closes: http://bugzilla.adiscon.com/show_bug.cgi?id=281 -- bugfix: omfile returns fatal error code for things that go really wrong - previously, RS_RET_RESUME was returned, which lead to a loop inside the - rule engine as omfile could not really recover. -- bugfix: rsyslogd -v always said 64 atomics were not present - thanks to mono_matsuko for the patch -- bugfix: potential abort after reading invalid X.509 certificate - closes: http://bugzilla.adiscon.com/show_bug.cgi?id=290 - Thanks to Tomas Heinrich for the patch -- enhanced module loader to not rely on PATH_MAX -- imuxsock: added capability to "annotate" messages with "trusted - information", which contains some properties obtained from the system - and as such sure to not be faked. This is inspired by the similiar idea - introduced in systemd. +- relicensed larger parts of the code under Apache (ASL) 2.0 --------------------------------------------------------------------------- Version 6.3.6 [DEVEL] 2011-09-19 - added $InputRELPServerBindRuleset directive to specify rulesets for RELP @@ -121,16 +87,41 @@ Version 6.3.0 [DEVEL] (rgerhards), 2011-06-01 - introduced new config system http://blog.gerhards.net/2011/06/new-rsyslog-config-system-materializes.html --------------------------------------------------------------------------- -Version 6.2.0 [v6-stable], 2011-0?-?? +Version 6.2.1 [v6-stable], 2012-01-?? +- change plugin config interface to be compatible with pre-v6.2 system + The functionality was already removed (because it is superseeded by the + v6.3+ config language), but code was still present. I have now removed + those parts that affect interface. Full removal will happen in v6.3, in + order to limit potential regressions. However, it was considered useful + enough to do the interface change in v6-stable; this also eases merging + branches! +- re-licensed larger parts of the codebase under the Apache license 2.0 +- bugfix: omprog made rsyslog abort on startup if not binary to + execute was configured +--------------------------------------------------------------------------- +Version 6.2.0 [v6-stable], 2012-01-09 - bugfix (kind of): removed numerical part from pri-text see v6 compatibility document for reasons - bugfix: race condition when extracting program name, APPNAME, structured data and PROCID (RFC5424 fields) could lead to invalid characters e.g. in dynamic file names or during forwarding (general malfunction of these fields in templates, mostly under heavy load) -- $Begin, $End, $StrictScoping directives have been removed as v6.4 will - provide the same functionality in a far better way. So we do not want - to clutter the code. +- bugfix: imuxsock did no longer ignore message-provided timestamp, if + so configured (the *default*). Lead to no longer sub-second timestamps. + closes: http://bugzilla.adiscon.com/show_bug.cgi?id=281 +- bugfix: omfile returns fatal error code for things that go really wrong + previously, RS_RET_RESUME was returned, which lead to a loop inside the + rule engine as omfile could not really recover. +- bugfix: rsyslogd -v always said 64 atomics were not present + thanks to mono_matsuko for the patch +- bugfix: potential abort after reading invalid X.509 certificate + closes: http://bugzilla.adiscon.com/show_bug.cgi?id=290 + Thanks to Tomas Heinrich for the patch +- enhanced module loader to not rely on PATH_MAX +- imuxsock: added capability to "annotate" messages with "trusted + information", which contains some properties obtained from the system + and as such sure to not be faked. This is inspired by the similiar idea + introduced in systemd. --------------------------------------------------------------------------- Version 6.1.12 [BETA], 2011-09-01 - bugfix/security: off-by-two bug in legacy syslog parser, CVE-2011-3200 diff --git a/configure.ac b/configure.ac index e19e351d..886b9c4e 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.6],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[6.3.7],[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 07de4530..565b3758 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.3.6 (devel branch) of rsyslog. +

              This documentation is for version 6.3.7 (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 793155415708271d94f1238d5294c08ad3831d3a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 31 Jan 2012 17:14:23 +0100 Subject: stats: generate friendly name for action queues, if possible --- action.c | 9 +++++++-- configure.ac | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/action.c b/action.c index f16146c1..e465b826 100644 --- a/action.c +++ b/action.c @@ -348,8 +348,13 @@ actionConstructFinalize(action_t *pThis) CHKiRet(statsobj.ConstructFinalize(pThis->statsobj)); /* create our queue */ - /* find a name for our queue */ - snprintf((char*) pszAName, sizeof(pszAName)/sizeof(uchar), "action %d queue", iActionNbr); + /* find a (friendly) name for our queue */ + if(pThis->pszName == NULL) { + snprintf((char*) pszAName, sizeof(pszAName)/sizeof(uchar), "action %d queue", iActionNbr); + } else { + snprintf((char*) pszAName, sizeof(pszAName)/sizeof(uchar), "%s queue", pThis->pszName); + } + pszAName[63] = '\0'; /* to be on the save side */ /* now check if we can run the action in "firehose mode" during stage one of * its processing (that is before messages are enqueued into the action q). diff --git a/configure.ac b/configure.ac index c6d775af..5bfaf42c 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],[5.8.6-newstats6],[rsyslog@lists.adiscon.com]) +AC_INIT([rsyslog],[5.8.7-newstats7],[rsyslog@lists.adiscon.com]) AM_INIT_AUTOMAKE m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) -- cgit v1.2.3 From 19a80194032b4bbdf6ad98bd00a89528137b4883 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 31 Jan 2012 17:35:41 +0100 Subject: stats: added unique (and friendly) name for ruleset queues --- runtime/ruleset.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/runtime/ruleset.c b/runtime/ruleset.c index 5ee2a55a..69968a52 100644 --- a/runtime/ruleset.c +++ b/runtime/ruleset.c @@ -500,6 +500,7 @@ debugPrintAll(void) static rsRetVal rulesetCreateQueue(void __attribute__((unused)) *pVal, int *pNewVal) { + uchar *rulesetMainQName; DEFiRet; if(pCurrRuleset == NULL) { @@ -518,7 +519,9 @@ rulesetCreateQueue(void __attribute__((unused)) *pVal, int *pNewVal) FINALIZE; /* if it is turned off, we do not need to change anything ;) */ dbgprintf("adding a ruleset-specific \"main\" queue"); - CHKiRet(createMainQueue(&pCurrRuleset->pQueue, UCHAR_CONSTANT("ruleset"))); + rulesetMainQName = (pCurrRuleset->pszName == NULL)? UCHAR_CONSTANT("ruleset") : + pCurrRuleset->pszName; + CHKiRet(createMainQueue(&pCurrRuleset->pQueue, rulesetMainQName)); finalize_it: RETiRet; -- cgit v1.2.3 From 9817f4b59abb8a8b5f0a49e24f7b3bdec4dd9ecb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 1 Feb 2012 15:13:06 +0100 Subject: omgssapi: fix compile errors --- plugins/omgssapi/omgssapi.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/plugins/omgssapi/omgssapi.c b/plugins/omgssapi/omgssapi.c index fcf6c3dd..818a7cfd 100644 --- a/plugins/omgssapi/omgssapi.c +++ b/plugins/omgssapi/omgssapi.c @@ -95,18 +95,12 @@ typedef enum gss_mode_e { GSSMODE_ENC } gss_mode_t; -typedef struct configSettings_s { +static struct configSettings_s { uchar *pszTplName; /* name of the default template to use */ char *gss_base_service_name; gss_mode_t gss_mode; -} configSettings_t; +} cs; -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ - -BEGINinitConfVars /* (re)set config variables to default values */ -CODESTARTinitConfVars - resetConfigVariables(NULL, NULL); -ENDinitConfVars /* get the syslog forward port from selector_t. The passed in * struct must be one that is setup for forwarding. @@ -699,7 +693,6 @@ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __a BEGINmodInit() CODESTARTmodInit -SCOPINGmodInit *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr CHKiRet(objUse(errmsg, CORE_COMPONENT)); -- cgit v1.2.3 From eda1278ece0ea1e5615a9f4d74f029b85eb35fb9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 1 Feb 2012 16:30:07 +0100 Subject: omsnmp: fixing compile problem --- ChangeLog | 2 +- plugins/omsnmp/omsnmp.c | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 737a9e9e..8ab49b93 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 6.3.7 [DEVEL] 2012-01-31 +Version 6.3.7 [DEVEL] 2012-02-01 - imported refactored v5.9.6 imklog linux driver, now combined with BSD driver - bugfix: rsyslog aborted during startup if there is an error in loading diff --git a/plugins/omsnmp/omsnmp.c b/plugins/omsnmp/omsnmp.c index 80230789..30daf963 100644 --- a/plugins/omsnmp/omsnmp.c +++ b/plugins/omsnmp/omsnmp.c @@ -106,8 +106,7 @@ typedef struct configSettings_s { SNMP_TRAP_ENTERPRISESPECIFIC (6) */ } configSettings_t; - -SCOPING_SUPPORT; /* must be set AFTER configSettings_t is defined */ +static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars @@ -512,9 +511,9 @@ ENDqueryEtryPt BEGINmodInit() CODESTARTmodInit -SCOPINGmodInit *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr + initConfVars(); CHKiRet(objUse(errmsg, CORE_COMPONENT)); CHKiRet(omsdRegCFSLineHdlr( (uchar *)"actionsnmptransport", 0, eCmdHdlrGetWord, NULL, &cs.pszTransport, STD_LOADABLE_MODULE_ID)); -- cgit v1.2.3 From ce8e072564da6c3ef16755d8c3df8614895a717e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 1 Feb 2012 17:35:03 +0100 Subject: conf file: bufgix: legacy parsing of some filters did not work correctly --- ChangeLog | 7 ++++--- grammar/lexer.l | 2 +- grammar/rainerscript.c | 1 - runtime/conf.c | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8ab49b93..80bfb620 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,9 +2,6 @@ Version 6.3.7 [DEVEL] 2012-02-01 - imported refactored v5.9.6 imklog linux driver, now combined with BSD driver -- bugfix: rsyslog aborted during startup if there is an error in loading - an action and legacy configuration mode is used -- bugfix: bsd klog driver did no longer compile - removed imtemplate/omtemplate template modules, as this was waste of time The actual input/output modules are better copy templates. Instead, the now-removed modules cost time for maintenance AND often caused confusion @@ -18,6 +15,10 @@ Version 6.3.7 [DEVEL] 2012-02-01 - bugfix: potential abort after reading invalid X.509 certificate closes: http://bugzilla.adiscon.com/show_bug.cgi?id=290 Thanks to Tomas Heinrich for the patch +- bufgix: legacy parsing of some filters did not work correctly +- bugfix: rsyslog aborted during startup if there is an error in loading + an action and legacy configuration mode is used +- bugfix: bsd klog driver did no longer compile - relicensed larger parts of the code under Apache (ASL) 2.0 --------------------------------------------------------------------------- Version 6.3.6 [DEVEL] 2011-09-19 diff --git a/grammar/lexer.l b/grammar/lexer.l index a3f8bedd..e688ffce 100644 --- a/grammar/lexer.l +++ b/grammar/lexer.l @@ -166,7 +166,7 @@ int fileno(FILE *stream); :[a-z0-9]+:[^\n]* | [\|\.\-\@\^?~>][^\n]+ | [a-z0-9_][a-z0-9_\-\+,;]* { yylval.s = strdup(yytext); - // printf("lex: LEGA ACT: '%s'\n", yytext); + dbgprintf("lex: LEGA ACT: '%s'\n", yytext); return LEGACY_ACTION; } ")" { BEGIN INITIAL; return ENDOBJ; } [a-z][a-z0-9_\.]* { yylval.estr = es_newStrFromCStr(yytext, yyleng); diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 22a90cb7..d1d64e6e 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -292,7 +292,6 @@ doGetQueueType(struct nvlst *valnode, struct cnfparamdescr *param, param->name, cstr); free(cstr); } -dbgprintf("XXXXX: queue type: %d\n", (int)val->val.d.n); val->val.datatype = 'N'; } diff --git a/runtime/conf.c b/runtime/conf.c index 37774902..7f6ad61a 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -596,7 +596,7 @@ rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) } /* skip to action part */ - if((iRet = parsSkipWhitespace(pPars, 1)) != RS_RET_OK) { + if((iRet = parsSkipWhitespace(pPars, 0)) != RS_RET_OK) { errmsg.LogError(0, iRet, "error %d skipping to action part - ignoring selector", iRet); rsParsDestruct(pPars); return(iRet); -- cgit v1.2.3 From 6b5321bcdba0b172cb9830c992721737468bc192 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 1 Feb 2012 17:46:47 +0100 Subject: cleanup: remove code for no-longer needed legacy conf functionality --- parse.c | 9 +++------ parse.h | 2 +- runtime/conf.c | 2 +- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/parse.c b/parse.c index 659d49cd..2d89030e 100644 --- a/parse.c +++ b/parse.c @@ -211,7 +211,7 @@ rsRetVal parsSkipAfterChar(rsParsObj *pThis, char c) * If bRequireOne is set to true, at least one whitespace * must exist, else an error is returned. */ -rsRetVal parsSkipWhitespace(rsParsObj *pThis, sbool bRequireOne) +rsRetVal parsSkipWhitespace(rsParsObj *pThis) { register unsigned char *pC; int numSkipped; @@ -230,9 +230,6 @@ rsRetVal parsSkipWhitespace(rsParsObj *pThis, sbool bRequireOne) ++numSkipped; } - if(bRequireOne && numSkipped == 0) - iRet = RS_RET_MISSING_WHITESPACE; - RETiRet; } @@ -261,7 +258,7 @@ rsRetVal parsDelimCStr(rsParsObj *pThis, cstr_t **ppCStr, char cDelim, int bTrim CHKiRet(rsCStrConstruct(&pCStr)); if(bTrimLeading) - parsSkipWhitespace(pThis, 0); + parsSkipWhitespace(pThis); pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; @@ -392,7 +389,7 @@ rsRetVal parsAddrWithBits(rsParsObj *pThis, struct NetAddr **pIP, int *pBits) CHKiRet(cstrConstruct(&pCStr)); - parsSkipWhitespace(pThis, 0); + parsSkipWhitespace(pThis); pC = rsCStrGetBufBeg(pThis->pCStr) + pThis->iCurrPos; /* we parse everything until either '/', ',' or diff --git a/parse.h b/parse.h index 69ae4b87..5121a84c 100644 --- a/parse.h +++ b/parse.h @@ -76,7 +76,7 @@ rsRetVal rsParsAssignString(rsParsObj *pThis, cstr_t *pCStr); rsRetVal parsInt(rsParsObj *pThis, int* pInt); /* Skip whitespace. Often used to trim parsable entries. */ -rsRetVal parsSkipWhitespace(rsParsObj *pThis, sbool bRequireOne); +rsRetVal parsSkipWhitespace(rsParsObj *pThis); /* Parse string up to a delimiter. * diff --git a/runtime/conf.c b/runtime/conf.c index 7f6ad61a..eec04df8 100644 --- a/runtime/conf.c +++ b/runtime/conf.c @@ -596,7 +596,7 @@ rsRetVal cflineProcessPropFilter(uchar **pline, register rule_t *f) } /* skip to action part */ - if((iRet = parsSkipWhitespace(pPars, 0)) != RS_RET_OK) { + if((iRet = parsSkipWhitespace(pPars)) != RS_RET_OK) { errmsg.LogError(0, iRet, "error %d skipping to action part - ignoring selector", iRet); rsParsDestruct(pPars); return(iRet); -- cgit v1.2.3 From 312b13ca0c69212273d92483ab878d192f6e4ed8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 2 Feb 2012 14:07:33 +0100 Subject: nit: release date for 6.3.7 --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 80bfb620..9e42b1ff 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ --------------------------------------------------------------------------- -Version 6.3.7 [DEVEL] 2012-02-01 +Version 6.3.7 [DEVEL] 2012-02-02 - imported refactored v5.9.6 imklog linux driver, now combined with BSD driver - removed imtemplate/omtemplate template modules, as this was waste of time -- cgit v1.2.3 From 03cf2a5113e130e4f64b048dc4dc6d2c0aa1b3b2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 2 Feb 2012 16:25:59 +0100 Subject: ommysql: added support for v6 config format --- plugins/ommysql/ommysql.c | 98 ++++++++++++++++++++++++++++++++++ tests/mysql-basic-cnf6.sh | 13 +++++ tests/testsuites/mysql-basic-cnf6.conf | 7 +++ 3 files changed, 118 insertions(+) create mode 100644 tests/mysql-basic-cnf6.sh create mode 100644 tests/testsuites/mysql-basic-cnf6.conf diff --git a/plugins/ommysql/ommysql.c b/plugins/ommysql/ommysql.c index 50ebf3a3..c5df404a 100644 --- a/plugins/ommysql/ommysql.c +++ b/plugins/ommysql/ommysql.c @@ -66,6 +66,7 @@ typedef struct _instanceData { unsigned uLastMySQLErrno; /* last errno returned by MySQL or 0 if all is well */ uchar * f_configfile; /* MySQL Client Configuration File */ uchar * f_configsection; /* MySQL Client Configuration Section */ + uchar *tplName; /* format template to use */ } instanceData; typedef struct configSettings_s { @@ -75,6 +76,25 @@ typedef struct configSettings_s { } configSettings_t; static configSettings_t cs; +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "server", eCmdHdlrGetWord, 1 }, + { "db", eCmdHdlrGetWord, 1 }, + { "uid", eCmdHdlrGetWord, 1 }, + { "pwd", eCmdHdlrGetWord, 1 }, + { "serverport", eCmdHdlrInt, 0 }, + { "mysqlconfig.file", eCmdHdlrGetWord, 0 }, + { "mysqlconfig.section", eCmdHdlrGetWord, 0 }, + { "template", eCmdHdlrGetWord, 0 } +}; +static struct cnfparamblk actpblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + + BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars resetConfigVariables(NULL, NULL); @@ -118,6 +138,9 @@ static void closeMySQL(instanceData *pData) BEGINfreeInstance CODESTARTfreeInstance + free(pData->f_configfile); + free(pData->f_configsection); + free(pData->tplName); closeMySQL(pData); ENDfreeInstance @@ -259,6 +282,80 @@ CODESTARTdoAction ENDdoAction +static inline void +setInstParamDefaults(instanceData *pData) +{ + pData->f_dbsrvPort = 0; + pData->f_configfile = NULL; + pData->f_configsection = NULL; + pData->tplName = NULL; + pData->f_hmysql = NULL; /* initialize, but connect only on first message (important for queued mode!) */ +} + + +/* note: we use the fixed-size buffers inside the config object to avoid + * changing too much of the previous plumbing. rgerhards, 2012-02-02 + */ +BEGINnewActInst + struct cnfparamvals *pvals; + int i; + char *cstr; +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, "server")) { + cstr = es_str2cstr(pvals[i].val.d.estr, NULL); + strncpy(pData->f_dbsrv, cstr, sizeof(pData->f_dbsrv)); + free(cstr); + } else if(!strcmp(actpblk.descr[i].name, "serverport")) { + pData->f_dbsrvPort = (int) pvals[i].val.d.n, NULL; + } else if(!strcmp(actpblk.descr[i].name, "db")) { + cstr = es_str2cstr(pvals[i].val.d.estr, NULL); + strncpy(pData->f_dbname, cstr, sizeof(pData->f_dbname)); + free(cstr); + } else if(!strcmp(actpblk.descr[i].name, "uid")) { + cstr = es_str2cstr(pvals[i].val.d.estr, NULL); + strncpy(pData->f_dbuid, cstr, sizeof(pData->f_dbuid)); + free(cstr); + } else if(!strcmp(actpblk.descr[i].name, "pwd")) { + cstr = es_str2cstr(pvals[i].val.d.estr, NULL); + strncpy(pData->f_dbpwd, cstr, sizeof(pData->f_dbpwd)); + free(cstr); + } else if(!strcmp(actpblk.descr[i].name, "mysqlconfig.file")) { + pData->f_configfile = (uchar*)es_str2cstr(pvals[i].val.d.estr, NULL); + } else if(!strcmp(actpblk.descr[i].name, "mysqlconfig.section")) { + pData->f_configsection = (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 { + dbgprintf("ommysql: program error, non-handled " + "param '%s'\n", actpblk.descr[i].name); + } + } + + if(pData->tplName == NULL) { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, (uchar*) strdup(" StdDBFmt"), + OMSR_RQD_TPL_OPT_SQL)); + } else { + CHKiRet(OMSRsetEntry(*ppOMSR, 0, + (uchar*) strdup((char*) pData->tplName), + OMSR_RQD_TPL_OPT_SQL)); + } +CODE_STD_FINALIZERnewActInst +dbgprintf("XXXX: added param, iRet %d\n", iRet); + cnfparamvalsDestruct(pvals, &actpblk); +ENDnewActInst + + BEGINparseSelectorAct int iMySQLPropErr = 0; CODESTARTparseSelectorAct @@ -337,6 +434,7 @@ ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES +CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES ENDqueryEtryPt diff --git a/tests/mysql-basic-cnf6.sh b/tests/mysql-basic-cnf6.sh new file mode 100644 index 00000000..8990ba35 --- /dev/null +++ b/tests/mysql-basic-cnf6.sh @@ -0,0 +1,13 @@ +# This file is part of the rsyslog project, released under GPLv3 +echo =============================================================================== +echo \[mysql-basic.sh\]: basic test for mysql-basic functionality +source $srcdir/diag.sh init +mysql --user=rsyslog --password=testbench < testsuites/mysql-truncate.sql +source $srcdir/diag.sh startup mysql-basic-cnf6.conf +source $srcdir/diag.sh injectmsg 0 5000 +source $srcdir/diag.sh shutdown-when-empty +source $srcdir/diag.sh wait-shutdown +# note "-s" is requried to suppress the select "field header" +mysql -s --user=rsyslog --password=testbench < testsuites/mysql-select-msg.sql > rsyslog.out.log +source $srcdir/diag.sh seq-check 0 4999 +source $srcdir/diag.sh exit diff --git a/tests/testsuites/mysql-basic-cnf6.conf b/tests/testsuites/mysql-basic-cnf6.conf new file mode 100644 index 00000000..bc95dc4f --- /dev/null +++ b/tests/testsuites/mysql-basic-cnf6.conf @@ -0,0 +1,7 @@ +$IncludeConfig diag-common.conf + +$ModLoad ../plugins/ommysql/.libs/ommysql +:msg, contains, "msgnum:" action(type="ommysql" + server="127.0.0.1" + db="Syslog + uid="rsyslog" pwd="testbench") -- cgit v1.2.3 From 5494790ece676ca0a07c0a62cb457338ec4cec90 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 2 Feb 2012 16:47:19 +0100 Subject: bugfix: abort during startup when rsyslog.conf v6+ format was used in a certain way --- ChangeLog | 4 ++++ action.c | 4 ++-- tests/Makefile.am | 3 +++ tests/mysql-basic-cnf6.sh | 0 tests/testsuites/mysql-basic-cnf6.conf | 8 ++++---- 5 files changed, 13 insertions(+), 6 deletions(-) mode change 100644 => 100755 tests/mysql-basic-cnf6.sh diff --git a/ChangeLog b/ChangeLog index 9e42b1ff..2a38431b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,8 @@ --------------------------------------------------------------------------- +Version 6.3.8 [DEVEL] 2012-02-?? +- bugfix: abort during startup when rsyslog.conf v6+ format was used in + a certain way +--------------------------------------------------------------------------- Version 6.3.7 [DEVEL] 2012-02-02 - imported refactored v5.9.6 imklog linux driver, now combined with BSD driver diff --git a/action.c b/action.c index b4b03ea1..0b0f27c3 100644 --- a/action.c +++ b/action.c @@ -1815,10 +1815,11 @@ doSubmitToActionQComplexBatch(action_t *pAction, batch_t *pBatch) * Defaults must have been set appropriately during action construct! * rgerhards, 2011-08-01 */ -rsRetVal +static rsRetVal actionApplyCnfParam(action_t *pAction, struct cnfparamvals *pvals) { int i; + for(i = 0 ; i < pblk.nParams ; ++i) { if(!pvals[i].bUsed) continue; @@ -1847,7 +1848,6 @@ actionApplyCnfParam(action_t *pAction, struct cnfparamvals *pvals) "param '%s'\n", pblk.descr[i].name); } } - cnfparamvalsDestruct(pvals, &pblk); return RS_RET_OK; } diff --git a/tests/Makefile.am b/tests/Makefile.am index 9893afab..50ce2e0b 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -82,6 +82,7 @@ endif if ENABLE_MYSQL_TESTS TESTS += \ mysql-basic.sh \ + mysql-basic-cnf6.sh \ mysql-asyn.sh if ENABLE_OMLIBDBI TESTS += \ @@ -457,8 +458,10 @@ EXTRA_DIST= 1.rstest 2.rstest 3.rstest err1.rstest \ libdbi-asyn.sh \ testsuites/libdbi-asyn.conf \ mysql-basic.sh \ + mysql-basic-cnf6.sh \ mysql-basic-vg.sh \ testsuites/mysql-basic.conf \ + testsuites/mysql-basic-cnf6.conf \ mysql-asyn.sh \ mysql-asyn-vg.sh \ testsuites/mysql-asyn.conf \ diff --git a/tests/mysql-basic-cnf6.sh b/tests/mysql-basic-cnf6.sh old mode 100644 new mode 100755 diff --git a/tests/testsuites/mysql-basic-cnf6.conf b/tests/testsuites/mysql-basic-cnf6.conf index bc95dc4f..12bd0b29 100644 --- a/tests/testsuites/mysql-basic-cnf6.conf +++ b/tests/testsuites/mysql-basic-cnf6.conf @@ -1,7 +1,7 @@ $IncludeConfig diag-common.conf $ModLoad ../plugins/ommysql/.libs/ommysql -:msg, contains, "msgnum:" action(type="ommysql" - server="127.0.0.1" - db="Syslog - uid="rsyslog" pwd="testbench") +if $msg contains 'msgnum' then { + action(type="ommysql" server="127.0.0.1" + db="Syslog" uid="rsyslog" pwd="testbench") +} -- cgit v1.2.3 From b467b44dae691c14cd2ddbaf90467e75063a237b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 2 Feb 2012 17:14:01 +0100 Subject: ommysql: updated doc --- doc/ommysql.html | 46 ++++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/doc/ommysql.html b/doc/ommysql.html index daef9cab..7769fb86 100644 --- a/doc/ommysql.html +++ b/doc/ommysql.html @@ -15,28 +15,37 @@

              This module provides native support for logging to MySQL databases. It offers superior performance over the more generic omlibdbi module.

              -

              Configuration Directives:

              -

              ommysql mostly uses the "old style" configuration, with almost everything on the -action line itself. A few newer features are being migrated to the new style-config -directive configuration system. +

              Action Parameters:

                -
              • $ActionOmmysqlServerPort <port>
                Permits to select +
              • server
                Name or address of the MySQL server +
              • serverport
                Permits to select a non-standard port for the MySQL server. The default is 0, which means the -system default port is used. There is no need to specify this directive unless +system default port is used. There is no need to specify this parameter unless you know the server is running on a non-standard listen port. -
              • $OmMySQLConfigFile <file name>
                Permits the selection +
              • db
                Database to use +
              • uid
                logon userid used to connect to server. Must have proper permissions. +
              • pwd
                the user's password +
              • template
                Template to use when submitting messages. +
              • mysqlconfig.file
                Permits the selection of an optional MySQL Client Library configuration file (my.cnf) for extended configuration functionality. The use of this configuration directive is necessary only if you have a non-standard environment or if fine-grained control over the database connection is desired.
              • -
              • $OmMySQLConfigSection <string>
                Permits the selection of the -section within the configuration file specified by the $OmMySQLConfigFile directive. +
              • mysqlconfig.section
                Permits the selection of the +section within the configuration file specified by the myselconfig.file parameter.
                This will likely only be used where the database administrator provides a single configuration file with multiple profiles. -
                This configuration directive is ignored unless $OmMySQLConfigFile is also used -in the rsyslog configration file. +
                This configuration parameter is ignored unless mysqlconfig.file is also used.
                If omitted, the MySQL Client Library default of "client" will be used.
              • -
              • Action parameters: +
              +

              Legacy (pre-v6) Configuration Directives:

              +

              ommysql mostly uses the "very old style" (v0) configuration, with almost everything on the +action line itself. +

                +
              • $ActionOmmysqlServerPort <port> - like the "serverport" action parameter. +
              • $OmMySQLConfigFile <file name> - like the "mysqlconfig.file" action parameter. +
              • $OmMySQLConfigSection <string> - like the "mysqlconfig.file" action parameter. +
              • Action line:
                :ommysql:database-server,database-name,database-userid,database-password
                All parameters should be filled in for a successful connect.
              @@ -57,15 +66,20 @@ database "syslog_db" on mysqlsever.example.com. The server is being accessed under the account of "user" with password "pwd".

              +

              Legacy Sample:

              +

              The same as above, but in legacy config format (pre rsyslog-v6): +

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

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

              +Released under the ASL 2.0.

              -- cgit v1.2.3 From 8b7924fb8a3fa24cefc573b7372514d26a684b2d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 2 Feb 2012 17:51:08 +0100 Subject: upgraded omlibdbi to support the new v6 config format --- ChangeLog | 3 ++ doc/omlibdbi.html | 56 ++++++++++++++++++------------ plugins/omlibdbi/omlibdbi.c | 84 +++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 119 insertions(+), 24 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2a38431b..f5ac54a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ --------------------------------------------------------------------------- Version 6.3.8 [DEVEL] 2012-02-?? +- upgraded more plugins to support the new v6 config format: + - ommysql + - omlibdbi - bugfix: abort during startup when rsyslog.conf v6+ format was used in a certain way --------------------------------------------------------------------------- diff --git a/doc/omlibdbi.html b/doc/omlibdbi.html index ec1d01b6..008dcb81 100644 --- a/doc/omlibdbi.html +++ b/doc/omlibdbi.html @@ -54,32 +54,38 @@ dlopen()ed plugin (as omlibdbi is). So in short, you probably save you a lot of headache if you make sure you have at least libdbi version 0.8.3 on your system.

              -

              Configuration Directives:

              +

              Action Parameters:

                -
              • $ActionLibdbiDriverDirectory /path/to/dbd/drivers
                This -is a global setting. It points libdbi to its driver directory. Usually, -you do not need to set it. If you installed libdbi-driver's at a -non-standard location, you may need to specify the directory here. If -you are unsure, do not use this configuration directive. Usually, everything works just fine.
              • $ActionLibdbiDriver drivername
                +
              • server
                Name or address of the MySQL server +
              • db
                Database to use +
              • uid
                logon userid used to connect to server. Must have proper permissions. +
              • pwd
                the user's password +
              • template
                Template to use when submitting messages. +
              • driver
                Name of the dbidriver to use, see libdbi-drivers documentation. As a quick excerpt, at least those were available at the time of this writiting "mysql" (suggest to use ommysql instead), "firebird" (Firbird and InterBase), "ingres", "msql", "Oracle", "sqlite", "sqlite3", "freetds" (for Microsoft SQL and Sybase) and "pgsql" (suggest to use ompgsql instead).
              • -
              • $ActionLibdbiHost -hostname
                +
              • driverdirectory
                +Path to the libdbi drivers. Usually, +you do not need to set it. If you installed libdbi-drivers at a +non-standard location, you may need to specify the directory here. If +you are unsure, do not use this configuration directive. +Usually, everything works just fine.
              • +
              +

              Legacy (pre-v6) Configuration Directives:

              +
                +
              • $ActionLibdbiDriverDirectory /path/to/dbd/drivers +- like the driverdirectory action parameter. +
              • $ActionLibdbiDriver drivername
                - like the drivername action parameter. +
              • $ActionLibdbiHost hostname - like the server action parameter The host to connect to.
              • -
              • $ActionLibdbiUserName -user
                -The user used to connect to the database.
              • -
              • $ActionlibdbiPassword
                -That user's password.
              • -
              • $ActionlibdbiDBName -db
                -The database that shall be written to.
              • -
              • selector -line: :omlibdbi:;template
                +
              • $ActionLibdbiUserName user - like the uid action parameter +
              • $ActionlibdbiPassword - like the pwd action parameter +
              • $ActionlibdbiDBName db - like the db action parameter +
              • selector line: :omlibdbi:;template
                executes the recently configured omlibdbi action. The ;template part is optional. If no template is provided, a default template is used (which is currently optimized for MySQL - sorry, folks...)
              • @@ -108,7 +114,14 @@ database "syslog_db" on mysqlsever.example.com. The server is MySQL and being accessed under the account of "user" with password "pwd" (if you have empty passwords, just remove the $ActionLibdbiPassword line).

                - +

                Sample:

                +

                The same as above, but in legacy config format (pre rsyslog-v6): +