summaryrefslogtreecommitdiffstats
path: root/runtime/rsconf.c
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/rsconf.c')
-rw-r--r--runtime/rsconf.c1601
1 files changed, 1601 insertions, 0 deletions
diff --git a/runtime/rsconf.c b/runtime/rsconf.c
new file mode 100644
index 0000000..27047a5
--- /dev/null
+++ b/runtime/rsconf.c
@@ -0,0 +1,1601 @@
+/* rsconf.c - the rsyslog configuration system.
+ *
+ * Module begun 2011-04-19 by Rainer Gerhards
+ *
+ * Copyright 2011-2023 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 <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+#include <stdarg.h>
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#include "rsyslog.h"
+#include "obj.h"
+#include "srUtils.h"
+#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"
+#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"
+#include "outchannel.h"
+#include "threads.h"
+#include "datetime.h"
+#include "parserif.h"
+#include "modules.h"
+#include "dirty.h"
+#include "template.h"
+#include "timezones.h"
+
+extern char* yytext;
+/* static data */
+DEFobjStaticHelpers
+DEFobjCurrIf(ruleset)
+DEFobjCurrIf(module)
+DEFobjCurrIf(conf)
+DEFobjCurrIf(glbl)
+DEFobjCurrIf(parser)
+DEFobjCurrIf(datetime)
+
+/* 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$.:%$.%\n$/:%$/%\n\n\"";
+static uchar template_SyslogProtocol23Format[] = "\"<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME% %APP-NAME% "
+"%PROCID% %MSGID% %STRUCTURED-DATA% %msg%\n\"";
+static uchar template_SyslogRFC5424Format[] = "\"<%PRI%>1 %TIMESTAMP:::date-rfc3339% %HOSTNAME% %APP-NAME% "
+"%PROCID% %MSGID% %STRUCTURED-DATA% %msg%\"";
+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%\"";
+static uchar template_SysklogdFileFormat[] = "\"%TIMESTAMP% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg%\n\"";
+static uchar template_StdJSONFmt[] = "\"{\\\"message\\\":\\\"%msg:::json%\\\",\\\"fromhost\\\":\\\""
+"%HOSTNAME:::json%\\\",\\\"facility\\\":\\\"%syslogfacility-text%\\\",\\\"priority\\\":\\\""
+"%syslogpriority-text%\\\",\\\"timereported\\\":\\\"%timereported:::date-rfc3339%\\\",\\\"timegenerated\\\":\\\""
+"%timegenerated:::date-rfc3339%\\\"}\"";
+static uchar template_FullJSONFmt[] = "\"{\\\"message\\\":\\\"%msg:::json%\\\","
+"\\\"fromhost\\\":\\\"%HOSTNAME:::json%\\\","
+"\\\"programname\\\":\\\"%programname%\\\","
+"\\\"procid\\\":\\\"%PROCID%\\\","
+"\\\"msgid\\\":\\\"%MSGID%\\\","
+"\\\"facility\\\":\\\"%syslogfacility-text%\\\","
+"\\\"priority\\\":\\\"%syslogpriority-text%\\\","
+"\\\"timereported\\\":\\\"%timereported:::date-rfc3339%\\\","
+"\\\"timegenerated\\\":\\\"%timegenerated:::date-rfc3339%\\\"}\"";
+static uchar template_StdClickHouseFmt[] = "\"INSERT INTO rsyslog.SystemEvents (severity, facility, "
+"timestamp, hostname, tag, message) VALUES (%syslogseverity%, %syslogfacility%, "
+"'%timereported:::date-unixtimestamp%', '%hostname%', '%syslogtag%', '%msg%')\",STDSQL";
+/* end templates */
+
+/* tables for interfacing with the v6 config system (as far as we need to) */
+static struct cnfparamdescr inppdescr[] = {
+ { "type", eCmdHdlrString, CNFPARAM_REQUIRED }
+};
+static struct cnfparamblk inppblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(inppdescr)/sizeof(struct cnfparamdescr),
+ inppdescr
+ };
+
+static struct cnfparamdescr parserpdescr[] = {
+ { "type", eCmdHdlrString, CNFPARAM_REQUIRED },
+ { "name", eCmdHdlrString, CNFPARAM_REQUIRED }
+};
+static struct cnfparamblk parserpblk =
+ { CNFPARAMBLK_VERSION,
+ sizeof(parserpdescr)/sizeof(struct cnfparamdescr),
+ parserpdescr
+ };
+
+/* forward-definitions */
+void cnfDoCfsysline(char *ln);
+
+int rsconfNeedDropPriv(rsconf_t *const cnf)
+{
+ return ((cnf->globals.gidDropPriv != 0) || (cnf->globals.uidDropPriv != 0));
+}
+
+static void cnfSetDefaults(rsconf_t *pThis)
+{
+#ifdef ENABLE_LIBCAPNG
+ pThis->globals.bAbortOnFailedLibcapngSetup = 1;
+ pThis->globals.bCapabilityDropEnabled = 1;
+#endif
+ pThis->globals.bAbortOnUncleanConfig = 0;
+ pThis->globals.bAbortOnFailedQueueStartup = 0;
+ pThis->globals.bReduceRepeatMsgs = 0;
+ pThis->globals.bDebugPrintTemplateList = 1;
+ pThis->globals.bDebugPrintModuleList = 0;
+ pThis->globals.bDebugPrintCfSysLineHandlerList = 0;
+ pThis->globals.bLogStatusMsgs = DFLT_bLogStatusMsgs;
+ pThis->globals.bErrMsgToStderr = 1;
+ pThis->globals.maxErrMsgToStderr = -1;
+ pThis->globals.umask = -1;
+ pThis->globals.gidDropPrivKeepSupplemental = 0;
+ pThis->globals.abortOnIDResolutionFail = 1;
+ pThis->templates.root = NULL;
+ pThis->templates.last = NULL;
+ pThis->templates.lastStatic = NULL;
+ pThis->actions.nbrActions = 0;
+ pThis->actions.iActionNbr = 0;
+ pThis->globals.pszWorkDir = NULL;
+ pThis->globals.bDropMalPTRMsgs = 0;
+ pThis->globals.operatingStateFile = NULL;
+ pThis->globals.iGnuTLSLoglevel = 0;
+ pThis->globals.debugOnShutdown = 0;
+ pThis->globals.pszDfltNetstrmDrvrCAF = NULL;
+ pThis->globals.pszDfltNetstrmDrvrCRLF = NULL;
+ pThis->globals.pszDfltNetstrmDrvrCertFile = NULL;
+ pThis->globals.pszDfltNetstrmDrvrKeyFile = NULL;
+ pThis->globals.pszDfltNetstrmDrvr = NULL;
+ pThis->globals.oversizeMsgErrorFile = NULL;
+ pThis->globals.reportOversizeMsg = 1;
+ pThis->globals.oversizeMsgInputMode = 0;
+ pThis->globals.reportChildProcessExits = REPORT_CHILD_PROCESS_EXITS_ERRORS;
+ pThis->globals.bActionReportSuspension = 1;
+ pThis->globals.bActionReportSuspensionCont = 0;
+ pThis->globals.janitorInterval = 10;
+ pThis->globals.reportNewSenders = 0;
+ pThis->globals.reportGoneAwaySenders = 0;
+ pThis->globals.senderStatsTimeout = 12 * 60 * 60; /* 12 hr timeout for senders */
+ pThis->globals.senderKeepTrack = 0;
+ pThis->globals.inputTimeoutShutdown = 1000;
+ pThis->globals.iDefPFFamily = PF_UNSPEC;
+ pThis->globals.ACLAddHostnameOnFail = 0;
+ pThis->globals.ACLDontResolve = 0;
+ pThis->globals.bDisableDNS = 0;
+ pThis->globals.bProcessInternalMessages = 0;
+ const char *const log_dflt = getenv("RSYSLOG_DFLT_LOG_INTERNAL");
+ if(log_dflt != NULL && !strcmp(log_dflt, "1"))
+ pThis->globals.bProcessInternalMessages = 1;
+ pThis->globals.glblDevOptions = 0;
+ pThis->globals.intMsgRateLimitItv = 5;
+ pThis->globals.intMsgRateLimitBurst = 500;
+ pThis->globals.intMsgsSeverityFilter = DFLT_INT_MSGS_SEV_FILTER;
+ pThis->globals.permitCtlC = glblPermitCtlC;
+
+ pThis->globals.actq_dflt_toQShutdown = 10;
+ pThis->globals.actq_dflt_toActShutdown = 1000;
+ pThis->globals.actq_dflt_toEnq = 2000;
+ pThis->globals.actq_dflt_toWrkShutdown = 60000;
+
+ pThis->globals.ruleset_dflt_toQShutdown = 1500;
+ pThis->globals.ruleset_dflt_toActShutdown = 1000;
+ pThis->globals.ruleset_dflt_toEnq = 2000;
+ pThis->globals.ruleset_dflt_toWrkShutdown = 60000;
+
+ pThis->globals.dnscacheDefaultTTL = 24 * 60 * 60;
+ pThis->globals.dnscacheEnableTTL = 0;
+ pThis->globals.shutdownQueueDoubleSize = 0;
+ pThis->globals.optionDisallowWarning = 1;
+ pThis->globals.bSupportCompressionExtension = 1;
+ #ifdef ENABLE_LIBLOGGING_STDLOG
+ pThis->globals.stdlog_hdl = stdlog_open("rsyslogd", 0, STDLOG_SYSLOG, NULL);
+ pThis->globals.stdlog_chanspec = NULL;
+ #endif
+ pThis->globals.iMaxLine = 8096;
+
+ /* timezone specific*/
+ pThis->timezones.tzinfos = NULL;
+ pThis->timezones.ntzinfos = 0;
+
+ /* queue params */
+ pThis->globals.mainQ.iMainMsgQueueSize = 100000;
+ pThis->globals.mainQ.iMainMsgQHighWtrMark = 80000;
+ pThis->globals.mainQ.iMainMsgQLowWtrMark = 20000;
+ pThis->globals.mainQ.iMainMsgQDiscardMark = 98000;
+ pThis->globals.mainQ.iMainMsgQDiscardSeverity = 8;
+ pThis->globals.mainQ.iMainMsgQueueNumWorkers = 2;
+ 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 = 40000;
+ pThis->globals.mainQ.iMainMsgQDeqSlowdown = 0;
+ pThis->globals.mainQ.iMainMsgQueMaxDiskSpace = 0;
+ pThis->globals.mainQ.iMainMsgQueDeqBatchSize = 256;
+ pThis->globals.mainQ.bMainMsgQSaveOnShutdown = 1;
+ pThis->globals.mainQ.iMainMsgQueueDeqtWinFromHr = 0;
+ pThis->globals.mainQ.iMainMsgQueueDeqtWinToHr = 25;
+ pThis->pMsgQueue = NULL;
+
+ pThis->globals.parser.cCCEscapeChar = '#';
+ pThis->globals.parser.bDropTrailingLF = 1;
+ pThis->globals.parser.bEscapeCCOnRcv = 1;
+ pThis->globals.parser.bSpaceLFOnRcv = 0;
+ pThis->globals.parser.bEscape8BitChars = 0;
+ pThis->globals.parser.bEscapeTab = 1;
+ pThis->globals.parser.bParserEscapeCCCStyle = 0;
+ pThis->globals.parser.bPermitSlashInProgramname = 0;
+ pThis->globals.parser.bParseHOSTNAMEandTAG = 1;
+
+ pThis->parsers.pDfltParsLst = NULL;
+ pThis->parsers.pParsLstRoot = NULL;
+}
+
+
+/* Standard-Constructor
+ */
+BEGINobjConstruct(rsconf) /* be sure to specify the object type also in END macro! */
+ cnfSetDefaults(pThis);
+ lookupInitCnf(&pThis->lu_tabs);
+ CHKiRet(dynstats_initCnf(&pThis->dynstats_buckets));
+ CHKiRet(perctile_initCnf(&pThis->perctile_buckets));
+ CHKiRet(llInit(&pThis->rulesets.llRulesets, rulesetDestructForLinkedList,
+ rulesetKeyDestruct, strcasecmp));
+finalize_it:
+ENDobjConstruct(rsconf)
+
+
+/* ConstructionFinalizer
+ */
+static rsRetVal
+rsconfConstructFinalize(rsconf_t __attribute__((unused)) *pThis)
+{
+ DEFiRet;
+ ISOBJ_TYPE_assert(pThis, rsconf);
+ RETiRet;
+}
+
+
+/* call freeCnf() module entry points AND free the module entries themselfes.
+ */
+static void
+freeCnf(rsconf_t *pThis)
+{
+ cfgmodules_etry_t *etry, *del;
+ etry = pThis->modules.root;
+ while(etry != NULL) {
+ if(etry->pMod->beginCnfLoad != NULL) {
+ dbgprintf("calling freeCnf(%p) for module '%s'\n",
+ etry->modCnf, (char*) module.GetName(etry->pMod));
+ etry->pMod->freeCnf(etry->modCnf);
+ }
+ del = etry;
+ etry = etry->next;
+ free(del);
+ }
+}
+
+/* destructor for the rsconf object */
+PROTOTYPEobjDestruct(rsconf);
+BEGINobjDestruct(rsconf) /* be sure to specify the object type also in END and CODESTART macros! */
+CODESTARTobjDestruct(rsconf)
+ freeCnf(pThis);
+ tplDeleteAll(pThis);
+ dynstats_destroyAllBuckets();
+ perctileBucketsDestruct();
+ ochDeleteAll();
+ freeTimezones(pThis);
+ parser.DestructParserList(&pThis->parsers.pDfltParsLst);
+ parser.destroyMasterParserList(pThis->parsers.pParsLstRoot);
+ free(pThis->globals.mainQ.pszMainMsgQFName);
+ free(pThis->globals.pszConfDAGFile);
+ free(pThis->globals.pszWorkDir);
+ free(pThis->globals.operatingStateFile);
+ free(pThis->globals.pszDfltNetstrmDrvrCAF);
+ free(pThis->globals.pszDfltNetstrmDrvrCRLF);
+ free(pThis->globals.pszDfltNetstrmDrvrCertFile);
+ free(pThis->globals.pszDfltNetstrmDrvrKeyFile);
+ free(pThis->globals.pszDfltNetstrmDrvr);
+ free(pThis->globals.oversizeMsgErrorFile);
+ #ifdef ENABLE_LIBLOGGING_STDLOG
+ stdlog_close(pThis->globals.stdlog_hdl);
+ free(pThis->globals.stdlog_chanspec);
+ #endif
+ lookupDestroyCnf();
+ llDestroy(&(pThis->rulesets.llRulesets));
+ENDobjDestruct(rsconf)
+
+
+/* DebugPrint support for the rsconf object */
+PROTOTYPEObjDebugPrint(rsconf);
+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",
+ 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);
+ dbgprintf(" drop Msgs with malicious PTR Record : %d\n",
+ glbl.GetDropMalPTRMsgs(pThis));
+ ruleset.DebugPrintAll(pThis);
+ dbgprintf("\n");
+ if(pThis->globals.bDebugPrintTemplateList)
+ tplPrintList(pThis);
+ if(pThis->globals.bDebugPrintModuleList)
+ 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(pThis));
+ ochPrintList(pThis);
+ 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)
+
+
+static rsRetVal
+parserProcessCnf(struct cnfobj *o)
+{
+ struct cnfparamvals *pvals;
+ modInfo_t *pMod;
+ uchar *cnfModName = NULL;
+ uchar *parserName = NULL;
+ int paramIdx;
+ void *parserInst;
+ parser_t *myparser;
+ DEFiRet;
+
+ pvals = nvlstGetParams(o->nvlst, &parserpblk, NULL);
+ if(pvals == NULL) {
+ ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
+ }
+ DBGPRINTF("input param blk after parserProcessCnf:\n");
+ cnfparamsPrint(&parserpblk, pvals);
+ paramIdx = cnfparamGetIdx(&parserpblk, "name");
+ parserName = (uchar*)es_str2cstr(pvals[paramIdx].val.d.estr, NULL);
+ if(parser.FindParser(loadConf->parsers.pParsLstRoot, &myparser, parserName) != RS_RET_PARSER_NOT_FOUND) {
+ LogError(0, RS_RET_PARSER_NAME_EXISTS,
+ "parser module name '%s' already exists", parserName);
+ ABORT_FINALIZE(RS_RET_PARSER_NAME_EXISTS);
+ }
+
+ paramIdx = cnfparamGetIdx(&parserpblk, "type");
+ cnfModName = (uchar*)es_str2cstr(pvals[paramIdx].val.d.estr, NULL);
+ if((pMod = module.FindWithCnfName(loadConf, cnfModName, eMOD_PARSER)) == NULL) {
+ LogError(0, RS_RET_MOD_UNKNOWN, "parser module name '%s' is unknown", cnfModName);
+ ABORT_FINALIZE(RS_RET_MOD_UNKNOWN);
+ }
+ if(pMod->mod.pm.newParserInst == NULL) {
+ LogError(0, RS_RET_MOD_NO_PARSER_STMT,
+ "parser module '%s' does not support parser() statement", cnfModName);
+ ABORT_FINALIZE(RS_RET_MOD_NO_INPUT_STMT);
+ }
+ CHKiRet(pMod->mod.pm.newParserInst(o->nvlst, &parserInst));
+
+ /* all well, so let's (try) to add parser to config */
+ CHKiRet(parserConstructViaModAndName(pMod, parserName, parserInst));
+finalize_it:
+ free(cnfModName);
+ free(parserName);
+ cnfparamvalsDestruct(pvals, &parserpblk);
+ RETiRet;
+}
+
+
+/* Process input() objects */
+static rsRetVal
+inputProcessCnf(struct cnfobj *o)
+{
+ struct cnfparamvals *pvals;
+ modInfo_t *pMod;
+ uchar *cnfModName = NULL;
+ int typeIdx;
+ DEFiRet;
+
+ pvals = nvlstGetParams(o->nvlst, &inppblk, NULL);
+ if(pvals == NULL) {
+ ABORT_FINALIZE(RS_RET_CONFIG_ERROR);
+ }
+ DBGPRINTF("input param blk after inputProcessCnf:\n");
+ cnfparamsPrint(&inppblk, pvals);
+ typeIdx = cnfparamGetIdx(&inppblk, "type");
+ cnfModName = (uchar*)es_str2cstr(pvals[typeIdx].val.d.estr, NULL);
+ if((pMod = module.FindWithCnfName(loadConf, cnfModName, eMOD_IN)) == NULL) {
+ LogError(0, RS_RET_MOD_UNKNOWN, "input module name '%s' is unknown", cnfModName);
+ ABORT_FINALIZE(RS_RET_MOD_UNKNOWN);
+ }
+ if(pMod->mod.im.newInpInst == NULL) {
+ LogError(0, RS_RET_MOD_NO_INPUT_STMT,
+ "input module '%s' does not support input() statement", cnfModName);
+ ABORT_FINALIZE(RS_RET_MOD_NO_INPUT_STMT);
+ }
+ iRet = pMod->mod.im.newInpInst(o->nvlst);
+finalize_it:
+ free(cnfModName);
+ cnfparamvalsDestruct(pvals, &inppblk);
+ RETiRet;
+}
+
+/*------------------------------ interface to flex/bison parser ------------------------------*/
+extern int yylineno;
+
+void
+parser_warnmsg(const char *fmt, ...)
+{
+ va_list ap;
+ char errBuf[1024];
+
+ va_start(ap, fmt);
+ if(vsnprintf(errBuf, sizeof(errBuf), fmt, ap) == sizeof(errBuf))
+ errBuf[sizeof(errBuf)-1] = '\0';
+ LogMsg(0, RS_RET_CONF_PARSE_WARNING, LOG_WARNING,
+ "warning during parsing file %s, on or before line %d: %s",
+ cnfcurrfn, yylineno, errBuf);
+ va_end(ap);
+}
+
+void
+parser_errmsg(const char *fmt, ...)
+{
+ va_list ap;
+ char errBuf[1024];
+
+ va_start(ap, fmt);
+ if(vsnprintf(errBuf, sizeof(errBuf), fmt, ap) == sizeof(errBuf))
+ errBuf[sizeof(errBuf)-1] = '\0';
+ if(cnfcurrfn == NULL) {
+ LogError(0, RS_RET_CONF_PARSE_ERROR,
+ "error during config processing: %s", errBuf);
+ } else {
+ LogError(0, RS_RET_CONF_PARSE_ERROR,
+ "error during parsing file %s, on or before line %d: %s",
+ cnfcurrfn, yylineno, errBuf);
+ }
+ va_end(ap);
+}
+
+int yyerror(const char *s); /* we need this prototype to make compiler happy */
+int
+yyerror(const char *s)
+{
+ parser_errmsg("%s on token '%s'", s, yytext);
+ return 0;
+}
+void ATTR_NONNULL()
+cnfDoObj(struct cnfobj *const o)
+{
+ int bDestructObj = 1;
+ int bChkUnuse = 1;
+ assert(o != NULL);
+
+ dbgprintf("cnf:global:obj: ");
+ cnfobjPrint(o);
+
+ /* We need to check for object disabling as early as here to cover most
+ * of them at once and avoid needless initializations
+ * - jvymazal 2020-02-12
+ */
+ if (nvlstChkDisabled(o->nvlst)) {
+ dbgprintf("object disabled by configuration\n");
+ return;
+ }
+
+ switch(o->objType) {
+ case CNFOBJ_GLOBAL:
+ glblProcessCnf(o);
+ break;
+ case CNFOBJ_TIMEZONE:
+ glblProcessTimezone(o);
+ break;
+ case CNFOBJ_MAINQ:
+ glblProcessMainQCnf(o);
+ bDestructObj = 0;
+ break;
+ case CNFOBJ_MODULE:
+ modulesProcessCnf(o);
+ break;
+ case CNFOBJ_INPUT:
+ inputProcessCnf(o);
+ break;
+ case CNFOBJ_LOOKUP_TABLE:
+ lookupTableDefProcessCnf(o);
+ break;
+ case CNFOBJ_DYN_STATS:
+ dynstats_processCnf(o);
+ break;
+ case CNFOBJ_PERCTILE_STATS:
+ perctile_processCnf(o);
+ break;
+ case CNFOBJ_PARSER:
+ parserProcessCnf(o);
+ break;
+ case CNFOBJ_TPL:
+ if(tplProcessCnf(o) != RS_RET_OK)
+ parser_errmsg("error processing template object");
+ break;
+ case CNFOBJ_RULESET:
+ rulesetProcessCnf(o);
+ break;
+ case CNFOBJ_PROPERTY:
+ case CNFOBJ_CONSTANT:
+ /* these types are processed at a later stage */
+ bChkUnuse = 0;
+ break;
+ case CNFOBJ_ACTION:
+ default:
+ dbgprintf("cnfDoObj program error: unexpected object type %u\n",
+ o->objType);
+ break;
+ }
+ if(bDestructObj) {
+ if(bChkUnuse)
+ nvlstChkUnused(o->nvlst);
+ cnfobjDestruct(o);
+ }
+}
+
+void cnfDoScript(struct cnfstmt *script)
+{
+ dbgprintf("cnf:global:script\n");
+ ruleset.AddScript(ruleset.GetCurrent(loadConf), script);
+}
+
+void cnfDoCfsysline(char *ln)
+{
+ DBGPRINTF("cnf:global:cfsysline: %s\n", ln);
+ /* the legacy system needs the "$" stripped */
+ conf.cfsysline((uchar*) ln+1);
+ free(ln);
+}
+
+void cnfDoBSDTag(char *ln)
+{
+ DBGPRINTF("cnf:global:BSD tag: %s\n", ln);
+ LogError(0, RS_RET_BSD_BLOCKS_UNSUPPORTED,
+ "BSD-style blocks are no longer supported in rsyslog, "
+ "see https://www.rsyslog.com/g/BSD for details and a "
+ "solution (Block '%s')", ln);
+ free(ln);
+}
+
+void cnfDoBSDHost(char *ln)
+{
+ DBGPRINTF("cnf:global:BSD host: %s\n", ln);
+ LogError(0, RS_RET_BSD_BLOCKS_UNSUPPORTED,
+ "BSD-style blocks are no longer supported in rsyslog, "
+ "see https://www.rsyslog.com/g/BSD for details and a "
+ "solution (Block '%s')", ln);
+ free(ln);
+}
+/*------------------------------ end interface to flex/bison parser ------------------------------*/
+
+
+
+/* drop to specified group
+ * if something goes wrong, the function never returns
+ */
+static
+rsRetVal doDropPrivGid(rsconf_t *cnf)
+{
+ int res;
+ uchar szBuf[1024];
+ DEFiRet;
+
+ if(!cnf->globals.gidDropPrivKeepSupplemental) {
+ res = setgroups(0, NULL); /* remove all supplemental group IDs */
+ if(res) {
+ LogError(errno, RS_RET_ERR_DROP_PRIV,
+ "could not remove supplemental group IDs");
+ ABORT_FINALIZE(RS_RET_ERR_DROP_PRIV);
+ }
+ DBGPRINTF("setgroups(0, NULL): %d\n", res);
+ }
+ res = setgid(cnf->globals.gidDropPriv);
+ if(res) {
+ LogError(errno, RS_RET_ERR_DROP_PRIV,
+ "could not set requested group id %d via setgid()", cnf->globals.gidDropPriv);
+ ABORT_FINALIZE(RS_RET_ERR_DROP_PRIV);
+ }
+
+ DBGPRINTF("setgid(%d): %d\n", cnf->globals.gidDropPriv, res);
+ snprintf((char*)szBuf, sizeof(szBuf), "rsyslogd's groupid changed to %d",
+ cnf->globals.gidDropPriv);
+ logmsgInternal(NO_ERRCODE, LOG_SYSLOG|LOG_INFO, szBuf, 0);
+finalize_it:
+ RETiRet;
+}
+
+
+/* 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(rsconf_t *cnf)
+{
+ int res;
+ uchar szBuf[1024];
+ struct passwd *pw;
+ gid_t gid;
+
+ /* Try to set appropriate supplementary groups for this user.
+ * Failure is not fatal.
+ */
+ pw = getpwuid(cnf->globals.uidDropPriv);
+ if (pw) {
+ gid = getgid();
+ res = initgroups(pw->pw_name, gid);
+ DBGPRINTF("initgroups(%s, %ld): %d\n", pw->pw_name, (long) gid, res);
+ } else {
+ LogError(errno, NO_ERRCODE, "could not get username for userid '%d'",
+ cnf->globals.uidDropPriv);
+ }
+
+ res = setuid(cnf->globals.uidDropPriv);
+ 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", cnf->globals.uidDropPriv, res);
+ snprintf((char*)szBuf, sizeof(szBuf), "rsyslogd's userid changed to %d", cnf->globals.uidDropPriv);
+ 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 rsRetVal
+dropPrivileges(rsconf_t *cnf)
+{
+ DEFiRet;
+
+ if(cnf->globals.gidDropPriv != 0) {
+ CHKiRet(doDropPrivGid(cnf));
+ DBGPRINTF("group privileges have been dropped to gid %u\n", (unsigned)
+ cnf->globals.gidDropPriv);
+ }
+
+ if(cnf->globals.uidDropPriv != 0) {
+ doDropPrivUid(cnf);
+ DBGPRINTF("user privileges have been dropped to uid %u\n", (unsigned)
+ cnf->globals.uidDropPriv);
+ }
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* 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 rsRetVal
+tellCoreConfigLoadDone(void)
+{
+ DBGPRINTF("telling rsyslog core that config load for %p is done\n", loadConf);
+ return glblDoneLoadCnf();
+}
+
+
+/* Tell input modules that the config parsing stage is over. */
+static rsRetVal
+tellModulesConfigLoadDone(void)
+{
+ cfgmodules_etry_t *node;
+
+ DBGPRINTF("telling modules that config load for %p is done\n", loadConf);
+ node = module.GetNxtCnfType(loadConf, NULL, eMOD_ANY);
+ while(node != NULL) {
+ DBGPRINTF("beginCnfLoad(%p) for module '%s'\n", node->pMod->beginCnfLoad, node->pMod->pszName);
+ if(node->pMod->beginCnfLoad != NULL) {
+ DBGPRINTF("calling endCnfLoad() for module '%s'\n", node->pMod->pszName);
+ node->pMod->endCnfLoad(node->modCnf);
+ }
+ node = module.GetNxtCnfType(loadConf, node, eMOD_ANY); // loadConf -> runConf
+ }
+
+ return RS_RET_OK; /* intentional: we do not care about module errors */
+}
+
+
+/* Tell input modules to verify config object */
+static rsRetVal
+tellModulesCheckConfig(void)
+{
+ cfgmodules_etry_t *node;
+ rsRetVal localRet;
+
+ DBGPRINTF("telling modules to check config %p\n", loadConf);
+ node = module.GetNxtCnfType(loadConf, NULL, eMOD_ANY);
+ while(node != NULL) {
+ 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(loadConf, node, eMOD_ANY); // runConf -> loadConf
+ }
+
+ return RS_RET_OK; /* intentional: we do not care about module errors */
+}
+
+
+/* Tell modules to activate current running config (pre privilege drop) */
+static rsRetVal
+tellModulesActivateConfigPrePrivDrop(void)
+{
+ cfgmodules_etry_t *node;
+ rsRetVal localRet;
+
+ 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("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) {
+ 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_ANY);
+ }
+
+ 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;
+
+ DBGPRINTF("telling modules to activate config %p\n", runConf);
+ node = module.GetNxtCnfType(runConf, NULL, eMOD_ANY);
+ while(node != NULL) {
+ if(node->pMod->beginCnfLoad != NULL && node->canActivate) {
+ DBGPRINTF("activating config %p for module %s\n",
+ runConf, node->pMod->pszName);
+ localRet = node->pMod->activateCnf(node->modCnf);
+ if(localRet != RS_RET_OK) {
+ 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_ANY);
+ }
+
+ 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)
+{
+ cfgmodules_etry_t *node;
+ int bNeedsCancel;
+
+ node = module.GetNxtCnfType(runConf, NULL, eMOD_IN);
+ while(node != NULL) {
+ if(node->canRun) {
+ bNeedsCancel = (node->pMod->isCompatibleWithFeature(sFEATURENonCancelInputTermination)
+ == RS_RET_OK) ? 0 : 1;
+ DBGPRINTF("running module %s with config %p, term mode: %s\n", node->pMod->pszName, node,
+ bNeedsCancel ? "cancel" : "cooperative/SIGTTIN");
+ thrdCreate(node->pMod->mod.im.runInput, node->pMod->mod.im.afterRun, bNeedsCancel,
+ (node->pMod->cnfName == NULL) ? node->pMod->pszName : node->pMod->cnfName);
+ }
+ node = module.GetNxtCnfType(runConf, node, eMOD_IN);
+ }
+
+ return RS_RET_OK; /* intentional: we do not care about module errors */
+}
+
+
+/* Make the modules check if they are ready to start.
+ */
+static rsRetVal
+startInputModules(void)
+{
+ DEFiRet;
+ cfgmodules_etry_t *node;
+
+ node = module.GetNxtCnfType(runConf, NULL, eMOD_IN);
+ while(node != NULL) {
+ 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);
+ }
+
+ return RS_RET_OK; /* intentional: we do not care about module errors */
+}
+
+/* load the main queue */
+static rsRetVal
+loadMainQueue(void)
+{
+ DEFiRet;
+ struct cnfobj *mainqCnfObj;
+
+ mainqCnfObj = glbl.GetmainqCnfObj();
+ DBGPRINTF("loadMainQueue: mainq cnf obj ptr is %p\n", mainqCnfObj);
+ /* create message queue */
+ iRet = createMainQueue(&loadConf->pMsgQueue, UCHAR_CONSTANT("main Q"),
+ (mainqCnfObj == NULL) ? NULL : mainqCnfObj->nvlst);
+ if (iRet == RS_RET_OK) {
+ if (runConf != NULL) { /* dynamic config reload */
+ int areEqual = queuesEqual(loadConf->pMsgQueue, runConf->pMsgQueue);
+ DBGPRINTF("Comparison of old and new main queues: %d\n", areEqual);
+ if (areEqual) { /* content of the new main queue is the same as it was in previous conf */
+ qqueueDestruct(&loadConf->pMsgQueue);
+ loadConf->pMsgQueue = runConf->pMsgQueue;
+ }
+ }
+ }
+
+ if(iRet != RS_RET_OK) {
+ /* 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;
+ }
+finalize_it:
+ glblDestructMainqCnfObj();
+ RETiRet;
+}
+
+/* activate the main queue */
+static rsRetVal
+activateMainQueue(void)
+{
+ DEFiRet;
+
+ DBGPRINTF("activateMainQueue: will try to activate main queue %p\n", runConf->pMsgQueue);
+
+ iRet = startMainQueue(runConf, runConf->pMsgQueue);
+ if(iRet != RS_RET_OK) {
+ /* 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;
+ }
+
+ if(runConf->globals.mainQ.MainMsgQueType == QUEUETYPE_DIRECT) {
+ PREFER_STORE_0_TO_INT(&bHaveMainQueue);
+ } else {
+ PREFER_STORE_1_TO_INT(&bHaveMainQueue);
+ }
+ DBGPRINTF("Main processing queue is initialized and running\n");
+finalize_it:
+ RETiRet;
+}
+
+
+/* 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;
+}
+
+/* Remove resources from previous config */
+static void
+cleanupOldCnf(rsconf_t *cnf)
+{
+ if (cnf == NULL)
+ FINALIZE;
+
+ if (runConf->pMsgQueue != cnf->pMsgQueue)
+ qqueueDestruct(&cnf->pMsgQueue);
+
+finalize_it:
+ return;
+}
+
+
+/* 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
+ */
+static rsRetVal
+activate(rsconf_t *cnf)
+{
+ DEFiRet;
+ rsconf_t *runCnfOld = runConf;
+
+ /* at this point, we "switch" over to the running conf */
+ runConf = cnf;
+ loadConf = NULL;
+# 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
+ setUmask(cnf->globals.umask);
+
+ /* 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
+ */
+ tellModulesActivateConfigPrePrivDrop();
+
+ CHKiRet(dropPrivileges(cnf));
+
+ lookupActivateConf();
+ tellModulesActivateConfig();
+ startInputModules();
+ CHKiRet(activateActions());
+ CHKiRet(activateRulesetQueues());
+ CHKiRet(activateMainQueue());
+ /* finally let the inputs run... */
+ runInputModules();
+ qqueueDoneLoadCnf(); /* we no longer need config-load-only data structures */
+
+ dbgprintf("configuration %p activated\n", cnf);
+ cleanupOldCnf(runCnfOld);
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* -------------------- some legacy config handlers --------------------
+ * TODO: move to conf.c?
+ */
+
+/* legacy config system: set the action resume interval */
+static rsRetVal setActionResumeInterval(void __attribute__((unused)) *pVal, int iNewVal)
+{
+ return actionSetGlobalResumeInterval(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(pRuleset, pszName));
+ CHKiRet(ruleset.ConstructFinalize(ourConf, pRuleset));
+ rulesetSetCurrRulesetPtr(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 {
+ 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));
+ 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;
+}
+
+
+/* legacy config system: reset config variables to default values. */
+static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
+{
+ free(loadConf->globals.mainQ.pszMainMsgQFName);
+
+ cnfSetDefaults(loadConf);
+
+ 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;
+}
+
+
+/* "load" a build in module and register it for the current load config */
+static rsRetVal
+regBuildInModule(rsRetVal (*modInit)(), uchar *name, void *pModHdlr)
+{
+ cfgmodules_etry_t *pNew;
+ cfgmodules_etry_t *pLast;
+ modInfo_t *pMod;
+ DEFiRet;
+ CHKiRet(module.doModInit(modInit, name, pModHdlr, &pMod));
+ readyModForCnf(pMod, &pNew, &pLast);
+ addModToCnfList(&pNew, pLast);
+finalize_it:
+ RETiRet;
+}
+
+
+/* load build-in modules
+ * very first version begun on 2007-07-23 by rgerhards
+ */
+static rsRetVal
+loadBuildInModules(void)
+{
+ DEFiRet;
+
+ CHKiRet(regBuildInModule(modInitFile, UCHAR_CONSTANT("builtin:omfile"), NULL));
+ CHKiRet(regBuildInModule(modInitPipe, UCHAR_CONSTANT("builtin:ompipe"), NULL));
+ CHKiRet(regBuildInModule(modInitShell, UCHAR_CONSTANT("builtin-shell"), NULL));
+ CHKiRet(regBuildInModule(modInitDiscard, UCHAR_CONSTANT("builtin:omdiscard"), NULL));
+# ifdef SYSLOG_INET
+ CHKiRet(regBuildInModule(modInitFwd, UCHAR_CONSTANT("builtin:omfwd"), 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(regBuildInModule(modInitUsrMsg, (uchar*) "builtin:omusrmsg", NULL));
+
+ /* load build-in parser modules */
+ CHKiRet(regBuildInModule(modInitpmrfc5424, UCHAR_CONSTANT("builtin:pmrfc5424"), NULL));
+ CHKiRet(regBuildInModule(modInitpmrfc3164, UCHAR_CONSTANT("builtin:pmrfc3164"), NULL));
+
+ /* 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(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) {
+ /* 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 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(pRuleset, UCHAR_CONSTANT("RSYSLOG_DefaultRuleset"));
+ ruleset.ConstructFinalize(loadConf, pRuleset);
+ rulesetSetCurrRulesetPtr(pRuleset);
+
+ /* now register config handlers */
+ CHKiRet(regCfSysLineHdlr((uchar *)"sleep", 0, eCmdHdlrGoneAway,
+ NULL, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"logrsyslogstatusmessages", 0, eCmdHdlrBinary,
+ NULL, &loadConf->globals.bLogStatusMsgs, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"errormessagestostderr", 0, eCmdHdlrBinary,
+ NULL, &loadConf->globals.bErrMsgToStderr, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"abortonuncleanconfig", 0, eCmdHdlrBinary,
+ NULL, &loadConf->globals.bAbortOnUncleanConfig, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"repeatedmsgreduction", 0, eCmdHdlrBinary,
+ NULL, &loadConf->globals.bReduceRepeatMsgs, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"debugprinttemplatelist", 0, eCmdHdlrBinary,
+ NULL, &(loadConf->globals.bDebugPrintTemplateList), NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"debugprintmodulelist", 0, eCmdHdlrBinary,
+ NULL, &(loadConf->globals.bDebugPrintModuleList), NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"debugprintcfsyslinehandlerlist", 0, eCmdHdlrBinary,
+ NULL, &(loadConf->globals.bDebugPrintCfSysLineHandlerList), NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouser", 0, eCmdHdlrUID,
+ NULL, &loadConf->globals.uidDropPriv, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptouserid", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.uidDropPriv, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroup", 0, eCmdHdlrGID,
+ NULL, &loadConf->globals.gidDropPriv, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"privdroptogroupid", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.gidDropPriv, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"generateconfiggraph", 0, eCmdHdlrGetWord,
+ NULL, &loadConf->globals.pszConfDAGFile, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"umask", 0, eCmdHdlrFileCreateMode,
+ NULL, &loadConf->globals.umask, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"maxopenfiles", 0, eCmdHdlrInt,
+ setMaxFiles, NULL, NULL));
+
+ CHKiRet(regCfSysLineHdlr((uchar *)"actionresumeinterval", 0, eCmdHdlrInt,
+ setActionResumeInterval, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"modload", 0, eCmdHdlrCustomHandler,
+ conf.doModLoad, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"defaultruleset", 0, eCmdHdlrGetWord,
+ setDefaultRuleset, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"ruleset", 0, eCmdHdlrGetWord,
+ setCurrRuleset, NULL, NULL));
+
+ /* handler for "larger" config statements (tie into legacy conf system) */
+ CHKiRet(regCfSysLineHdlr((uchar *)"template", 0, eCmdHdlrCustomHandler,
+ conf.doNameLine, (void*)DIR_TEMPLATE, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"outchannel", 0, eCmdHdlrCustomHandler,
+ conf.doNameLine, (void*)DIR_OUTCHANNEL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"allowedsender", 0, eCmdHdlrCustomHandler,
+ conf.doNameLine, (void*)DIR_ALLOWEDSENDER, NULL));
+
+ /* 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));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesize", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueueSize, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuehighwatermark", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQHighWtrMark, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuelowwatermark", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQLowWtrMark, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardmark", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQDiscardMark, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuediscardseverity", 0, eCmdHdlrSeverity,
+ NULL, &loadConf->globals.mainQ.iMainMsgQDiscardSeverity, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuecheckpointinterval", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQPersistUpdCnt, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesyncqueuefiles", 0, eCmdHdlrBinary,
+ NULL, &loadConf->globals.mainQ.bMainMsgQSyncQeueFiles, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetype", 0, eCmdHdlrGetWord,
+ setMainMsgQueType, NULL, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreads", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueueNumWorkers, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutshutdown", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQtoQShutdown, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutactioncompletion", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQtoActShutdown, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuetimeoutenqueue", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQtoEnq, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkertimeoutthreadshutdown", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQtoWrkShutdown, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeueslowdown", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQDeqSlowdown, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueueworkerthreadminimummessages", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQWrkMinMsgs, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxfilesize", 0, eCmdHdlrSize,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueMaxFileSize, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuebatchsize", 0, eCmdHdlrSize,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueDeqBatchSize, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuemaxdiskspace", 0, eCmdHdlrSize,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueMaxDiskSpace, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuesaveonshutdown", 0, eCmdHdlrBinary,
+ NULL, &loadConf->globals.mainQ.bMainMsgQSaveOnShutdown, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimebegin", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueueDeqtWinFromHr, NULL));
+ CHKiRet(regCfSysLineHdlr((uchar *)"mainmsgqueuedequeuetimeend", 0, eCmdHdlrInt,
+ NULL, &loadConf->globals.mainQ.iMainMsgQueueDeqtWinToHr, NULL));
+ /* 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));
+
+ /* finally, the reset handler */
+ CHKiRet(regCfSysLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
+ resetConfigVariables, NULL, NULL));
+
+ /* initialize the build-in templates */
+ pTmp = template_DebugFormat;
+ tplAddLine(ourConf, "RSYSLOG_DebugFormat", &pTmp);
+ pTmp = template_SyslogProtocol23Format;
+ tplAddLine(ourConf, "RSYSLOG_SyslogProtocol23Format", &pTmp);
+ pTmp = template_SyslogRFC5424Format;
+ tplAddLine(ourConf, "RSYSLOG_SyslogRFC5424Format", &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_SysklogdFileFormat;
+ tplAddLine(ourConf, "RSYSLOG_SysklogdFileFormat", &pTmp);
+ pTmp = template_StdPgSQLFmt;
+ tplAddLine(ourConf, " StdPgSQLFmt", &pTmp);
+ pTmp = template_StdJSONFmt;
+ tplAddLine(ourConf, " StdJSONFmt", &pTmp);
+ pTmp = template_FullJSONFmt;
+ tplAddLine(ourConf, " FullJSONFmt", &pTmp);
+ pTmp = template_StdClickHouseFmt;
+ tplAddLine(ourConf, " StdClickHouseFmt", &pTmp);
+ pTmp = template_spoofadr;
+ tplLastStaticInit(ourConf, tplAddLine(ourConf, "RSYSLOG_omudpspoofDfltSourceTpl", &pTmp));
+
+finalize_it:
+ RETiRet;
+}
+
+
+/* validate the configuration pointed by conf, generate error messages, do
+ * optimizations, etc, etc,...
+ */
+static rsRetVal
+validateConf(rsconf_t *cnf)
+{
+ DEFiRet;
+
+ /* some checks */
+ if(cnf->globals.mainQ.iMainMsgQueueNumWorkers < 1) {
+ LogError(0, NO_ERRCODE, "$MainMsgQueueNumWorkers must be at least 1! Set to 1.\n");
+ cnf->globals.mainQ.iMainMsgQueueNumWorkers = 1;
+ }
+
+ if(cnf->globals.mainQ.MainMsgQueType == QUEUETYPE_DISK) {
+ errno = 0; /* for logerror! */
+ if(glbl.GetWorkDir(cnf) == NULL) {
+ LogError(0, NO_ERRCODE, "No $WorkDirectory specified - can not run main "
+ "message queue in 'disk' mode. Using 'FixedArray' instead.\n");
+ cnf->globals.mainQ.MainMsgQueType = QUEUETYPE_FIXED_ARRAY;
+ }
+ if(cnf->globals.mainQ.pszMainMsgQFName == NULL) {
+ LogError(0, NO_ERRCODE, "No $MainMsgQueueFileName specified - can not run main "
+ "message queue in 'disk' mode. Using 'FixedArray' instead.\n");
+ cnf->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.
+ * 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
+ */
+static rsRetVal
+load(rsconf_t **cnf, uchar *confFile)
+{
+ int iNbrActions = 0;
+ int r;
+ rsRetVal delayed_iRet = RS_RET_OK;
+ DEFiRet;
+
+ CHKiRet(rsconfConstruct(&loadConf));
+ ourConf = loadConf; // TODO: remove, once ourConf is gone!
+
+ CHKiRet(loadBuildInModules());
+ CHKiRet(initLegacyConf());
+
+ /* open the configuration file */
+ r = cnfSetLexFile((char*)confFile);
+ if(r == 0) {
+ r = yyparse();
+ conf.GetNbrActActions(loadConf, &iNbrActions);
+ }
+
+ /* we run the optimizer even if we have an error, as it may spit out
+ * additional error messages and we want to see these even if we abort.
+ */
+ rulesetOptimizeAll(loadConf);
+
+ if(r == 1) {
+ LogError(0, RS_RET_CONF_PARSE_ERROR, "could not interpret master "
+ "config file '%s'.", confFile);
+ /* we usually keep running with the failure, so we need to continue for now */
+ delayed_iRet = RS_RET_CONF_PARSE_ERROR;
+ } else if(r == 2) { /* file not found? */
+ LogError(errno, RS_RET_CONF_FILE_NOT_FOUND, "could not open config file '%s'",
+ confFile);
+ ABORT_FINALIZE(RS_RET_CONF_FILE_NOT_FOUND);
+ } else if( (iNbrActions == 0)
+ && !(iConfigVerify & CONF_VERIFY_PARTIAL_CONF)) {
+ LogError(0, RS_RET_NO_ACTIONS, "there are no active actions configured. "
+ "Inputs would run, but no output whatsoever were created.");
+ ABORT_FINALIZE(RS_RET_NO_ACTIONS);
+ }
+ tellLexEndParsing();
+ DBGPRINTF("Number of actions in this configuration: %d\n", loadConf->actions.iActionNbr);
+
+ CHKiRet(tellCoreConfigLoadDone());
+ tellModulesConfigLoadDone();
+
+ tellModulesCheckConfig();
+ CHKiRet(validateConf(loadConf));
+ CHKiRet(loadMainQueue());
+
+ /* 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) {
+ if(iRet == RS_RET_OK)
+ iRet = RS_RET_VALIDATION_RUN;
+ FINALIZE;
+ }
+
+ /* 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 master config %p\n", loadConf);
+ rsconfDebugPrint(loadConf);
+
+finalize_it:
+ if(iRet == RS_RET_OK && delayed_iRet != RS_RET_OK) {
+ iRet = delayed_iRet;
+ }
+ RETiRet;
+}
+
+
+/* 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->Destruct = rsconfDestruct;
+ pIf->DebugPrint = rsconfDebugPrint;
+ pIf->Load = load;
+ pIf->Activate = activate;
+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 */
+ CHKiRet(objUse(ruleset, CORE_COMPONENT));
+ CHKiRet(objUse(module, CORE_COMPONENT));
+ CHKiRet(objUse(conf, CORE_COMPONENT));
+ CHKiRet(objUse(glbl, CORE_COMPONENT));
+ CHKiRet(objUse(datetime, CORE_COMPONENT));
+ CHKiRet(objUse(parser, CORE_COMPONENT));
+
+ /* 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 */
+ objRelease(ruleset, CORE_COMPONENT);
+ objRelease(module, CORE_COMPONENT);
+ objRelease(conf, CORE_COMPONENT);
+ objRelease(glbl, CORE_COMPONENT);
+ objRelease(datetime, CORE_COMPONENT);
+ objRelease(parser, CORE_COMPONENT);
+ENDObjClassExit(rsconf)