diff options
author | Robin Burchell w00t@inspircd.org <Robin Burchell w00t@inspircd.org@5417fbe8-f217-4b02-8779-1006273d7864> | 2008-11-09 16:56:54 +0000 |
---|---|---|
committer | Robin Burchell w00t@inspircd.org <Robin Burchell w00t@inspircd.org@5417fbe8-f217-4b02-8779-1006273d7864> | 2008-11-09 16:56:54 +0000 |
commit | 65fd49d3628dd8d3bde8f70b58ac458785a261d7 (patch) | |
tree | 0b6148ca77f747d4ef2732e5c004292868fd9bf3 | |
parent | cd71f37e2d1361498c516715e4b83d5909422327 (diff) |
Move loadModule() and unloadModule() inside ModuleManager::
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@1614 5417fbe8-f217-4b02-8779-1006273d7864
-rw-r--r-- | include/modules.h | 67 | ||||
-rw-r--r-- | src/core/os_modload.c | 2 | ||||
-rw-r--r-- | src/core/os_modunload.c | 2 | ||||
-rw-r--r-- | src/module.cpp | 7 | ||||
-rw-r--r-- | src/modulemanager.cpp | 243 | ||||
-rw-r--r-- | src/modules.c | 280 |
6 files changed, 294 insertions, 307 deletions
diff --git a/include/modules.h b/include/modules.h index 884ece7eb..4f3962682 100644 --- a/include/modules.h +++ b/include/modules.h @@ -132,27 +132,19 @@ struct ModuleLang_ { char **argv; }; -/** Used to manage modules. - */ -CoreExport class ModuleManager -{ - public: - /** - * Load up a list of modules. - * @param total_modules The number of modules to load - * @param module_list The list of modules to load - **/ - static void LoadModuleList(int total_modules, char **module_list); -}; - /** Every module in Anope is actually a class. */ CoreExport class Module { public: - // XXX :( + /** The module name (e.g. os_modload) + */ std::string name; - char *filename; + + /** The temporary path/filename + */ + std::string filename; + void *handle; time_t time; std::string version; @@ -250,6 +242,40 @@ CoreExport class Module int DelCommand(CommandHash * cmdTable[], const char *name); }; + + + +/** Used to manage modules. + */ +CoreExport class ModuleManager +{ + public: + /** + * Load up a list of modules. + * @param total_modules The number of modules to load + * @param module_list The list of modules to load + **/ + static void LoadModuleList(int total_modules, char **module_list); + + /** + * Loads a given module. + * @param m the module to load + * @param u the user who loaded it, NULL for auto-load + * @return MOD_ERR_OK on success, anything else on fail + */ + static int LoadModule(const std::string &modname, User * u); + + /** + * Unload the given module. + * @param m the module to unload + * @param u the user who unloaded it + * @return MOD_ERR_OK on success, anything else on fail + */ + static int UnloadModule(Module *m, User * u); +}; + + + struct ModuleHash_ { char *name; Module *m; @@ -354,17 +380,8 @@ int addModule(Module *m); /* Add a module to the module hash */ int delModule(Module *m); /* Remove a module from the module hash */ MDE Module *findModule(const char *name); /* Find a module */ -/** Loads a given Anope module into the core, initialising relevant structures, - * and calls the module's constructor. - * @param modname The name of the module to load (e.g. os_modload) - * @param u The user loading the module, or NULL for no user. - * @return XXX, document me. - */ -int loadModule(const std::string &modname, User *u); - int encryption_module_init(void); /* Load the encryption module */ int protocol_module_init(void); /* Load the IRCD Protocol Module up*/ -int unloadModule(Module *m, User *u); /* Unload the given module from the pro */ void moduleCallBackPrepForUnload(const char *mod_name); MDE void moduleCallBackDeleteEntry(ModuleCallBack * prev); MDE char *moduleGetLastBuffer(void); @@ -424,7 +441,7 @@ int destroyEventHook(EvtHook * evh); MDE void moduleInsertLanguage(int langNumber, int ac, const char **av); MDE void moduleNoticeLang(char *source, User *u, int number, ...); -MDE char *moduleGetLangString(User * u, int number); +MDE const char *moduleGetLangString(User * u, int number); MDE void moduleDeleteLanguage(int langNumber); /*************************************************************************/ diff --git a/src/core/os_modload.c b/src/core/os_modload.c index eb83cb1c7..3c7ce4a39 100644 --- a/src/core/os_modload.c +++ b/src/core/os_modload.c @@ -71,7 +71,7 @@ int do_modload(User * u) return MOD_CONT; } - int status = loadModule(name, u); + int status = ModuleManager::LoadModule(name, u); if (status != MOD_ERR_OK) { notice_lang(s_OperServ, u, OPER_MODULE_LOAD_FAIL, m->name.c_str()); diff --git a/src/core/os_modunload.c b/src/core/os_modunload.c index bfdf1b323..8fde45fc8 100644 --- a/src/core/os_modunload.c +++ b/src/core/os_modunload.c @@ -75,7 +75,7 @@ int do_modunload(User *u) alog("Trying to unload module [%s]", name); - status = unloadModule(m, u); + status = ModuleManager::UnloadModule(m, u); if (!status) { diff --git a/src/module.cpp b/src/module.cpp index 422d1a643..3f9aabaed 100644 --- a/src/module.cpp +++ b/src/module.cpp @@ -21,7 +21,6 @@ Module::Module(const std::string &mname, const std::string &creator) { this->name = mname; /* Our name */ - this->filename = NULL; this->nickHelp = NULL; this->chanHelp = NULL; this->memoHelp = NULL; @@ -46,11 +45,7 @@ Module::~Module() for (i = 0; i < NUM_LANGS; i++) moduleDeleteLanguage(i); - if (this->filename) - { - remove(this->filename); - free(this->filename); - } + remove(this->filename.c_str()); if (this->handle) { diff --git a/src/modulemanager.cpp b/src/modulemanager.cpp index 1e5a8f8bb..3d22fb50a 100644 --- a/src/modulemanager.cpp +++ b/src/modulemanager.cpp @@ -12,6 +12,12 @@ #include "language.h" #include "version.h" +#if !defined(_WIN32) + #include <dlfcn.h> +#else + const char *ano_moderr(void); +#endif + void ModuleManager::LoadModuleList(int total_modules, char **module_list) { int idx; @@ -20,9 +26,244 @@ void ModuleManager::LoadModuleList(int total_modules, char **module_list) for (idx = 0; idx < total_modules; idx++) { m = findModule(module_list[idx]); if (!m) { - status = loadModule(module_list[idx], NULL); + status = ModuleManager::LoadModule(module_list[idx], NULL); mod_current_module = NULL; mod_current_user = NULL; } } } + +/** + * Copy the module from the modules folder to the runtime folder. + * This will prevent module updates while the modules is loaded from + * triggering a segfault, as the actaul file in use will be in the + * runtime folder. + * @param name the name of the module to copy + * @param output the destination to copy the module to + * @return MOD_ERR_OK on success + */ +static int moduleCopyFile(const char *name, const char *output) +{ + int ch; + FILE *source, *target; + int srcfp; + char input[4096]; + int len; + + strncpy(input, MODULE_PATH, 4095); /* Get full path with module extension */ + len = strlen(input); + strncat(input, name, 4095 - len); + len = strlen(output); + strncat(input, MODULE_EXT, 4095 - len); + +#ifndef _WIN32 + if ((srcfp = mkstemp((char *)output)) == -1) + return MOD_ERR_FILE_IO; +#else + if (!mktemp(output)) + return MOD_ERR_FILE_IO; +#endif + + if (debug) + alog("Runtime module location: %s", output); + + /* Linux/UNIX should ignore the b param, why do we still have seperate + * calls for it here? -GD + */ +#ifndef _WIN32 + if ((source = fopen(input, "r")) == NULL) { +#else + if ((source = fopen(input, "rb")) == NULL) { +#endif + return MOD_ERR_NOEXIST; + } +#ifndef _WIN32 + if ((target = fdopen(srcfp, "w")) == NULL) { +#else + if ((target = fopen(output, "wb")) == NULL) { +#endif + return MOD_ERR_FILE_IO; + } + while ((ch = fgetc(source)) != EOF) { + fputc(ch, target); + } + fclose(source); + if (fclose(target) != 0) { + return MOD_ERR_FILE_IO; + } + return MOD_ERR_OK; +} + +/** + * Search all loaded modules looking for a protocol module. + * @return 1 if one is found. + **/ +static int protocolModuleLoaded() +{ + int idx = 0; + ModuleHash *current = NULL; + + for (idx = 0; idx != MAX_CMD_HASH; idx++) { + for (current = MODULE_HASH[idx]; current; current = current->next) { + if (current->m->type == PROTOCOL) { + return 1; + } + } + } + return 0; +} + +/** + * Search all loaded modules looking for an encryption module. + * @ return 1 if one is loaded + **/ +static int encryptionModuleLoaded() +{ + int idx = 0; + ModuleHash *current = NULL; + + for (idx = 0; idx != MAX_CMD_HASH; idx++) { + for (current = MODULE_HASH[idx]; current; current = current->next) { + if (current->m->type == ENCRYPTION) { + return 1; + } + } + } + return 0; +} + +int ModuleManager::LoadModule(const std::string &modname, User * u) +{ + int len; + const char *err; + Module * (*func) (const std::string &); + int ret = 0; + + if (modname.empty()) + return MOD_ERR_PARAMS; + + if (findModule(modname.c_str()) != NULL) + return MOD_ERR_EXISTS; + + if (debug) + alog("trying to load [%s]", modname.c_str()); + + /* Generate the filename for the temporary copy of the module */ + std::string pbuf; + pbuf = MODULE_PATH; +#ifndef _WIN32 + pbuf += "runtime/"; +#else + pbuf += "runtime\\"; +#endif + pbuf += modname; + pbuf += MODULE_EXT; + pbuf += "."; + pbuf += "XXXXXX"; + + /* Don't skip return value checking! -GD */ + if ((ret = moduleCopyFile(modname.c_str(), pbuf.c_str())) != MOD_ERR_OK) + { + /* XXX: This used to assign filename here, but I don't think that was correct.. + * even if it was, it makes life very fucking difficult, so. + */ + return ret; + } + + ano_modclearerr(); + + void *handle = ano_modopen(pbuf.c_str()); + if (handle == NULL && (err = ano_moderr()) != NULL) + { + alog("%s", err); + return MOD_ERR_NOLOAD; + } + + ano_modclearerr(); + func = (Module *(*)(const std::string &))ano_modsym(handle, "init_module"); + if (func == NULL && (err = ano_moderr()) != NULL) + { + alog("No magical init function found, not an Anope module"); + ano_modclose(handle); + return MOD_ERR_NOLOAD; + } + + if (!func) + { + throw CoreException("Couldn't find constructor, yet moderror wasn't set?"); + } + + mod_current_module_name = modname.c_str(); + + /* Create module. */ + std::string nick; + if (u) + nick = u->nick; + else + nick = ""; + + Module *m; + + try + { + m = func(nick); + } + catch (ModuleException &ex) + { + alog("Error while loading %s: %s", modname.c_str(), ex.GetReason()); + return MOD_STOP; + } + + mod_current_module = m; + mod_current_user = u; + m->filename = pbuf; + m->handle = handle; + + if (m->type == PROTOCOL && protocolModuleLoaded()) + { + alog("You cannot load two protocol modules"); + ret = MOD_STOP; + } + else if (m->type == ENCRYPTION && encryptionModuleLoaded()) + { + alog("You cannot load two encryption modules"); + ret = MOD_STOP; + } + + mod_current_module_name = NULL; + + if (u) + { + ircdproto->SendGlobops(s_OperServ, "%s loaded module %s", u->nick, modname.c_str()); + notice_lang(s_OperServ, u, OPER_MODULE_LOADED, modname.c_str()); + } + addModule(m); + return MOD_ERR_OK; +} + +int ModuleManager::UnloadModule(Module * m, User * u) +{ + if (!m || !m->handle) + { + if (u) + notice_lang(s_OperServ, u, OPER_MODULE_REMOVE_FAIL, m->name.c_str()); + return MOD_ERR_PARAMS; + } + + if (m->type == PROTOCOL || m->type == ENCRYPTION) + { + if (u) + notice_lang(s_OperServ, u, OPER_MODULE_NO_UNLOAD); + return MOD_ERR_NOUNLOAD; + } + + if (u) + { + ircdproto->SendGlobops(s_OperServ, "%s unloaded module %s", u->nick, m->name.c_str()); + notice_lang(s_OperServ, u, OPER_MODULE_UNLOADED, m->name.c_str()); + } + + delModule(m); + return MOD_ERR_OK; +} + diff --git a/src/modules.c b/src/modules.c index 296700354..674f8d110 100644 --- a/src/modules.c +++ b/src/modules.c @@ -177,7 +177,7 @@ int encryption_module_init(void) { int ret = 0; alog("Loading Encryption Module: [%s]", EncModule); - ret = loadModule(EncModule, NULL); + ret = ModuleManager::LoadModule(EncModule, NULL); if (ret == MOD_ERR_OK) findModule(EncModule)->SetType(ENCRYPTION); mod_current_module = NULL; @@ -192,7 +192,7 @@ int protocol_module_init(void) int ret = 0; alog("Loading IRCD Protocol Module: [%s]", IRCDModule); - ret = loadModule(IRCDModule, NULL); + ret = ModuleManager::LoadModule(IRCDModule, NULL); if (ret == MOD_ERR_OK) { @@ -368,272 +368,6 @@ Module *findModule(const char *name) } -/** - * Search all loaded modules looking for a protocol module. - * @return 1 if one is found. - **/ -int protocolModuleLoaded() -{ - int idx = 0; - ModuleHash *current = NULL; - - for (idx = 0; idx != MAX_CMD_HASH; idx++) { - for (current = MODULE_HASH[idx]; current; current = current->next) { - if (current->m->type == PROTOCOL) { - return 1; - } - } - } - return 0; -} - -/** - * Search all loaded modules looking for an encryption module. - * @ return 1 if one is loaded - **/ -int encryptionModuleLoaded() -{ - int idx = 0; - ModuleHash *current = NULL; - - for (idx = 0; idx != MAX_CMD_HASH; idx++) { - for (current = MODULE_HASH[idx]; current; current = current->next) { - if (current->m->type == ENCRYPTION) { - return 1; - } - } - } - return 0; -} - -/** - * Copy the module from the modules folder to the runtime folder. - * This will prevent module updates while the modules is loaded from - * triggering a segfault, as the actaul file in use will be in the - * runtime folder. - * @param name the name of the module to copy - * @param output the destination to copy the module to - * @return MOD_ERR_OK on success - */ -static int moduleCopyFile(const char *name, char *output) -{ - int ch; - FILE *source, *target; - int srcfp; - char input[4096]; - int len; - - strncpy(input, MODULE_PATH, 4095); /* Get full path with module extension */ - len = strlen(input); - strncat(input, name, 4095 - len); - len = strlen(output); - strncat(input, MODULE_EXT, 4095 - len); - -#ifndef _WIN32 - if ((srcfp = mkstemp(output)) == -1) - return MOD_ERR_FILE_IO; -#else - if (!mktemp(output)) - return MOD_ERR_FILE_IO; -#endif - - if (debug) - alog("Runtime module location: %s", output); - - /* Linux/UNIX should ignore the b param, why do we still have seperate - * calls for it here? -GD - */ -#ifndef _WIN32 - if ((source = fopen(input, "r")) == NULL) { -#else - if ((source = fopen(input, "rb")) == NULL) { -#endif - return MOD_ERR_NOEXIST; - } -#ifndef _WIN32 - if ((target = fdopen(srcfp, "w")) == NULL) { -#else - if ((target = fopen(output, "wb")) == NULL) { -#endif - return MOD_ERR_FILE_IO; - } - while ((ch = fgetc(source)) != EOF) { - fputc(ch, target); - } - fclose(source); - if (fclose(target) != 0) { - return MOD_ERR_FILE_IO; - } - return MOD_ERR_OK; -} - -/** - * Loads a given module. - * @param m the module to load - * @param u the user who loaded it, NULL for auto-load - * @return MOD_ERR_OK on success, anything else on fail - */ -int loadModule(const std::string &modname, User * u) -{ - char buf[4096]; - int len; - const char *err; - Module * (*func) (const std::string &); - int ret = 0; - - if (modname.empty()) - return MOD_ERR_PARAMS; - - if (findModule(modname.c_str()) != NULL) - return MOD_ERR_EXISTS; - - if (debug) - alog("trying to load [%s]", modname.c_str()); - - /* Generate the filename for the temporary copy of the module */ - strncpy(buf, MODULE_PATH, 4095); /* Get full path with module extension */ - len = strlen(buf); -#ifndef _WIN32 - strncat(buf, "runtime/", 4095 - len); -#else - strncat(buf, "runtime\\", 4095 - len); -#endif - len = strlen(buf); - strncat(buf, modname.c_str(), 4095 - len); - len = strlen(buf); - strncat(buf, MODULE_EXT, 4095 - len); - len = strlen(buf); - strncat(buf, ".", 4095 - len); - len = strlen(buf); - strncat(buf, "XXXXXX", 4095 - len); - buf[4095] = '\0'; - /* Don't skip return value checking! -GD */ - if ((ret = moduleCopyFile(modname.c_str(), buf)) != MOD_ERR_OK) - { - /* XXX: This used to assign filename here, but I don't think that was correct.. - * even if it was, it makes life very fucking difficult, so. - */ -// m->filename = sstrdup(buf); - return ret; - } - - ano_modclearerr(); - - void *handle = ano_modopen(buf); - if (handle == NULL && (err = ano_moderr()) != NULL) - { - alog("%s", err); - return MOD_ERR_NOLOAD; - } - - ano_modclearerr(); - func = (Module *(*)(const std::string &))ano_modsym(handle, "init_module"); - if (func == NULL && (err = ano_moderr()) != NULL) - { - alog("No magical init function found, not an Anope module, or a very old module(?)"); - ano_modclose(handle); /* If no AnopeInit - it isnt an Anope Module, close it */ - return MOD_ERR_NOLOAD; - } - - if (!func) - { - throw CoreException("Couldn't find constructor, yet moderror wasn't set?"); - } - - mod_current_module_name = modname.c_str(); - - /* Create module. */ - std::string nick; - if (u) - nick = u->nick; - else - nick = ""; - - Module *m; - - try - { - m = func(nick); - } - catch (ModuleException &ex) - { - alog("Error while loading %s: %s", modname.c_str(), ex.GetReason()); - return MOD_STOP; - } - - mod_current_module = m; - mod_current_user = u; - m->filename = sstrdup(buf); - m->handle = handle; - -/* - if (ret == MOD_STOP) { - alog("%s requested unload...", m->name); - unloadModule(m, NULL); - mod_current_module_name = NULL; - return MOD_ERR_NOLOAD; - } -*/ - if (m->type == PROTOCOL && protocolModuleLoaded()) - { - alog("You cannot load two protocol modules"); - ret = MOD_STOP; - } - else if (m->type == ENCRYPTION && encryptionModuleLoaded()) - { - alog("You cannot load two encryption modules"); - ret = MOD_STOP; - } - - mod_current_module_name = NULL; - - if (u) - { - ircdproto->SendGlobops(s_OperServ, "%s loaded module %s", u->nick, modname.c_str()); - notice_lang(s_OperServ, u, OPER_MODULE_LOADED, modname.c_str()); - } - addModule(m); - return MOD_ERR_OK; -} - -/** - * Unload the given module. - * @param m the module to unload - * @param u the user who unloaded it - * @return MOD_ERR_OK on success, anything else on fail - */ -int unloadModule(Module * m, User * u) -{ - void (*func) (void); - - if (!m || !m->handle) { - if (u) { - notice_lang(s_OperServ, u, OPER_MODULE_REMOVE_FAIL, m->name.c_str()); - } - return MOD_ERR_PARAMS; - } - - if (m->type == PROTOCOL) { - if (u) { - notice_lang(s_OperServ, u, OPER_MODULE_NO_UNLOAD); - } - return MOD_ERR_NOUNLOAD; - } else if(m->type == ENCRYPTION) { - if (u) { - notice_lang(s_OperServ, u, OPER_MODULE_NO_UNLOAD); - } - return MOD_ERR_NOUNLOAD; - } - - if (u) { - ircdproto->SendGlobops(s_OperServ, "%s unloaded module %s", u->nick, - m->name.c_str()); - notice_lang(s_OperServ, u, OPER_MODULE_UNLOADED, m->name.c_str()); - } - delModule(m); - return MOD_ERR_OK; -} - /******************************************************************************* * Command Functions *******************************************************************************/ @@ -949,13 +683,13 @@ static int internal_delCommand(CommandHash * cmdTable[], Command * c, const char * @param name the name of the command to delete from the service * @return returns MOD_ERR_OK on success */ -int Module::DelCommand(CommandHash * cmdTable[], const char *name) +int Module::DelCommand(CommandHash * cmdTable[], const char *dname) { Command *c = NULL; Command *cmd = NULL; int status = 0; - c = findCommand(cmdTable, name); + c = findCommand(cmdTable, dname); if (!c) { return MOD_ERR_NOEXIST; } @@ -965,11 +699,11 @@ int Module::DelCommand(CommandHash * cmdTable[], const char *name) if (cmd->mod_name && cmd->mod_name == this->name) { if (debug >= 2) { - displayCommandFromHash(cmdTable, name); + displayCommandFromHash(cmdTable, dname); } status = internal_delCommand(cmdTable, cmd, this->name.c_str()); if (debug >= 2) { - displayCommandFromHash(cmdTable, name); + displayCommandFromHash(cmdTable, dname); } } } @@ -2176,7 +1910,7 @@ void moduleNoticeLang(char *source, User * u, int number, ...) * @param u The user to send the message to * @param number The message number **/ -char *moduleGetLangString(User * u, int number) +const char *moduleGetLangString(User * u, int number) { int lang = NSDefLanguage; |