From 8f8f65abb66d1a7839c30c2d1b4b4d653a8990cc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 16 Apr 2008 10:26:54 +0200 Subject: moved files to the runtime there are still some files left which could go into the runtime, but I think we will delete most of them once we are done with the full modularization. --- runtime/modules.c | 803 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 803 insertions(+) create mode 100644 runtime/modules.c (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c new file mode 100644 index 00000000..f10390c7 --- /dev/null +++ b/runtime/modules.c @@ -0,0 +1,803 @@ +/* modules.c + * This is the implementation of syslogd modules object. + * This object handles plug-ins and build-in modules of all kind. + * + * Modules are reference-counted. Anyone who access a module must call + * Use() before any function is accessed and Release() when he is done. + * When the reference count reaches 0, rsyslog unloads the module (that + * may be changed in the future to cache modules). Rsyslog does NOT + * unload modules with a reference count > 0, even if the unload + * method is called! + * + * File begun on 2007-07-22 by RGerhards + * + * Copyright 2007 Rainer Gerhards and Adiscon GmbH. + * + * This file is part of the rsyslog runtime library. + * + * The rsyslog runtime library is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * The rsyslog runtime library 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with the rsyslog runtime library. If not, see . + * + * A copy of the GPL can be found in the file "COPYING" in this distribution. + * A copy of the LGPL can be found in the file "COPYING.LESSER" in this distribution. + */ +#include "config.h" +#include "rsyslog.h" +#include +#include +#include +#include +#include +#include +#include +#ifdef OS_BSD +# include "libgen.h" +#endif + +#include /* TODO: replace this with the libtools equivalent! */ + +#include +#include + +#include "syslogd.h" +#include "cfsysline.h" +#include "modules.h" +#include "errmsg.h" + +/* static data */ +DEFobjStaticHelpers +DEFobjCurrIf(errmsg) + +static modInfo_t *pLoadedModules = NULL; /* list of currently-loaded modules */ +static modInfo_t *pLoadedModulesLast = NULL; /* tail-pointer */ + +/* config settings */ +uchar *pModDir = NULL; /* read-only after startup */ + + +#ifdef DEBUG +/* we add some home-grown support to track our users (and detect who does not free us). In + * the long term, this should probably be migrated into debug.c (TODO). -- rgerhards, 2008-03-11 + */ + +/* add a user to the current list of users (always at the root) */ +static void +modUsrAdd(modInfo_t *pThis, char *pszUsr) +{ + modUsr_t *pUsr; + + BEGINfunc + if((pUsr = calloc(1, sizeof(modUsr_t))) == NULL) + goto finalize_it; + + if((pUsr->pszFile = strdup(pszUsr)) == NULL) { + free(pUsr); + goto finalize_it; + } + + if(pThis->pModUsrRoot != NULL) { + pUsr->pNext = pThis->pModUsrRoot; + } + pThis->pModUsrRoot = pUsr; + +finalize_it: + ENDfunc; +} + + +/* remove a user from the current user list + * rgerhards, 2008-03-11 + */ +static void +modUsrDel(modInfo_t *pThis, char *pszUsr) +{ + modUsr_t *pUsr; + modUsr_t *pPrev = NULL; + + for(pUsr = pThis->pModUsrRoot ; pUsr != NULL ; pUsr = pUsr->pNext) { + if(!strcmp(pUsr->pszFile, pszUsr)) + break; + else + pPrev = pUsr; + } + + if(pUsr == NULL) { + dbgprintf("oops - tried to delete user %s from module %s and it wasn't registered as one...\n", + pszUsr, pThis->pszName); + } else { + if(pPrev == NULL) { + /* This was at the root! */ + pThis->pModUsrRoot = pUsr->pNext; + } else { + pPrev->pNext = pUsr->pNext; + } + /* free ressources */ + free(pUsr->pszFile); + free(pUsr); + pUsr = NULL; /* just to make sure... */ + } +} + + +/* print a short list all all source files using the module in question + * rgerhards, 2008-03-11 + */ +static void +modUsrPrint(modInfo_t *pThis) +{ + modUsr_t *pUsr; + + for(pUsr = pThis->pModUsrRoot ; pUsr != NULL ; pUsr = pUsr->pNext) { + dbgprintf("\tmodule %s is currently in use by file %s\n", + pThis->pszName, pUsr->pszFile); + } +} + + +/* print all loaded modules and who is accessing them. This is primarily intended + * to be called at end of run to detect "module leaks" and who is causing them. + * rgerhards, 2008-03-11 + */ +//static void +void +modUsrPrintAll(void) +{ + modInfo_t *pMod; + + BEGINfunc + for(pMod = pLoadedModules ; pMod != NULL ; pMod = pMod->pNext) { + dbgprintf("printing users of loadable module %s, refcount %u, ptr %p, type %d\n", pMod->pszName, pMod->uRefCnt, pMod, pMod->eType); + modUsrPrint(pMod); + } + ENDfunc +} + +#endif /* #ifdef DEBUG */ + + +/* Construct a new module object + */ +static rsRetVal moduleConstruct(modInfo_t **pThis) +{ + modInfo_t *pNew; + + if((pNew = calloc(1, sizeof(modInfo_t))) == NULL) + return RS_RET_OUT_OF_MEMORY; + + /* OK, we got the element, now initialize members that should + * not be zero-filled. + */ + + *pThis = pNew; + return RS_RET_OK; +} + + +/* Destructs a module object. The object must not be linked to the + * linked list of modules. Please note that all other dependencies on this + * modules must have been removed before (e.g. CfSysLineHandlers!) + */ +static void moduleDestruct(modInfo_t *pThis) +{ + assert(pThis != NULL); + if(pThis->pszName != NULL) + free(pThis->pszName); + if(pThis->pModHdlr != NULL) { +# ifdef VALGRIND +# warning "dlclose disabled for valgrind" +# else + dlclose(pThis->pModHdlr); +# endif + } + + free(pThis); +} + + +/* The following function is the queryEntryPoint for host-based entry points. + * Modules may call it to get access to core interface functions. Please note + * that utility functions can be accessed via shared libraries - at least this + * is my current shool of thinking. + * Please note that the implementation as a query interface allows to take + * care of plug-in interface version differences. -- rgerhards, 2007-07-31 + */ +static rsRetVal queryHostEtryPt(uchar *name, rsRetVal (**pEtryPoint)()) +{ + DEFiRet; + + if((name == NULL) || (pEtryPoint == NULL)) + return RS_RET_PARAM_ERROR; + + if(!strcmp((char*) name, "regCfSysLineHdlr")) { + *pEtryPoint = regCfSysLineHdlr; + } else if(!strcmp((char*) name, "objGetObjInterface")) { + *pEtryPoint = objGetObjInterface; + } else { + *pEtryPoint = NULL; /* to be on the safe side */ + ABORT_FINALIZE(RS_RET_ENTRY_POINT_NOT_FOUND); + } + +finalize_it: + RETiRet; +} + + +/* get the name of a module + */ +static uchar *modGetName(modInfo_t *pThis) +{ + return((pThis->pszName == NULL) ? (uchar*) "" : pThis->pszName); +} + + +/* get the state-name of a module. The state name is its name + * together with a short description of the module state (which + * is pulled from the module itself. + * rgerhards, 2007-07-24 + * TODO: the actual state name is not yet pulled + */ +static uchar *modGetStateName(modInfo_t *pThis) +{ + return(modGetName(pThis)); +} + + +/* Add a module to the loaded module linked list + */ +static inline void +addModToList(modInfo_t *pThis) +{ + assert(pThis != NULL); + + if(pLoadedModules == NULL) { + pLoadedModules = pLoadedModulesLast = pThis; + } else { + /* there already exist entries */ + pThis->pPrev = pLoadedModulesLast; + pLoadedModulesLast->pNext = pThis; + pLoadedModulesLast = pThis; + } +} + + +/* Get the next module pointer - this is used to traverse the list. + * The function returns the next pointer or NULL, if there is no next one. + * The last object must be provided to the function. If NULL is provided, + * it starts at the root of the list. Even in this case, NULL may be + * returned - then, the list is empty. + * rgerhards, 2007-07-23 + */ +static modInfo_t *GetNxt(modInfo_t *pThis) +{ + modInfo_t *pNew; + + if(pThis == NULL) + pNew = pLoadedModules; + else + pNew = pThis->pNext; + + return(pNew); +} + + +/* this function is like GetNxt(), but it returns pointers to + * modules of specific type only. As we currently deal just with output modules, + * it is a dummy, to be filled with real code later. + * rgerhards, 2007-07-24 + */ +static modInfo_t *GetNxtType(modInfo_t *pThis, eModType_t rqtdType) +{ + modInfo_t *pMod = pThis; + + do { + pMod = GetNxt(pMod); + } while(!(pMod == NULL || pMod->eType == rqtdType)); /* warning: do ... while() */ + + return pMod; +} + + +/* Prepare a module for unloading. + * This is currently a dummy, to be filled when we have a plug-in + * interface - rgerhards, 2007-08-09 + * rgerhards, 2007-11-21: + * When this function is called, all instance-data must already have + * been destroyed. In the case of output modules, this happens when the + * rule set is being destroyed. When we implement other module types, we + * need to think how we handle it there (and if we have any instance data). + * rgerhards, 2008-03-10: reject unload request if the module has a reference + * count > 0. + */ +static rsRetVal +modPrepareUnload(modInfo_t *pThis) +{ + DEFiRet; + void *pModCookie; + + assert(pThis != NULL); + + if(pThis->uRefCnt > 0) { + dbgprintf("rejecting unload of module '%s' because it has a refcount of %d\n", + pThis->pszName, pThis->uRefCnt); + ABORT_FINALIZE(RS_RET_MODULE_STILL_REFERENCED); + } + + CHKiRet(pThis->modGetID(&pModCookie)); + pThis->modExit(); /* tell the module to get ready for unload */ + CHKiRet(unregCfSysLineHdlrs4Owner(pModCookie)); + +finalize_it: + RETiRet; +} + + +/* Add an already-loaded module to the module linked list. This function does + * everything needed to fully initialize the module. + */ +static rsRetVal +doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_t*), uchar *name, void *pModHdlr) +{ + DEFiRet; + modInfo_t *pNew = NULL; + rsRetVal (*modGetType)(eModType_t *pType); + + assert(modInit != NULL); + + if((iRet = moduleConstruct(&pNew)) != RS_RET_OK) { + pNew = NULL; + ABORT_FINALIZE(iRet); + } + + CHKiRet((*modInit)(CURR_MOD_IF_VERSION, &pNew->iIFVers, &pNew->modQueryEtryPt, queryHostEtryPt, pNew)); + + if(pNew->iIFVers != CURR_MOD_IF_VERSION) { + ABORT_FINALIZE(RS_RET_MISSING_INTERFACE); + } + + /* We now poll the module to see what type it is. We do this only once as this + * can never change in the lifetime of an module. -- rgerhards, 2007-12-14 + */ + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getType", &modGetType)); + CHKiRet((iRet = (*modGetType)(&pNew->eType)) != RS_RET_OK); + dbgprintf("module of type %d being loaded.\n", pNew->eType); + + /* OK, we know we can successfully work with the module. So we now fill the + * rest of the data elements. First we load the interfaces common to all + * module types. + */ + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"modGetID", &pNew->modGetID)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"modExit", &pNew->modExit)); + + /* ... and now the module-specific interfaces */ + switch(pNew->eType) { + case eMOD_IN: + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"runInput", &pNew->mod.im.runInput)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"willRun", &pNew->mod.im.willRun)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"afterRun", &pNew->mod.im.afterRun)); + break; + case eMOD_OUT: + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeInstance", &pNew->freeInstance)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"dbgPrintInstInfo", &pNew->dbgPrintInstInfo)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"doAction", &pNew->mod.om.doAction)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"parseSelectorAct", &pNew->mod.om.parseSelectorAct)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"isCompatibleWithFeature", &pNew->isCompatibleWithFeature)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"tryResume", &pNew->tryResume)); + break; + case eMOD_LIB: + break; + } + + pNew->pszName = (uchar*) strdup((char*)name); /* we do not care if strdup() fails, we can accept that */ + pNew->pModHdlr = pModHdlr; + /* TODO: take this from module */ + if(pModHdlr == NULL) + pNew->eLinkType = eMOD_LINK_STATIC; + else + pNew->eLinkType = eMOD_LINK_DYNAMIC_LOADED; + + /* we initialized the structure, now let's add it to the linked list of modules */ + addModToList(pNew); + +finalize_it: + if(iRet != RS_RET_OK) { + if(pNew != NULL) + moduleDestruct(pNew); + } + + RETiRet; +} + +/* Print loaded modules. This is more or less a + * debug or test aid, but anyhow I think it's worth it... + * This only works if the dbgprintf() subsystem is initialized. + * TODO: update for new input modules! + */ +static void modPrintList(void) +{ + modInfo_t *pMod; + + pMod = GetNxt(NULL); + while(pMod != NULL) { + dbgprintf("Loaded Module: Name='%s', IFVersion=%d, ", + (char*) modGetName(pMod), pMod->iIFVers); + dbgprintf("type="); + switch(pMod->eType) { + case eMOD_OUT: + dbgprintf("output"); + break; + case eMOD_IN: + dbgprintf("input"); + break; + case eMOD_LIB: + dbgprintf("library"); + break; + } + dbgprintf(" module.\n"); + dbgprintf("Entry points:\n"); + dbgprintf("\tqueryEtryPt: 0x%lx\n", (unsigned long) pMod->modQueryEtryPt); + dbgprintf("\tdoAction: 0x%lx\n", (unsigned long) pMod->mod.om.doAction); + dbgprintf("\tparseSelectorAct: 0x%lx\n", (unsigned long) pMod->mod.om.parseSelectorAct); + dbgprintf("\tdbgPrintInstInfo: 0x%lx\n", (unsigned long) pMod->dbgPrintInstInfo); + dbgprintf("\tfreeInstance: 0x%lx\n", (unsigned long) pMod->freeInstance); + dbgprintf("\n"); + pMod = GetNxt(pMod); /* done, go next */ + } +} + + +/* unlink and destroy a module. The caller must provide a pointer to the module + * itself as well as one to its immediate predecessor. + * rgerhards, 2008-02-26 + */ +static rsRetVal +modUnlinkAndDestroy(modInfo_t **ppThis) +{ + DEFiRet; + modInfo_t *pThis; + + assert(ppThis != NULL); + pThis = *ppThis; + assert(pThis != NULL); + + /* first check if we are permitted to unload */ + if(pThis->eType == eMOD_LIB) { + if(pThis->uRefCnt > 0) { + dbgprintf("module %s NOT unloaded because it still has a refcount of %u\n", + pThis->pszName, pThis->uRefCnt); +# ifdef DEBUG + //modUsrPrintAll(); +# endif + ABORT_FINALIZE(RS_RET_MODULE_STILL_REFERENCED); + } + } + + /* we need to unlink the module before we can destruct it -- rgerhards, 2008-02-26 */ + if(pThis->pPrev == NULL) { + /* module is root, so we need to set a new root */ + pLoadedModules = pThis->pNext; + } else { + pThis->pPrev->pNext = pThis->pNext; + } + + if(pThis->pNext == NULL) { + pLoadedModulesLast = pThis->pPrev; + } else { + pThis->pNext->pPrev = pThis->pPrev; + } + + /* finally, we are ready for the module to go away... */ + dbgprintf("Unloading module %s\n", modGetName(pThis)); + CHKiRet(modPrepareUnload(pThis)); + *ppThis = pThis->pNext; + + moduleDestruct(pThis); + +finalize_it: + RETiRet; +} + + +/* unload all loaded modules of a specific type (use eMOD_ALL if you want to + * unload all module types). The unload happens only if the module is no longer + * referenced. So some modules may survive this call. + * rgerhards, 2008-03-11 + */ +static rsRetVal +modUnloadAndDestructAll(eModLinkType_t modLinkTypesToUnload) +{ + DEFiRet; + modInfo_t *pModCurr; /* module currently being processed */ + + pModCurr = GetNxt(NULL); + while(pModCurr != NULL) { + if(modLinkTypesToUnload == eMOD_LINK_ALL || pModCurr->eLinkType == modLinkTypesToUnload) { + if(modUnlinkAndDestroy(&pModCurr) == RS_RET_MODULE_STILL_REFERENCED) { + pModCurr = GetNxt(pModCurr); + } + /* Note: if the module was successfully unloaded, it has updated the + * pModCurr pointer to the next module. So we do NOT need to advance + * to the next module on successful unload. + */ + } else { + pModCurr = GetNxt(pModCurr); + } + } + +# ifdef DEBUG + if(pLoadedModules != NULL) { + dbgprintf("modules still loaded after module.UnloadAndDestructAll:\n"); + modUsrPrintAll(); + } +# endif + + RETiRet; +} + + +/* load a module and initialize it, based on doModLoad() from conf.c + * rgerhards, 2008-03-05 + * varmojfekoj added support for dynamically loadable modules on 2007-08-13 + * rgerhards, 2007-09-25: please note that the non-threadsafe function dlerror() is + * called below. This is ok because modules are currently only loaded during + * configuration file processing, which is executed on a single thread. Should we + * change that design at any stage (what is unlikely), we need to find a + * replacement. + */ +static rsRetVal +Load(uchar *pModName) +{ + DEFiRet; + + size_t iPathLen, iModNameLen; + uchar szPath[PATH_MAX]; + uchar *pModNameCmp; + int bHasExtension; + void *pModHdlr, *pModInit; + modInfo_t *pModInfo; + + assert(pModName != NULL); + dbgprintf("Requested to load module '%s'\n", pModName); + + iModNameLen = strlen((char *) pModName); + if(iModNameLen > 3 && !strcmp((char *) pModName + iModNameLen - 3, ".so")) { + iModNameLen -= 3; + bHasExtension = TRUE; + } else + bHasExtension = FALSE; + + pModInfo = GetNxt(NULL); + while(pModInfo != NULL) { + if(!strncmp((char *) pModName, (char *) (pModNameCmp = modGetName(pModInfo)), iModNameLen) && + (!*(pModNameCmp + iModNameLen) || !strcmp((char *) pModNameCmp + iModNameLen, ".so"))) { + dbgprintf("Module '%s' already loaded\n", pModName); + ABORT_FINALIZE(RS_RET_OK); + } + pModInfo = GetNxt(pModInfo); + } + + /* now build our load module name */ + if(*pModName == '/') { + *szPath = '\0'; /* we do not need to append the path - its already in the module name */ + iPathLen = 0; + } else { + *szPath = '\0'; + strncat((char *) szPath, (pModDir == NULL) ? _PATH_MODDIR : (char*) pModDir, sizeof(szPath) - 1); + iPathLen = strlen((char*) szPath); + if((szPath[iPathLen - 1] != '/')) { + if((iPathLen <= sizeof(szPath) - 2)) { + szPath[iPathLen++] = '/'; + szPath[iPathLen] = '\0'; + } else { + errmsg.LogError(NO_ERRCODE, "could not load module '%s', path too long\n", pModName); + ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); + } + } + } + + /* ... add actual name ... */ + strncat((char *) szPath, (char *) pModName, sizeof(szPath) - iPathLen - 1); + + /* now see if we have an extension and, if not, append ".so" */ + if(!bHasExtension) { + /* we do not have an extension and so need to add ".so" + * TODO: I guess this is highly importable, so we should change the + * algo over time... -- rgerhards, 2008-03-05 + */ + /* ... so now add the extension */ + strncat((char *) szPath, ".so", sizeof(szPath) - strlen((char*) szPath) - 1); + iPathLen += 3; + } + + if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) { + errmsg.LogError(NO_ERRCODE, "could not load module '%s', path too long\n", pModName); + ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); + } + + /* complete load path constructed, so ... GO! */ + dbgprintf("loading module '%s'\n", szPath); + if(!(pModHdlr = dlopen((char *) szPath, RTLD_NOW))) { + errmsg.LogError(NO_ERRCODE, "could not load module '%s', dlopen: %s\n", szPath, dlerror()); + ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_DLOPEN); + } + if(!(pModInit = dlsym(pModHdlr, "modInit"))) { + errmsg.LogError(NO_ERRCODE, "could not load module '%s', dlsym: %s\n", szPath, dlerror()); + dlclose(pModHdlr); + ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_NO_INIT); + } + if((iRet = doModInit(pModInit, (uchar*) pModName, pModHdlr)) != RS_RET_OK) { + errmsg.LogError(NO_ERRCODE, "could not load module '%s', rsyslog error %d\n", szPath, iRet); + dlclose(pModHdlr); + ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_INIT_FAILED); + } + +finalize_it: + RETiRet; +} + + +/* set the default module load directory. A NULL value may be provided, in + * which case any previous value is deleted but no new one set. The caller-provided + * string is duplicated. If it needs to be freed, that's the caller's duty. + * rgerhards, 2008-03-07 + */ +static rsRetVal +SetModDir(uchar *pszModDir) +{ + DEFiRet; + + dbgprintf("setting default module load directory '%s'\n", pszModDir); + if(pModDir != NULL) { + free(pModDir); + } + + pModDir = (uchar*) strdup((char*)pszModDir); + + RETiRet; +} + + +/* Reference-Counting object access: add 1 to the current reference count. Must be + * called by anyone interested in using a module. -- rgerhards, 20080-03-10 + */ +static rsRetVal +Use(char *srcFile, modInfo_t *pThis) +{ + DEFiRet; + + assert(pThis != NULL); + pThis->uRefCnt++; + dbgprintf("source file %s requested reference for module '%s', reference count now %u\n", + srcFile, pThis->pszName, pThis->uRefCnt); + +# ifdef DEBUG + modUsrAdd(pThis, srcFile); +# endif + + RETiRet; + +} + + +/* Reference-Counting object access: subract one from the current refcount. Must + * by called by anyone who no longer needs a module. If count reaches 0, the + * module is unloaded. -- rgerhards, 20080-03-10 + */ +static rsRetVal +Release(char *srcFile, modInfo_t **ppThis) +{ + DEFiRet; + modInfo_t *pThis; + + assert(ppThis != NULL); + pThis = *ppThis; + assert(pThis != NULL); + if(pThis->uRefCnt == 0) { + /* oops, we are already at 0? */ + dbgprintf("internal error: module '%s' already has a refcount of 0 (released by %s)!\n", + pThis->pszName, srcFile); + } else { + --pThis->uRefCnt; + dbgprintf("file %s released module '%s', reference count now %u\n", + srcFile, pThis->pszName, pThis->uRefCnt); +# ifdef DEBUG + modUsrDel(pThis, srcFile); + modUsrPrint(pThis); +# endif + } + + if(pThis->uRefCnt == 0) { + /* we have a zero refcount, so we must unload the module */ + dbgprintf("module '%s' has zero reference count, unloading...\n", pThis->pszName); + modUnlinkAndDestroy(&pThis); + /* we must NOT do a *ppThis = NULL, because ppThis now points into freed memory! + * If in doubt, see obj.c::ReleaseObj() for how we are called. + */ + } + + RETiRet; + +} + + +/* exit our class + * rgerhards, 2008-03-11 + */ +BEGINObjClassExit(module, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MACRO! */ +CODESTARTObjClassExit(module) + /* release objects we no longer need */ + objRelease(errmsg, CORE_COMPONENT); + +# ifdef DEBUG + modUsrPrintAll(); /* debug aid - TODO: integrate with debug.c, at least the settings! */ +# endif +ENDObjClassExit(module) + + +/* queryInterface function + * rgerhards, 2008-03-05 + */ +BEGINobjQueryInterface(module) +CODESTARTobjQueryInterface(module) + if(pIf->ifVersion != moduleCURR_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->GetNxt = GetNxt; + pIf->GetNxtType = GetNxtType; + pIf->GetName = modGetName; + pIf->GetStateName = modGetStateName; + pIf->PrintList = modPrintList; + pIf->UnloadAndDestructAll = modUnloadAndDestructAll; + pIf->doModInit = doModInit; + pIf->SetModDir = SetModDir; + pIf->Load = Load; + pIf->Use = Use; + pIf->Release = Release; +finalize_it: +ENDobjQueryInterface(module) + + +/* Initialize our class. Must be called as the very first method + * before anything else is called inside this class. + * rgerhards, 2008-03-05 + */ +BEGINAbstractObjClassInit(module, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */ + uchar *pModPath; + + /* use any module load path specified in the environment */ + if((pModPath = (uchar*) getenv("RSYSLOG_MODDIR")) != NULL) { + SetModDir(pModPath); + } + + /* now check if another module path was set via the command line (-M) + * if so, that overrides the environment. Please note that we must use + * a global setting here because the command line parser can NOT call + * into the module object, because it is not initialized at that point. So + * instead a global setting is changed and we pick it up as soon as we + * initialize -- rgerhards, 2008-04-04 + */ + if(glblModPath != NULL) { + SetModDir(glblModPath); + } + + /* request objects we use */ + CHKiRet(objUse(errmsg, CORE_COMPONENT)); +ENDObjClassInit(module) + +/* vi:set ai: + */ -- cgit v1.2.3 From d9b0c77d3e719d4c08361e62f3b067228c30f6a9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 16 Apr 2008 15:27:53 +0200 Subject: some more cleanup reduced dependencies, moved non-runtime files to its own directory except for some whom's status is unclear --- runtime/modules.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index f10390c7..8ae9f038 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -49,7 +49,7 @@ #include #include -#include "syslogd.h" +#include "dirty.h" #include "cfsysline.h" #include "modules.h" #include "errmsg.h" -- cgit v1.2.3 From 60309004dfc57c3243abb2f01042950201596773 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 17 Apr 2008 12:46:57 +0200 Subject: completed better modularity of runtime - added the ability to specify an error log function for the runtime - removed dependency of core runtime on dirty.h Note that it is "better" modularity, not perfect. There is still work to do, but I think we can for the time being proceed with other things. --- runtime/modules.c | 1 - 1 file changed, 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 8ae9f038..c156fef2 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -49,7 +49,6 @@ #include #include -#include "dirty.h" #include "cfsysline.h" #include "modules.h" #include "errmsg.h" -- cgit v1.2.3 From 055d4ffc2afc77e03a3d31720d4a0998f8c3d92c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 29 Apr 2008 15:36:22 +0200 Subject: fixed problem with module unload sequence --- runtime/modules.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index c156fef2..1e59a5fc 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -522,11 +522,16 @@ modUnloadAndDestructAll(eModLinkType_t modLinkTypesToUnload) if(modLinkTypesToUnload == eMOD_LINK_ALL || pModCurr->eLinkType == modLinkTypesToUnload) { if(modUnlinkAndDestroy(&pModCurr) == RS_RET_MODULE_STILL_REFERENCED) { pModCurr = GetNxt(pModCurr); + } else { + /* Note: if the module was successfully unloaded, it has updated the + * pModCurr pointer to the next module. However, the unload process may + * still have indirectly referenced the pointer list in a way that the + * unloaded module is not aware of. So we restart the unload process + * to make sure we do not fall into a trap (what we did ;)). The + * performance toll is minimal. -- rgerhards, 2008-04-28 + */ + pModCurr = GetNxt(NULL); } - /* Note: if the module was successfully unloaded, it has updated the - * pModCurr pointer to the next module. So we do NOT need to advance - * to the next module on successful unload. - */ } else { pModCurr = GetNxt(pModCurr); } -- cgit v1.2.3 From 083d52c86199f64306f1af058b3d4771a37c342f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 20 Jun 2008 08:53:58 +0200 Subject: bugfix: some error states were swapped ... in gnutls code, resulting in some hard too understand error messages. Also genereally improved certificate error messages a bit. Also, added GnuTLS debugging support. --- runtime/modules.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 1e59a5fc..502e6525 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -538,10 +538,12 @@ modUnloadAndDestructAll(eModLinkType_t modLinkTypesToUnload) } # ifdef DEBUG + /* DEV DEBUG only! if(pLoadedModules != NULL) { dbgprintf("modules still loaded after module.UnloadAndDestructAll:\n"); modUsrPrintAll(); } + */ # endif RETiRet; -- cgit v1.2.3 From 3f6c73a8b7ff2c6d9c931876d823f2b4ef6bbea2 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 27 Jun 2008 12:52:45 +0200 Subject: added (internal) error codes to error messages Also added redirector to web description of error codes closes bug http://bugzilla.adiscon.com/show_bug.cgi?id=20 --- runtime/modules.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 502e6525..ceb4768c 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -604,7 +604,7 @@ Load(uchar *pModName) szPath[iPathLen++] = '/'; szPath[iPathLen] = '\0'; } else { - errmsg.LogError(NO_ERRCODE, "could not load module '%s', path too long\n", pModName); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); } } @@ -625,23 +625,23 @@ Load(uchar *pModName) } if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) { - errmsg.LogError(NO_ERRCODE, "could not load module '%s', path too long\n", pModName); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); } /* complete load path constructed, so ... GO! */ dbgprintf("loading module '%s'\n", szPath); if(!(pModHdlr = dlopen((char *) szPath, RTLD_NOW))) { - errmsg.LogError(NO_ERRCODE, "could not load module '%s', dlopen: %s\n", szPath, dlerror()); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", szPath, dlerror()); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_DLOPEN); } if(!(pModInit = dlsym(pModHdlr, "modInit"))) { - errmsg.LogError(NO_ERRCODE, "could not load module '%s', dlsym: %s\n", szPath, dlerror()); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_NO_INIT, "could not load module '%s', dlsym: %s\n", szPath, dlerror()); dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_NO_INIT); } if((iRet = doModInit(pModInit, (uchar*) pModName, pModHdlr)) != RS_RET_OK) { - errmsg.LogError(NO_ERRCODE, "could not load module '%s', rsyslog error %d\n", szPath, iRet); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_INIT_FAILED, "could not load module '%s', rsyslog error %d\n", szPath, iRet); dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_INIT_FAILED); } -- cgit v1.2.3 From 19ccebbf4c49c5f9954c7a1a092399303156a1f3 Mon Sep 17 00:00:00 2001 From: Marius Tomaschewski Date: Mon, 20 Oct 2008 17:36:31 +0200 Subject: added capability to support multiple module search pathes. Signed-off-by: Rainer Gerhards --- runtime/modules.c | 108 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 73 insertions(+), 35 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index ceb4768c..d5730ede 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -570,6 +570,8 @@ Load(uchar *pModName) int bHasExtension; void *pModHdlr, *pModInit; modInfo_t *pModInfo; + uchar *pModDirCurr, *pModDirNext; + int iLoadCnt; assert(pModName != NULL); dbgprintf("Requested to load module '%s'\n", pModName); @@ -591,48 +593,84 @@ Load(uchar *pModName) pModInfo = GetNxt(pModInfo); } - /* now build our load module name */ - if(*pModName == '/') { - *szPath = '\0'; /* we do not need to append the path - its already in the module name */ - iPathLen = 0; - } else { - *szPath = '\0'; - strncat((char *) szPath, (pModDir == NULL) ? _PATH_MODDIR : (char*) pModDir, sizeof(szPath) - 1); - iPathLen = strlen((char*) szPath); - if((szPath[iPathLen - 1] != '/')) { - if((iPathLen <= sizeof(szPath) - 2)) { - szPath[iPathLen++] = '/'; - szPath[iPathLen] = '\0'; - } else { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); + pModDirCurr = (uchar *)((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir); + pModDirNext = NULL; + pModHdlr = NULL; + iLoadCnt = 0; + do { + /* now build our load module name */ + if(*pModName == '/') { + *szPath = '\0'; /* we do not need to append the path - its already in the module name */ + iPathLen = 0; + } else { + *szPath = '\0'; + + iPathLen = strlen((char *)pModDirCurr); + pModDirNext = (uchar *)strchr((char *)pModDirCurr, ':'); + if(pModDirNext) + iPathLen = (size_t)(pModDirNext - pModDirCurr); + + if(iPathLen == 0) { + if(pModDirNext) { + pModDirCurr = pModDirNext + 1; + continue; + } + break; + } else if(iPathLen > sizeof(szPath) - 1) { + errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', module path too long\n", pModName); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); } + + strncat((char *) szPath, (char *)pModDirCurr, iPathLen); + iPathLen = strlen((char*) szPath); + + if(pModDirNext) + pModDirCurr = pModDirNext + 1; + + if((szPath[iPathLen - 1] != '/')) { + if((iPathLen <= sizeof(szPath) - 2)) { + szPath[iPathLen++] = '/'; + szPath[iPathLen] = '\0'; + } else { + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); + ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); + } + } } - } - /* ... add actual name ... */ - strncat((char *) szPath, (char *) pModName, sizeof(szPath) - iPathLen - 1); + /* ... add actual name ... */ + strncat((char *) szPath, (char *) pModName, sizeof(szPath) - iPathLen - 1); + + /* now see if we have an extension and, if not, append ".so" */ + if(!bHasExtension) { + /* we do not have an extension and so need to add ".so" + * TODO: I guess this is highly importable, so we should change the + * algo over time... -- rgerhards, 2008-03-05 + */ + /* ... so now add the extension */ + strncat((char *) szPath, ".so", sizeof(szPath) - strlen((char*) szPath) - 1); + iPathLen += 3; + } - /* now see if we have an extension and, if not, append ".so" */ - if(!bHasExtension) { - /* we do not have an extension and so need to add ".so" - * TODO: I guess this is highly importable, so we should change the - * algo over time... -- rgerhards, 2008-03-05 - */ - /* ... so now add the extension */ - strncat((char *) szPath, ".so", sizeof(szPath) - strlen((char*) szPath) - 1); - iPathLen += 3; - } + if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) { + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); + ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); + } - if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); - ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); - } + /* complete load path constructed, so ... GO! */ + dbgprintf("loading module '%s'\n", szPath); + pModHdlr = dlopen((char *) szPath, RTLD_NOW); + iLoadCnt++; + + } while(pModHdlr == NULL && *pModName != '/' && pModDirNext); - /* complete load path constructed, so ... GO! */ - dbgprintf("loading module '%s'\n", szPath); - if(!(pModHdlr = dlopen((char *) szPath, RTLD_NOW))) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", szPath, dlerror()); + if(!pModHdlr) { + if(iLoadCnt) { + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", szPath, dlerror()); + } else { + errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', ModDir was '%s'\n", szPath, + ((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir)); + } ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_DLOPEN); } if(!(pModInit = dlsym(pModHdlr, "modInit"))) { -- cgit v1.2.3 From 6334d335d89ae5df344f833c5095e9dea2abf6fb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 23 Oct 2008 14:46:47 +0200 Subject: added configuration directive "HUPisRestart" ...which enables to configure HUP to be either a full restart or "just" a leightweight way to close open files --- runtime/modules.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index d5730ede..169d234b 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -347,6 +347,7 @@ static rsRetVal doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_t*), uchar *name, void *pModHdlr) { DEFiRet; + rsRetVal localRet; modInfo_t *pNew = NULL; rsRetVal (*modGetType)(eModType_t *pType); @@ -391,6 +392,10 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"parseSelectorAct", &pNew->mod.om.parseSelectorAct)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"isCompatibleWithFeature", &pNew->isCompatibleWithFeature)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"tryResume", &pNew->tryResume)); + /* try load optional interfaces */ + localRet = (*pNew->modQueryEtryPt)((uchar*)"doHUP", &pNew->doHUP); + if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) + ABORT_FINALIZE(localRet); break; case eMOD_LIB: break; -- cgit v1.2.3 From 2e388db9ac91eae35ac836b329c8bcadd319a409 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 5 Mar 2009 11:10:43 +0100 Subject: integrated various patches for solaris Unfortunatley, I do not have the full list of contributors available. The patch set was compiled by Ben Taylor, and I made some further changes to adopt it to the news rsyslog branch. Others provided much of the base work, but I can not find the names of the original authors. If you happen to be one of them, please let me know so that I can give proper credits. --- runtime/modules.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 169d234b..d548a949 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -49,6 +49,10 @@ #include #include +#ifdef OS_SOLARIS +# define PATH_MAX MAXPATHLEN +#endif + #include "cfsysline.h" #include "modules.h" #include "errmsg.h" -- cgit v1.2.3 From bbfa04fbe63f1bbb47f5cdc683045cf2775b3977 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 19 Mar 2009 17:50:07 +0100 Subject: improved testing support worked on ways to provide a better test suite: - added -T rsyslogd command line option, enables to specify a directory where to chroot() into on startup. This is NOT a security feature but introduced to support testing. Thus, -T does not make sure chroot() is used in a secure way. (may be removed later) - added omstdout module for testing purposes. Spits out all messages to stdout - no config option, no other features - modified $ModLoad statement so that for modules whom's name starts with a dot, no path is prepended (this enables relative-pathes and should not break any valid current config) --- runtime/modules.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index d548a949..cef4eac6 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -608,7 +608,7 @@ Load(uchar *pModName) iLoadCnt = 0; do { /* now build our load module name */ - if(*pModName == '/') { + if(*pModName == '/' || *pModName == '.') { *szPath = '\0'; /* we do not need to append the path - its already in the module name */ iPathLen = 0; } else { -- cgit v1.2.3 From ec0e2c3e7df6addc02431628daddfeae49b92af7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 3 Apr 2009 12:51:02 +0200 Subject: added a new way how output plugins may be passed parameters. This is more efficient for some outputs. They new can receive fields not only as a single string but rather in an array where each string is seperated. --- runtime/modules.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index cef4eac6..9fdb48e7 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -225,6 +225,8 @@ static rsRetVal queryHostEtryPt(uchar *name, rsRetVal (**pEtryPoint)()) *pEtryPoint = regCfSysLineHdlr; } else if(!strcmp((char*) name, "objGetObjInterface")) { *pEtryPoint = objGetObjInterface; + } else if(!strcmp((char*) name, "OMSRgetSupportedTplOpts")) { + *pEtryPoint = OMSRgetSupportedTplOpts; } else { *pEtryPoint = NULL; /* to be on the safe side */ ABORT_FINALIZE(RS_RET_ENTRY_POINT_NOT_FOUND); -- cgit v1.2.3 From 10bab38993ae6853d7e23c6f6bd44eb0ed69e001 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 27 Apr 2009 15:40:54 +0200 Subject: begin implementation of new transactional output module interface code is not complete, error cases are not handled. --- runtime/modules.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 9fdb48e7..024c1c9a 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -207,19 +207,38 @@ static void moduleDestruct(modInfo_t *pThis) } +/* This enables a module to query the core for specific features. + * rgerhards, 2009-04-22 + */ +static rsRetVal queryCoreFeatureSupport(int *pBool, unsigned uFeat) +{ + DEFiRet; + + if((pBool == NULL)) + ABORT_FINALIZE(RS_RET_PARAM_ERROR); + + *pBool = (uFeat & CORE_FEATURE_BATCHING) ? 1 : 0; + +finalize_it: + RETiRet; +} + + /* The following function is the queryEntryPoint for host-based entry points. * Modules may call it to get access to core interface functions. Please note * that utility functions can be accessed via shared libraries - at least this * is my current shool of thinking. * Please note that the implementation as a query interface allows to take * care of plug-in interface version differences. -- rgerhards, 2007-07-31 + * ... but often it better not to use a new interface. So we now add core + * functions here that a plugin may request. -- rgerhards, 2009-04-22 */ static rsRetVal queryHostEtryPt(uchar *name, rsRetVal (**pEtryPoint)()) { DEFiRet; if((name == NULL) || (pEtryPoint == NULL)) - return RS_RET_PARAM_ERROR; + ABORT_FINALIZE(RS_RET_PARAM_ERROR); if(!strcmp((char*) name, "regCfSysLineHdlr")) { *pEtryPoint = regCfSysLineHdlr; @@ -227,6 +246,8 @@ static rsRetVal queryHostEtryPt(uchar *name, rsRetVal (**pEtryPoint)()) *pEtryPoint = objGetObjInterface; } else if(!strcmp((char*) name, "OMSRgetSupportedTplOpts")) { *pEtryPoint = OMSRgetSupportedTplOpts; + } else if(!strcmp((char*) name, "queryCoreFeatureSupport")) { + *pEtryPoint = queryCoreFeatureSupport; } else { *pEtryPoint = NULL; /* to be on the safe side */ ABORT_FINALIZE(RS_RET_ENTRY_POINT_NOT_FOUND); @@ -400,6 +421,12 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"tryResume", &pNew->tryResume)); /* try load optional interfaces */ localRet = (*pNew->modQueryEtryPt)((uchar*)"doHUP", &pNew->doHUP); + if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) + ABORT_FINALIZE(localRet); + localRet = (*pNew->modQueryEtryPt)((uchar*)"beginTransaction", &pNew->mod.om.beginTransaction); + if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) + ABORT_FINALIZE(localRet); + localRet = (*pNew->modQueryEtryPt)((uchar*)"endTransaction", &pNew->mod.om.endTransaction); if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) ABORT_FINALIZE(localRet); break; -- cgit v1.2.3 From 68877497a131d5b7c5b1588b771a623fc0ad41c1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 7 May 2009 10:44:46 +0200 Subject: first shot at action state machine implemention (untested) I am commiting it so that the code is visible, but will no begin with the test environment. --- runtime/modules.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 024c1c9a..bfd87a71 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -68,6 +68,21 @@ static modInfo_t *pLoadedModulesLast = NULL; /* tail-pointer */ uchar *pModDir = NULL; /* read-only after startup */ +/* we provide a set of dummy functions for output modules that do not support the + * transactional interface. As they do not do this, they commit each message they + * receive, and as such the dummies can always return RS_RET_OK without causing + * harm. This simplifies things as in action processing we do not need to check + * if the transactional entry points exist. + */ +static rsRetVal dummyBeginTransaction() +{ + return RS_RET_OK; +} +static rsRetVal dummyEndTransaction() +{ + return RS_RET_OK; +} + #ifdef DEBUG /* we add some home-grown support to track our users (and detect who does not free us). In * the long term, this should probably be migrated into debug.c (TODO). -- rgerhards, 2008-03-11 @@ -423,11 +438,17 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ localRet = (*pNew->modQueryEtryPt)((uchar*)"doHUP", &pNew->doHUP); if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) ABORT_FINALIZE(localRet); + localRet = (*pNew->modQueryEtryPt)((uchar*)"beginTransaction", &pNew->mod.om.beginTransaction); - if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) + if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) + pNew->mod.om.beginTransaction = dummyBeginTransaction; + else if(localRet != RS_RET_OK) ABORT_FINALIZE(localRet); + localRet = (*pNew->modQueryEtryPt)((uchar*)"endTransaction", &pNew->mod.om.endTransaction); - if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) + if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) + pNew->mod.om.beginTransaction = dummyEndTransaction; + else if(localRet != RS_RET_OK) ABORT_FINALIZE(localRet); break; case eMOD_LIB: -- cgit v1.2.3 From 7a7ec37f99f3dd5120952e6ca6263dd72061abb1 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 May 2009 13:02:06 +0200 Subject: improved testbench / solved imdiag race condition imdiag/imtcp had a modload race condition (as imdiag is a testing aid, this has no implications for production deployments). Also, I replaced netcat by a custom program to talk to imdiag. This, for the first time ever, is now a Java program. I plan to add some GUI troubleshooting tools and thought it is a good idea to start doing things in Java that can simply be done in that language. --- runtime/modules.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 9fdb48e7..3e8662a3 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef OS_BSD # include "libgen.h" #endif @@ -61,6 +62,14 @@ DEFobjStaticHelpers DEFobjCurrIf(errmsg) +/* we must ensure that only one thread at one time tries to load or unload + * modules, otherwise we may see race conditions. This first came up with + * imdiag/imtcp, which both use the same stream drivers. Below is the mutex + * for that handling. + * rgerhards, 2009-05-25 + */ +static pthread_mutex_t mutLoadUnload; + static modInfo_t *pLoadedModules = NULL; /* list of currently-loaded modules */ static modInfo_t *pLoadedModulesLast = NULL; /* tail-pointer */ @@ -479,6 +488,8 @@ modUnlinkAndDestroy(modInfo_t **ppThis) pThis = *ppThis; assert(pThis != NULL); + pthread_mutex_lock(&mutLoadUnload); + /* first check if we are permitted to unload */ if(pThis->eType == eMOD_LIB) { if(pThis->uRefCnt > 0) { @@ -513,6 +524,7 @@ modUnlinkAndDestroy(modInfo_t **ppThis) moduleDestruct(pThis); finalize_it: + pthread_mutex_unlock(&mutLoadUnload); RETiRet; } @@ -587,6 +599,8 @@ Load(uchar *pModName) assert(pModName != NULL); dbgprintf("Requested to load module '%s'\n", pModName); + pthread_mutex_lock(&mutLoadUnload); + iModNameLen = strlen((char *) pModName); if(iModNameLen > 3 && !strcmp((char *) pModName + iModNameLen - 3, ".so")) { iModNameLen -= 3; @@ -696,6 +710,7 @@ Load(uchar *pModName) } finalize_it: + pthread_mutex_unlock(&mutLoadUnload); RETiRet; } @@ -791,6 +806,7 @@ BEGINObjClassExit(module, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MA CODESTARTObjClassExit(module) /* release objects we no longer need */ objRelease(errmsg, CORE_COMPONENT); + pthread_mutex_destroy(&mutLoadUnload); # ifdef DEBUG modUsrPrintAll(); /* debug aid - TODO: integrate with debug.c, at least the settings! */ @@ -833,6 +849,7 @@ ENDobjQueryInterface(module) */ BEGINAbstractObjClassInit(module, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */ uchar *pModPath; + pthread_mutexattr_t mutAttr; /* use any module load path specified in the environment */ if((pModPath = (uchar*) getenv("RSYSLOG_MODDIR")) != NULL) { @@ -850,6 +867,10 @@ BEGINAbstractObjClassInit(module, 1, OBJ_IS_CORE_MODULE) /* class, version - CHA SetModDir(glblModPath); } + pthread_mutexattr_init(&mutAttr); + pthread_mutexattr_settype(&mutAttr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&mutLoadUnload, &mutAttr); + /* request objects we use */ CHKiRet(objUse(errmsg, CORE_COMPONENT)); ENDObjClassInit(module) -- cgit v1.2.3 From b9549380270fa68e27e8ee3f049c7d34156a85ff Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 May 2009 14:16:31 +0200 Subject: solved some issues with testbench & a race condition --- runtime/modules.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 3e8662a3..32ae659f 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -806,7 +806,15 @@ BEGINObjClassExit(module, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MA CODESTARTObjClassExit(module) /* release objects we no longer need */ objRelease(errmsg, CORE_COMPONENT); - pthread_mutex_destroy(&mutLoadUnload); + /* We have a problem in our reference counting, which leads to this function + * being called too early. This usually is no problem, but if we destroy + * the mutex object, we get into trouble. So rather than finding the root cause, + * we do not release the mutex right now and have a very, very slight leak. + * We know that otherwise no bad effects happen, so this acceptable for the + * time being. -- rgerhards, 2009-05-25 + * + * TODO: add again: pthread_mutex_destroy(&mutLoadUnload); + */ # ifdef DEBUG modUsrPrintAll(); /* debug aid - TODO: integrate with debug.c, at least the settings! */ -- cgit v1.2.3 From e747478051f4f81a872c791710933881c9564d64 Mon Sep 17 00:00:00 2001 From: Michael Terry Date: Mon, 29 Jun 2009 11:18:55 +0200 Subject: separate willRun and runInput calls for input modules Signed-off-by: Rainer Gerhards --- runtime/modules.c | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 32ae659f..bd201252 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -399,6 +399,7 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"runInput", &pNew->mod.im.runInput)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"willRun", &pNew->mod.im.willRun)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"afterRun", &pNew->mod.im.afterRun)); + pNew->mod.im.bCanRun = 0; break; case eMOD_OUT: CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeInstance", &pNew->freeInstance)); -- cgit v1.2.3 From 7d92de155c832e0a4af2cb3b65f7cef909b19f8d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 20 Jul 2009 18:36:30 +0200 Subject: internal: added ability to terminate input modules not via pthread_cancel... ... but an alternate approach via pthread_kill. This is somewhat safer as we do not need to think about the cancel-safeness of all libraries we use. However, not all inputs can easily supported, so this now is a feature that can be requested by the input module (the most important ones request it). --- runtime/modules.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 0ec6b1ce..b588909e 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -77,8 +77,9 @@ static modInfo_t *pLoadedModulesLast = NULL; /* tail-pointer */ uchar *pModDir = NULL; /* read-only after startup */ -/* we provide a set of dummy functions for output modules that do not support the - * transactional interface. As they do not do this, they commit each message they +/* we provide a set of dummy functions for modules that do not support the + * some interfaces. + * On the commit feature: As the modules do not support it, they commit each message they * receive, and as such the dummies can always return RS_RET_OK without causing * harm. This simplifies things as in action processing we do not need to check * if the transactional entry points exist. @@ -91,6 +92,11 @@ static rsRetVal dummyEndTransaction() { return RS_RET_OK; } +static rsRetVal dummyIsCompatibleWithFeature() +{ +dbgprintf("XXX: dummy isCompatibleWithFeature called!\n"); + return RS_RET_INCOMPATIBLE; +} #ifdef DEBUG /* we add some home-grown support to track our users (and detect who does not free us). In @@ -428,6 +434,11 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ */ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"modGetID", &pNew->modGetID)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"modExit", &pNew->modExit)); + localRet = (*pNew->modQueryEtryPt)((uchar*)"isCompatibleWithFeature", &pNew->isCompatibleWithFeature); + if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) + pNew->isCompatibleWithFeature = dummyIsCompatibleWithFeature; + else if(localRet != RS_RET_OK) + ABORT_FINALIZE(localRet); /* ... and now the module-specific interfaces */ switch(pNew->eType) { @@ -442,7 +453,6 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"dbgPrintInstInfo", &pNew->dbgPrintInstInfo)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"doAction", &pNew->mod.om.doAction)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"parseSelectorAct", &pNew->mod.om.parseSelectorAct)); - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"isCompatibleWithFeature", &pNew->isCompatibleWithFeature)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"tryResume", &pNew->tryResume)); /* try load optional interfaces */ localRet = (*pNew->modQueryEtryPt)((uchar*)"doHUP", &pNew->doHUP); -- cgit v1.2.3 From feeb622c4e0c622559df803f8df6da39bf3015e7 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 30 Jul 2009 09:47:47 +0200 Subject: bugfix: discard action caused segfault --- runtime/modules.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index b588909e..eee3b46e 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -466,10 +466,12 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ ABORT_FINALIZE(localRet); localRet = (*pNew->modQueryEtryPt)((uchar*)"endTransaction", &pNew->mod.om.endTransaction); - if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) - pNew->mod.om.beginTransaction = dummyEndTransaction; - else if(localRet != RS_RET_OK) + if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { + pNew->mod.om.endTransaction = dummyEndTransaction; + //pNew->mod.om.beginTransaction = dummyEndTransaction; + } else if(localRet != RS_RET_OK) { ABORT_FINALIZE(localRet); + } break; case eMOD_LIB: break; -- cgit v1.2.3 From 21aef2dffdc958cd92c7ac174fc398b4265acd6d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 2 Oct 2009 16:11:13 +0200 Subject: bugfix[minor]: CHKiRet improperly used --- runtime/modules.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index bd201252..871f356a 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -383,7 +383,7 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ * can never change in the lifetime of an module. -- rgerhards, 2007-12-14 */ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getType", &modGetType)); - CHKiRet((iRet = (*modGetType)(&pNew->eType)) != RS_RET_OK); + CHKiRet((*modGetType)(&pNew->eType)); dbgprintf("module of type %d being loaded.\n", pNew->eType); /* OK, we know we can successfully work with the module. So we now fill the -- cgit v1.2.3 From 6f511cecfae3592f271627ebcb41e6a8c4f831e9 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 3 Nov 2009 12:39:48 +0100 Subject: more cleanup and working towards a parser module calling interface I cleaned up a lot of config variable access along the way. This version compiles and runs, but does not yet offer any enhanced functionality. pmrfc5424 is just a dummy that is not yet being used. --- runtime/modules.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index bdb15e7f..5321c5e8 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -475,6 +475,9 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ break; case eMOD_LIB: break; + case eMOD_PARSER: + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"parse", &pNew->mod.pm.parse)); + break; } pNew->pszName = (uchar*) strdup((char*)name); /* we do not care if strdup() fails, we can accept that */ @@ -521,6 +524,9 @@ static void modPrintList(void) case eMOD_LIB: dbgprintf("library"); break; + case eMOD_PARSER: + dbgprintf("parser"); + break; } dbgprintf(" module.\n"); dbgprintf("Entry points:\n"); -- cgit v1.2.3 From b1db196953713dd09c499a3edf81347bd903c19e Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 3 Nov 2009 18:44:02 +0100 Subject: one step closer to dynamically loadable parsers This is a milestone commit, which adds new code that breaks nothing, but also does not add any visible change. Just prep work... --- runtime/modules.c | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 5321c5e8..41645a27 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -11,7 +11,7 @@ * * File begun on 2007-07-22 by RGerhards * - * Copyright 2007 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007, 2009 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -57,10 +57,12 @@ #include "cfsysline.h" #include "modules.h" #include "errmsg.h" +#include "parser.h" /* static data */ DEFobjStaticHelpers DEFobjCurrIf(errmsg) +DEFobjCurrIf(parser) /* we must ensure that only one thread at one time tries to load or unload * modules, otherwise we may see race conditions. This first came up with @@ -94,7 +96,6 @@ static rsRetVal dummyEndTransaction() } static rsRetVal dummyIsCompatibleWithFeature() { -dbgprintf("XXX: dummy isCompatibleWithFeature called!\n"); return RS_RET_INCOMPATIBLE; } @@ -403,10 +404,13 @@ finalize_it: static rsRetVal doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_t*), uchar *name, void *pModHdlr) { - DEFiRet; rsRetVal localRet; modInfo_t *pNew = NULL; + uchar *pParserName; + parser_t *pParser; /* used for parser modules */ + rsRetVal (*GetParserName)(uchar**); rsRetVal (*modGetType)(eModType_t *pType); + DEFiRet; assert(modInit != NULL); @@ -476,7 +480,27 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ case eMOD_LIB: break; case eMOD_PARSER: + /* first, we need to obtain the parser object. We could not do that during + * init as that would have caused class bootstrap issues which are not + * absolutely necessary. Note that we can call objUse() multiple times, it + * handles that. + */ + CHKiRet(objUse(parser, CORE_COMPONENT)); + /* here, we create a new parser object */ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"parse", &pNew->mod.pm.parse)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"GetParserName", &GetParserName)); + CHKiRet(GetParserName(&pParserName)); + CHKiRet(parser.Construct(&pParser)); + + /* check some features */ + localRet = pNew->isCompatibleWithFeature(sFEATUREAtomaticSanitazion); + if(localRet == RS_RET_OK){ + CHKiRet(parser.SetDoSanitazion(pParser, TRUE)); + } + + CHKiRet(parser.SetName(pParser, pParserName)); + CHKiRet(parser.SetModPtr(pParser, pNew)); + CHKiRet(parser.ConstructFinalize(pParser)); break; } @@ -873,6 +897,7 @@ BEGINObjClassExit(module, OBJ_IS_LOADABLE_MODULE) /* CHANGE class also in END MA CODESTARTObjClassExit(module) /* release objects we no longer need */ objRelease(errmsg, CORE_COMPONENT); + objRelease(parser, CORE_COMPONENT); /* We have a problem in our reference counting, which leads to this function * being called too early. This usually is no problem, but if we destroy * the mutex object, we get into trouble. So rather than finding the root cause, -- cgit v1.2.3 From ef661fe13c0ab5018afedb1cb5b8cffab05ad7c4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 4 Nov 2009 11:33:09 +0100 Subject: finalized parser module calling interface looks like we are almost done and need only to add the ruleset parser-specific config options. --- runtime/modules.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 41645a27..fd3468d8 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -493,10 +493,14 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet(parser.Construct(&pParser)); /* check some features */ - localRet = pNew->isCompatibleWithFeature(sFEATUREAtomaticSanitazion); + localRet = pNew->isCompatibleWithFeature(sFEATUREAutomaticSanitazion); if(localRet == RS_RET_OK){ CHKiRet(parser.SetDoSanitazion(pParser, TRUE)); } + localRet = pNew->isCompatibleWithFeature(sFEATUREAutomaticPRIParsing); + if(localRet == RS_RET_OK){ + CHKiRet(parser.SetDoPRIParsing(pParser, TRUE)); + } CHKiRet(parser.SetName(pParser, pParserName)); CHKiRet(parser.SetModPtr(pParser, pNew)); -- cgit v1.2.3 From 809c7e3cdcba3bef8d29702f37c3c8b580c3d1bd Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 25 Nov 2009 16:14:06 +0100 Subject: enhanced module debug output ... and addes some (later-to-be-removed) debug code to support finding a problem in transaction handling. --- runtime/modules.c | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index fd3468d8..1af94abc 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -472,7 +472,6 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ localRet = (*pNew->modQueryEtryPt)((uchar*)"endTransaction", &pNew->mod.om.endTransaction); if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { pNew->mod.om.endTransaction = dummyEndTransaction; - //pNew->mod.om.beginTransaction = dummyEndTransaction; } else if(localRet != RS_RET_OK) { ABORT_FINALIZE(localRet); } @@ -559,10 +558,35 @@ static void modPrintList(void) dbgprintf(" module.\n"); dbgprintf("Entry points:\n"); dbgprintf("\tqueryEtryPt: 0x%lx\n", (unsigned long) pMod->modQueryEtryPt); - dbgprintf("\tdoAction: 0x%lx\n", (unsigned long) pMod->mod.om.doAction); - dbgprintf("\tparseSelectorAct: 0x%lx\n", (unsigned long) pMod->mod.om.parseSelectorAct); dbgprintf("\tdbgPrintInstInfo: 0x%lx\n", (unsigned long) pMod->dbgPrintInstInfo); dbgprintf("\tfreeInstance: 0x%lx\n", (unsigned long) pMod->freeInstance); + switch(pMod->eType) { + case eMOD_OUT: + dbgprintf("Output Module Entry Points:\n"); + dbgprintf("\tdoAction: 0x%lx\n", (unsigned long) pMod->mod.om.doAction); + dbgprintf("\tparseSelectorAct: 0x%lx\n", (unsigned long) pMod->mod.om.parseSelectorAct); + dbgprintf("\ttryResume: 0x%lx\n", (unsigned long) pMod->tryResume); + dbgprintf("\tdoHUP: 0x%lx\n", (unsigned long) pMod->doHUP); + dbgprintf("\tBeginTransaction: 0x%lx\n", (unsigned long) + ((pMod->mod.om.beginTransaction == dummyBeginTransaction) ? + 0 : pMod->mod.om.beginTransaction)); + dbgprintf("\tEndTransaction: 0x%lx\n", (unsigned long) + ((pMod->mod.om.endTransaction == dummyEndTransaction) ? + 0 : pMod->mod.om.endTransaction)); + break; + case eMOD_IN: + dbgprintf("Input Module Entry Points\n"); + dbgprintf("\trunInput: 0x%lx\n", (unsigned long) pMod->mod.im.runInput); + dbgprintf("\twillRun: 0x%lx\n", (unsigned long) pMod->mod.im.willRun); + dbgprintf("\tafterRun: 0x%lx\n", (unsigned long) pMod->mod.im.afterRun); + break; + case eMOD_LIB: + break; + case eMOD_PARSER: + dbgprintf("Parser Module Entry Points\n"); + dbgprintf("\tparse: 0x%lx\n", (unsigned long) pMod->mod.pm.parse); + break; + } dbgprintf("\n"); pMod = GetNxt(pMod); /* done, go next */ } -- cgit v1.2.3 From 527bfcea5c9ca5c8414620a022f097d4e53af784 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 1 Jun 2010 18:51:55 +0200 Subject: first implementation of strgen interface and a first built-in strgen module. Some tweaks and more default strgens are needed, but the code doesn't look too bad ;) --- runtime/modules.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 1af94abc..d7362753 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -58,11 +58,13 @@ #include "modules.h" #include "errmsg.h" #include "parser.h" +#include "strgen.h" /* static data */ DEFobjStaticHelpers DEFobjCurrIf(errmsg) DEFobjCurrIf(parser) +DEFobjCurrIf(strgen) /* we must ensure that only one thread at one time tries to load or unload * modules, otherwise we may see race conditions. This first came up with @@ -406,9 +408,10 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ { rsRetVal localRet; modInfo_t *pNew = NULL; - uchar *pParserName; + uchar *pName; parser_t *pParser; /* used for parser modules */ - rsRetVal (*GetParserName)(uchar**); + strgen_t *pStrgen; /* used for strgen modules */ + rsRetVal (*GetName)(uchar**); rsRetVal (*modGetType)(eModType_t *pType); DEFiRet; @@ -487,8 +490,8 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet(objUse(parser, CORE_COMPONENT)); /* here, we create a new parser object */ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"parse", &pNew->mod.pm.parse)); - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"GetParserName", &GetParserName)); - CHKiRet(GetParserName(&pParserName)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"GetParserName", &GetName)); + CHKiRet(GetName(&pName)); CHKiRet(parser.Construct(&pParser)); /* check some features */ @@ -501,10 +504,26 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet(parser.SetDoPRIParsing(pParser, TRUE)); } - CHKiRet(parser.SetName(pParser, pParserName)); + CHKiRet(parser.SetName(pParser, pName)); CHKiRet(parser.SetModPtr(pParser, pNew)); CHKiRet(parser.ConstructFinalize(pParser)); break; + case eMOD_STRGEN: + /* first, we need to obtain the strgen object. We could not do that during + * init as that would have caused class bootstrap issues which are not + * absolutely necessary. Note that we can call objUse() multiple times, it + * handles that. + */ + CHKiRet(objUse(strgen, CORE_COMPONENT)); + /* here, we create a new parser object */ + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"strgen", &pNew->mod.sm.strgen)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"GetName", &GetName)); + CHKiRet(GetName(&pName)); + CHKiRet(strgen.Construct(&pStrgen)); + CHKiRet(strgen.SetName(pStrgen, pName)); + CHKiRet(strgen.SetModPtr(pStrgen, pNew)); + CHKiRet(strgen.ConstructFinalize(pStrgen)); + break; } pNew->pszName = (uchar*) strdup((char*)name); /* we do not care if strdup() fails, we can accept that */ @@ -554,6 +573,9 @@ static void modPrintList(void) case eMOD_PARSER: dbgprintf("parser"); break; + case eMOD_STRGEN: + dbgprintf("strgen"); + break; } dbgprintf(" module.\n"); dbgprintf("Entry points:\n"); @@ -586,6 +608,10 @@ static void modPrintList(void) dbgprintf("Parser Module Entry Points\n"); dbgprintf("\tparse: 0x%lx\n", (unsigned long) pMod->mod.pm.parse); break; + case eMOD_STRGEN: + dbgprintf("Strgen Module Entry Points\n"); + dbgprintf("\tstrgen: 0x%lx\n", (unsigned long) pMod->mod.sm.strgen); + break; } dbgprintf("\n"); pMod = GetNxt(pMod); /* done, go next */ -- cgit v1.2.3 From d18b238f16a7ff4dbb998314b6d76ffb8b2acf59 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 27 Jul 2010 09:44:35 +0200 Subject: milestone commit: output plugin interface changes (may NOT run) The output interface has been changed, but we do not yet utilize the new interface. Also, it looks like a regression was introduced. But before hunting it down, I'd like to make a commit (what also easys the regresion hunt). --- runtime/modules.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index d7362753..73a0012c 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -350,8 +350,7 @@ static modInfo_t *GetNxt(modInfo_t *pThis) /* this function is like GetNxt(), but it returns pointers to - * modules of specific type only. As we currently deal just with output modules, - * it is a dummy, to be filled with real code later. + * modules of specific type only. * rgerhards, 2007-07-24 */ static modInfo_t *GetNxtType(modInfo_t *pThis, eModType_t rqtdType) @@ -461,6 +460,8 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"doAction", &pNew->mod.om.doAction)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"parseSelectorAct", &pNew->mod.om.parseSelectorAct)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"tryResume", &pNew->tryResume)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"newScope", &pNew->mod.om.newScope)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"restoreScope", &pNew->mod.om.restoreScope)); /* try load optional interfaces */ localRet = (*pNew->modQueryEtryPt)((uchar*)"doHUP", &pNew->doHUP); if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) @@ -589,6 +590,8 @@ static void modPrintList(void) dbgprintf("\tparseSelectorAct: 0x%lx\n", (unsigned long) pMod->mod.om.parseSelectorAct); dbgprintf("\ttryResume: 0x%lx\n", (unsigned long) pMod->tryResume); dbgprintf("\tdoHUP: 0x%lx\n", (unsigned long) pMod->doHUP); + dbgprintf("\tnewScope: 0x%lx\n", (unsigned long) pMod->mod.om.newScope); + dbgprintf("\trestoreScope: 0x%lx\n", (unsigned long) pMod->mod.om.restoreScope); dbgprintf("\tBeginTransaction: 0x%lx\n", (unsigned long) ((pMod->mod.om.beginTransaction == dummyBeginTransaction) ? 0 : pMod->mod.om.beginTransaction)); -- cgit v1.2.3 From d1eb6e0edc51a78f3209448e800b25eda50340f2 Mon Sep 17 00:00:00 2001 From: Bojan Smojver Date: Wed, 23 Feb 2011 11:25:43 +0100 Subject: added work-around for bug in gtls, which causes fd leak when using TLS The capability has been added for module to specify that they do not like being unloaded. related bug tracker: http://bugzilla.adiscon.com/show_bug.cgi?id=222 Signed-off-by: Rainer Gerhards --- runtime/modules.c | 48 ++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 44 insertions(+), 4 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index d7362753..86e7c695 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -77,6 +77,9 @@ static pthread_mutex_t mutLoadUnload; static modInfo_t *pLoadedModules = NULL; /* list of currently-loaded modules */ static modInfo_t *pLoadedModulesLast = NULL; /* tail-pointer */ +/* already dlopen()-ed libs */ +static struct dlhandle_s *pHandles = NULL; + /* config settings */ uchar *pModDir = NULL; /* read-only after startup */ @@ -232,7 +235,9 @@ static void moduleDestruct(modInfo_t *pThis) # ifdef VALGRIND # warning "dlclose disabled for valgrind" # else - dlclose(pThis->pModHdlr); + if (pThis->eKeepType == eMOD_NOKEEP) { + dlclose(pThis->pModHdlr); + } # endif } @@ -413,6 +418,8 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ strgen_t *pStrgen; /* used for strgen modules */ rsRetVal (*GetName)(uchar**); rsRetVal (*modGetType)(eModType_t *pType); + rsRetVal (*modGetKeepType)(eModKeepType_t *pKeepType); + struct dlhandle_s *pHandle = NULL; DEFiRet; assert(modInit != NULL); @@ -433,6 +440,8 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ */ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getType", &modGetType)); CHKiRet((*modGetType)(&pNew->eType)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getKeepType", &modGetKeepType)); + CHKiRet((*modGetKeepType)(&pNew->eKeepType)); dbgprintf("module of type %d being loaded.\n", pNew->eType); /* OK, we know we can successfully work with the module. So we now fill the @@ -529,11 +538,28 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ pNew->pszName = (uchar*) strdup((char*)name); /* we do not care if strdup() fails, we can accept that */ pNew->pModHdlr = pModHdlr; /* TODO: take this from module */ - if(pModHdlr == NULL) + if(pModHdlr == NULL) { pNew->eLinkType = eMOD_LINK_STATIC; - else + } else { pNew->eLinkType = eMOD_LINK_DYNAMIC_LOADED; + /* if we need to keep the linked module, save it */ + if (pNew->eKeepType == eMOD_KEEP) { + if((pHandle = calloc(1, sizeof (*pHandle))) == NULL) { + iRet = RS_RET_OUT_OF_MEMORY; + goto finalize_it; + } + + strncpy((char *)pHandle->szName, + (char *)name, PATH_MAX - 1); + pHandle->szName[PATH_MAX - 1] = '\0'; + pHandle->pModHdlr = pModHdlr; + pHandle->next = pHandles; + + pHandles = pHandle; + } + } + /* we initialized the structure, now let's add it to the linked list of modules */ addModToList(pNew); @@ -740,6 +766,7 @@ Load(uchar *pModName) modInfo_t *pModInfo; uchar *pModDirCurr, *pModDirNext; int iLoadCnt; + struct dlhandle_s *pHandle = NULL; assert(pModName != NULL); dbgprintf("Requested to load module '%s'\n", pModName); @@ -829,7 +856,20 @@ Load(uchar *pModName) /* complete load path constructed, so ... GO! */ dbgprintf("loading module '%s'\n", szPath); - pModHdlr = dlopen((char *) szPath, RTLD_NOW); + + /* see if we have this one already */ + for (pHandle = pHandles; pHandle; pHandle = pHandle->next) { + if (!strcmp((char *)pModName, (char *)pHandle->szName)) { + pModHdlr = pHandle->pModHdlr; + break; + } + } + + /* not found, try to dynamically link it */ + if (!pModHdlr) { + pModHdlr = dlopen((char *) szPath, RTLD_NOW); + } + iLoadCnt++; } while(pModHdlr == NULL && *pModName != '/' && pModDirNext); -- cgit v1.2.3 From 87f8ac6dc4343eb4664ca5e234c163c399afca1b Mon Sep 17 00:00:00 2001 From: Bojan Smojver Date: Fri, 4 Mar 2011 07:55:53 +0100 Subject: bugfix: regression: memory leak in module loader Signed-off-by: Rainer Gerhards --- runtime/modules.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 86e7c695..4541bddf 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -545,18 +545,26 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ /* if we need to keep the linked module, save it */ if (pNew->eKeepType == eMOD_KEEP) { - if((pHandle = calloc(1, sizeof (*pHandle))) == NULL) { - iRet = RS_RET_OUT_OF_MEMORY; - goto finalize_it; + /* see if we have this one already */ + for (pHandle = pHandles; pHandle; pHandle = pHandle->next) { + if (!strcmp((char *)name, (char *)pHandle->pszName)) + break; } - strncpy((char *)pHandle->szName, - (char *)name, PATH_MAX - 1); - pHandle->szName[PATH_MAX - 1] = '\0'; - pHandle->pModHdlr = pModHdlr; - pHandle->next = pHandles; + /* not found, create it */ + if (!pHandle) { + if((pHandle = malloc(sizeof (*pHandle))) == NULL) { + ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); + } + if((pHandle->pszName = (uchar*) strdup((char*)name)) == NULL) { + free(pHandle); + ABORT_FINALIZE(RS_RET_OUT_OF_MEMORY); + } + pHandle->pModHdlr = pModHdlr; + pHandle->next = pHandles; - pHandles = pHandle; + pHandles = pHandle; + } } } @@ -859,7 +867,7 @@ Load(uchar *pModName) /* see if we have this one already */ for (pHandle = pHandles; pHandle; pHandle = pHandle->next) { - if (!strcmp((char *)pModName, (char *)pHandle->szName)) { + if (!strcmp((char *)pModName, (char *)pHandle->pszName)) { pModHdlr = pHandle->pModHdlr; break; } -- cgit v1.2.3 From 13ecf8a6ef5a5b69819865a2b9b524d4c561f5de Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Apr 2011 14:27:41 +0200 Subject: step: config handler setting from syslogd.c moved to rsconf.c --- runtime/modules.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 8ede134b..7389909d 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -55,6 +55,7 @@ #endif #include "cfsysline.h" +#include "rsconf.h" #include "modules.h" #include "errmsg.h" #include "parser.h" @@ -80,9 +81,7 @@ static modInfo_t *pLoadedModulesLast = NULL; /* tail-pointer */ /* already dlopen()-ed libs */ static struct dlhandle_s *pHandles = NULL; -/* config settings */ -uchar *pModDir = NULL; /* read-only after startup */ - +static uchar *pModDir; /* directory where loadable modules are found */ /* we provide a set of dummy functions for modules that do not support the * some interfaces. @@ -801,7 +800,8 @@ Load(uchar *pModName) pModInfo = GetNxt(pModInfo); } - pModDirCurr = (uchar *)((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir); + pModDirCurr = (uchar *)((pModDir == NULL) ? + _PATH_MODDIR : (char *)pModDir); pModDirNext = NULL; pModHdlr = NULL; iLoadCnt = 0; @@ -1013,6 +1013,7 @@ CODESTARTObjClassExit(module) * TODO: add again: pthread_mutex_destroy(&mutLoadUnload); */ + free(pModDir); # ifdef DEBUG modUsrPrintAll(); /* debug aid - TODO: integrate with debug.c, at least the settings! */ # endif -- cgit v1.2.3 From 706121052d2c2c0bca42b3f8f1e785dd96369772 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Apr 2011 13:33:06 +0200 Subject: step: shuffled module-related code from syslogd.c to rsconf.c ... plus some minor cleanup/code shuffle --- runtime/modules.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 7389909d..88a9bb79 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -11,7 +11,7 @@ * * File begun on 2007-07-22 by RGerhards * - * Copyright 2007, 2009 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * -- cgit v1.2.3 From 4f8457ffe3bc0a104a86ac79622844c4206adbbb Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Apr 2011 15:38:06 +0200 Subject: step: added config-specific module list --- runtime/modules.c | 124 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 100 insertions(+), 24 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 88a9bb79..8cdc9bb1 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -318,7 +318,7 @@ static uchar *modGetStateName(modInfo_t *pThis) /* Add a module to the loaded module linked list */ static inline void -addModToList(modInfo_t *pThis) +addModToGlblList(modInfo_t *pThis) { assert(pThis != NULL); @@ -333,6 +333,53 @@ addModToList(modInfo_t *pThis) } +/* Add a module to the config module list for current loadConf + */ +static inline rsRetVal +addModToCnfList(modInfo_t *pThis) +{ + cfgmodules_etry_t *pNew; + cfgmodules_etry_t *pLast; + DEFiRet; + assert(pThis != NULL); + + if(loadConf == NULL) { + /* we are in an early init state */ + FINALIZE; + } + + /* check for duplicates and, as a side-activity, identify last node */ + pLast = loadConf->modules.root; + if(pLast != NULL) { + while(1) { /* loop broken inside */ + if(pLast->pMod == pThis) { + DBGPRINTF("module '%s' already in this config\n", modGetName(pThis)); + FINALIZE; + } + if(pLast->next == NULL) + break; + pLast = pLast -> next; + } + } + + /* if we reach this point, pLast is the tail pointer */ + + CHKmalloc(pNew = MALLOC(sizeof(cfgmodules_etry_t))); + pNew->next = NULL; + pNew->pMod = pThis; + + if(pLast == NULL) { + loadConf->modules.root = pNew; + } else { + /* there already exist entries */ + pLast->next = pNew; + } + +finalize_it: + RETiRet; +} + + /* Get the next module pointer - this is used to traverse the list. * The function returns the next pointer or NULL, if there is no next one. * The last object must be provided to the function. If NULL is provided, @@ -407,7 +454,8 @@ finalize_it: * everything needed to fully initialize the module. */ static rsRetVal -doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_t*), uchar *name, void *pModHdlr) +doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_t*), + uchar *name, void *pModHdlr, modInfo_t **pNewModule) { rsRetVal localRet; modInfo_t *pNew = NULL; @@ -569,12 +617,14 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ } /* we initialized the structure, now let's add it to the linked list of modules */ - addModToList(pNew); + addModToGlblList(pNew); + *pNewModule = pNew; finalize_it: if(iRet != RS_RET_OK) { if(pNew != NULL) moduleDestruct(pNew); + *pNewModule = NULL; } RETiRet; @@ -753,6 +803,27 @@ modUnloadAndDestructAll(eModLinkType_t modLinkTypesToUnload) RETiRet; } +/* find module with given name in global list */ +static inline rsRetVal +findModule(uchar *pModName, int iModNameLen, modInfo_t **pMod) +{ + modInfo_t *pModInfo; + uchar *pModNameCmp; + DEFiRet; + + pModInfo = GetNxt(NULL); + while(pModInfo != NULL) { + if(!strncmp((char *) pModName, (char *) (pModNameCmp = modGetName(pModInfo)), iModNameLen) && + (!*(pModNameCmp + iModNameLen) || !strcmp((char *) pModNameCmp + iModNameLen, ".so"))) { + dbgprintf("Module '%s' found\n", pModName); + break; + } + pModInfo = GetNxt(pModInfo); + } + *pMod = pModInfo; + RETiRet; +} + /* load a module and initialize it, based on doModLoad() from conf.c * rgerhards, 2008-03-05 @@ -762,15 +833,20 @@ modUnloadAndDestructAll(eModLinkType_t modLinkTypesToUnload) * configuration file processing, which is executed on a single thread. Should we * change that design at any stage (what is unlikely), we need to find a * replacement. + * rgerhards, 2011-04-27: + * Parameter "bConfLoad" tells us if the load was triggered by a config handler, in + * which case we need to tie the loaded module to the current config. If bConfLoad == 0, + * the system loads a module for internal reasons, this is not directly tied to a + * configuration. We could also think if it would be useful to add only certain types + * of modules, but the current implementation at least looks simpler. */ static rsRetVal -Load(uchar *pModName) +Load(uchar *pModName, sbool bConfLoad) { DEFiRet; size_t iPathLen, iModNameLen; uchar szPath[PATH_MAX]; - uchar *pModNameCmp; int bHasExtension; void *pModHdlr, *pModInit; modInfo_t *pModInfo; @@ -790,14 +866,12 @@ Load(uchar *pModName) } else bHasExtension = FALSE; - pModInfo = GetNxt(NULL); - while(pModInfo != NULL) { - if(!strncmp((char *) pModName, (char *) (pModNameCmp = modGetName(pModInfo)), iModNameLen) && - (!*(pModNameCmp + iModNameLen) || !strcmp((char *) pModNameCmp + iModNameLen, ".so"))) { - dbgprintf("Module '%s' already loaded\n", pModName); - ABORT_FINALIZE(RS_RET_OK); - } - pModInfo = GetNxt(pModInfo); + CHKiRet(findModule(pModName, iModNameLen, &pModInfo)); + if(pModInfo != NULL) { + if(bConfLoad) + addModToCnfList(pModInfo); + dbgprintf("Module '%s' already loaded\n", pModName); + FINALIZE; } pModDirCurr = (uchar *)((pModDir == NULL) ? @@ -825,7 +899,8 @@ Load(uchar *pModName) } break; } else if(iPathLen > sizeof(szPath) - 1) { - errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', module path too long\n", pModName); + errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', " + "module path too long\n", pModName); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); } @@ -851,17 +926,13 @@ Load(uchar *pModName) /* now see if we have an extension and, if not, append ".so" */ if(!bHasExtension) { - /* we do not have an extension and so need to add ".so" - * TODO: I guess this is highly importable, so we should change the - * algo over time... -- rgerhards, 2008-03-05 - */ - /* ... so now add the extension */ strncat((char *) szPath, ".so", sizeof(szPath) - strlen((char*) szPath) - 1); iPathLen += 3; } if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, + "could not load module '%s', path too long\n", pModName); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); } @@ -887,7 +958,8 @@ Load(uchar *pModName) if(!pModHdlr) { if(iLoadCnt) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", szPath, dlerror()); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, + "could not load module '%s', dlopen: %s\n", szPath, dlerror()); } else { errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', ModDir was '%s'\n", szPath, ((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir)); @@ -895,15 +967,19 @@ Load(uchar *pModName) ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_DLOPEN); } if(!(pModInit = dlsym(pModHdlr, "modInit"))) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_NO_INIT, "could not load module '%s', dlsym: %s\n", szPath, dlerror()); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_NO_INIT, + "could not load module '%s', dlsym: %s\n", szPath, dlerror()); dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_NO_INIT); } - if((iRet = doModInit(pModInit, (uchar*) pModName, pModHdlr)) != RS_RET_OK) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_INIT_FAILED, "could not load module '%s', rsyslog error %d\n", szPath, iRet); + if((iRet = doModInit(pModInit, (uchar*) pModName, pModHdlr, &pModInfo)) != RS_RET_OK) { + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_INIT_FAILED, + "could not load module '%s', rsyslog error %d\n", szPath, iRet); dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_INIT_FAILED); } + if(bConfLoad) + addModToCnfList(pModInfo); finalize_it: pthread_mutex_unlock(&mutLoadUnload); -- cgit v1.2.3 From 5cd3cdf3c82ef49506124ace13d20c52afd5d44a Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 27 Apr 2011 17:11:41 +0200 Subject: step: config-specific module list used during config processing --- runtime/modules.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 8cdc9bb1..69c89790 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -335,7 +335,7 @@ addModToGlblList(modInfo_t *pThis) /* Add a module to the config module list for current loadConf */ -static inline rsRetVal +rsRetVal addModToCnfList(modInfo_t *pThis) { cfgmodules_etry_t *pNew; @@ -401,18 +401,31 @@ static modInfo_t *GetNxt(modInfo_t *pThis) /* this function is like GetNxt(), but it returns pointers to - * modules of specific type only. - * rgerhards, 2007-07-24 + * modules of specific type only. Only modules from the provided + * config are returned. Note that processing speed could be improved, + * but this is really not relevant, as config file loading is not really + * something we are concerned about in regard to runtime. */ -static modInfo_t *GetNxtType(modInfo_t *pThis, eModType_t rqtdType) +static modInfo_t *GetNxtCnfType(rsconf_t *cnf, modInfo_t *pThis, eModType_t rqtdType) { - modInfo_t *pMod = pThis; + cfgmodules_etry_t *node; + + if(pThis == NULL) { /* start at beginning of module list */ + node = cnf->modules.root; + } else { /* start at last location - then we need to find the module in the config list */ + for(node = cnf->modules.root ; node != NULL && node->pMod != pThis ; node = node->next) + /*search only, all done in for() */; + if(node != NULL) + node = node->next; /* skip to NEXT element in list */ + } - do { - pMod = GetNxt(pMod); - } while(!(pMod == NULL || pMod->eType == rqtdType)); /* warning: do ... while() */ +dbgprintf("XXXX: entering node, ptr %p: %s\n", node, (node == NULL)? "":modGetName(node->pMod)); + while(node != NULL && node->pMod->eType != rqtdType) { + node = node->next; /* warning: do ... while() */ +dbgprintf("XXXX: in loop, ptr %p: %s\n", node, (node == NULL)? "":modGetName(node->pMod)); + } - return pMod; + return (node == NULL) ? NULL : node->pMod; } @@ -1111,7 +1124,7 @@ CODESTARTobjQueryInterface(module) * of course, also affects the "if" above). */ pIf->GetNxt = GetNxt; - pIf->GetNxtType = GetNxtType; + pIf->GetNxtCnfType = GetNxtCnfType; pIf->GetName = modGetName; pIf->GetStateName = modGetStateName; pIf->PrintList = modPrintList; -- cgit v1.2.3 From d0d9f823b79c5649dad18cb1d8d7744796ae0907 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 3 May 2011 18:02:18 +0200 Subject: step: put plumbing in place for new input module config system --- runtime/modules.c | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 69c89790..67f16e65 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -362,12 +362,19 @@ addModToCnfList(modInfo_t *pThis) } } - /* if we reach this point, pLast is the tail pointer */ + /* if we reach this point, pLast is the tail pointer and this module is new + * inside the currently loaded config. So, iff it is an input module, let's + * pass it a pointer which it can populate with a pointer to its module conf. + */ CHKmalloc(pNew = MALLOC(sizeof(cfgmodules_etry_t))); pNew->next = NULL; pNew->pMod = pThis; + if(pThis->eType == eMOD_IN) { + CHKiRet(pThis->mod.im.beginCnfLoad(&pNew->modCnf)); + } + if(pLast == NULL) { loadConf->modules.root = pNew; } else { @@ -401,31 +408,27 @@ static modInfo_t *GetNxt(modInfo_t *pThis) /* this function is like GetNxt(), but it returns pointers to + * the configmodules entry, which than can be used to obtain the + * actual module pointer. Note that it returns those for * modules of specific type only. Only modules from the provided * config are returned. Note that processing speed could be improved, * but this is really not relevant, as config file loading is not really * something we are concerned about in regard to runtime. */ -static modInfo_t *GetNxtCnfType(rsconf_t *cnf, modInfo_t *pThis, eModType_t rqtdType) +static cfgmodules_etry_t +*GetNxtCnfType(rsconf_t *cnf, cfgmodules_etry_t *node, eModType_t rqtdType) { - cfgmodules_etry_t *node; - - if(pThis == NULL) { /* start at beginning of module list */ + if(node == NULL) { /* start at beginning of module list */ node = cnf->modules.root; - } else { /* start at last location - then we need to find the module in the config list */ - for(node = cnf->modules.root ; node != NULL && node->pMod != pThis ; node = node->next) - /*search only, all done in for() */; - if(node != NULL) - node = node->next; /* skip to NEXT element in list */ + } else { + node = node->next; } -dbgprintf("XXXX: entering node, ptr %p: %s\n", node, (node == NULL)? "":modGetName(node->pMod)); while(node != NULL && node->pMod->eType != rqtdType) { node = node->next; /* warning: do ... while() */ -dbgprintf("XXXX: in loop, ptr %p: %s\n", node, (node == NULL)? "":modGetName(node->pMod)); } - return (node == NULL) ? NULL : node->pMod; + return node; } @@ -518,6 +521,11 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ /* ... and now the module-specific interfaces */ switch(pNew->eType) { case eMOD_IN: + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"beginCnfLoad", &pNew->mod.im.beginCnfLoad)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"endCnfLoad", &pNew->mod.im.endCnfLoad)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeCnf", &pNew->mod.im.freeCnf)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"checkCnf", &pNew->mod.im.checkCnf)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"activateCnf", &pNew->mod.im.activateCnf)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"runInput", &pNew->mod.im.runInput)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"willRun", &pNew->mod.im.willRun)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"afterRun", &pNew->mod.im.afterRun)); @@ -697,6 +705,9 @@ static void modPrintList(void) break; case eMOD_IN: dbgprintf("Input Module Entry Points\n"); + dbgprintf("\tbeginCnfLoad: 0x%lx\n", (unsigned long) pMod->mod.im.beginCnfLoad); + dbgprintf("\tendCnfLoad: 0x%lx\n", (unsigned long) pMod->mod.im.endCnfLoad); + dbgprintf("\tfreeCnf: 0x%lx\n", (unsigned long) pMod->mod.im.freeCnf); dbgprintf("\trunInput: 0x%lx\n", (unsigned long) pMod->mod.im.runInput); dbgprintf("\twillRun: 0x%lx\n", (unsigned long) pMod->mod.im.willRun); dbgprintf("\tafterRun: 0x%lx\n", (unsigned long) pMod->mod.im.afterRun); @@ -928,7 +939,8 @@ Load(uchar *pModName, sbool bConfLoad) szPath[iPathLen++] = '/'; szPath[iPathLen] = '\0'; } else { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, + "could not load module '%s', path too long\n", pModName); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); } } -- cgit v1.2.3 From 79d46017e49d39b5de2d783cc3bcbeb696535bfc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 4 May 2011 14:41:08 +0200 Subject: step: imudp utilizes interim new input module interface --- runtime/modules.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 67f16e65..e2e12a3b 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -372,7 +372,7 @@ addModToCnfList(modInfo_t *pThis) pNew->pMod = pThis; if(pThis->eType == eMOD_IN) { - CHKiRet(pThis->mod.im.beginCnfLoad(&pNew->modCnf)); + CHKiRet(pThis->mod.im.beginCnfLoad(&pNew->modCnf, loadConf)); } if(pLast == NULL) { -- cgit v1.2.3 From b056c258d7bab528034ec8c8749cdcf0d0102268 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 6 May 2011 08:43:15 +0200 Subject: step: generalized new config interface for all module types --- runtime/modules.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index e2e12a3b..bf944dba 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -371,8 +371,9 @@ addModToCnfList(modInfo_t *pThis) pNew->next = NULL; pNew->pMod = pThis; - if(pThis->eType == eMOD_IN) { - CHKiRet(pThis->mod.im.beginCnfLoad(&pNew->modCnf, loadConf)); +dbgprintf("XXXX: beginCnfLoad %p\n", pThis->beginCnfLoad); + if(pThis->beginCnfLoad != NULL) { + CHKiRet(pThis->beginCnfLoad(&pNew->modCnf, loadConf)); } if(pLast == NULL) { @@ -424,8 +425,10 @@ static cfgmodules_etry_t node = node->next; } - while(node != NULL && node->pMod->eType != rqtdType) { - node = node->next; /* warning: do ... while() */ + if(rqtdType != eMOD_ANY) { /* if any, we already have the right one! */ + while(node != NULL && node->pMod->eType != rqtdType) { + node = node->next; /* warning: do ... while() */ + } } return node; @@ -518,14 +521,21 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ else if(localRet != RS_RET_OK) ABORT_FINALIZE(localRet); + /* optional calls for new config system */ + localRet = (*pNew->modQueryEtryPt)((uchar*)"beginCnfLoad", &pNew->beginCnfLoad); + if(localRet == RS_RET_OK) { + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"endCnfLoad", &pNew->endCnfLoad)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeCnf", &pNew->freeCnf)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"checkCnf", &pNew->checkCnf)); + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"activateCnf", &pNew->activateCnf)); + } else if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { + pNew->beginCnfLoad = NULL; /* flag as non-present */ + } else { + ABORT_FINALIZE(localRet); + } /* ... and now the module-specific interfaces */ switch(pNew->eType) { case eMOD_IN: - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"beginCnfLoad", &pNew->mod.im.beginCnfLoad)); - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"endCnfLoad", &pNew->mod.im.endCnfLoad)); - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeCnf", &pNew->mod.im.freeCnf)); - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"checkCnf", &pNew->mod.im.checkCnf)); - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"activateCnf", &pNew->mod.im.activateCnf)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"runInput", &pNew->mod.im.runInput)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"willRun", &pNew->mod.im.willRun)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"afterRun", &pNew->mod.im.afterRun)); @@ -602,6 +612,10 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet(strgen.SetModPtr(pStrgen, pNew)); CHKiRet(strgen.ConstructFinalize(pStrgen)); break; + case eMOD_ANY: /* this is mostly to keep the compiler happy! */ + DBGPRINTF("PROGRAM ERROR: eMOD_ANY set as module type\n"); + assert(0); + break; } pNew->pszName = (uchar*) strdup((char*)name); /* we do not care if strdup() fails, we can accept that */ @@ -681,12 +695,19 @@ static void modPrintList(void) case eMOD_STRGEN: dbgprintf("strgen"); break; + case eMOD_ANY: /* this is mostly to keep the compiler happy! */ + DBGPRINTF("PROGRAM ERROR: eMOD_ANY set as module type\n"); + assert(0); + break; } dbgprintf(" module.\n"); dbgprintf("Entry points:\n"); dbgprintf("\tqueryEtryPt: 0x%lx\n", (unsigned long) pMod->modQueryEtryPt); dbgprintf("\tdbgPrintInstInfo: 0x%lx\n", (unsigned long) pMod->dbgPrintInstInfo); dbgprintf("\tfreeInstance: 0x%lx\n", (unsigned long) pMod->freeInstance); + dbgprintf("\tbeginCnfLoad: 0x%lx\n", (unsigned long) pMod->beginCnfLoad); + dbgprintf("\tendCnfLoad: 0x%lx\n", (unsigned long) pMod->endCnfLoad); + dbgprintf("\tfreeCnf: 0x%lx\n", (unsigned long) pMod->freeCnf); switch(pMod->eType) { case eMOD_OUT: dbgprintf("Output Module Entry Points:\n"); @@ -705,9 +726,6 @@ static void modPrintList(void) break; case eMOD_IN: dbgprintf("Input Module Entry Points\n"); - dbgprintf("\tbeginCnfLoad: 0x%lx\n", (unsigned long) pMod->mod.im.beginCnfLoad); - dbgprintf("\tendCnfLoad: 0x%lx\n", (unsigned long) pMod->mod.im.endCnfLoad); - dbgprintf("\tfreeCnf: 0x%lx\n", (unsigned long) pMod->mod.im.freeCnf); dbgprintf("\trunInput: 0x%lx\n", (unsigned long) pMod->mod.im.runInput); dbgprintf("\twillRun: 0x%lx\n", (unsigned long) pMod->mod.im.willRun); dbgprintf("\tafterRun: 0x%lx\n", (unsigned long) pMod->mod.im.afterRun); @@ -722,6 +740,8 @@ static void modPrintList(void) dbgprintf("Strgen Module Entry Points\n"); dbgprintf("\tstrgen: 0x%lx\n", (unsigned long) pMod->mod.sm.strgen); break; + case eMOD_ANY: /* this is mostly to keep the compiler happy! */ + break; } dbgprintf("\n"); pMod = GetNxt(pMod); /* done, go next */ -- cgit v1.2.3 From ff2bb192f2c566f189a9d104d83d7a70c7888774 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 6 May 2011 10:06:32 +0200 Subject: step: conf interface now natively supports priv drop --- runtime/modules.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index bf944dba..4cd1ef4f 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -371,7 +371,6 @@ addModToCnfList(modInfo_t *pThis) pNew->next = NULL; pNew->pMod = pThis; -dbgprintf("XXXX: beginCnfLoad %p\n", pThis->beginCnfLoad); if(pThis->beginCnfLoad != NULL) { CHKiRet(pThis->beginCnfLoad(&pNew->modCnf, loadConf)); } @@ -528,6 +527,12 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeCnf", &pNew->freeCnf)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"checkCnf", &pNew->checkCnf)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"activateCnf", &pNew->activateCnf)); + localRet = (*pNew->modQueryEtryPt)((uchar*)"activateCnfPrePrivDrop", &pNew->activateCnfPrePrivDrop); + if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { + pNew->activateCnfPrePrivDrop = NULL; + } else { + CHKiRet(localRet); + } } else if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { pNew->beginCnfLoad = NULL; /* flag as non-present */ } else { @@ -706,7 +711,9 @@ static void modPrintList(void) dbgprintf("\tdbgPrintInstInfo: 0x%lx\n", (unsigned long) pMod->dbgPrintInstInfo); dbgprintf("\tfreeInstance: 0x%lx\n", (unsigned long) pMod->freeInstance); dbgprintf("\tbeginCnfLoad: 0x%lx\n", (unsigned long) pMod->beginCnfLoad); - dbgprintf("\tendCnfLoad: 0x%lx\n", (unsigned long) pMod->endCnfLoad); + dbgprintf("\tcheckCnf: 0x%lx\n", (unsigned long) pMod->checkCnf); + dbgprintf("\tactivateCnfPrePrivDrop: 0x%lx\n", (unsigned long) pMod->activateCnfPrePrivDrop); + dbgprintf("\tactivateCnf: 0x%lx\n", (unsigned long) pMod->activateCnf); dbgprintf("\tfreeCnf: 0x%lx\n", (unsigned long) pMod->freeCnf); switch(pMod->eType) { case eMOD_OUT: -- cgit v1.2.3 From 2b56e6051d4d2bb03886dbad47458d1843aa9ebe Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 12 May 2011 15:04:50 +0200 Subject: regression fix: activation for legacy modules handled incorrectly --- runtime/modules.c | 1 + 1 file changed, 1 insertion(+) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 4cd1ef4f..ad93ff38 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -368,6 +368,7 @@ addModToCnfList(modInfo_t *pThis) */ CHKmalloc(pNew = MALLOC(sizeof(cfgmodules_etry_t))); + pNew->canActivate = 1; pNew->next = NULL; pNew->pMod = pThis; -- cgit v1.2.3 From a7e3afb20b461f608f478e8fca15b02e67d6d9c3 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 20 Jul 2011 10:47:24 +0200 Subject: milestone: added module config names --- runtime/modules.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index ad93ff38..9ab03574 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -485,6 +485,8 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ rsRetVal (*modGetType)(eModType_t *pType); rsRetVal (*modGetKeepType)(eModKeepType_t *pKeepType); struct dlhandle_s *pHandle = NULL; + rsRetVal (*getModCnfName)(uchar **cnfName); + uchar *cnfName; DEFiRet; assert(modInit != NULL); @@ -507,7 +509,7 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*modGetType)(&pNew->eType)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getKeepType", &modGetKeepType)); CHKiRet((*modGetKeepType)(&pNew->eKeepType)); - dbgprintf("module of type %d being loaded.\n", pNew->eType); + dbgprintf("module %s of type %d being loaded.\n", name, pNew->eType); /* OK, we know we can successfully work with the module. So we now fill the * rest of the data elements. First we load the interfaces common to all @@ -524,6 +526,7 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ /* optional calls for new config system */ localRet = (*pNew->modQueryEtryPt)((uchar*)"beginCnfLoad", &pNew->beginCnfLoad); if(localRet == RS_RET_OK) { + dbgprintf("module %s supports rsyslog v6 config interface\n", name); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"endCnfLoad", &pNew->endCnfLoad)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeCnf", &pNew->freeCnf)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"checkCnf", &pNew->checkCnf)); @@ -534,6 +537,11 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ } else { CHKiRet(localRet); } + CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getModCnfName", &getModCnfName)); + getModCnfName(&cnfName); + pNew->cnfName = (uchar*) strdup((char*)cnfName); + /**< we do not care if strdup() fails, we can accept that */ + dbgprintf("module config name is '%s'\n", cnfName); } else if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { pNew->beginCnfLoad = NULL; /* flag as non-present */ } else { @@ -626,7 +634,6 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ pNew->pszName = (uchar*) strdup((char*)name); /* we do not care if strdup() fails, we can accept that */ pNew->pModHdlr = pModHdlr; - /* TODO: take this from module */ if(pModHdlr == NULL) { pNew->eLinkType = eMOD_LINK_STATIC; } else { -- cgit v1.2.3 From 686540cebee2920341911860c0019e687174daa8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 20 Jul 2011 14:27:20 +0200 Subject: milestone: on the way to a new action conf interface to plugins... --- runtime/modules.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 9ab03574..d09ba770 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -524,6 +524,15 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ ABORT_FINALIZE(localRet); /* optional calls for new config system */ + localRet = (*pNew->modQueryEtryPt)((uchar*)"getModCnfName", &getModCnfName); + if(localRet == RS_RET_OK) { + if(getModCnfName(&cnfName) == RS_RET_OK) + pNew->cnfName = (uchar*) strdup((char*)cnfName); + /**< we do not care if strdup() fails, we can accept that */ + else + pNew->cnfName = NULL; + dbgprintf("module config name is '%s'\n", cnfName); + } localRet = (*pNew->modQueryEtryPt)((uchar*)"beginCnfLoad", &pNew->beginCnfLoad); if(localRet == RS_RET_OK) { dbgprintf("module %s supports rsyslog v6 config interface\n", name); @@ -537,11 +546,6 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ } else { CHKiRet(localRet); } - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getModCnfName", &getModCnfName)); - getModCnfName(&cnfName); - pNew->cnfName = (uchar*) strdup((char*)cnfName); - /**< we do not care if strdup() fails, we can accept that */ - dbgprintf("module config name is '%s'\n", cnfName); } else if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { pNew->beginCnfLoad = NULL; /* flag as non-present */ } else { -- cgit v1.2.3 From 5820c5f3e8dc69bdee969d6487d084e884595069 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 20 Jul 2011 17:37:44 +0200 Subject: milestone: done plumbing to call plugin create action instance entry point --- runtime/modules.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index d09ba770..59eaec34 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -427,7 +427,7 @@ static cfgmodules_etry_t if(rqtdType != eMOD_ANY) { /* if any, we already have the right one! */ while(node != NULL && node->pMod->eType != rqtdType) { - node = node->next; /* warning: do ... while() */ + node = node->next; } } @@ -435,6 +435,25 @@ static cfgmodules_etry_t } +/* Find a module with the given conf name and type. Returns NULL if none + * can be found, otherwise module found. + */ +static modInfo_t * +FindWithCnfName(rsconf_t *cnf, uchar *name, eModType_t rqtdType) +{ + cfgmodules_etry_t *node; + + node = cnf->modules.root; + while(node != NULL && node->pMod->eType != rqtdType) { + if(!strcasecmp((char*)node->pMod->cnfName, (char*)name)) + break; + node = node->next; + } + + return node == NULL ? NULL : node->pMod; +} + + /* Prepare a module for unloading. * This is currently a dummy, to be filled when we have a plug-in * interface - rgerhards, 2007-08-09 @@ -1179,6 +1198,7 @@ CODESTARTobjQueryInterface(module) pIf->GetName = modGetName; pIf->GetStateName = modGetStateName; pIf->PrintList = modPrintList; + pIf->FindWithCnfName = FindWithCnfName; pIf->UnloadAndDestructAll = modUnloadAndDestructAll; pIf->doModInit = doModInit; pIf->SetModDir = SetModDir; -- cgit v1.2.3 From 9ce9fbb28f7a7a1a0380cc272a90be077cd9c1bc Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Jul 2011 11:14:52 +0200 Subject: milestone: new output plugin interface call added --- runtime/modules.c | 58 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 40 insertions(+), 18 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 59eaec34..f6b4bad9 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -90,18 +90,30 @@ static uchar *pModDir; /* directory where loadable modules are found */ * harm. This simplifies things as in action processing we do not need to check * if the transactional entry points exist. */ -static rsRetVal dummyBeginTransaction() +static rsRetVal +dummyBeginTransaction() { return RS_RET_OK; } -static rsRetVal dummyEndTransaction() +static rsRetVal +dummyEndTransaction() { return RS_RET_OK; } -static rsRetVal dummyIsCompatibleWithFeature() +static rsRetVal +dummyIsCompatibleWithFeature() { return RS_RET_INCOMPATIBLE; } +static rsRetVal +dummynewActInst(uchar *modName, struct nvlst __attribute__((unused)) *dummy1, + void __attribute__((unused)) **dummy2, omodStringRequest_t __attribute__((unused)) **dummy3) +{ + errmsg.LogError(0, RS_RET_CONFOBJ_UNSUPPORTED, "config objects are not " + "supported by module '%s' -- legacy config options " + "MUST be used instead", modName); + return RS_RET_CONFOBJ_UNSUPPORTED; +} #ifdef DEBUG /* we add some home-grown support to track our users (and detect who does not free us). In @@ -443,11 +455,14 @@ FindWithCnfName(rsconf_t *cnf, uchar *name, eModType_t rqtdType) { cfgmodules_etry_t *node; - node = cnf->modules.root; - while(node != NULL && node->pMod->eType != rqtdType) { + ; + for( node = cnf->modules.root + ; node != NULL + ; node = node->next) { + if(node->pMod->eType != rqtdType || node->pMod->cnfName == NULL) + continue; if(!strcasecmp((char*)node->pMod->cnfName, (char*)name)) break; - node = node->next; } return node == NULL ? NULL : node->pMod; @@ -603,6 +618,13 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ } else if(localRet != RS_RET_OK) { ABORT_FINALIZE(localRet); } + + localRet = (*pNew->modQueryEtryPt)((uchar*)"newActInst", &pNew->mod.om.newActInst); + if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { + pNew->mod.om.newActInst = dummynewActInst; + } else if(localRet != RS_RET_OK) { + ABORT_FINALIZE(localRet); + } break; case eMOD_LIB: break; @@ -749,18 +771,18 @@ static void modPrintList(void) switch(pMod->eType) { case eMOD_OUT: dbgprintf("Output Module Entry Points:\n"); - dbgprintf("\tdoAction: 0x%lx\n", (unsigned long) pMod->mod.om.doAction); - dbgprintf("\tparseSelectorAct: 0x%lx\n", (unsigned long) pMod->mod.om.parseSelectorAct); - dbgprintf("\ttryResume: 0x%lx\n", (unsigned long) pMod->tryResume); - dbgprintf("\tdoHUP: 0x%lx\n", (unsigned long) pMod->doHUP); - dbgprintf("\tnewScope: 0x%lx\n", (unsigned long) pMod->mod.om.newScope); - dbgprintf("\trestoreScope: 0x%lx\n", (unsigned long) pMod->mod.om.restoreScope); - dbgprintf("\tBeginTransaction: 0x%lx\n", (unsigned long) - ((pMod->mod.om.beginTransaction == dummyBeginTransaction) ? - 0 : pMod->mod.om.beginTransaction)); - dbgprintf("\tEndTransaction: 0x%lx\n", (unsigned long) - ((pMod->mod.om.endTransaction == dummyEndTransaction) ? - 0 : pMod->mod.om.endTransaction)); + dbgprintf("\tdoAction: %p\n", pMod->mod.om.doAction); + dbgprintf("\tparseSelectorAct: %p\n", pMod->mod.om.parseSelectorAct); + dbgprintf("\tnewActInst: %p\n", (pMod->mod.om.newActInst == dummynewActInst) ? + NULL : pMod->mod.om.newActInst); + dbgprintf("\ttryResume: %p\n", pMod->tryResume); + dbgprintf("\tdoHUP: %p\n", pMod->doHUP); + dbgprintf("\tnewScope: %p\n", pMod->mod.om.newScope); + dbgprintf("\trestoreScope: %p\n", pMod->mod.om.restoreScope); + dbgprintf("\tBeginTransaction: %p\n", ((pMod->mod.om.beginTransaction == dummyBeginTransaction) ? + NULL : pMod->mod.om.beginTransaction)); + dbgprintf("\tEndTransaction: %p\n", ((pMod->mod.om.endTransaction == dummyEndTransaction) ? + NULL : pMod->mod.om.endTransaction)); break; case eMOD_IN: dbgprintf("Input Module Entry Points\n"); -- cgit v1.2.3 From 63446424c057f527c9c17be7e06f306a130789b4 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Jul 2011 13:55:45 +0200 Subject: fixing minor memory leaks --- runtime/modules.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index f6b4bad9..0f132bdf 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -240,8 +240,8 @@ static rsRetVal moduleConstruct(modInfo_t **pThis) static void moduleDestruct(modInfo_t *pThis) { assert(pThis != NULL); - if(pThis->pszName != NULL) - free(pThis->pszName); + free(pThis->pszName); + free(pThis->cnfName); if(pThis->pModHdlr != NULL) { # ifdef VALGRIND # warning "dlclose disabled for valgrind" -- cgit v1.2.3 From 01c7c9ffc6771f73df9ee0bc18e30534d6c6974c Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Fri, 16 Dec 2011 12:14:48 +0100 Subject: enhanced module loader to not rely on PATH_MAX --- runtime/modules.c | 80 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 34 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 4541bddf..6a32b2e8 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -767,7 +767,6 @@ Load(uchar *pModName) DEFiRet; size_t iPathLen, iModNameLen; - uchar szPath[PATH_MAX]; uchar *pModNameCmp; int bHasExtension; void *pModHdlr, *pModInit; @@ -775,13 +774,25 @@ Load(uchar *pModName) uchar *pModDirCurr, *pModDirNext; int iLoadCnt; struct dlhandle_s *pHandle = NULL; +# ifdef PATH_MAX + uchar pathBuf[PATH_MAX+1]; +# else + uchar pathBuf[4096]; +# endif + uchar *pPathBuf = pathBuf; + size_t lenPathBuf = sizeof(pathBuf); assert(pModName != NULL); dbgprintf("Requested to load module '%s'\n", pModName); + iModNameLen = strlen((char*)pModName); + /* overhead for a full path is potentially 1 byte for a slash, + * three bytes for ".so" and one byte for '\0'. + */ +# define PATHBUF_OVERHEAD 1 + iModNameLen + 3 + 1 + pthread_mutex_lock(&mutLoadUnload); - iModNameLen = strlen((char *) pModName); if(iModNameLen > 3 && !strcmp((char *) pModName + iModNameLen - 3, ".so")) { iModNameLen -= 3; bHasExtension = TRUE; @@ -802,13 +813,19 @@ Load(uchar *pModName) pModDirNext = NULL; pModHdlr = NULL; iLoadCnt = 0; - do { - /* now build our load module name */ + do { /* now build our load module name */ if(*pModName == '/' || *pModName == '.') { - *szPath = '\0'; /* we do not need to append the path - its already in the module name */ + if(lenPathBuf < PATHBUF_OVERHEAD) { + if(pPathBuf != pathBuf) /* already malloc()ed memory? */ + free(pPathBuf); + /* we always alloc enough memory for everything we potentiall need to add */ + lenPathBuf = PATHBUF_OVERHEAD; + CHKmalloc(pPathBuf = malloc(sizeof(char)*lenPathBuf)); + } + *pPathBuf = '\0'; /* we do not need to append the path - its already in the module name */ iPathLen = 0; } else { - *szPath = '\0'; + *pPathBuf = '\0'; iPathLen = strlen((char *)pModDirCurr); pModDirNext = (uchar *)strchr((char *)pModDirCurr, ':'); @@ -821,30 +838,27 @@ Load(uchar *pModName) continue; } break; - } else if(iPathLen > sizeof(szPath) - 1) { - errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', module path too long\n", pModName); - ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); + } else if(iPathLen > lenPathBuf - PATHBUF_OVERHEAD) { + if(pPathBuf != pathBuf) /* already malloc()ed memory? */ + free(pPathBuf); + /* we always alloc enough memory for everything we potentiall need to add */ + lenPathBuf = iPathLen + PATHBUF_OVERHEAD; + CHKmalloc(pPathBuf = malloc(sizeof(char)*lenPathBuf)); } - strncat((char *) szPath, (char *)pModDirCurr, iPathLen); - iPathLen = strlen((char*) szPath); + memcpy((char *) pPathBuf, (char *)pModDirCurr, iPathLen); + if((pPathBuf[iPathLen - 1] != '/')) { + /* we have space, made sure in previous check */ + pPathBuf[iPathLen++] = '/'; + } + pPathBuf[iPathLen] = '\0'; if(pModDirNext) pModDirCurr = pModDirNext + 1; - - if((szPath[iPathLen - 1] != '/')) { - if((iPathLen <= sizeof(szPath) - 2)) { - szPath[iPathLen++] = '/'; - szPath[iPathLen] = '\0'; - } else { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); - ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); - } - } } /* ... add actual name ... */ - strncat((char *) szPath, (char *) pModName, sizeof(szPath) - iPathLen - 1); + strncat((char *) pPathBuf, (char *) pModName, lenPathBuf - iPathLen - 1); /* now see if we have an extension and, if not, append ".so" */ if(!bHasExtension) { @@ -853,17 +867,12 @@ Load(uchar *pModName) * algo over time... -- rgerhards, 2008-03-05 */ /* ... so now add the extension */ - strncat((char *) szPath, ".so", sizeof(szPath) - strlen((char*) szPath) - 1); + strncat((char *) pPathBuf, ".so", lenPathBuf - strlen((char*) pPathBuf) - 1); iPathLen += 3; } - if(iPathLen + strlen((char*) pModName) >= sizeof(szPath)) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_PATHLEN, "could not load module '%s', path too long\n", pModName); - ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_PATHLEN); - } - /* complete load path constructed, so ... GO! */ - dbgprintf("loading module '%s'\n", szPath); + dbgprintf("loading module '%s'\n", pPathBuf); /* see if we have this one already */ for (pHandle = pHandles; pHandle; pHandle = pHandle->next) { @@ -875,7 +884,7 @@ Load(uchar *pModName) /* not found, try to dynamically link it */ if (!pModHdlr) { - pModHdlr = dlopen((char *) szPath, RTLD_NOW); + pModHdlr = dlopen((char *) pPathBuf, RTLD_NOW); } iLoadCnt++; @@ -884,25 +893,28 @@ Load(uchar *pModName) if(!pModHdlr) { if(iLoadCnt) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", szPath, dlerror()); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_DLOPEN, "could not load module '%s', dlopen: %s\n", + pPathBuf, dlerror()); } else { - errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', ModDir was '%s'\n", szPath, + errmsg.LogError(0, NO_ERRCODE, "could not load module '%s', ModDir was '%s'\n", pPathBuf, ((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir)); } ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_DLOPEN); } if(!(pModInit = dlsym(pModHdlr, "modInit"))) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_NO_INIT, "could not load module '%s', dlsym: %s\n", szPath, dlerror()); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_NO_INIT, "could not load module '%s', dlsym: %s\n", pPathBuf, dlerror()); dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_NO_INIT); } if((iRet = doModInit(pModInit, (uchar*) pModName, pModHdlr)) != RS_RET_OK) { - errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_INIT_FAILED, "could not load module '%s', rsyslog error %d\n", szPath, iRet); + errmsg.LogError(0, RS_RET_MODULE_LOAD_ERR_INIT_FAILED, "could not load module '%s', rsyslog error %d\n", pPathBuf, iRet); dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_INIT_FAILED); } finalize_it: + if(pPathBuf != pathBuf) /* used malloc()ed memory? */ + free(pPathBuf); pthread_mutex_unlock(&mutLoadUnload); RETiRet; } -- cgit v1.2.3 From 1049537cd853c9714c4bdc3fe4296dda8507900d Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 19 Jan 2012 14:10:29 +0100 Subject: removing the newScope/resumeScope macro interfaces to make using pre-v6-plugins even easier --- runtime/modules.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 8ede134b..23b5c94e 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -469,8 +469,6 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"doAction", &pNew->mod.om.doAction)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"parseSelectorAct", &pNew->mod.om.parseSelectorAct)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"tryResume", &pNew->tryResume)); - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"newScope", &pNew->mod.om.newScope)); - CHKiRet((*pNew->modQueryEtryPt)((uchar*)"restoreScope", &pNew->mod.om.restoreScope)); /* try load optional interfaces */ localRet = (*pNew->modQueryEtryPt)((uchar*)"doHUP", &pNew->doHUP); if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) @@ -624,8 +622,6 @@ static void modPrintList(void) dbgprintf("\tparseSelectorAct: 0x%lx\n", (unsigned long) pMod->mod.om.parseSelectorAct); dbgprintf("\ttryResume: 0x%lx\n", (unsigned long) pMod->tryResume); dbgprintf("\tdoHUP: 0x%lx\n", (unsigned long) pMod->doHUP); - dbgprintf("\tnewScope: 0x%lx\n", (unsigned long) pMod->mod.om.newScope); - dbgprintf("\trestoreScope: 0x%lx\n", (unsigned long) pMod->mod.om.restoreScope); dbgprintf("\tBeginTransaction: 0x%lx\n", (unsigned long) ((pMod->mod.om.beginTransaction == dummyBeginTransaction) ? 0 : pMod->mod.om.beginTransaction)); -- cgit v1.2.3 From 290f41f9470d06e4f207ca38c3175c578f6202ec Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 6 Jun 2012 12:56:53 +0200 Subject: bugfix: potential hang due to mutex deadlock closes: http://bugzilla.adiscon.com/show_bug.cgi?id=316 Thanks to Andreas Piesk for reporting&analyzing this bug as well as providing patches and other help in resolving it. --- runtime/modules.c | 31 ++++--------------------------- 1 file changed, 4 insertions(+), 27 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 4541bddf..c2054e40 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -66,14 +66,6 @@ DEFobjCurrIf(errmsg) DEFobjCurrIf(parser) DEFobjCurrIf(strgen) -/* we must ensure that only one thread at one time tries to load or unload - * modules, otherwise we may see race conditions. This first came up with - * imdiag/imtcp, which both use the same stream drivers. Below is the mutex - * for that handling. - * rgerhards, 2009-05-25 - */ -static pthread_mutex_t mutLoadUnload; - static modInfo_t *pLoadedModules = NULL; /* list of currently-loaded modules */ static modInfo_t *pLoadedModulesLast = NULL; /* tail-pointer */ @@ -667,7 +659,7 @@ modUnlinkAndDestroy(modInfo_t **ppThis) pThis = *ppThis; assert(pThis != NULL); - pthread_mutex_lock(&mutLoadUnload); + pthread_mutex_lock(&mutObjGlobalOp); /* first check if we are permitted to unload */ if(pThis->eType == eMOD_LIB) { @@ -703,7 +695,7 @@ modUnlinkAndDestroy(modInfo_t **ppThis) moduleDestruct(pThis); finalize_it: - pthread_mutex_unlock(&mutLoadUnload); + pthread_mutex_unlock(&mutObjGlobalOp); RETiRet; } @@ -779,7 +771,7 @@ Load(uchar *pModName) assert(pModName != NULL); dbgprintf("Requested to load module '%s'\n", pModName); - pthread_mutex_lock(&mutLoadUnload); + pthread_mutex_lock(&mutObjGlobalOp); iModNameLen = strlen((char *) pModName); if(iModNameLen > 3 && !strcmp((char *) pModName + iModNameLen - 3, ".so")) { @@ -903,7 +895,7 @@ Load(uchar *pModName) } finalize_it: - pthread_mutex_unlock(&mutLoadUnload); + pthread_mutex_unlock(&mutObjGlobalOp); RETiRet; } @@ -1000,16 +992,6 @@ CODESTARTObjClassExit(module) /* release objects we no longer need */ objRelease(errmsg, CORE_COMPONENT); objRelease(parser, CORE_COMPONENT); - /* We have a problem in our reference counting, which leads to this function - * being called too early. This usually is no problem, but if we destroy - * the mutex object, we get into trouble. So rather than finding the root cause, - * we do not release the mutex right now and have a very, very slight leak. - * We know that otherwise no bad effects happen, so this acceptable for the - * time being. -- rgerhards, 2009-05-25 - * - * TODO: add again: pthread_mutex_destroy(&mutLoadUnload); - */ - # ifdef DEBUG modUsrPrintAll(); /* debug aid - TODO: integrate with debug.c, at least the settings! */ # endif @@ -1051,7 +1033,6 @@ ENDobjQueryInterface(module) */ BEGINAbstractObjClassInit(module, 1, OBJ_IS_CORE_MODULE) /* class, version - CHANGE class also in END MACRO! */ uchar *pModPath; - pthread_mutexattr_t mutAttr; /* use any module load path specified in the environment */ if((pModPath = (uchar*) getenv("RSYSLOG_MODDIR")) != NULL) { @@ -1069,10 +1050,6 @@ BEGINAbstractObjClassInit(module, 1, OBJ_IS_CORE_MODULE) /* class, version - CHA SetModDir(glblModPath); } - pthread_mutexattr_init(&mutAttr); - pthread_mutexattr_settype(&mutAttr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&mutLoadUnload, &mutAttr); - /* request objects we use */ CHKiRet(objUse(errmsg, CORE_COMPONENT)); ENDObjClassInit(module) -- cgit v1.2.3 From 46ccc9e77f5e2ee3ded1ca79e973fafdc37e4c0f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 20 Jun 2012 09:34:31 +0200 Subject: milestone: module() can load module in legacy mode --- runtime/modules.c | 52 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index dac3bd95..4ab5b206 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -11,7 +11,7 @@ * * File begun on 2007-07-22 by RGerhards * - * Copyright 2007-2011 Rainer Gerhards and Adiscon GmbH. + * Copyright 2007-2012 Rainer Gerhards and Adiscon GmbH. * * This file is part of the rsyslog runtime library. * @@ -75,6 +75,18 @@ static struct dlhandle_s *pHandles = NULL; static uchar *pModDir; /* directory where loadable modules are found */ +/* tables for interfacing with the v6 config system */ +/* action (instance) parameters */ +static struct cnfparamdescr actpdescr[] = { + { "load", eCmdHdlrGetWord, 1 } +}; +static struct cnfparamblk pblk = + { CNFPARAMBLK_VERSION, + sizeof(actpdescr)/sizeof(struct cnfparamdescr), + actpdescr + }; + + /* we provide a set of dummy functions for modules that do not support the * some interfaces. * On the commit feature: As the modules do not support it, they commit each message they @@ -931,9 +943,10 @@ findModule(uchar *pModName, int iModNameLen, modInfo_t **pMod) * the system loads a module for internal reasons, this is not directly tied to a * configuration. We could also think if it would be useful to add only certain types * of modules, but the current implementation at least looks simpler. + * Note: pvals = NULL means legacy config system */ static rsRetVal -Load(uchar *pModName, sbool bConfLoad) +Load(uchar *pModName, sbool bConfLoad, struct cnfparamvals *pvals) { DEFiRet; @@ -954,7 +967,7 @@ Load(uchar *pModName, sbool bConfLoad) size_t lenPathBuf = sizeof(pathBuf); assert(pModName != NULL); - dbgprintf("Requested to load module '%s'\n", pModName); + DBGPRINTF("Requested to load module '%s'\n", pModName); iModNameLen = strlen((char*)pModName); /* overhead for a full path is potentially 1 byte for a slash, @@ -1093,6 +1106,39 @@ finalize_it: } +/* the v6+ way of loading modules: process a "module(...)" directive. + * rgerhards, 2012-06-20 + */ +rsRetVal +modulesProcessCnf(struct cnfobj *o) +{ + struct cnfparamvals *pvals; + uchar *cnfModName = NULL; + int typeIdx; + DEFiRet; + + pvals = nvlstGetParams(o->nvlst, &pblk, NULL); + if(pvals == NULL) { + ABORT_FINALIZE(RS_RET_ERR); + } + DBGPRINTF("modulesProcessCnf params:\n"); + cnfparamsPrint(&pblk, pvals); + typeIdx = cnfparamGetIdx(&pblk, "load"); + if(pvals[typeIdx].bUsed == 0) { + errmsg.LogError(0, RS_RET_CONF_RQRD_PARAM_MISSING, "module type missing"); + ABORT_FINALIZE(RS_RET_CONF_RQRD_PARAM_MISSING); + } + + cnfModName = (uchar*)es_str2cstr(pvals[typeIdx].val.d.estr, NULL); + iRet = Load(cnfModName, 1, pvals); + +finalize_it: + free(cnfModName); + cnfparamvalsDestruct(pvals, &pblk); + RETiRet; +} + + /* set the default module load directory. A NULL value may be provided, in * which case any previous value is deleted but no new one set. The caller-provided * string is duplicated. If it needs to be freed, that's the caller's duty. -- cgit v1.2.3 From 4b150db338ae885ea3a3bb7cc5b5f84e2fc96e89 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 21 Jun 2012 16:19:20 +0200 Subject: milestone: module() config statement basically works some nits to iron out, only omfile actually support module params --- runtime/modules.c | 49 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 12 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 4ab5b206..e7ae72cc 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -349,7 +349,8 @@ addModToGlblList(modInfo_t *pThis) } -/* Add a module to the config module list for current loadConf +/* Add a module to the config module list for current loadConf and + * provide its config params to it. */ rsRetVal addModToCnfList(modInfo_t *pThis) @@ -370,11 +371,16 @@ addModToCnfList(modInfo_t *pThis) while(1) { /* loop broken inside */ if(pLast->pMod == pThis) { DBGPRINTF("module '%s' already in this config\n", modGetName(pThis)); + if(strncmp((char*)modGetName(pThis), "builtin:", sizeof("builtin:")-1)) { + errmsg.LogError(0, RS_RET_MODULE_ALREADY_IN_CONF, + "module '%s' already in this config, cannot be added\n", modGetName(pThis)); + ABORT_FINALIZE(RS_RET_MODULE_ALREADY_IN_CONF); + } FINALIZE; } if(pLast->next == NULL) break; - pLast = pLast -> next; + pLast = pLast->next; } } @@ -547,7 +553,7 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*modGetType)(&pNew->eType)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"getKeepType", &modGetKeepType)); CHKiRet((*modGetKeepType)(&pNew->eKeepType)); - dbgprintf("module %s of type %d being loaded.\n", name, pNew->eType); + dbgprintf("module %s of type %d being loaded (keepType=%d).\n", name, pNew->eType, pNew->eKeepType); /* OK, we know we can successfully work with the module. So we now fill the * rest of the data elements. First we load the interfaces common to all @@ -560,6 +566,11 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ pNew->isCompatibleWithFeature = dummyIsCompatibleWithFeature; else if(localRet != RS_RET_OK) ABORT_FINALIZE(localRet); + localRet = (*pNew->modQueryEtryPt)((uchar*)"setModCnf", &pNew->setModCnf); + if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) + pNew->setModCnf = NULL; + else if(localRet != RS_RET_OK) + ABORT_FINALIZE(localRet); /* optional calls for new config system */ localRet = (*pNew->modQueryEtryPt)((uchar*)"getModCnfName", &getModCnfName); @@ -766,6 +777,7 @@ static void modPrintList(void) dbgprintf("\tdbgPrintInstInfo: 0x%lx\n", (unsigned long) pMod->dbgPrintInstInfo); dbgprintf("\tfreeInstance: 0x%lx\n", (unsigned long) pMod->freeInstance); dbgprintf("\tbeginCnfLoad: 0x%lx\n", (unsigned long) pMod->beginCnfLoad); + dbgprintf("\tSetModCnf: 0x%lx\n", (unsigned long) pMod->setModCnf); dbgprintf("\tcheckCnf: 0x%lx\n", (unsigned long) pMod->checkCnf); dbgprintf("\tactivateCnfPrePrivDrop: 0x%lx\n", (unsigned long) pMod->activateCnfPrePrivDrop); dbgprintf("\tactivateCnf: 0x%lx\n", (unsigned long) pMod->activateCnf); @@ -946,12 +958,9 @@ findModule(uchar *pModName, int iModNameLen, modInfo_t **pMod) * Note: pvals = NULL means legacy config system */ static rsRetVal -Load(uchar *pModName, sbool bConfLoad, struct cnfparamvals *pvals) +Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) { - DEFiRet; - size_t iPathLen, iModNameLen; - uchar *pModNameCmp; int bHasExtension; void *pModHdlr, *pModInit; modInfo_t *pModInfo; @@ -965,6 +974,8 @@ Load(uchar *pModName, sbool bConfLoad, struct cnfparamvals *pvals) # endif uchar *pPathBuf = pathBuf; size_t lenPathBuf = sizeof(pathBuf); + rsRetVal localRet; + DEFiRet; assert(pModName != NULL); DBGPRINTF("Requested to load module '%s'\n", pModName); @@ -985,9 +996,19 @@ Load(uchar *pModName, sbool bConfLoad, struct cnfparamvals *pvals) CHKiRet(findModule(pModName, iModNameLen, &pModInfo)); if(pModInfo != NULL) { - if(bConfLoad) - addModToCnfList(pModInfo); - dbgprintf("Module '%s' already loaded\n", pModName); + DBGPRINTF("Module '%s' already loaded\n", pModName); + if(bConfLoad) { + localRet = addModToCnfList(pModInfo); + if(pModInfo->setModCnf != NULL && localRet == RS_RET_OK) { + if(!strncmp((char*)pModName, "builtin:", sizeof("builtin:")-1)) { + /* for built-in moules, we need to call setModConf, + * because there is no way to set parameters at load + * time for obvious reasons... + */ + pModInfo->setModCnf(lst); + } + } + } FINALIZE; } @@ -1095,8 +1116,12 @@ Load(uchar *pModName, sbool bConfLoad, struct cnfparamvals *pvals) dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_INIT_FAILED); } - if(bConfLoad) + + if(bConfLoad) { addModToCnfList(pModInfo); + if(pModInfo->setModCnf != NULL) + pModInfo->setModCnf(lst); + } finalize_it: if(pPathBuf != pathBuf) /* used malloc()ed memory? */ @@ -1130,7 +1155,7 @@ modulesProcessCnf(struct cnfobj *o) } cnfModName = (uchar*)es_str2cstr(pvals[typeIdx].val.d.estr, NULL); - iRet = Load(cnfModName, 1, pvals); + iRet = Load(cnfModName, 1, o->nvlst); finalize_it: free(cnfModName); -- cgit v1.2.3 From bf85d81790a26945e404c6fdfdddad5eadbaa371 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 25 Jun 2012 12:35:46 +0200 Subject: implemented freeCnf() module interface & fixed some mem leaks The interface was actually not present in older versions, even though some modules already used it. The implementation was now done, and not in 6.3/6.4 because the resulting memory leak was ultra-slim and the new interface handling has some potential to seriously break things. Not the kind of thing you want to add in late beta state, if avoidable. --- runtime/modules.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index e7ae72cc..6417cecd 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -1001,11 +1001,19 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) localRet = addModToCnfList(pModInfo); if(pModInfo->setModCnf != NULL && localRet == RS_RET_OK) { if(!strncmp((char*)pModName, "builtin:", sizeof("builtin:")-1)) { - /* for built-in moules, we need to call setModConf, - * because there is no way to set parameters at load - * time for obvious reasons... - */ - pModInfo->setModCnf(lst); + if(pModInfo->bSetModCnfCalled) { + errmsg.LogError(0, RS_RET_DUP_PARAM, + "parameters for built-in module %s already set - ignored\n", + pModName); + ABORT_FINALIZE(RS_RET_DUP_PARAM); + } else { + /* for built-in moules, we need to call setModConf, + * because there is no way to set parameters at load + * time for obvious reasons... + */ + pModInfo->setModCnf(lst); + pModInfo->bSetModCnfCalled = 1; + } } } } @@ -1119,8 +1127,10 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) if(bConfLoad) { addModToCnfList(pModInfo); - if(pModInfo->setModCnf != NULL) + if(pModInfo->setModCnf != NULL) { pModInfo->setModCnf(lst); + pModInfo->bSetModCnfCalled = 1; + } } finalize_it: -- cgit v1.2.3 From 9b0d03bf8f5eb89d5a1966df16187c5c6757c578 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 26 Jun 2012 17:18:20 +0200 Subject: modules: call new-style entry point only when new-style stmt is used This provides a way for modules to differentiate between old- and new- style config, so that they can react accordingly. --- runtime/modules.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 6417cecd..bc8580f1 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -1011,7 +1011,8 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) * because there is no way to set parameters at load * time for obvious reasons... */ - pModInfo->setModCnf(lst); + if(lst != NULL) + pModInfo->setModCnf(lst); pModInfo->bSetModCnfCalled = 1; } } @@ -1128,7 +1129,8 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) if(bConfLoad) { addModToCnfList(pModInfo); if(pModInfo->setModCnf != NULL) { - pModInfo->setModCnf(lst); + if(lst != NULL) + pModInfo->setModCnf(lst); pModInfo->bSetModCnfCalled = 1; } } -- cgit v1.2.3 From 9faf2240c4a8f09f3f6c2c9bbd47e48520524e03 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 22 Aug 2012 15:29:02 +0200 Subject: changed TRUE/FALSE to RSTRUE/RSFALSE This is done to prevent name claches with libraries. --- runtime/modules.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index b353e983..45788ef7 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -498,11 +498,11 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ /* check some features */ localRet = pNew->isCompatibleWithFeature(sFEATUREAutomaticSanitazion); if(localRet == RS_RET_OK){ - CHKiRet(parser.SetDoSanitazion(pParser, TRUE)); + CHKiRet(parser.SetDoSanitazion(pParser, RSTRUE)); } localRet = pNew->isCompatibleWithFeature(sFEATUREAutomaticPRIParsing); if(localRet == RS_RET_OK){ - CHKiRet(parser.SetDoPRIParsing(pParser, TRUE)); + CHKiRet(parser.SetDoPRIParsing(pParser, RSTRUE)); } CHKiRet(parser.SetName(pParser, pName)); @@ -787,9 +787,9 @@ Load(uchar *pModName) if(iModNameLen > 3 && !strcmp((char *) pModName + iModNameLen - 3, ".so")) { iModNameLen -= 3; - bHasExtension = TRUE; + bHasExtension = RSTRUE; } else - bHasExtension = FALSE; + bHasExtension = RSFALSE; pModInfo = GetNxt(NULL); while(pModInfo != NULL) { -- cgit v1.2.3 From d397bb25265b8b0926af050c4187cfbc5ab074ca Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 25 Sep 2012 15:19:34 +0200 Subject: fix invalid free caused by optimized script execution --- runtime/modules.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index d3c51e90..8675e414 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -313,7 +313,8 @@ finalize_it: /* get the name of a module */ -static uchar *modGetName(modInfo_t *pThis) +uchar * +modGetName(modInfo_t *pThis) { return((pThis->pszName == NULL) ? (uchar*) "" : pThis->pszName); } -- cgit v1.2.3 From 7c2183ee323dc062b0dde6bac4cd9c5afa4ab369 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Wed, 26 Sep 2012 12:25:10 +0200 Subject: input stmt: add core engine plumbing --- runtime/modules.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index d3c51e90..c0dd0ffb 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -607,6 +607,12 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ CHKiRet((*pNew->modQueryEtryPt)((uchar*)"willRun", &pNew->mod.im.willRun)); CHKiRet((*pNew->modQueryEtryPt)((uchar*)"afterRun", &pNew->mod.im.afterRun)); pNew->mod.im.bCanRun = 0; + localRet = (*pNew->modQueryEtryPt)((uchar*)"newInpInst", &pNew->mod.im.newInpInst); + if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { + pNew->mod.om.newActInst = NULL; + } else if(localRet != RS_RET_OK) { + ABORT_FINALIZE(localRet); + } break; case eMOD_OUT: CHKiRet((*pNew->modQueryEtryPt)((uchar*)"freeInstance", &pNew->freeInstance)); @@ -625,7 +631,8 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ else if(localRet != RS_RET_OK) ABORT_FINALIZE(localRet); - localRet = (*pNew->modQueryEtryPt)((uchar*)"endTransaction", &pNew->mod.om.endTransaction); + localRet = (*pNew->modQueryEtryPt)((uchar*)"endTransaction", + &pNew->mod.om.endTransaction); if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) { pNew->mod.om.endTransaction = dummyEndTransaction; } else if(localRet != RS_RET_OK) { -- cgit v1.2.3 From 77b4efaeecf53678a3de579d73567e61c3b4785b Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Thu, 27 Sep 2012 14:22:23 +0200 Subject: Do not load module if it had errorneous parameters --- runtime/modules.c | 61 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 52 insertions(+), 9 deletions(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index c0dd0ffb..5706685f 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -349,11 +349,13 @@ addModToGlblList(modInfo_t *pThis) } -/* Add a module to the config module list for current loadConf and - * provide its config params to it. +/* ready module for config processing. this includes checking if the module + * is already in the config, so this function may return errors. Returns a + * pointer to the last module inthe current config. That pointer needs to + * be passed to addModToCnfLst() when it is called later in the process. */ rsRetVal -addModToCnfList(modInfo_t *pThis) +readyModForCnf(modInfo_t *pThis, cfgmodules_etry_t **ppNew, cfgmodules_etry_t **ppLast) { cfgmodules_etry_t *pNew; cfgmodules_etry_t *pLast; @@ -361,8 +363,7 @@ addModToCnfList(modInfo_t *pThis) assert(pThis != NULL); if(loadConf == NULL) { - /* we are in an early init state */ - FINALIZE; + FINALIZE; /* we are in an early init state */ } /* check for duplicates and, as a side-activity, identify last node */ @@ -398,6 +399,36 @@ addModToCnfList(modInfo_t *pThis) CHKiRet(pThis->beginCnfLoad(&pNew->modCnf, loadConf)); } + *ppLast = pLast; + *ppNew = pNew; +finalize_it: + RETiRet; +} + + +/* abort the creation of a module entry without adding it to the + * module list. Needed to prevent mem leaks. + */ +static inline void +abortCnfUse(cfgmodules_etry_t *pNew) +{ + free(pNew); +} + + +/* Add a module to the config module list for current loadConf. + * Requires last pointer obtained by readyModForCnf(). + */ +rsRetVal +addModToCnfList(cfgmodules_etry_t *pNew, cfgmodules_etry_t *pLast) +{ + DEFiRet; + assert(pNew != NULL); + + if(loadConf == NULL) { + FINALIZE; /* we are in an early init state */ + } + if(pLast == NULL) { loadConf->modules.root = pNew; } else { @@ -971,6 +1002,8 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) int bHasExtension; void *pModHdlr, *pModInit; modInfo_t *pModInfo; + cfgmodules_etry_t *pNew; + cfgmodules_etry_t *pLast; uchar *pModDirCurr, *pModDirNext; int iLoadCnt; struct dlhandle_s *pHandle = NULL; @@ -1005,8 +1038,9 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) if(pModInfo != NULL) { DBGPRINTF("Module '%s' already loaded\n", pModName); if(bConfLoad) { - localRet = addModToCnfList(pModInfo); + localRet = readyModForCnf(pModInfo, &pNew, &pLast); if(pModInfo->setModCnf != NULL && localRet == RS_RET_OK) { + addModToCnfList(pNew, pLast); if(!strncmp((char*)pModName, "builtin:", sizeof("builtin:")-1)) { if(pModInfo->bSetModCnfCalled) { errmsg.LogError(0, RS_RET_DUP_PARAM, @@ -1134,12 +1168,21 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) } if(bConfLoad) { - addModToCnfList(pModInfo); + readyModForCnf(pModInfo, &pNew, &pLast); if(pModInfo->setModCnf != NULL) { - if(lst != NULL) - pModInfo->setModCnf(lst); + if(lst != NULL) { + localRet = pModInfo->setModCnf(lst); + if(localRet != RS_RET_OK) { + errmsg.LogError(0, localRet, + "module '%s', failed processing config parameters", + pPathBuf); + abortCnfUse(pNew); + ABORT_FINALIZE(localRet); + } + } pModInfo->bSetModCnfCalled = 1; } + addModToCnfList(pNew, pLast); } finalize_it: -- cgit v1.2.3 From d9cde56eb8532bd660d6feb2249562afac0c40f6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 8 Apr 2013 17:55:52 +0200 Subject: add output module interface to facilitate cooperative shutdown ... in more complex cases (where receiving SIGTTIN is not sufficient). See also: http://blog.gerhards.net/2013/04/rsyslog-output-plugin-wrangling.html --- runtime/modules.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 9f7ff31c..e9d8d959 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -657,6 +657,10 @@ doModInit(rsRetVal (*modInit)(int, int*, rsRetVal(**)(), rsRetVal(*)(), modInfo_ if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) ABORT_FINALIZE(localRet); + localRet = (*pNew->modQueryEtryPt)((uchar*)"SetShutdownImmdtPtr", &pNew->mod.om.SetShutdownImmdtPtr); + if(localRet != RS_RET_OK && localRet != RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) + ABORT_FINALIZE(localRet); + localRet = (*pNew->modQueryEtryPt)((uchar*)"beginTransaction", &pNew->mod.om.beginTransaction); if(localRet == RS_RET_MODULE_ENTRY_POINT_NOT_FOUND) pNew->mod.om.beginTransaction = dummyBeginTransaction; -- cgit v1.2.3 From d275d116fcdcff14ff71642cf7b4f563a2b42eff Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Mon, 6 May 2013 07:39:33 +0200 Subject: bugfix: potential segfault on startup when builtin module was specified in module() statement. Thanks to Marius Tomaschewski for reporting the bug. --- runtime/modules.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'runtime/modules.c') diff --git a/runtime/modules.c b/runtime/modules.c index 9f7ff31c..ca444895 100644 --- a/runtime/modules.c +++ b/runtime/modules.c @@ -1041,7 +1041,6 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) if(bConfLoad) { localRet = readyModForCnf(pModInfo, &pNew, &pLast); if(pModInfo->setModCnf != NULL && localRet == RS_RET_OK) { - addModToCnfList(pNew, pLast); if(!strncmp((char*)pModName, "builtin:", sizeof("builtin:")-1)) { if(pModInfo->bSetModCnfCalled) { errmsg.LogError(0, RS_RET_DUP_PARAM, @@ -1057,6 +1056,11 @@ Load(uchar *pModName, sbool bConfLoad, struct nvlst *lst) pModInfo->setModCnf(lst); pModInfo->bSetModCnfCalled = 1; } + } else { + /* regular modules need to be added to conf list (for + * builtins, this happend during initial load). + */ + addModToCnfList(pNew, pLast); } } } -- cgit v1.2.3