diff options
Diffstat (limited to 'runtime/modules.c')
-rw-r--r-- | runtime/modules.c | 169 |
1 files changed, 151 insertions, 18 deletions
diff --git a/runtime/modules.c b/runtime/modules.c index 39f977dd..5706685f 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 @@ -337,10 +349,13 @@ addModToGlblList(modInfo_t *pThis) } -/* Add a module to the config module list for current loadConf +/* 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; @@ -348,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 */ @@ -358,11 +372,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; } } @@ -380,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 { @@ -535,7 +584,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 @@ -548,6 +597,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); @@ -584,6 +638,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)); @@ -602,7 +662,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) { @@ -754,6 +815,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); @@ -931,17 +993,17 @@ 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 nvlst *lst) { - DEFiRet; - size_t iPathLen, iModNameLen; - uchar *pModNameCmp; 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; @@ -952,9 +1014,11 @@ Load(uchar *pModName, sbool bConfLoad) # endif uchar *pPathBuf = pathBuf; size_t lenPathBuf = sizeof(pathBuf); + rsRetVal localRet; + DEFiRet; 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, @@ -972,9 +1036,29 @@ Load(uchar *pModName, sbool bConfLoad) 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 = 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, + "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... + */ + if(lst != NULL) + pModInfo->setModCnf(lst); + pModInfo->bSetModCnfCalled = 1; + } + } + } + } FINALIZE; } @@ -1082,8 +1166,24 @@ Load(uchar *pModName, sbool bConfLoad) dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_INIT_FAILED); } - if(bConfLoad) - addModToCnfList(pModInfo); + + if(bConfLoad) { + readyModForCnf(pModInfo, &pNew, &pLast); + if(pModInfo->setModCnf != NULL) { + 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: if(pPathBuf != pathBuf) /* used malloc()ed memory? */ @@ -1093,6 +1193,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, o->nvlst); + +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. |