mirror of
https://github.com/rsyslog/rsyslog.git
synced 2025-12-21 20:40:42 +01:00
418 lines
13 KiB
C
418 lines
13 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 Rainer Gerhards and Adiscon GmbH.
|
|
*
|
|
* This file is part of rsyslog.
|
|
*
|
|
* Rsyslog is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Rsyslog is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Rsyslog. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
* A copy of the GPL can be found in the file "COPYING" in this distribution.
|
|
*/
|
|
#ifndef MODULE_TEMPLATE_H_INCLUDED
|
|
#define MODULE_TEMPLATE_H_INCLUDED 1
|
|
|
|
#include "objomsr.h"
|
|
|
|
/* macro to define standard output-module static data members
|
|
*/
|
|
#define DEF_OMOD_STATIC_DATA \
|
|
static rsRetVal (*omsdRegCFSLineHdlr)();
|
|
|
|
/* 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;\
|
|
}
|
|
|
|
/* 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;\
|
|
return iRet;\
|
|
}
|
|
|
|
/* 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 */\
|
|
return iRet;\
|
|
}
|
|
|
|
/* isCompatibleWithFeature()
|
|
*/
|
|
#define BEGINisCompatibleWithFeature \
|
|
static rsRetVal isCompatibleWithFeature(syslogFeature __attribute__((unused)) eFeat)\
|
|
{\
|
|
rsRetVal iRet = RS_RET_INCOMPATIBLE;
|
|
|
|
#define CODESTARTisCompatibleWithFeature
|
|
|
|
#define ENDisCompatibleWithFeature \
|
|
return iRet;\
|
|
}
|
|
|
|
/* doAction()
|
|
*/
|
|
#define BEGINdoAction \
|
|
static rsRetVal doAction(uchar __attribute__((unused)) **ppString, unsigned __attribute__((unused)) iMsgOpts, instanceData __attribute__((unused)) *pData)\
|
|
{\
|
|
DEFiRet;
|
|
|
|
#define CODESTARTdoAction \
|
|
/* ppString may be NULL if the output module requested no strings */
|
|
|
|
#define ENDdoAction \
|
|
return iRet;\
|
|
}
|
|
|
|
|
|
/* 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;
|
|
|
|
#define ENDdbgPrintInstInfo \
|
|
return iRet;\
|
|
}
|
|
|
|
|
|
/* needUDPSocket()
|
|
* Talks back to syslogd if the global UDP syslog socket is needed for
|
|
* sending. Returns 0 if not, 1 if needed. This interface hopefully goes
|
|
* away at some time, because it is kind of a hack. However, currently
|
|
* there is no way around it, so we need to support it.
|
|
* rgerhards, 2007-07-26
|
|
*/
|
|
#define BEGINneedUDPSocket \
|
|
static rsRetVal needUDPSocket(void *pModData)\
|
|
{\
|
|
rsRetVal iRet = RS_RET_FALSE;\
|
|
instanceData *pData = NULL;
|
|
|
|
#define CODESTARTneedUDPSocket \
|
|
pData = (instanceData*) pModData;
|
|
|
|
#define ENDneedUDPSocket \
|
|
return iRet;\
|
|
}
|
|
|
|
|
|
/* onSelectReadyWrite()
|
|
* Extra comments:
|
|
* This is called when select() returned with a writable file descriptor
|
|
* for this module. The fd was most probably obtained by getWriteFDForSelect()
|
|
* before.
|
|
*/
|
|
#define BEGINonSelectReadyWrite \
|
|
static rsRetVal onSelectReadyWrite(void *pModData)\
|
|
{\
|
|
rsRetVal iRet = RS_RET_NONE;\
|
|
instanceData *pData = NULL;
|
|
|
|
#define CODESTARTonSelectReadyWrite \
|
|
pData = (instanceData*) pModData;
|
|
|
|
#define ENDonSelectReadyWrite \
|
|
return iRet;\
|
|
}
|
|
|
|
|
|
/* getWriteFDForSelect()
|
|
* Extra comments:
|
|
* Gets writefd for select call. Must only be returned when the selector must
|
|
* be written to. If the module has no such fds, it must return RS_RET_NONE.
|
|
* In this case, the default implementation is sufficient.
|
|
* This interface will probably go away over time, but we need it now to
|
|
* continue modularization.
|
|
*/
|
|
#define BEGINgetWriteFDForSelect \
|
|
static rsRetVal getWriteFDForSelect(void *pModData, short __attribute__((unused)) *fd)\
|
|
{\
|
|
rsRetVal iRet = RS_RET_NONE;\
|
|
instanceData *pData = NULL;
|
|
|
|
#define CODESTARTgetWriteFDForSelect \
|
|
assert(fd != NULL);\
|
|
pData = (instanceData*) pModData;
|
|
|
|
#define ENDgetWriteFDForSelect \
|
|
return iRet;\
|
|
}
|
|
|
|
|
|
/* 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:\
|
|
if(iRet == RS_RET_OK || 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 \
|
|
return iRet;\
|
|
}
|
|
|
|
|
|
/* 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(instanceData __attribute__((unused)) *pData)\
|
|
{\
|
|
DEFiRet;
|
|
|
|
#define CODESTARTtryResume \
|
|
assert(pData != NULL);
|
|
|
|
#define ENDtryResume \
|
|
return iRet;\
|
|
}
|
|
|
|
|
|
|
|
/* 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)\
|
|
iRet = (*pEtryPoint == NULL) ? RS_RET_NOT_FOUND : RS_RET_OK;\
|
|
return iRet;\
|
|
}
|
|
|
|
/* the following definition is the standard block for queryEtryPt for output
|
|
* modules. This can be used if no specific handling (e.g. to cover version
|
|
* differences) is needed.
|
|
*/
|
|
#define CODEqueryEtryPt_STD_OMOD_QUERIES \
|
|
if(!strcmp((char*) name, "doAction")) {\
|
|
*pEtryPoint = doAction;\
|
|
} else if(!strcmp((char*) name, "parseSelectorAct")) {\
|
|
*pEtryPoint = parseSelectorAct;\
|
|
} else if(!strcmp((char*) name, "isCompatibleWithFeature")) {\
|
|
*pEtryPoint = isCompatibleWithFeature;\
|
|
} else if(!strcmp((char*) name, "dbgPrintInstInfo")) {\
|
|
*pEtryPoint = dbgPrintInstInfo;\
|
|
} else if(!strcmp((char*) name, "freeInstance")) {\
|
|
*pEtryPoint = freeInstance;\
|
|
} else if(!strcmp((char*) name, "modExit")) {\
|
|
*pEtryPoint = modExit;\
|
|
} else if(!strcmp((char*) name, "getWriteFDForSelect")) {\
|
|
*pEtryPoint = getWriteFDForSelect;\
|
|
} else if(!strcmp((char*) name, "onSelectReadyWrite")) {\
|
|
*pEtryPoint = onSelectReadyWrite;\
|
|
} else if(!strcmp((char*) name, "needUDPSocket")) {\
|
|
*pEtryPoint = needUDPSocket;\
|
|
} else if(!strcmp((char*) name, "tryResume")) {\
|
|
*pEtryPoint = tryResume;\
|
|
} else if(!strcmp((char*) name, "modGetID")) {\
|
|
*pEtryPoint = modGetID;\
|
|
}
|
|
|
|
|
|
/* 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 alwaysy 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 modInit##uniqName(int iIFVersRequested __attribute__((unused)), int *ipIFVersProvided, rsRetVal (**pQueryEtryPt)(), rsRetVal (*pHostQueryEtryPt)(uchar*, rsRetVal (**)()))\
|
|
{\
|
|
DEFiRet;
|
|
|
|
#define CODESTARTmodInit \
|
|
assert(pHostQueryEtryPt != NULL);\
|
|
if((pQueryEtryPt == NULL) || (ipIFVersProvided == NULL))\
|
|
return RS_RET_PARAM_ERROR;
|
|
|
|
#define ENDmodInit \
|
|
finalize_it:\
|
|
*pQueryEtryPt = queryEtryPt;\
|
|
return iRet;\
|
|
}
|
|
|
|
|
|
/* definitions for host API queries */
|
|
#define CODEmodInit_QueryRegCFSLineHdlr \
|
|
CHKiRet(pHostQueryEtryPt((uchar*)"regCfSysLineHdlr", &omsdRegCFSLineHdlr));
|
|
|
|
#endif /* #ifndef MODULE_TEMPLATE_H_INCLUDED */
|
|
|
|
/* modExit()
|
|
* This is the counterpart to modInit(). It destroys a module and makes it ready for
|
|
* unloading. It is similiar to freeInstance() for the instance data. Please note that
|
|
* this entry point needs to free any module-globale 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 \
|
|
return iRet;\
|
|
}
|
|
|
|
/*
|
|
* vi:set ai:
|
|
*/
|