rsyslog/runtime/module-template.h
Rainer Gerhards e0dcad6cdf
pmrfc3164: add headerless message detection and handling
This patch adds a robust, optional mechanism for handling "headerless" input—
log messages that do not conform to traditional syslog formatting.

- **Headerless detection (opt-in)**
  - Controlled by the new `detect.headerless` boolean (default: off)
  - Detects messages with **no PRI** and **no valid timestamp**
  - Excludes structured inputs (e.g. JSON starting with `{` or `[`) as
    before
  - Injects default `hostname` and `tag` values
  - Flags message internally as `HEADERLESS_MSG` for further processing

- **Fallback processing options**
  - `headerless.ruleset`: route headerless messages to a dedicated ruleset
  - `headerless.errorfile`: optionally store raw input to a file
  - `headerless.drop`: discard headerless messages early if desired

- **Thread-safe HUP signal handling**
  - New `doHUPParser` entry point allows safe log rotation for error file
  - Follows standard reopen-on-write pattern post-HUP

- **Testing & Maintenance**
  - Adds two test cases: `pmrfc3164-headerless.sh` and `pmrfc3164-drop.sh`
  - Extends documentation for all new parameters
  - Cleans up code formatting, includes, and bumps copyright

Some environments produce mixed or malformed input streams. This patch enables
early, lightweight detection of non-syslog input, with customizable recovery
and routing strategies. It avoids unnecessary parsing work and gives operators
better tools to isolate or discard garbage input—without breaking legacy behavior.
2025-07-31 10:39:24 +02:00

1205 lines
50 KiB
C

