1
0
mirror of https://github.com/anope/anope.git synced 2026-07-08 23:43:13 +02:00

Move loadModule() and unloadModule() inside ModuleManager::

git-svn-id: http://anope.svn.sourceforge.net/svnroot/anope/trunk@1614 5417fbe8-f217-4b02-8779-1006273d7864
This commit is contained in:
Robin Burchell w00t@inspircd.org
2008-11-09 16:56:54 +00:00
parent cd71f37e2d
commit 65fd49d362
6 changed files with 294 additions and 307 deletions
+42 -25
View File
@@ -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);
/*************************************************************************/
+1 -1
View File
@@ -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());
+1 -1
View File
@@ -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)
{
+1 -6
View File
@@ -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)
{
+242 -1
View File
@@ -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;
}
+7 -273
View File
@@ -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;