summaryrefslogtreecommitdiff
path: root/src/modulemanager.cpp
diff options
context:
space:
mode:
authorRobin Burchell w00t@inspircd.org <Robin Burchell w00t@inspircd.org@5417fbe8-f217-4b02-8779-1006273d7864>2008-11-09 16:56:54 +0000
committerRobin Burchell w00t@inspircd.org <Robin Burchell w00t@inspircd.org@5417fbe8-f217-4b02-8779-1006273d7864>2008-11-09 16:56:54 +0000
commit65fd49d3628dd8d3bde8f70b58ac458785a261d7 (patch)
tree0b6148ca77f747d4ef2732e5c004292868fd9bf3 /src/modulemanager.cpp
parentcd71f37e2d1361498c516715e4b83d5909422327 (diff)
Move loadModule() and unloadModule() inside ModuleManager::
git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@1614 5417fbe8-f217-4b02-8779-1006273d7864
Diffstat (limited to 'src/modulemanager.cpp')
-rw-r--r--src/modulemanager.cpp243
1 files changed, 242 insertions, 1 deletions
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;
+}
+