/* omruleset.c * This is a very special output module. It permits to pass a message object * to another rule set. While this is a very simple action, it enables very * complex configurations, e.g. it supports high-speed "and" conditions, sending * data to the same file in a non-racy way, include functionality as well as * some high-performance optimizations (in case the rule sets have the necessary * queue definitions). So while this code is small, it is pretty important. * * NOTE: read comments in module-template.h for details on the calling interface! * * File begun on 2009-11-02 by RGerhards * * Copyright 2009-2016 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * * 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" #include #include #include #include #include #include #include #include #include "conf.h" #include "syslogd-types.h" #include "template.h" #include "module-template.h" #include "errmsg.h" #include "ruleset.h" #include "cfsysline.h" #include "dirty.h" MODULE_TYPE_OUTPUT MODULE_TYPE_NOKEEP MODULE_CNFNAME("omruleset") static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal); /* static data */ DEFobjCurrIf(ruleset); /* internal structures */ DEF_OMOD_STATIC_DATA /* config variables */ typedef struct _instanceData { ruleset_t *pRuleset; /* ruleset to enqueue to */ uchar *pszRulesetName; /* primarily for debugging/display purposes */ } instanceData; typedef struct wrkrInstanceData { instanceData *pData; } wrkrInstanceData_t; typedef struct configSettings_s { ruleset_t *pRuleset; /* ruleset to enqueue message to (NULL = Default, not recommended) */ uchar *pszRulesetName; } configSettings_t; static configSettings_t cs; BEGINinitConfVars /* (re)set config variables to default values */ CODESTARTinitConfVars resetConfigVariables(NULL, NULL); ENDinitConfVars BEGINcreateInstance CODESTARTcreateInstance ENDcreateInstance BEGINcreateWrkrInstance CODESTARTcreateWrkrInstance ENDcreateWrkrInstance BEGINisCompatibleWithFeature CODESTARTisCompatibleWithFeature ENDisCompatibleWithFeature BEGINfreeWrkrInstance CODESTARTfreeWrkrInstance ENDfreeWrkrInstance BEGINfreeInstance CODESTARTfreeInstance free(pData->pszRulesetName); ENDfreeInstance BEGINdbgPrintInstInfo CODESTARTdbgPrintInstInfo dbgprintf("omruleset target %s[%p]\n", (char*) pData->pszRulesetName, pData->pRuleset); ENDdbgPrintInstInfo BEGINtryResume CODESTARTtryResume ENDtryResume /* Note that we change the flow control type to "no delay", because at this point in * rsyslog procesing we can not really slow down the producer any longer, as we already * work off a queue. So a delay would just block out execution for longer than needed. */ BEGINdoAction_NoStrings smsg_t **ppMsg = (smsg_t **) pMsgData; smsg_t *pMsg; CODESTARTdoAction CHKmalloc(pMsg = MsgDup(ppMsg[0])); DBGPRINTF(":omruleset: forwarding message %p to ruleset %s[%p]\n", pMsg, (char*) pWrkrData->pData->pszRulesetName, pWrkrData->pData->pRuleset); MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY); MsgSetRuleset(pMsg, pWrkrData->pData->pRuleset); /* Note: we intentionally use submitMsg2() here, as we process messages * that were already run through the rate-limiter. So it is (at least) * questionable if they were rate-limited again. */ submitMsg2(pMsg); finalize_it: ENDdoAction /* set the ruleset name */ static rsRetVal setRuleset(void __attribute__((unused)) *pVal, uchar *pszName) { rsRetVal localRet; DEFiRet; localRet = ruleset.GetRuleset(ourConf, &cs.pRuleset, pszName); if(localRet == RS_RET_NOT_FOUND) { LogError(0, RS_RET_RULESET_NOT_FOUND, "error: ruleset '%s' not found - ignored", pszName); } CHKiRet(localRet); cs.pszRulesetName = pszName; /* save for later display purposes */ finalize_it: if(iRet != RS_RET_OK) { /* cleanup needed? */ free(pszName); } RETiRet; } BEGINparseSelectorAct int iTplOpts; CODESTARTparseSelectorAct CODE_STD_STRING_REQUESTparseSelectorAct(1) /* first check if this config line is actually for us */ if(strncmp((char*) p, ":omruleset:", sizeof(":omruleset:") - 1)) { ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED); } if(cs.pRuleset == NULL) { LogError(0, RS_RET_NO_RULESET, "error: no ruleset was specified, use " "$ActionOmrulesetRulesetName directive first!"); ABORT_FINALIZE(RS_RET_NO_RULESET); } /* ok, if we reach this point, we have something for us */ p += sizeof(":omruleset:") - 1; /* eat indicator sequence (-1 because of '\0'!) */ CHKiRet(createInstance(&pData)); LogMsg(0, RS_RET_DEPRECATED, LOG_WARNING, "warning: omruleset is deprecated, consider " "using the 'call' statement instead"); /* check if a non-standard template is to be applied */ if(*(p-1) == ';') --p; iTplOpts = OMSR_TPL_AS_MSG; /* we call the message below because we need to call it via our interface definition. However, * the format specified (if any) is always ignored. */ CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, iTplOpts, (uchar*) "RSYSLOG_FileFormat")); pData->pRuleset = cs.pRuleset; pData->pszRulesetName = cs.pszRulesetName; cs.pRuleset = NULL; /* re-set, because there is a high risk of unwanted behavior if we leave it in! */ cs.pszRulesetName = NULL; /* note: we must not free, as we handed over this pointer to the instanceDat to the instanceDataa! */ CODE_STD_FINALIZERparseSelectorAct ENDparseSelectorAct BEGINmodExit CODESTARTmodExit free(cs.pszRulesetName); objRelease(ruleset, CORE_COMPONENT); ENDmodExit BEGINqueryEtryPt CODESTARTqueryEtryPt CODEqueryEtryPt_STD_OMOD_QUERIES CODEqueryEtryPt_STD_OMOD8_QUERIES CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES ENDqueryEtryPt /* Reset config variables for this module to default values. */ static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal) { DEFiRet; cs.pRuleset = NULL; free(cs.pszRulesetName); cs.pszRulesetName = NULL; RETiRet; } BEGINmodInit() rsRetVal localRet; rsRetVal (*pomsrGetSupportedTplOpts)(unsigned long *pOpts); unsigned long opts; int bMsgPassingSupported; /* does core support template passing as an array? */ CODESTARTmodInit INITLegCnfVars *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */ CODEmodInit_QueryRegCFSLineHdlr /* check if the rsyslog core supports parameter passing code */ bMsgPassingSupported = 0; localRet = pHostQueryEtryPt((uchar*)"OMSRgetSupportedTplOpts", &pomsrGetSupportedTplOpts); if(localRet == RS_RET_OK) { /* found entry point, so let's see if core supports msg passing */ CHKiRet((*pomsrGetSupportedTplOpts)(&opts)); if(opts & OMSR_TPL_AS_MSG) bMsgPassingSupported = 1; } else if(localRet != RS_RET_ENTRY_POINT_NOT_FOUND) { ABORT_FINALIZE(localRet); /* Something else went wrong, what is not acceptable */ } if(!bMsgPassingSupported) { DBGPRINTF("omruleset: msg-passing is not supported by rsyslog core, can not continue.\n"); ABORT_FINALIZE(RS_RET_NO_MSG_PASSING); } CHKiRet(objUse(ruleset, CORE_COMPONENT)); LogMsg(0, RS_RET_DEPRECATED, LOG_WARNING, "warning: omruleset is deprecated, consider " "using the 'call' statement instead"); CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomrulesetrulesetname", 0, eCmdHdlrGetWord, setRuleset, NULL, STD_LOADABLE_MODULE_ID)); CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler, resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID)); ENDmodInit /* vi:set ai: */