/* module-template.h
* This header contains macros that can be used to implement the
* plumbing of modules.
*
* File begun on 2007-07-25 by RGerhards
*
* Copyright 2007-2025 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 MODULE_TEMPLATE_H_INCLUDED
#define MODULE_TEMPLATE_H_INCLUDED 1
#include "modules.h"
#include "obj.h"
#include "objomsr.h"
#include "threads.h"
/* macro to define standard output-module static data members
*/
#define DEF_MOD_STATIC_DATA \
static __attribute__((unused)) rsRetVal (*omsdRegCFSLineHdlr)(uchar * pCmdName, int bChainingPermitted, \
ecslCmdHdrlType eType, rsRetVal (*pHdlr)(), \
void *pData, void *pOwnerCookie)
#define DEF_OMOD_STATIC_DATA \
DEF_MOD_STATIC_DATA; \
DEFobjCurrIf(obj) static __attribute__((unused)) int bCoreSupportsBatching;
#define DEF_IMOD_STATIC_DATA \
DEF_MOD_STATIC_DATA; \
DEFobjCurrIf(obj)
#define DEF_LMOD_STATIC_DATA DEF_MOD_STATIC_DATA
#define DEF_PMOD_STATIC_DATA \
DEFobjCurrIf(obj); \
DEF_MOD_STATIC_DATA
#define DEF_SMOD_STATIC_DATA \
DEFobjCurrIf(obj); \
DEF_MOD_STATIC_DATA
#define DEF_FMOD_STATIC_DATA \
DEFobjCurrIf(obj); \
DEF_MOD_STATIC_DATA
/* Macro to define the module type. Each module can only have a single type. If
* a module provides multiple types, several separate modules must be created which
* then should share a single library containing the majority of code. This macro
* must be present in each module. -- rgerhards, 2007-12-14
* Note that MODULE_TYPE_TESTBENCH is reserved for testbenches, but
* declared in their own header files (because the rest does not need these
* defines). -- rgerhards, 2008-06-13
*/
#define MODULE_TYPE(x) \
static rsRetVal modGetType(eModType_t *modType) { \
*modType = x; \
return RS_RET_OK; \
}
#define MODULE_TYPE_INPUT MODULE_TYPE(eMOD_IN)
#define MODULE_TYPE_OUTPUT MODULE_TYPE(eMOD_OUT)
#define MODULE_TYPE_PARSER MODULE_TYPE(eMOD_PARSER)
#define MODULE_TYPE_STRGEN MODULE_TYPE(eMOD_STRGEN)
#define MODULE_TYPE_FUNCTION MODULE_TYPE(eMOD_FUNCTION)
#define MODULE_TYPE_LIB \
DEF_LMOD_STATIC_DATA; \
MODULE_TYPE(eMOD_LIB)
/* Macro to define whether the module should be kept dynamically linked.
*/
#define MODULE_KEEP_TYPE(x) \
static rsRetVal modGetKeepType(eModKeepType_t *modKeepType) { \
*modKeepType = x; \
return RS_RET_OK; \
}
#define MODULE_TYPE_NOKEEP MODULE_KEEP_TYPE(eMOD_NOKEEP)
#define MODULE_TYPE_KEEP MODULE_KEEP_TYPE(eMOD_KEEP)
/* macro to define a unique module id. This must be able to fit in a void*. The
* module id must be unique inside a running rsyslogd application. It is used to
* track ownership of several objects. Most importantly, when the module is
* unloaded the module id value is used to find what needs to be destroyed.
* We currently use a pointer to modExit() as the module id. This sounds to be
* reasonable save, as each module must have this entry point AND there is no valid
* reason for twice this entry point being in memory.
* rgerhards, 2007-11-21
*/
#define STD_LOADABLE_MODULE_ID ((void *)modExit)
/* macro to implement the "modGetID()" interface function
* rgerhards 2007-11-21
*/
#define DEFmodGetID \
static rsRetVal modGetID(void **pID) { \
*pID = STD_LOADABLE_MODULE_ID; \
return RS_RET_OK; \
}
/* macro to provide the v6 config system module name
*/
#define MODULE_CNFNAME(name) \
static 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()):
*
* BEGINcreateInstance
* ... custom variable definitions (on stack) ... (if any)
* CODESTARTcreateInstance
* ... custom code ... (if any)
* ENDcreateInstance
*/
/* createInstance()
*/
#define BEGINcreateInstance \
static rsRetVal createInstance(instanceData **ppData) { \
DEFiRet; /* store error code here */ \
instanceData *pData; /* use this to point to data elements */
#define CODESTARTcreateInstance \
if ((pData = calloc(1, sizeof(instanceData))) == NULL) { \
*ppData = NULL; \
return RS_RET_OUT_OF_MEMORY; \
}
#define ENDcreateInstance \
*ppData = pData; \
RETiRet; \
}
/* freeInstance()
* This is the cleanup function for the module instance. It is called immediately before
* the module instance is destroyed (unloaded). The module should do any cleanup
* here, e.g. close file, free instantance heap memory and the like. Control will
* not be passed back to the module once this function is finished. Keep in mind,
* however, that other instances may still be loaded and used. So do not destroy
* anything that may be used by another instance. If you have such a ressource, you
* currently need to do the instance counting yourself.
*/
#define BEGINfreeInstance \
static rsRetVal freeInstance(void *pModData) { \
DEFiRet; \
instanceData *pData;
#define CODESTARTfreeInstance pData = (instanceData *)pModData;
#define ENDfreeInstance \
if (pData != NULL) free(pData); /* we need to free this in any case */ \
RETiRet; \
}
/* createWrkrInstance()
*/
#define BEGINcreateWrkrInstance \
static rsRetVal createWrkrInstance(wrkrInstanceData_t **ppWrkrData, instanceData *pData) { \
DEFiRet; /* store error code here */ \
wrkrInstanceData_t *pWrkrData; /* use this to point to data elements */
#define CODESTARTcreateWrkrInstance \
if ((pWrkrData = calloc(1, sizeof(wrkrInstanceData_t))) == NULL) { \
*ppWrkrData = NULL; \
return RS_RET_OUT_OF_MEMORY; \
} \
pWrkrData->pData = pData;
#define ENDcreateWrkrInstance \
*ppWrkrData = pWrkrData; \
RETiRet; \
}
/* freeWrkrInstance */
#define BEGINfreeWrkrInstance \
static rsRetVal freeWrkrInstance(void *pd) { \
DEFiRet; \
wrkrInstanceData_t *pWrkrData;
#define CODESTARTfreeWrkrInstance pWrkrData = (wrkrInstanceData_t *)pd;
#define ENDfreeWrkrInstance \
if (pWrkrData != NULL) free(pWrkrData); /* we need to free this in any case */ \
RETiRet; \
}
/* isCompatibleWithFeature()
*/
#define BEGINisCompatibleWithFeature \
static rsRetVal isCompatibleWithFeature(syslogFeature __attribute__((unused)) eFeat) { \
rsRetVal iRet = RS_RET_INCOMPATIBLE;
#define CODESTARTisCompatibleWithFeature
#define ENDisCompatibleWithFeature \
RETiRet; \
}
/* beginTransaction()
* introduced in v4.3.3 -- rgerhards, 2009-04-27
*/
#define BEGINbeginTransaction \
static rsRetVal beginTransaction(wrkrInstanceData_t __attribute__((unused)) * pWrkrData) { \
DEFiRet;
#define CODESTARTbeginTransaction /* currently empty, but may be extended */
#define ENDbeginTransaction \
RETiRet; \
}
/* commitTransaction()
* Commits a transaction. Note that beginTransaction() must have been
* called before this entry point. It receives the full batch of messages
* to be processed in pParam parameter.
* introduced in v8.1.3 -- rgerhards, 2013-12-04
*/
#define BEGINcommitTransaction \
static rsRetVal commitTransaction(wrkrInstanceData_t __attribute__((unused)) *const pWrkrData, \
actWrkrIParams_t *const pParams, const unsigned nParams) { \
DEFiRet;
#define CODESTARTcommitTransaction /* currently empty, but may be extended */
#define ENDcommitTransaction \
RETiRet; \
}
/* endTransaction()
* introduced in v4.3.3 -- rgerhards, 2009-04-27
*/
#define BEGINendTransaction \
static rsRetVal endTransaction(wrkrInstanceData_t __attribute__((unused)) * pWrkrData) { \
DEFiRet;
#define CODESTARTendTransaction /* currently empty, but may be extended */
#define ENDendTransaction \
RETiRet; \
}
/* doAction()
*/
#define BEGINdoAction \
static rsRetVal doAction(void *pMsgData, wrkrInstanceData_t __attribute__((unused)) * pWrkrData) { \
uchar **ppString = (uchar **)pMsgData; \
DEFiRet;
#define CODESTARTdoAction /* ppString may be NULL if the output module requested no strings */
#define ENDdoAction \
RETiRet; \
}
/* below is a variant of doAction where the passed-in data is not the common
* case of string.
*/
#define BEGINdoAction_NoStrings \
static rsRetVal doAction(void *pMsgData, wrkrInstanceData_t __attribute__((unused)) * pWrkrData) { \
DEFiRet;
/* dbgPrintInstInfo()
* Extra comments:
* Print debug information about this instance.
*/
#define BEGINdbgPrintInstInfo \
static rsRetVal dbgPrintInstInfo(void *pModData) { \
DEFiRet; \
instanceData *pData = NULL;
#define CODESTARTdbgPrintInstInfo \
pData = (instanceData *)pModData; \
(void)pData; /* prevent compiler warning if unused! */
#define ENDdbgPrintInstInfo \
RETiRet; \
}
/* parseSelectorAct()
* Extra comments:
* try to process a selector action line. Checks if the action
* applies to this module and, if so, processed it. If not, it
* is left untouched. The driver will then call another module.
* 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 CODESTARTparseSelectorAct.
*/
#define BEGINparseSelectorAct \
static rsRetVal parseSelectorAct(uchar **pp, void **ppModData, omodStringRequest_t **ppOMSR) { \
DEFiRet; \
uchar *p; \
instanceData *pData = NULL;
#define CODESTARTparseSelectorAct \
assert(pp != NULL); \
assert(ppModData != NULL); \
assert(ppOMSR != NULL); \
p = *pp;
#define CODE_STD_STRING_REQUESTparseSelectorAct(NumStrReqEntries) CHKiRet(OMSRconstruct(ppOMSR, NumStrReqEntries));
#define CODE_STD_FINALIZERparseSelectorAct \
finalize_it : ATTR_UNUSED; /* semi-colon needed according to gcc doc! */ \
if (iRet == RS_RET_OK || iRet == RS_RET_OK_WARN || iRet == RS_RET_SUSPENDED) { \
*ppModData = pData; \
*pp = p; \
} else { \
/* cleanup, we failed */ \
if (*ppOMSR != NULL) { \
OMSRdestruct(*ppOMSR); \
*ppOMSR = NULL; \
} \
if (pData != NULL) { \
freeInstance(pData); \
} \
}
#define ENDparseSelectorAct \
RETiRet; \
}
/* a special replacement macro for modules that do not support legacy config at all */
#define NO_LEGACY_CONF_parseSelectorAct \
static rsRetVal parseSelectorAct(uchar **pp ATTR_UNUSED, void **ppModData ATTR_UNUSED, \
omodStringRequest_t **ppOMSR ATTR_UNUSED) { \
return RS_RET_LEGA_ACT_NOT_SUPPORTED; \
}
/* 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(uchar __attribute__((unused)) * modName, struct nvlst __attribute__((unused)) * lst, \
void **ppModData, omodStringRequest_t **ppOMSR) { \
DEFiRet; \
instanceData *pData = NULL; \
*ppOMSR = 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; \
}
/* newInpInst()
* This is basically the equivalent to newActInst() for creating input
* module (listener) instances.
*/
#define BEGINnewInpInst \
static rsRetVal newInpInst(struct nvlst *lst) { \
DEFiRet;
#define CODESTARTnewInpInst
#define CODE_STD_FINALIZERnewInpInst
#define ENDnewInpInst \
RETiRet; \
}
/* newParserInst()
* This is basically the equivalent to newActInst() for creating parser
* module (listener) instances.
*/
#define BEGINnewParserInst \
static rsRetVal newParserInst(struct nvlst *lst, void *pinst) { \
instanceConf_t *inst; \
DEFiRet;
#define CODESTARTnewParserInst
#define CODE_STD_FINALIZERnewParserInst
#define ENDnewParserInst \
if (iRet == RS_RET_OK) *((instanceConf_t **)pinst) = inst; \
RETiRet; \
}
/* freeParserInst */
#define BEGINfreeParserInst \
static rsRetVal freeParserInst(void *pi) { \
DEFiRet; \
instanceConf_t *pInst;
#define CODESTARTfreeParserInst pInst = (instanceConf_t *)pi;
#define ENDfreeParserInst \
if (pInst != NULL) free(pInst); \
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,
* 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
*/
#define BEGINtryResume \
static rsRetVal tryResume(wrkrInstanceData_t __attribute__((unused)) * pWrkrData) { \
DEFiRet;
#define CODESTARTtryResume assert(pWrkrData != NULL);
#define ENDtryResume \
RETiRet; \
}
/* initConfVars() - initialize pre-v6.3-config variables
*/
#define BEGINinitConfVars \
static rsRetVal initConfVars(void) { \
DEFiRet;
#define CODESTARTinitConfVars
#define ENDinitConfVars \
RETiRet; \
}
/* queryEtryPt()
*/
#define BEGINqueryEtryPt \
DEFmodGetID static rsRetVal queryEtryPt(uchar *name, rsRetVal (**pEtryPoint)()) { \
DEFiRet;
#define CODESTARTqueryEtryPt \
if ((name == NULL) || (pEtryPoint == NULL)) { \
return RS_RET_PARAM_ERROR; \
} \
*pEtryPoint = NULL;
#define ENDqueryEtryPt \
if (iRet == RS_RET_OK) \
if (*pEtryPoint == NULL) { \
dbgprintf("entry point '%s' not present in module\n", name); \
iRet = RS_RET_MODULE_ENTRY_POINT_NOT_FOUND; \
} \
RETiRet; \
}
/** \addtogroup module_entrypoint_blocks
* \{
* \brief Standard queryEtryPt block for all module types.
*
* Must be included in every module. This defines default queries
* like `modExit`, `modGetID`, etc.
*/
#define CODEqueryEtryPt_STD_MOD_QUERIES \
if (!strcmp((char *)name, "modExit")) { \
*pEtryPoint = modExit; \
} \
if (!strcmp((char *)name, "modGetID")) { \
*pEtryPoint = modGetID; \
} \
if (!strcmp((char *)name, "getType")) { \
*pEtryPoint = modGetType; \
} \
if (!strcmp((char *)name, "getKeepType")) { \
*pEtryPoint = modGetKeepType; \
}
/**
* \brief Standard block for output modules without transaction support.
*/
#define CODEqueryEtryPt_STD_OMOD_QUERIES \
CODEqueryEtryPt_STD_MOD_QUERIES if (!strcmp((char *)name, "doAction")) { \
*pEtryPoint = doAction; \
} \
if (!strcmp((char *)name, "dbgPrintInstInfo")) { \
*pEtryPoint = dbgPrintInstInfo; \
} \
if (!strcmp((char *)name, "freeInstance")) { \
*pEtryPoint = freeInstance; \
} \
if (!strcmp((char *)name, "parseSelectorAct")) { \
*pEtryPoint = parseSelectorAct; \
} \
if (!strcmp((char *)name, "isCompatibleWithFeature")) { \
*pEtryPoint = isCompatibleWithFeature; \
} \
if (!strcmp((char *)name, "tryResume")) { \
*pEtryPoint = tryResume; \
}
/**
* \brief Standard block for output modules using the transaction interface.
*/
#define CODEqueryEtryPt_STD_OMODTX_QUERIES \
CODEqueryEtryPt_STD_MOD_QUERIES if (!strcmp((char *)name, "beginTransaction")) { \
*pEtryPoint = beginTransaction; \
} \
if (!strcmp((char *)name, "commitTransaction")) { \
*pEtryPoint = commitTransaction; \
} \
if (!strcmp((char *)name, "dbgPrintInstInfo")) { \
*pEtryPoint = dbgPrintInstInfo; \
} \
if (!strcmp((char *)name, "freeInstance")) { \
*pEtryPoint = freeInstance; \
} \
if (!strcmp((char *)name, "parseSelectorAct")) { \
*pEtryPoint = parseSelectorAct; \
} \
if (!strcmp((char *)name, "isCompatibleWithFeature")) { \
*pEtryPoint = isCompatibleWithFeature; \
} \
if (!strcmp((char *)name, "tryResume")) { \
*pEtryPoint = tryResume; \
}
/**
* \brief Additional methods for output module v8+ support.
*/
#define CODEqueryEtryPt_STD_OMOD8_QUERIES \
if (!strcmp((char *)name, "createWrkrInstance")) { \
*pEtryPoint = createWrkrInstance; \
} \
if (!strcmp((char *)name, "freeWrkrInstance")) { \
*pEtryPoint = freeWrkrInstance; \
}
/**
* \brief For output modules with transaction interface extension.
*/
#define CODEqueryEtryPt_TXIF_OMOD_QUERIES \
if (!strcmp((char *)name, "beginTransaction")) { \
*pEtryPoint = beginTransaction; \
} \
if (!strcmp((char *)name, "endTransaction")) { \
*pEtryPoint = endTransaction; \
}
/**
* \brief Optional support for feature compatibility query.
*/
#define CODEqueryEtryPt_IsCompatibleWithFeature_IF_OMOD_QUERIES \
if (!strcmp((char *)name, "isCompatibleWithFeature")) { \
*pEtryPoint = isCompatibleWithFeature; \
}
/**
* \brief Standard block for input modules.
*/
#define CODEqueryEtryPt_STD_IMOD_QUERIES \
CODEqueryEtryPt_STD_MOD_QUERIES if (!strcmp((char *)name, "runInput")) { \
*pEtryPoint = runInput; \
} \
if (!strcmp((char *)name, "willRun")) { \
*pEtryPoint = willRun; \
} \
if (!strcmp((char *)name, "afterRun")) { \
*pEtryPoint = afterRun; \
}
/**
* \brief For modules using the config interface v2.
*/
#define CODEqueryEtryPt_STD_CONF2_QUERIES \
if (!strcmp((char *)name, "beginCnfLoad")) { \
*pEtryPoint = beginCnfLoad; \
} \
if (!strcmp((char *)name, "endCnfLoad")) { \
*pEtryPoint = endCnfLoad; \
} \
if (!strcmp((char *)name, "checkCnf")) { \
*pEtryPoint = checkCnf; \
} \
if (!strcmp((char *)name, "activateCnf")) { \
*pEtryPoint = activateCnf; \
} \
if (!strcmp((char *)name, "freeCnf")) { \
*pEtryPoint = freeCnf; \
} \
CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES
#define CODEqueryEtryPt_STD_CONF2_setModCnf_QUERIES \
if (!strcmp((char *)name, "setModCnf")) { \
*pEtryPoint = setModCnf; \
}
#define CODEqueryEtryPt_STD_CONF2_OMOD_QUERIES \
if (!strcmp((char *)name, "newActInst")) { \
*pEtryPoint = newActInst; \
} \
CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES
#define CODEqueryEtryPt_STD_CONF2_IMOD_QUERIES \
if (!strcmp((char *)name, "newInpInst")) { \
*pEtryPoint = newInpInst; \
} \
CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES
#define CODEqueryEtryPt_STD_CONF2_PREPRIVDROP_QUERIES \
if (!strcmp((char *)name, "activateCnfPrePrivDrop")) { \
*pEtryPoint = activateCnfPrePrivDrop; \
}
/**
* \brief Config interface v6 module name support.
*/
#define CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES \
if (!strcmp((char *)name, "getModCnfName")) { \
*pEtryPoint = modGetCnfName; \
}
/**
* \brief Standard block for library modules.
*/
#define CODEqueryEtryPt_STD_LIB_QUERIES CODEqueryEtryPt_STD_MOD_QUERIES
/**
* \brief Standard block for parser modules.
*/
#define CODEqueryEtryPt_STD_PMOD_QUERIES \
CODEqueryEtryPt_STD_MOD_QUERIES if (!strcmp((char *)name, "parse")) { \
*pEtryPoint = parse; \
} \
if (!strcmp((char *)name, "GetParserName")) { \
*pEtryPoint = GetParserName; \
}
/**
* \brief Standard block for parser modules using config v2.
*/
#define CODEqueryEtryPt_STD_PMOD2_QUERIES \
CODEqueryEtryPt_STD_MOD_QUERIES if (!strcmp((char *)name, "parse2")) { \
*pEtryPoint = parse2; \
} \
if (!strcmp((char *)name, "GetParserName")) { \
*pEtryPoint = GetParserName; \
} \
if (!strcmp((char *)name, "newParserInst")) { \
*pEtryPoint = newParserInst; \
} \
if (!strcmp((char *)name, "checkParserInst")) { \
*pEtryPoint = checkParserInst; \
} \
if (!strcmp((char *)name, "freeParserInst")) { \
*pEtryPoint = freeParserInst; \
} \
CODEqueryEtryPt_STD_CONF2_CNFNAME_QUERIES
/**
* \brief Standard block for rscript function modules.
*/
#define CODEqueryEtryPt_STD_FMOD_QUERIES \
CODEqueryEtryPt_STD_MOD_QUERIES if (!strcmp((char *)name, "getFunctArray")) { \
*pEtryPoint = getFunctArray; \
}
/**
* \brief Standard block for strgen modules.
*/
#define CODEqueryEtryPt_STD_SMOD_QUERIES \
CODEqueryEtryPt_STD_MOD_QUERIES if (!strcmp((char *)name, "strgen")) { \
*pEtryPoint = strgen; \
} \
if (!strcmp((char *)name, "GetName")) { \
*pEtryPoint = GetStrgenName; \
}
/** \} */ // end of module_entrypoint_blocks
/* modInit()
* This has an extra parameter, which is the specific name of the modInit
* function. That is needed for built-in modules, which must have unique
* names in order to link statically. Please note that this is always only
* the case with modInit() and NO other entry point. The reason is that only
* modInit() is visible form a linker/loader point of view. All other entry
* points are passed via rsyslog-internal query functions and are defined
* static inside the modules source. This is an important concept, as it allows
* us to support different interface versions within a single module. (Granted,
* we do not currently have different interface versions, so we can not put
* it to a test - but our firm believe is that we can do all abstraction needed...)
*
* Extra Comments:
* initialize the module
*
* Later, much more must be done. So far, we only return a pointer
* to the queryEtryPt() function
* TODO: do interface version checking & handshaking
* iIfVersRequetsed is the version of the interface specification that the
* caller would like to see being used. ipIFVersProvided is what we
* decide to provide.
* rgerhards, 2007-11-21: see modExit() comment below for important information
* on the need to initialize static data with code. modInit() may be called on a
* cached, left-in-memory copy of a previous incarnation.
*/
#define BEGINmodInit(uniqName) \
rsRetVal __attribute__((unused)) modInit##uniqName( \
int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), \
rsRetVal (*pHostQueryEtryPt)(uchar *, rsRetVal(**)()), modInfo_t __attribute__((unused)) * pModInfo); \
rsRetVal __attribute__((unused)) modInit##uniqName( \
int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), \
rsRetVal (*pHostQueryEtryPt)(uchar *, rsRetVal(**)()), modInfo_t __attribute__((unused)) * pModInfo) { \
DEFiRet; \
rsRetVal (*pObjGetObjInterface)(obj_if_t * pIf);
#define CODESTARTmodInit \
assert(pHostQueryEtryPt != NULL); \
iRet = pHostQueryEtryPt((uchar *)"objGetObjInterface", &pObjGetObjInterface); \
if ((iRet != RS_RET_OK) || (pQueryEtryPt == NULL) || (ipIFVersProvided == NULL) || \
(pObjGetObjInterface == NULL)) { \
return (iRet == RS_RET_OK) ? RS_RET_PARAM_ERROR : iRet; \
} \
/* now get the obj interface so that we can access other objects */ \
CHKiRet(pObjGetObjInterface(&obj))
/* do those initializations necessary for legacy config variables */
#define INITLegCnfVars initConfVars()
#define ENDmodInit \
finalize_it : *pQueryEtryPt = queryEtryPt; \
RETiRet; \
}
/* now come some check functions, which enable a standard way of obtaining feature
* information from the core. feat is the to-be-tested feature and featVar is a
* variable that receives the result (0-not support, 1-supported).
* This must be a macro, so that it is put into the output's code. Otherwise, we
* would need to rely on a library entry point, which is what we intend to avoid ;)
* rgerhards, 2009-04-27
*/
#define INITChkCoreFeature(featVar, feat) \
{ \
rsRetVal MACRO_Ret; \
rsRetVal (*pQueryCoreFeatureSupport)(int *, unsigned); \
int bSupportsIt; \
featVar = 0; \
MACRO_Ret = pHostQueryEtryPt((uchar *)"queryCoreFeatureSupport", &pQueryCoreFeatureSupport); \
if (MACRO_Ret == RS_RET_OK) { \
/* found entry point, so let's see if core supports it */ \
CHKiRet((*pQueryCoreFeatureSupport)(&bSupportsIt, feat)); \
if (bSupportsIt) featVar = 1; \
} else if (MACRO_Ret != RS_RET_ENTRY_POINT_NOT_FOUND) { \
ABORT_FINALIZE(MACRO_Ret); /* Something else went wrong, what is not acceptable */ \
} \
}
/* definitions for host API queries */
#define CODEmodInit_QueryRegCFSLineHdlr CHKiRet(pHostQueryEtryPt((uchar *)"regCfSysLineHdlr", &omsdRegCFSLineHdlr));
/* modExit()
* This is the counterpart to modInit(). It destroys a module and makes it ready for
* unloading. It is similiar to freeInstance() for the instance data. Please note that
* this entry point needs to free any module-global data structures and registrations.
* For example, the CfSysLineHandlers a module has registered need to be unregistered
* here. This entry point is only called immediately before unloading of the module. So
* it is likely to be destroyed. HOWEVER, the caller may decide to keep the module cached.
* So a module must never assume that it is actually destroyed. A call to modInit() may
* happen immediately after modExit(). So a module can NOT assume that static data elements
* are being re-initialized by the loader - this must always be done by module code itself.
* It is suggested to do this in modInit(). - rgerhards, 2007-11-21
*/
#define BEGINmodExit \
static rsRetVal modExit(void) { \
DEFiRet;
#define CODESTARTmodExit
#define ENDmodExit \
RETiRet; \
}
/* 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, __attribute__((unused)) rsconf_t *pConf) { \
modConfData_t *pModConf; \
DEFiRet;
#define CODESTARTbeginCnfLoad \
if ((pModConf = calloc(1, sizeof(modConfData_t))) == NULL) { \
*ptr = NULL; \
return RS_RET_OUT_OF_MEMORY; \
}
#define ENDbeginCnfLoad \
*ptr = pModConf; \
RETiRet; \
}
/* setModCnf()
* This function permits to set module global parameters via the v2 config
* interface. It may be called multiple times, but parameters must not be
* set in a conflicting way. The module must use its current config load
* context when processing the directives.
* Note that lst may be NULL, especially if the module is loaded via the
* legacy config system. The module must check for this.
* NOTE: This entry point must only be implemented if module global
* parameters are actually required.
*/
#define BEGINsetModCnf \
static rsRetVal setModCnf(struct nvlst *lst) { \
DEFiRet;
#define CODESTARTsetModCnf
#define ENDsetModCnf \
RETiRet; \
}
/* endCnfLoad()
* This is a function tells an input module that the current config load ended.
* It gets a last chance to make changes to its in-memory config object. After
* 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 __attribute__((unused)) *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 __attribute__((unused)) *pModConf = (modConfData_t *)ptr; \
DEFiRet;
#define CODESTARTcheckCnf
#define ENDcheckCnf \
RETiRet; \
}
/* checkParserInst() - verifies a parser instance configuration */
#define BEGINcheckParserInst \
static rsRetVal checkParserInst(void *const ptr) { \
instanceConf_t __attribute__((unused)) *pInst = (instanceConf_t *)ptr; \
DEFiRet;
#define CODESTARTcheckParserInst
#define ENDcheckParserInst \
RETiRet; \
}
/* 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.
* rgerhards, 2011-05-03
*/
#define BEGINactivateCnf \
static rsRetVal activateCnf(modConfData_t *ptr) { \
modConfData_t __attribute__((unused)) *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
* thread. This is handled by the rsyslog engine. It needs to spawn off new threads only
* if there is a module-internal need to do so.
*/
#define BEGINrunInput \
static rsRetVal runInput(thrdInfo_t __attribute__((unused)) * pThrd) { \
DEFiRet;
#define CODESTARTrunInput dbgSetThrdName((uchar *)__FILE__); /* we need to provide something better later */
#define ENDrunInput \
RETiRet; \
}
/* willRun()
* This is a function that will be replaced in the longer term. It is used so
* that a module can tell the caller if it will run or not. This is to be replaced
* when we introduce input module instances. However, these require config syntax
* changes and I may (or may not... ;)) hold that until another config file
* format is available. -- rgerhards, 2007-12-17
* returns RS_RET_NO_RUN if it will not run (RS_RET_OK or error otherwise)
*/
#define BEGINwillRun \
static rsRetVal willRun(void) { \
DEFiRet;
#define CODESTARTwillRun
#define ENDwillRun \
RETiRet; \
}
/* afterRun()
* This function is called after an input module has been run and its thread has
* been terminated. It shall do any necessary cleanup.
* This is expected to evolve into a freeInstance type of call once the input module
* interface evolves to support multiple instances.
* rgerhards, 2007-12-17
*/
#define BEGINafterRun \
static rsRetVal afterRun(void) { \
DEFiRet;
#define CODESTARTafterRun
#define ENDafterRun \
RETiRet; \
}
/* doHUP()
* This function is optional. Currently, it is available to output plugins
* only, but may be made available to other types of plugins in the future.
* A plugin does not need to define this entry point. If if does, it gets
* called when a HUP at the action level is to be done. A plugin should register
* this function so that it can close files, connection or other ressources
* on HUP - if it can be assume the user wanted to do this as a part of HUP
* processing. Note that the name "HUP" has historical reasons, it stems back
* to the infamous SIGHUP which was sent to restart a syslogd. We still retain
* that legacy, but may move this to a different signal.
* rgerhards, 2008-10-22
*/
#define CODEqueryEtryPt_doHUP \
if (!strcmp((char *)name, "doHUP")) { \
*pEtryPoint = doHUP; \
}
#define BEGINdoHUP \
static rsRetVal doHUP(instanceData __attribute__((unused)) * pData) { \
DEFiRet;
#define CODESTARTdoHUP
#define ENDdoHUP \
RETiRet; \
}
/* doHUPParser()
*/
#define CODEqueryEtryPt_doHUPParser \
if (!strcmp((char *)name, "doHUP")) { \
*pEtryPoint = doHUP; \
}
#define BEGINdoHUPParser \
static rsRetVal doHUP(instanceConf_t __attribute__((unused)) * pData) { \
DEFiRet;
#define CODESTARTdoHUPParser
#define ENDdoHUPParser \
RETiRet; \
}
/* doHUPWrkr()
* This is like doHUP(), but on an action worker level.
* rgerhards, 2015-03-25
*/
#define CODEqueryEtryPt_doHUPWrkr \
if (!strcmp((char *)name, "doHUPWrkr")) { \
*pEtryPoint = doHUPWrkr; \
}
#define BEGINdoHUPWrkr \
static rsRetVal doHUPWrkr(wrkrInstanceData_t __attribute__((unused)) * pWrkrData) { \
DEFiRet;
#define CODESTARTdoHUPWrkr
#define ENDdoHUPWrkr \
RETiRet; \
}
/* SetShutdownImmdtPtr()
* This function is optional. If defined by an output plugin, it is called
* each time the action is invoked to set the "ShutdownImmediate" pointer,
* which is used during termination to indicate the action should shutdown
* as quickly as possible.
*/
#define CODEqueryEtryPt_SetShutdownImmdtPtr \
else if (!strcmp((char *)name, "SetShutdownImmdtPtr")) { \
*pEtryPoint = SetShutdownImmdtPtr; \
}
#define BEGINSetShutdownImmdtPtr \
static rsRetVal SetShutdownImmdtPtr(instanceData __attribute__((unused)) * pData, int *pPtr) { \
DEFiRet;
#define CODESTARTSetShutdownImmdtPtr
#define ENDSetShutdownImmdtPtr \
RETiRet; \
}
/* parse() - main entry point of parser modules (v1 config interface)
*/
#define BEGINparse \
static rsRetVal parse(smsg_t *pMsg) { \
DEFiRet;
#define CODESTARTparse assert(pMsg != NULL);
#define ENDparse \
RETiRet; \
}
/* parse2() - main entry point of parser modules (v2+ config interface)
*/
#define BEGINparse2 \
static rsRetVal parse2(instanceConf_t *const pInst, smsg_t *pMsg) { \
DEFiRet;
#define CODESTARTparse2 \
assert(pInst != NULL); \
assert(pMsg != NULL);
#define ENDparse2 \
RETiRet; \
}
/* strgen() - main entry point of parser modules
* Note that we do NOT use size_t as this permits us to store the
* values directly into optimized heap structures.
* ppBuf is the buffer pointer
* pLenBuf is the current max size of this buffer
* pStrLen is an output parameter that MUST hold the length
* of the generated string on exit (this is cached)
*/
#define BEGINstrgen \
static rsRetVal strgen(smsg_t *const pMsg, actWrkrIParams_t *const iparam) { \
DEFiRet;
#define CODESTARTstrgen assert(pMsg != NULL);
#define ENDstrgen \
RETiRet; \
}
/* getFunctArray() - main entry point of parser modules
* Note that we do NOT use size_t as this permits us to store the
* values directly into optimized heap structures.
* ppBuf is the buffer pointer
* pLenBuf is the current max size of this buffer
* pStrLen is an output parameter that MUST hold the length
* of the generated string on exit (this is cached)
*/
#define BEGINgetFunctArray \
static rsRetVal getFunctArray(int *const version, const struct scriptFunct **const functArray) { \
DEFiRet;
#define CODESTARTgetFunctArray
#define ENDgetFunctArray \
RETiRet; \
}
/* function to specify the parser name. This is done via a single command which
* receives a ANSI string as parameter.
*/
#define PARSER_NAME(x) \
static rsRetVal GetParserName(uchar **ppSz) { \
*ppSz = UCHAR_CONSTANT(x); \
return RS_RET_OK; \
}
/* function to specify the strgen name. This is done via a single command which
* receives a ANSI string as parameter.
*/
#define STRGEN_NAME(x) \
static rsRetVal GetStrgenName(uchar **ppSz) { \
*ppSz = UCHAR_CONSTANT(x); \
return RS_RET_OK; \
}
#endif /* #ifndef MODULE_TEMPLATE_H_INCLUDED */