summaryrefslogtreecommitdiff
path: root/src/modulemanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modulemanager.cpp')
-rw-r--r--src/modulemanager.cpp298
1 files changed, 82 insertions, 216 deletions
diff --git a/src/modulemanager.cpp b/src/modulemanager.cpp
index 2cda9e256..d4883eccb 100644
--- a/src/modulemanager.cpp
+++ b/src/modulemanager.cpp
@@ -1,16 +1,27 @@
-/* Modular support
+/*
+ * Anope IRC Services
*
- * (C) 2003-2016 Anope Team
- * Contact us at team@anope.org
+ * Copyright (C) 2008-2016 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,22 +32,31 @@
#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;
}
-
+
for (dirent *dp; (dp = readdir(dirp));)
{
if (!dp->d_ino)
@@ -62,17 +82,17 @@ void ModuleManager::CleanupRuntimeDirectory()
static ModuleReturn moduleCopyFile(const Anope::string &name, Anope::string &output)
{
Anope::string input = Anope::ModuleDir + "/modules/" + name + ".so";
-
+
struct stat s;
if (stat(input.c_str(), &s) == -1)
return MOD_ERR_NOEXIST;
else if (!S_ISREG(s.st_mode))
return MOD_ERR_NOEXIST;
-
+
std::ifstream source(input.c_str(), std::ios_base::in | std::ios_base::binary);
if (!source.is_open())
return MOD_ERR_NOEXIST;
-
+
char *tmp_output = strdup(output.c_str());
int target_fd = mkstemp(tmp_output);
if (target_fd == -1 || close(target_fd) == -1)
@@ -84,8 +104,8 @@ 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())
{
@@ -103,7 +123,7 @@ static ModuleReturn moduleCopyFile(const Anope::string &name, Anope::string &out
target.write(buffer, read_len);
want -= read_len;
}
-
+
source.close();
target.close();
@@ -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,17 +221,7 @@ 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;
@@ -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,17 +260,14 @@ 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)
{
@@ -270,43 +275,19 @@ ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u)
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,144 +347,29 @@ 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())
unlink(filename.c_str());
#endif
-
- 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;
+ return MOD_ERR_OK;
}
void ModuleManager::UnloadAll()
@@ -516,7 +382,7 @@ void ModuleManager::UnloadAll()
if ((m->type & j) == m->type)
modules.push_back(m->name);
}
-
+
for (unsigned i = 0; i < modules.size(); ++i)
{
Module *m = FindModule(modules[i]);