diff options
Diffstat (limited to 'src/modulemanager.cpp')
-rw-r--r-- | src/modulemanager.cpp | 289 |
1 files changed, 78 insertions, 211 deletions
diff --git a/src/modulemanager.cpp b/src/modulemanager.cpp index ce17e61ae..4631370ac 100644 --- a/src/modulemanager.cpp +++ b/src/modulemanager.cpp @@ -1,16 +1,27 @@ -/* Modular support +/* + * Anope IRC Services * - * (C) 2003-2017 Anope Team - * Contact us at team@anope.org + * Copyright (C) 2008-2017 Anope Team <team@anope.org> * - * Please read COPYING and README for further details. + * This file is part of Anope. Anope is free software; you can + * redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software + * Foundation, version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see see <http://www.gnu.org/licenses/>. */ #include "services.h" #include "modules.h" #include "users.h" -#include "regchannel.h" #include "config.h" +#include "event.h" #include <sys/types.h> #include <sys/stat.h> @@ -21,19 +32,28 @@ #endif std::list<Module *> ModuleManager::Modules; -std::vector<Module *> ModuleManager::EventHandlers[I_SIZE]; + +void ModuleDef::Depends(const Anope::string &modname) +{ + dependencies.push_back(modname); +} + +const std::vector<Anope::string> &ModuleDef::GetDependencies() +{ + return dependencies; +} #ifdef _WIN32 void ModuleManager::CleanupRuntimeDirectory() { Anope::string dirbuf = Anope::DataDir + "/runtime"; - Log(LOG_DEBUG) << "Cleaning out Module run time directory (" << dirbuf << ") - this may take a moment, please wait"; + Anope::Logger.Debug("Cleaning out Module run time directory ({0}) - this may take a moment please wait", dirbuf); DIR *dirp = opendir(dirbuf.c_str()); if (!dirp) { - Log(LOG_DEBUG) << "Cannot open directory (" << dirbuf << ")"; + Anope::Logger.Debug("Cannot open directory ({0})", dirbuf); return; } @@ -84,7 +104,7 @@ static ModuleReturn moduleCopyFile(const Anope::string &name, Anope::string &out output = tmp_output; free(tmp_output); - Log(LOG_DEBUG_2) << "Runtime module location: " << output; + Anope::Logger.Debug2("Runtime module location: {0}", output); std::ofstream target(output.c_str(), std::ios_base::in | std::ios_base::binary); if (!target.is_open()) @@ -111,22 +131,6 @@ static ModuleReturn moduleCopyFile(const Anope::string &name, Anope::string &out } #endif -/* This code was found online at http://www.linuxjournal.com/article/3687#comment-26593 - * - * This function will take a pointer from either dlsym or GetProcAddress and cast it in - * a way that won't cause C++ warnings/errors to come up. - */ -template <class TYPE> static TYPE function_cast(void *symbol) -{ - union - { - void *symbol; - TYPE function; - } cast; - cast.symbol = symbol; - return cast.function; -} - ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) { if (modname.empty()) @@ -135,24 +139,24 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) if (FindModule(modname)) return MOD_ERR_EXISTS; - Log(LOG_DEBUG) << "Trying to load module: " << modname; + Anope::Logger.Debug("Trying to load module: {0}", modname); #ifdef _WIN32 /* Generate the filename for the temporary copy of the module */ - Anope::string pbuf = Anope::DataDir + "/runtime/" + modname + ".so.XXXXXX"; + Anope::string pbuf = Anope::DataDir + "/runtime/" + modname.replace_all_cs("/", "_") + ".so.XXXXXX"; /* Don't skip return value checking! -GD */ ModuleReturn ret = moduleCopyFile(modname, pbuf); if (ret != MOD_ERR_OK) { if (ret == MOD_ERR_NOEXIST) - Log(LOG_TERMINAL) << "Error while loading " << modname << " (file does not exist)"; + Anope::Logger.Terminal(_("Error while loading {0} (file does not exist)"), modname); else if (ret == MOD_ERR_FILE_IO) - Log(LOG_TERMINAL) << "Error while loading " << modname << " (file IO error, check file permissions and diskspace)"; + Anope::Logger.Terminal(_("Error while loading {0} (file IO error, check file permissions and diskspace)"), modname); return ret; } #else - Anope::string pbuf = Anope::ModuleDir + "/modules/" + modname + ".so"; + Anope::string pbuf = Anope::ModuleDir + "/modules/" + modname.replace_all_cs("/", "_") + ".so"; #endif dlerror(); @@ -161,41 +165,53 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) if (!handle) { if (err && *err) - Log() << err; + Anope::Logger.Log(err); + return MOD_ERR_NOLOAD; + } + + dlerror(); + AnopeModule *module = static_cast<AnopeModule *>(dlsym(handle, "AnopeMod")); + err = dlerror(); + if (!module || module->api_version != ANOPE_MODAPI_VER) + { + Anope::Logger.Log("No module symbols function found, not an Anope module"); + if (err && *err) + Anope::Logger.Log(err); + dlclose(handle); return MOD_ERR_NOLOAD; } try { - ModuleVersion v = GetVersion(handle); + ModuleVersion v = module->version(); if (v.GetMajor() < Anope::VersionMajor() || (v.GetMajor() == Anope::VersionMajor() && v.GetMinor() < Anope::VersionMinor())) { - Log() << "Module " << modname << " is compiled against an older version of Anope " << v.GetMajor() << "." << v.GetMinor() << ", this is " << Anope::VersionShort(); + Anope::Logger.Log(_("Module {0} is compiled against an older version of Anope {1}.{2}, this is {3}"), modname, v.GetMajor(), v.GetMinor(), Anope::VersionShort()); dlclose(handle); return MOD_ERR_VERSION; } else if (v.GetMajor() > Anope::VersionMajor() || (v.GetMajor() == Anope::VersionMajor() && v.GetMinor() > Anope::VersionMinor())) { - Log() << "Module " << modname << " is compiled against a newer version of Anope " << v.GetMajor() << "." << v.GetMinor() << ", this is " << Anope::VersionShort(); + Anope::Logger.Log(_("Module {0} is compiled against a newer version of Anope {1}.{2}, this is {3}"), modname, v.GetMajor(), v.GetMinor(), Anope::VersionShort()); dlclose(handle); return MOD_ERR_VERSION; } else if (v.GetPatch() < Anope::VersionPatch()) { - Log() << "Module " << modname << " is compiled against an older version of Anope, " << v.GetMajor() << "." << v.GetMinor() << "." << v.GetPatch() << ", this is " << Anope::VersionShort(); + Anope::Logger.Log(_("Module {0} is compiled against an older version of Anope, {1}.{2}.{3}, this is {4}"), modname, v.GetMajor(), v.GetMinor(), v.GetPatch(), Anope::VersionShort()); dlclose(handle); return MOD_ERR_VERSION; } else if (v.GetPatch() > Anope::VersionPatch()) { - Log() << "Module " << modname << " is compiled against a newer version of Anope, " << v.GetMajor() << "." << v.GetMinor() << "." << v.GetPatch() << ", this is " << Anope::VersionShort(); + Anope::Logger.Log(_("Module {0} is compiled against a newer version of Anope, {1}.{2}.{3}, this is {4}"), modname, v.GetMajor(), v.GetMinor(), v.GetPatch(), Anope::VersionShort()); dlclose(handle); return MOD_ERR_VERSION; } else { - Log(LOG_DEBUG_2) << "Module " << modname << " is compiled against current version of Anope " << Anope::VersionShort(); + Anope::Logger.Debug2("Module {0} is compiled against current version of Anope {1}", Anope::VersionShort()); } } catch (const ModuleException &ex) @@ -205,18 +221,8 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) return MOD_ERR_NOLOAD; } - dlerror(); - Module *(*func)(const Anope::string &, const Anope::string &) = function_cast<Module *(*)(const Anope::string &, const Anope::string &)>(dlsym(handle, "AnopeInit")); - err = dlerror(); - if (!func) - { - Log() << "No init function found, not an Anope module"; - if (err && *err) - Log(LOG_DEBUG) << err; - dlclose(handle); - return MOD_ERR_NOLOAD; - } - + ModuleDef *def = module->init(); + /* Create module. */ Anope::string nick; if (u) @@ -227,23 +233,25 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) ModuleReturn moderr = MOD_ERR_OK; try { - m = func(modname, nick); + m = def->Create(modname, nick); } catch (const ModuleException &ex) { - Log() << "Error while loading " << modname << ": " << ex.GetReason(); + Anope::Logger.Log(_("Error while loading {0}: {1}"), modname, ex.GetReason()); moderr = MOD_ERR_EXCEPTION; } - + if (moderr != MOD_ERR_OK) { if (dlclose(handle)) - Log() << dlerror(); + Anope::Logger.Log(dlerror()); return moderr; } m->filename = pbuf; m->handle = handle; + m->def = def; + m->module = module; /* Initialize config */ try @@ -252,61 +260,34 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) } catch (const ModuleException &ex) { - Log() << "Module " << modname << " couldn't load:" << ex.GetReason(); + Anope::Logger.Log(_("Module {0} couldn't load: {1}"), modname, ex.GetReason()); moderr = MOD_ERR_EXCEPTION; } catch (const ConfigException &ex) { - Log() << "Module " << modname << " couldn't load due to configuration problems: " << ex.GetReason(); + Anope::Logger.Log(_("Module {0} couldn't load due to configuration problems: {1}"), modname, ex.GetReason()); moderr = MOD_ERR_EXCEPTION; } - catch (const NotImplementedException &ex) - { - } - + if (moderr != MOD_ERR_OK) { DeleteModule(m); return moderr; } - Log(LOG_DEBUG) << "Module " << modname << " loaded."; - - /* Attach module to all events */ - for (unsigned i = 0; i < I_SIZE; ++i) - EventHandlers[i].push_back(m); - - m->Prioritize(); + Anope::Logger.Log(_("Module {0} loaded"), modname); - FOREACH_MOD(OnModuleLoad, (u, m)); + EventManager::Get()->Dispatch(&Event::ModuleLoad::OnModuleLoad, u, m); return MOD_ERR_OK; } -ModuleVersion ModuleManager::GetVersion(void *handle) -{ - dlerror(); - ModuleVersionC (*func)() = function_cast<ModuleVersionC (*)()>(dlsym(handle, "AnopeVersion"));; - if (!func) - { - Log() << "No version function found, not an Anope module"; - - const char *err = dlerror(); - if (err && *err) - Log(LOG_DEBUG) << err; - - throw ModuleException("No version"); - } - - return func(); -} - ModuleReturn ModuleManager::UnloadModule(Module *m, User *u) { if (!m) return MOD_ERR_PARAMS; - FOREACH_MOD(OnModuleUnload, (u, m)); + EventManager::Get()->Dispatch(&Event::ModuleUnload::OnModuleUnload, u, m); return DeleteModule(m); } @@ -366,24 +347,22 @@ ModuleReturn ModuleManager::DeleteModule(Module *m) if (!m || !m->handle) return MOD_ERR_PARAMS; + Serialize::Unregister(m); + void *handle = m->handle; Anope::string filename = m->filename; - Log(LOG_DEBUG) << "Unloading module " << m->name; + Anope::Logger.Log("Unloading module {0}", m->name); - dlerror(); - void (*destroy_func)(Module *m) = function_cast<void (*)(Module *)>(dlsym(m->handle, "AnopeFini")); - const char *err = dlerror(); - if (!destroy_func || (err && *err)) - { - Log() << "No destroy function found for " << m->name << ", chancing delete..."; - delete m; /* we just have to chance they haven't overwrote the delete operator then... */ - } - else - destroy_func(m); /* Let the module delete it self, just in case */ + ModuleDef *def = m->def; + AnopeModule *module = m->module; + def->Destroy(m); + module->fini(def); + + dlerror(); if (dlclose(handle)) - Log() << dlerror(); + Anope::Logger.Log(dlerror()); #ifdef _WIN32 if (!filename.empty()) @@ -393,119 +372,6 @@ ModuleReturn ModuleManager::DeleteModule(Module *m) return MOD_ERR_OK; } -void ModuleManager::DetachAll(Module *mod) -{ - for (unsigned i = 0; i < I_SIZE; ++i) - { - std::vector<Module *> &mods = EventHandlers[i]; - std::vector<Module *>::iterator it2 = std::find(mods.begin(), mods.end(), mod); - if (it2 != mods.end()) - mods.erase(it2); - } -} - -bool ModuleManager::SetPriority(Module *mod, Priority s) -{ - for (unsigned i = 0; i < I_SIZE; ++i) - SetPriority(mod, static_cast<Implementation>(i), s); - - return true; -} - -bool ModuleManager::SetPriority(Module *mod, Implementation i, Priority s, Module **modules, size_t sz) -{ - /** To change the priority of a module, we first find its position in the vector, - * then we find the position of the other modules in the vector that this module - * wants to be before/after. We pick off either the first or last of these depending - * on which they want, and we make sure our module is *at least* before or after - * the first or last of this subset, depending again on the type of priority. - */ - - /* Locate our module. This is O(n) but it only occurs on module load so we're - * not too bothered about it - */ - size_t source = 0; - bool found = false; - for (size_t x = 0, end = EventHandlers[i].size(); x != end; ++x) - if (EventHandlers[i][x] == mod) - { - source = x; - found = true; - break; - } - - /* Eh? this module doesn't exist, probably trying to set priority on an event - * they're not attached to. - */ - if (!found) - return false; - - size_t swap_pos = 0; - bool swap = true; - switch (s) - { - /* Dummy value */ - case PRIORITY_DONTCARE: - swap = false; - break; - /* Module wants to be first, sod everything else */ - case PRIORITY_FIRST: - swap_pos = 0; - break; - /* Module is submissive and wants to be last... awww. */ - case PRIORITY_LAST: - if (EventHandlers[i].empty()) - swap_pos = 0; - else - swap_pos = EventHandlers[i].size() - 1; - break; - /* Place this module after a set of other modules */ - case PRIORITY_AFTER: - /* Find the latest possible position */ - swap_pos = 0; - swap = false; - for (size_t x = 0, end = EventHandlers[i].size(); x != end; ++x) - for (size_t n = 0; n < sz; ++n) - if (modules[n] && EventHandlers[i][x] == modules[n] && x >= swap_pos && source <= swap_pos) - { - swap_pos = x; - swap = true; - } - break; - /* Place this module before a set of other modules */ - case PRIORITY_BEFORE: - swap_pos = EventHandlers[i].size() - 1; - swap = false; - for (size_t x = 0, end = EventHandlers[i].size(); x != end; ++x) - for (size_t n = 0; n < sz; ++n) - if (modules[n] && EventHandlers[i][x] == modules[n] && x <= swap_pos && source >= swap_pos) - { - swap = true; - swap_pos = x; - } - } - - /* Do we need to swap? */ - if (swap && swap_pos != source) - { - /* Suggestion from Phoenix, "shuffle" the modules to better retain call order */ - int incrmnt = 1; - - if (source > swap_pos) - incrmnt = -1; - - for (unsigned j = source; j != swap_pos; j += incrmnt) - { - if (j + incrmnt > EventHandlers[i].size() - 1 || (!j && incrmnt == -1)) - continue; - - std::swap(EventHandlers[i][j], EventHandlers[i][j + incrmnt]); - } - } - - return true; -} - void ModuleManager::UnloadAll() { std::vector<Anope::string> modules; @@ -524,3 +390,4 @@ void ModuleManager::UnloadAll() UnloadModule(m, NULL); } } + |