diff options
Diffstat (limited to 'src/modules.cpp')
-rw-r--r-- | src/modules.cpp | 223 |
1 files changed, 223 insertions, 0 deletions
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++) |