/* 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; uchar *pModDirCurr, *pModDirNext; int iLoadCnt; struct dlhandle_s *pHandle = NULL; 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; 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); } pModDirCurr = (uchar *)((pModDir == NULL) ? _PATH_MODDIR : (char *)pModDir); pModDirNext = NULL; pModHdlr = NULL; iLoadCnt = 0; 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 */ 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); /* 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); } /* complete load path constructed, so ... GO! */ dbgprintf("loading module '%s'\n", szPath); /* see if we have this one already */ for (pHandle = pHandles; pHandle; pHandle = pHandle->next) { if (!strcmp((char *)pModName, (char *)pHandle->pszName)) { 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); 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"))) { 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); dlclose(pModHdlr); ABORT_FINALIZE(RS_RET_MODULE_LOAD_ERR_INIT_FAILED); } finalize_it: pthread_mutex_unlock(&mutLoadUnload); 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; }