diff options
-rw-r--r-- | src/inspircd.cpp | 217 | ||||
-rw-r--r-- | src/modules.cpp | 223 |
2 files changed, 223 insertions, 217 deletions
diff --git a/src/inspircd.cpp b/src/inspircd.cpp index c35bf32c3..1df8c280b 100644 --- a/src/inspircd.cpp +++ b/src/inspircd.cpp @@ -832,223 +832,6 @@ void InspIRCd::BuildISupport() Config->Update005(); } -bool InspIRCd::UnloadModule(const char* filename) -{ - std::string filename_str = filename; - for (unsigned int j = 0; j != Config->module_names.size(); j++) - { - if (Config->module_names[j] == filename_str) - { - if (modules[j]->GetVersion().Flags & VF_STATIC) - { - this->Log(DEFAULT,"Failed to unload STATIC module %s",filename); - snprintf(MODERR,MAXBUF,"Module not unloadable (marked static)"); - return false; - } - std::pair<int,std::string> intercount = GetInterfaceInstanceCount(modules[j]); - if (intercount.first > 0) - { - this->Log(DEFAULT,"Failed to unload module %s, being used by %d other(s) via interface '%s'",filename, intercount.first, intercount.second.c_str()); - snprintf(MODERR,MAXBUF,"Module not unloadable (Still in use by %d other module%s which %s using its interface '%s') -- unload dependent modules first!", - intercount.first, - intercount.first > 1 ? "s" : "", - intercount.first > 1 ? "are" : "is", - intercount.second.c_str()); - return false; - } - /* Give the module a chance to tidy out all its metadata */ - for (chan_hash::iterator c = this->chanlist->begin(); c != this->chanlist->end(); c++) - { - modules[j]->OnCleanup(TYPE_CHANNEL,c->second); - } - for (user_hash::iterator u = this->clientlist->begin(); u != this->clientlist->end(); u++) - { - modules[j]->OnCleanup(TYPE_USER,u->second); - } - - /* Tidy up any dangling resolvers */ - this->Res->CleanResolvers(modules[j]); - - FOREACH_MOD_I(this,I_OnUnloadModule,OnUnloadModule(modules[j],Config->module_names[j])); - - for(int t = 0; t < 255; t++) - { - Config->global_implementation[t] -= Config->implement_lists[j][t]; - } - - /* We have to renumber implement_lists after unload because the module numbers change! - */ - for(int j2 = j; j2 < 254; j2++) - { - for(int t = 0; t < 255; t++) - { - Config->implement_lists[j2][t] = Config->implement_lists[j2+1][t]; - } - } - - // found the module - Parser->RemoveCommands(filename); - this->EraseModule(j); - this->EraseFactory(j); - this->Log(DEFAULT,"Module %s unloaded",filename); - this->ModCount--; - BuildISupport(); - return true; - } - } - this->Log(DEFAULT,"Module %s is not loaded, cannot unload it!",filename); - snprintf(MODERR,MAXBUF,"Module not loaded"); - return false; -} - -bool InspIRCd::LoadModule(const char* filename) -{ - /* Do we have a glob pattern in the filename? - * The user wants to load multiple modules which - * match the pattern. - */ - if (strchr(filename,'*') || (strchr(filename,'?'))) - { - int n_match = 0; - DIR* library = opendir(Config->ModPath); - if (library) - { - /* Try and locate and load all modules matching the pattern */ - dirent* entry = NULL; - while ((entry = readdir(library))) - { - if (this->MatchText(entry->d_name, filename)) - { - if (!this->LoadModule(entry->d_name)) - n_match++; - } - } - closedir(library); - } - /* Loadmodule will now return false if any one of the modules failed - * to load (but wont abort when it encounters a bad one) and when 1 or - * more modules were actually loaded. - */ - return (n_match > 0); - } - - char modfile[MAXBUF]; - snprintf(modfile,MAXBUF,"%s/%s",Config->ModPath,filename); - std::string filename_str = filename; - - if (!ServerConfig::DirValid(modfile)) - { - this->Log(DEFAULT,"Module %s is not within the modules directory.",modfile); - snprintf(MODERR,MAXBUF,"Module %s is not within the modules directory.",modfile); - return false; - } - if (ServerConfig::FileExists(modfile)) - { - - for (unsigned int j = 0; j < Config->module_names.size(); j++) - { - if (Config->module_names[j] == filename_str) - { - this->Log(DEFAULT,"Module %s is already loaded, cannot load a module twice!",modfile); - snprintf(MODERR,MAXBUF,"Module already loaded"); - return false; - } - } - Module* m = NULL; - ircd_module* a = NULL; - try - { - a = new ircd_module(this, modfile); - factory[this->ModCount+1] = a; - if (factory[this->ModCount+1]->LastError()) - { - this->Log(DEFAULT,"Unable to load %s: %s",modfile,factory[this->ModCount+1]->LastError()); - snprintf(MODERR,MAXBUF,"Loader/Linker error: %s",factory[this->ModCount+1]->LastError()); - return false; - } - if ((long)factory[this->ModCount+1]->factory != -1) - { - m = factory[this->ModCount+1]->factory->CreateModule(this); - - Version v = m->GetVersion(); - - if (v.API != API_VERSION) - { - delete m; - this->Log(DEFAULT,"Unable to load %s: Incorrect module API version: %d (our version: %d)",modfile,v.API,API_VERSION); - snprintf(MODERR,MAXBUF,"Loader/Linker error: Incorrect module API version: %d (our version: %d)",v.API,API_VERSION); - return false; - } - else - { - this->Log(DEFAULT,"New module introduced: %s (API version %d, Module version %d.%d.%d.%d)%s", filename, v.API, v.Major, v.Minor, v.Revision, v.Build, (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]")); - } - - modules[this->ModCount+1] = m; - /* save the module and the module's classfactory, if - * this isnt done, random crashes can occur :/ */ - Config->module_names.push_back(filename); - - char* x = &Config->implement_lists[this->ModCount+1][0]; - for(int t = 0; t < 255; t++) - x[t] = 0; - - modules[this->ModCount+1]->Implements(x); - - for(int t = 0; t < 255; t++) - Config->global_implementation[t] += Config->implement_lists[this->ModCount+1][t]; - } - else - { - this->Log(DEFAULT,"Unable to load %s",modfile); - snprintf(MODERR,MAXBUF,"Factory function failed: Probably missing init_module() entrypoint."); - return false; - } - } - catch (CoreException& modexcept) - { - this->Log(DEFAULT,"Unable to load %s: %s",modfile,modexcept.GetReason()); - snprintf(MODERR,MAXBUF,"Factory function of %s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); - return false; - } - } - else - { - this->Log(DEFAULT,"InspIRCd: startup: Module Not Found %s",modfile); - snprintf(MODERR,MAXBUF,"Module file could not be found"); - return false; - } - this->ModCount++; - FOREACH_MOD_I(this,I_OnLoadModule,OnLoadModule(modules[this->ModCount],filename_str)); - // now work out which modules, if any, want to move to the back of the queue, - // and if they do, move them there. - std::vector<std::string> put_to_back; - std::vector<std::string> put_to_front; - std::map<std::string,std::string> put_before; - std::map<std::string,std::string> put_after; - for (unsigned int j = 0; j < Config->module_names.size(); j++) - { - if (modules[j]->Prioritize() == PRIORITY_LAST) - put_to_back.push_back(Config->module_names[j]); - else if (modules[j]->Prioritize() == PRIORITY_FIRST) - put_to_front.push_back(Config->module_names[j]); - else if ((modules[j]->Prioritize() & 0xFF) == PRIORITY_BEFORE) - put_before[Config->module_names[j]] = Config->module_names[modules[j]->Prioritize() >> 8]; - else if ((modules[j]->Prioritize() & 0xFF) == PRIORITY_AFTER) - put_after[Config->module_names[j]] = Config->module_names[modules[j]->Prioritize() >> 8]; - } - for (unsigned int j = 0; j < put_to_back.size(); j++) - MoveToLast(put_to_back[j]); - for (unsigned int j = 0; j < put_to_front.size(); j++) - MoveToFirst(put_to_front[j]); - for (std::map<std::string,std::string>::iterator j = put_before.begin(); j != put_before.end(); j++) - MoveBefore(j->first,j->second); - for (std::map<std::string,std::string>::iterator j = put_after.begin(); j != put_after.end(); j++) - MoveAfter(j->first,j->second); - BuildISupport(); - return true; -} - void InspIRCd::DoOneIteration(bool process_module_sockets) { #ifndef WIN32 diff --git a/src/modules.cpp b/src/modules.cpp index 00d7e7871..f0ef1f383 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -23,6 +23,11 @@ #include "command_parse.h" #include "dns.h" + +#ifndef WIN32 + #include <dirent.h> +#endif + // version is a simple class for holding a modules version number Version::Version(int major, int minor, int revision, int build, int flags, int api_ver) : Major(major), Minor(minor), Revision(revision), Build(build), Flags(flags), API(api_ver) @@ -194,6 +199,224 @@ void Module::OnBuildExemptList(MessageType message_type, chanrec* chan, userrec void Module::OnGarbageCollect() { } void Module::OnBufferFlushed(userrec* user) { } + +bool InspIRCd::UnloadModule(const char* filename) +{ + std::string filename_str = filename; + for (unsigned int j = 0; j != Config->module_names.size(); j++) + { + if (Config->module_names[j] == filename_str) + { + if (modules[j]->GetVersion().Flags & VF_STATIC) + { + this->Log(DEFAULT,"Failed to unload STATIC module %s",filename); + snprintf(MODERR,MAXBUF,"Module not unloadable (marked static)"); + return false; + } + std::pair<int,std::string> intercount = GetInterfaceInstanceCount(modules[j]); + if (intercount.first > 0) + { + this->Log(DEFAULT,"Failed to unload module %s, being used by %d other(s) via interface '%s'",filename, intercount.first, intercount.second.c_str()); + snprintf(MODERR,MAXBUF,"Module not unloadable (Still in use by %d other module%s which %s using its interface '%s') -- unload dependent modules first!", + intercount.first, + intercount.first > 1 ? "s" : "", + intercount.first > 1 ? "are" : "is", + intercount.second.c_str()); + return false; + } + /* Give the module a chance to tidy out all its metadata */ + for (chan_hash::iterator c = this->chanlist->begin(); c != this->chanlist->end(); c++) + { + modules[j]->OnCleanup(TYPE_CHANNEL,c->second); + } + for (user_hash::iterator u = this->clientlist->begin(); u != this->clientlist->end(); u++) + { + modules[j]->OnCleanup(TYPE_USER,u->second); + } + + /* Tidy up any dangling resolvers */ + this->Res->CleanResolvers(modules[j]); + + FOREACH_MOD_I(this,I_OnUnloadModule,OnUnloadModule(modules[j],Config->module_names[j])); + + for(int t = 0; t < 255; t++) + { + Config->global_implementation[t] -= Config->implement_lists[j][t]; + } + + /* We have to renumber implement_lists after unload because the module numbers change! + */ + for(int j2 = j; j2 < 254; j2++) + { + for(int t = 0; t < 255; t++) + { + Config->implement_lists[j2][t] = Config->implement_lists[j2+1][t]; + } + } + + // found the module + Parser->RemoveCommands(filename); + this->EraseModule(j); + this->EraseFactory(j); + this->Log(DEFAULT,"Module %s unloaded",filename); + this->ModCount--; + BuildISupport(); + return true; + } + } + this->Log(DEFAULT,"Module %s is not loaded, cannot unload it!",filename); + snprintf(MODERR,MAXBUF,"Module not loaded"); + return false; +} + +bool InspIRCd::LoadModule(const char* filename) +{ + /* Do we have a glob pattern in the filename? + * The user wants to load multiple modules which + * match the pattern. + */ + if (strchr(filename,'*') || (strchr(filename,'?'))) + { + int n_match = 0; + DIR* library = opendir(Config->ModPath); + if (library) + { + /* Try and locate and load all modules matching the pattern */ + dirent* entry = NULL; + while ((entry = readdir(library))) + { + if (this->MatchText(entry->d_name, filename)) + { + if (!this->LoadModule(entry->d_name)) + n_match++; + } + } + closedir(library); + } + /* Loadmodule will now return false if any one of the modules failed + * to load (but wont abort when it encounters a bad one) and when 1 or + * more modules were actually loaded. + */ + return (n_match > 0); + } + + char modfile[MAXBUF]; + snprintf(modfile,MAXBUF,"%s/%s",Config->ModPath,filename); + std::string filename_str = filename; + + if (!ServerConfig::DirValid(modfile)) + { + this->Log(DEFAULT,"Module %s is not within the modules directory.",modfile); + snprintf(MODERR,MAXBUF,"Module %s is not within the modules directory.",modfile); + return false; + } + if (ServerConfig::FileExists(modfile)) + { + + for (unsigned int j = 0; j < Config->module_names.size(); j++) + { + if (Config->module_names[j] == filename_str) + { + this->Log(DEFAULT,"Module %s is already loaded, cannot load a module twice!",modfile); + snprintf(MODERR,MAXBUF,"Module already loaded"); + return false; + } + } + Module* m = NULL; + ircd_module* a = NULL; + try + { + a = new ircd_module(this, modfile); + factory[this->ModCount+1] = a; + if (factory[this->ModCount+1]->LastError()) + { + this->Log(DEFAULT,"Unable to load %s: %s",modfile,factory[this->ModCount+1]->LastError()); + snprintf(MODERR,MAXBUF,"Loader/Linker error: %s",factory[this->ModCount+1]->LastError()); + return false; + } + if ((long)factory[this->ModCount+1]->factory != -1) + { + m = factory[this->ModCount+1]->factory->CreateModule(this); + + Version v = m->GetVersion(); + + if (v.API != API_VERSION) + { + delete m; + this->Log(DEFAULT,"Unable to load %s: Incorrect module API version: %d (our version: %d)",modfile,v.API,API_VERSION); + snprintf(MODERR,MAXBUF,"Loader/Linker error: Incorrect module API version: %d (our version: %d)",v.API,API_VERSION); + return false; + } + else + { + this->Log(DEFAULT,"New module introduced: %s (API version %d, Module version %d.%d.%d.%d)%s", filename, v.API, v.Major, v.Minor, v.Revision, v.Build, (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]")); + } + + modules[this->ModCount+1] = m; + /* save the module and the module's classfactory, if + * this isnt done, random crashes can occur :/ */ + Config->module_names.push_back(filename); + + char* x = &Config->implement_lists[this->ModCount+1][0]; + for(int t = 0; t < 255; t++) + x[t] = 0; + + modules[this->ModCount+1]->Implements(x); + + for(int t = 0; t < 255; t++) + Config->global_implementation[t] += Config->implement_lists[this->ModCount+1][t]; + } + else + { + this->Log(DEFAULT,"Unable to load %s",modfile); + snprintf(MODERR,MAXBUF,"Factory function failed: Probably missing init_module() entrypoint."); + return false; + } + } + catch (CoreException& modexcept) + { + this->Log(DEFAULT,"Unable to load %s: %s",modfile,modexcept.GetReason()); + snprintf(MODERR,MAXBUF,"Factory function of %s threw an exception: %s", modexcept.GetSource(), modexcept.GetReason()); + return false; + } + } + else + { + this->Log(DEFAULT,"InspIRCd: startup: Module Not Found %s",modfile); + snprintf(MODERR,MAXBUF,"Module file could not be found"); + return false; + } + this->ModCount++; + FOREACH_MOD_I(this,I_OnLoadModule,OnLoadModule(modules[this->ModCount],filename_str)); + // now work out which modules, if any, want to move to the back of the queue, + // and if they do, move them there. + std::vector<std::string> put_to_back; + std::vector<std::string> put_to_front; + std::map<std::string,std::string> put_before; + std::map<std::string,std::string> put_after; + for (unsigned int j = 0; j < Config->module_names.size(); j++) + { + if (modules[j]->Prioritize() == PRIORITY_LAST) + put_to_back.push_back(Config->module_names[j]); + else if (modules[j]->Prioritize() == PRIORITY_FIRST) + put_to_front.push_back(Config->module_names[j]); + else if ((modules[j]->Prioritize() & 0xFF) == PRIORITY_BEFORE) + put_before[Config->module_names[j]] = Config->module_names[modules[j]->Prioritize() >> 8]; + else if ((modules[j]->Prioritize() & 0xFF) == PRIORITY_AFTER) + put_after[Config->module_names[j]] = Config->module_names[modules[j]->Prioritize() >> 8]; + } + for (unsigned int j = 0; j < put_to_back.size(); j++) + MoveToLast(put_to_back[j]); + for (unsigned int j = 0; j < put_to_front.size(); j++) + MoveToFirst(put_to_front[j]); + for (std::map<std::string,std::string>::iterator j = put_before.begin(); j != put_before.end(); j++) + MoveBefore(j->first,j->second); + for (std::map<std::string,std::string>::iterator j = put_after.begin(); j != put_after.end(); j++) + MoveAfter(j->first,j->second); + BuildISupport(); + return true; +} + long InspIRCd::PriorityAfter(const std::string &modulename) { for (unsigned int j = 0; j < this->Config->module_names.size(); j++) |