1 /* omruleset.c
2 * This is a very special output module. It permits to pass a message object
3 * to another rule set. While this is a very simple action, it enables very
4 * complex configurations, e.g. it supports high-speed "and" conditions, sending
5 * data to the same file in a non-racy way, include functionality as well as
6 * some high-performance optimizations (in case the rule sets have the necessary
7 * queue definitions). So while this code is small, it is pretty important.
8 *
9 * NOTE: read comments in module-template.h for details on the calling interface!
10 *
11 * File begun on 2009-11-02 by RGerhards
12 *
13 * Copyright 2009-2016 Rainer Gerhards and Adiscon GmbH.
14 *
15 * This file is part of rsyslog.
16 *
17 * Licensed under the Apache License, Version 2.0 (the "License");
18 * you may not use this file except in compliance with the License.
19 * You may obtain a copy of the License at
20 *
21 * http://www.apache.org/licenses/LICENSE-2.0
22 * -or-
23 * see COPYING.ASL20 in the source distribution
24 *
25 * Unless required by applicable law or agreed to in writing, software
26 * distributed under the License is distributed on an "AS IS" BASIS,
27 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 * See the License for the specific language governing permissions and
29 * limitations under the License.
30 */
31 #include "config.h"
32 #include "rsyslog.h"
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <assert.h>
38 #include <signal.h>
39 #include <errno.h>
40 #include <unistd.h>
41 #include "conf.h"
42 #include "syslogd-types.h"
43 #include "template.h"
44 #include "module-template.h"
45 #include "errmsg.h"
46 #include "ruleset.h"
47 #include "cfsysline.h"
48 #include "dirty.h"
49
50 MODULE_TYPE_OUTPUT
51 MODULE_TYPE_NOKEEP
52 MODULE_CNFNAME("omruleset")
53
54 static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal);
55
56 /* static data */
57 DEFobjCurrIf(ruleset);
58
59 /* internal structures
60 */
61 DEF_OMOD_STATIC_DATA
62
63 /* config variables */
64
65
66 typedef struct _instanceData {
67 ruleset_t *pRuleset; /* ruleset to enqueue to */
68 uchar *pszRulesetName; /* primarily for debugging/display purposes */
69 } instanceData;
70
71 typedef struct wrkrInstanceData {
72 instanceData *pData;
73 } wrkrInstanceData_t;
74
75 typedef struct configSettings_s {
76 ruleset_t *pRuleset; /* ruleset to enqueue message to (NULL = Default, not recommended) */
77 uchar *pszRulesetName;
78 } configSettings_t;
79 static configSettings_t cs;
80
81 BEGINinitConfVars /* (re)set config variables to default values */
82 CODESTARTinitConfVars
83 resetConfigVariables(NULL, NULL);
84 ENDinitConfVars
85
86
87 BEGINcreateInstance
88 CODESTARTcreateInstance
89 ENDcreateInstance
90
91
92 BEGINcreateWrkrInstance
93 CODESTARTcreateWrkrInstance
94 ENDcreateWrkrInstance
95
96
97 BEGINisCompatibleWithFeature
98 CODESTARTisCompatibleWithFeature
99 ENDisCompatibleWithFeature
100
101
102 BEGINfreeWrkrInstance
103 CODESTARTfreeWrkrInstance
104 ENDfreeWrkrInstance
105
106
107 BEGINfreeInstance
108 CODESTARTfreeInstance
109 free(pData->pszRulesetName);
110 ENDfreeInstance
111
112
113 BEGINdbgPrintInstInfo
114 CODESTARTdbgPrintInstInfo
115 dbgprintf("omruleset target %s[%p]\n", (char*) pData->pszRulesetName, pData->pRuleset);
116 ENDdbgPrintInstInfo
117
118
119 BEGINtryResume
120 CODESTARTtryResume
121 ENDtryResume
122
123 /* Note that we change the flow control type to "no delay", because at this point in
124 * rsyslog procesing we can not really slow down the producer any longer, as we already
125 * work off a queue. So a delay would just block out execution for longer than needed.
126 */
127 BEGINdoAction_NoStrings
128 smsg_t **ppMsg = (smsg_t **) pMsgData;
129 smsg_t *pMsg;
130 CODESTARTdoAction
131 CHKmalloc(pMsg = MsgDup(ppMsg[0]));
132 DBGPRINTF(":omruleset: forwarding message %p to ruleset %s[%p]\n", pMsg,
133 (char*) pWrkrData->pData->pszRulesetName, pWrkrData->pData->pRuleset);
134 MsgSetFlowControlType(pMsg, eFLOWCTL_NO_DELAY);
135 MsgSetRuleset(pMsg, pWrkrData->pData->pRuleset);
136 /* Note: we intentionally use submitMsg2() here, as we process messages
137 * that were already run through the rate-limiter. So it is (at least)
138 * questionable if they were rate-limited again.
139 */
140 submitMsg2(pMsg);
141 finalize_it:
142 ENDdoAction
143
144 /* set the ruleset name */
145 static rsRetVal
setRuleset(void * pVal,uchar * pszName)146 setRuleset(void __attribute__((unused)) *pVal, uchar *pszName)
147 {
148 rsRetVal localRet;
149 DEFiRet;
150
151 localRet = ruleset.GetRuleset(ourConf, &cs.pRuleset, pszName);
152 if(localRet == RS_RET_NOT_FOUND) {
153 LogError(0, RS_RET_RULESET_NOT_FOUND, "error: ruleset '%s' not found - ignored", pszName);
154 }
155 CHKiRet(localRet);
156 cs.pszRulesetName = pszName; /* save for later display purposes */
157
158 finalize_it:
159 if(iRet != RS_RET_OK) { /* cleanup needed? */
160 free(pszName);
161 }
162 RETiRet;
163 }
164
165
166 BEGINparseSelectorAct
167 int iTplOpts;
168 CODESTARTparseSelectorAct
169 CODE_STD_STRING_REQUESTparseSelectorAct(1)
170 /* first check if this config line is actually for us */
171 if(strncmp((char*) p, ":omruleset:", sizeof(":omruleset:") - 1)) {
172 ABORT_FINALIZE(RS_RET_CONFLINE_UNPROCESSED);
173 }
174
175 if(cs.pRuleset == NULL) {
176 LogError(0, RS_RET_NO_RULESET, "error: no ruleset was specified, use "
177 "$ActionOmrulesetRulesetName directive first!");
178 ABORT_FINALIZE(RS_RET_NO_RULESET);
179 }
180
181 /* ok, if we reach this point, we have something for us */
182 p += sizeof(":omruleset:") - 1; /* eat indicator sequence (-1 because of '\0'!) */
183 CHKiRet(createInstance(&pData));
184
185 LogMsg(0, RS_RET_DEPRECATED, LOG_WARNING,
186 "warning: omruleset is deprecated, consider "
187 "using the 'call' statement instead");
188
189 /* check if a non-standard template is to be applied */
190 if(*(p-1) == ';')
191 --p;
192 iTplOpts = OMSR_TPL_AS_MSG;
193 /* we call the message below because we need to call it via our interface definition. However,
194 * the format specified (if any) is always ignored.
195 */
196 CHKiRet(cflineParseTemplateName(&p, *ppOMSR, 0, iTplOpts, (uchar*) "RSYSLOG_FileFormat"));
197 pData->pRuleset = cs.pRuleset;
198 pData->pszRulesetName = cs.pszRulesetName;
199 cs.pRuleset = NULL;
200 /* re-set, because there is a high risk of unwanted behavior if we leave it in! */
201 cs.pszRulesetName = NULL;
202 /* note: we must not free, as we handed over this pointer to the instanceDat to the instanceDataa! */
203 CODE_STD_FINALIZERparseSelectorAct
204 ENDparseSelectorAct
205
206
207 BEGINmodExit
208 CODESTARTmodExit
209 free(cs.pszRulesetName);
210 objRelease(ruleset, CORE_COMPONENT);
211 ENDmodExit
212
213
214 BEGINqueryEtryPt
215 CODESTARTqueryEtryPt
216 CODEqueryEtryPt_STD_OMOD_QUERIES
217 CODEqueryEtryPt_STD_OMOD8_QUERIES
218 CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES
219 ENDqueryEtryPt
220
221
222
223 /* Reset config variables for this module to default values.
224 */
resetConfigVariables(uchar * pp,void * pVal)225 static rsRetVal resetConfigVariables(uchar __attribute__((unused)) *pp, void __attribute__((unused)) *pVal)
226 {
227 DEFiRet;
228 cs.pRuleset = NULL;
229 free(cs.pszRulesetName);
230 cs.pszRulesetName = NULL;
231 RETiRet;
232 }
233
234
235 BEGINmodInit()
236 rsRetVal localRet;
237 rsRetVal (*pomsrGetSupportedTplOpts)(unsigned long *pOpts);
238 unsigned long opts;
239 int bMsgPassingSupported; /* does core support template passing as an array? */
240 CODESTARTmodInit
241 INITLegCnfVars
242 *ipIFVersProvided = CURR_MOD_IF_VERSION; /* we only support the current interface specification */
243 CODEmodInit_QueryRegCFSLineHdlr
244 /* check if the rsyslog core supports parameter passing code */
245 bMsgPassingSupported = 0;
246 localRet = pHostQueryEtryPt((uchar*)"OMSRgetSupportedTplOpts", &pomsrGetSupportedTplOpts);
247 if(localRet == RS_RET_OK) {
248 /* found entry point, so let's see if core supports msg passing */
249 CHKiRet((*pomsrGetSupportedTplOpts)(&opts));
250 if(opts & OMSR_TPL_AS_MSG)
251 bMsgPassingSupported = 1;
252 } else if(localRet != RS_RET_ENTRY_POINT_NOT_FOUND) {
253 ABORT_FINALIZE(localRet); /* Something else went wrong, what is not acceptable */
254 }
255
256 if(!bMsgPassingSupported) {
257 DBGPRINTF("omruleset: msg-passing is not supported by rsyslog core, can not continue.\n");
258 ABORT_FINALIZE(RS_RET_NO_MSG_PASSING);
259 }
260
261 CHKiRet(objUse(ruleset, CORE_COMPONENT));
262
263 LogMsg(0, RS_RET_DEPRECATED, LOG_WARNING,
264 "warning: omruleset is deprecated, consider "
265 "using the 'call' statement instead");
266
267 CHKiRet(omsdRegCFSLineHdlr((uchar *)"actionomrulesetrulesetname", 0, eCmdHdlrGetWord,
268 setRuleset, NULL, STD_LOADABLE_MODULE_ID));
269 CHKiRet(omsdRegCFSLineHdlr((uchar *)"resetconfigvariables", 1, eCmdHdlrCustomHandler,
270 resetConfigVariables, NULL, STD_LOADABLE_MODULE_ID));
271 ENDmodInit
272
273 /* vi:set ai:
274 */
275