/** Handle /MODULES */ CmdResult CommandModules::Handle (const std::vector<std::string>& parameters, User *user) { // Don't ask remote servers about their modules unless the local user asking is an oper // 2.0 asks anyway, so let's handle that the same way bool for_us = (parameters.empty() || parameters[0] == ServerInstance->Config->ServerName); if ((!for_us) || (!IS_LOCAL(user))) { if (!user->IsOper()) { user->WriteNotice("*** You cannot check what modules other servers have loaded."); return CMD_FAILURE; } // From an oper and not for us, forward if (!for_us) return CMD_SUCCESS; } const ModuleManager::ModuleMap& mods = ServerInstance->Modules->GetModules(); for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i) { Module* m = i->second; Version V = m->GetVersion(); if (user->HasPrivPermission("servers/auspex")) { std::string flags("SvcC"); int pos = 0; for (int mult = 1; mult <= VF_OPTCOMMON; mult *= 2, ++pos) if (!(V.Flags & mult)) flags[pos] = '-'; #ifdef PURE_STATIC user->SendText(":%s 702 %s :%p %s %s :%s", ServerInstance->Config->ServerName.c_str(), user->nick.c_str(), (void*)m, m->ModuleSourceFile.c_str(), flags.c_str(), V.description.c_str()); #else std::string srcrev = m->ModuleDLLManager->GetVersion(); user->SendText(":%s 702 %s :%p %s %s :%s - %s", ServerInstance->Config->ServerName.c_str(), user->nick.c_str(), (void*)m, m->ModuleSourceFile.c_str(), flags.c_str(), V.description.c_str(), srcrev.c_str()); #endif } else { user->SendText(":%s 702 %s :%s %s", ServerInstance->Config->ServerName.c_str(), user->nick.c_str(), m->ModuleSourceFile.c_str(), V.description.c_str()); } } user->SendText(":%s 703 %s :End of MODULES list", ServerInstance->Config->ServerName.c_str(), user->nick.c_str()); return CMD_SUCCESS; }
/** Handle /MODULES */ CmdResult CommandModules::Handle(User* user, const Params& parameters) { // Don't ask remote servers about their modules unless the local user asking is an oper // 2.0 asks anyway, so let's handle that the same way bool for_us = (parameters.empty() || irc::equals(parameters[0], ServerInstance->Config->ServerName)); if ((!for_us) || (!IS_LOCAL(user))) { if (!user->IsOper()) { user->WriteNotice("*** You cannot check what modules other servers have loaded."); return CMD_FAILURE; } // From an oper and not for us, forward if (!for_us) return CMD_SUCCESS; } const ModuleManager::ModuleMap& mods = ServerInstance->Modules.GetModules(); for (ModuleManager::ModuleMap::const_iterator i = mods.begin(); i != mods.end(); ++i) { Module* m = i->second; Version V = m->GetVersion(); if (IS_LOCAL(user) && user->HasPrivPermission("servers/auspex")) { std::string flags("VCO"); size_t pos = 0; for (int mult = 2; mult <= VF_OPTCOMMON; mult *= 2, ++pos) if (!(V.Flags & mult)) flags[pos] = '-'; std::string srcrev = m->ModuleDLLManager->GetVersion(); user->WriteRemoteNumeric(RPL_MODLIST, m->ModuleSourceFile, srcrev.empty() ? "*" : srcrev, flags, V.description); } else { user->WriteRemoteNumeric(RPL_MODLIST, m->ModuleSourceFile, '*', '*', V.description); } } user->WriteRemoteNumeric(RPL_ENDOFMODLIST, "End of MODULES list"); return CMD_SUCCESS; }
std::string TreeSocket::MyModules(int filter) { std::vector<std::string> modlist = ServerInstance->Modules->GetAllModuleNames(filter); std::string capabilities; sort(modlist.begin(),modlist.end()); for (std::vector<std::string>::const_iterator i = modlist.begin(); i != modlist.end(); ++i) { if (i != modlist.begin()) capabilities.push_back(' '); capabilities.append(*i); Module* m = ServerInstance->Modules->Find(*i); Version v = m->GetVersion(); if (!v.link_data.empty()) { capabilities.push_back('='); capabilities.append(v.link_data); } } return capabilities; }
void SpanningTreeUtilities::RouteCommand(TreeServer* origin, CommandBase* thiscmd, const parameterlist& parameters, User* user) { const std::string& command = thiscmd->name; RouteDescriptor routing = thiscmd->GetRouting(user, parameters); if (routing.type == ROUTE_TYPE_LOCALONLY) return; const bool encap = ((routing.type == ROUTE_TYPE_OPT_BCAST) || (routing.type == ROUTE_TYPE_OPT_UCAST)); CmdBuilder params(user, encap ? "ENCAP" : command.c_str()); if (routing.type == ROUTE_TYPE_OPT_BCAST) { params.push('*'); params.push_back(command); } else if (routing.type == ROUTE_TYPE_OPT_UCAST) { TreeServer* sdest = FindServer(routing.serverdest); if (!sdest) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Trying to route ENCAP to nonexistant server %s", routing.serverdest.c_str()); return; } params.push_back(sdest->GetID()); params.push_back(command); } else { Module* srcmodule = thiscmd->creator; Version ver = srcmodule->GetVersion(); if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator) { ServerInstance->Logs->Log(MODNAME, LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s", command.c_str(), srcmodule->ModuleSourceFile.c_str()); return; } } std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd); params.push_back(output_text); if (routing.type == ROUTE_TYPE_MESSAGE) { char pfx = 0; std::string dest = routing.serverdest; if (ServerInstance->Modes->FindPrefix(dest[0])) { pfx = dest[0]; dest = dest.substr(1); } if (dest[0] == '#') { Channel* c = ServerInstance->FindChan(dest); if (!c) return; // TODO OnBuildExemptList hook was here CUList exempts; SendChannelMessage(user->uuid, c, parameters[1], pfx, exempts, command.c_str(), origin ? origin->GetSocket() : NULL); } else if (dest[0] == '$') { params.Forward(origin); } else { // user target? User* d = ServerInstance->FindNick(dest); if (!d) return; TreeServer* tsd = BestRouteTo(d->server); if (tsd == origin) // huh? no routing stuff around in a circle, please. return; params.Unicast(d); } } else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST) { params.Forward(origin); } else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST) { if (origin && routing.serverdest == origin->GetName()) return; params.Unicast(routing.serverdest); } }
bool ModuleManager::Load(const std::string& modname, bool defer) { /* Don't allow people to specify paths for modules, it doesn't work as expected */ if (modname.find('/') != std::string::npos) { LastModuleError = "You can't load modules with a path: " + modname; return false; } const std::string filename = ExpandModName(modname); const std::string moduleFile = ServerInstance->Config->Paths.PrependModule(filename); if (!FileSystem::FileExists(moduleFile)) { LastModuleError = "Module file could not be found: " + filename; ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } if (Modules.find(filename) != Modules.end()) { LastModuleError = "Module " + filename + " is already loaded, cannot load a module twice!"; ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } Module* newmod = NULL; DLLManager* newhandle = new DLLManager(moduleFile.c_str()); ServiceList newservices; if (!defer) this->NewServices = &newservices; try { newmod = newhandle->CallInit(); this->NewServices = NULL; if (newmod) { newmod->ModuleSourceFile = filename; newmod->ModuleDLLManager = newhandle; newmod->dying = false; Modules[filename] = newmod; std::string version = newhandle->GetVersion(); if (defer) { ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s (Module version %s)", filename.c_str(), version.c_str()); } else { ConfigStatus confstatus; AttachAll(newmod); AddServices(newservices); newmod->init(); newmod->ReadConfig(confstatus); Version v = newmod->GetVersion(); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "New module introduced: %s (Module version %s)%s", filename.c_str(), version.c_str(), (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]")); } } else { LastModuleError = "Unable to load " + filename + ": " + newhandle->LastError(); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); delete newhandle; return false; } } catch (CoreException& modexcept) { this->NewServices = NULL; // failure in module constructor if (newmod) { DoSafeUnload(newmod); ServerInstance->GlobalCulls.AddItem(newhandle); } else delete newhandle; LastModuleError = "Unable to load " + filename + ": " + modexcept.GetReason(); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } if (defer) return true; FOREACH_MOD(OnLoadModule, (newmod)); PrioritizeHooks(); ServerInstance->ISupport.Build(); return true; }
void SpanningTreeUtilities::RouteCommand(TreeServer* origin, Command* thiscmd, const parameterlist& parameters, User* user) { const std::string& command = thiscmd->name; RouteDescriptor routing = thiscmd->GetRouting(user, parameters); std::string sent_cmd = command; parameterlist params; if (routing.type == ROUTE_TYPE_LOCALONLY) { return; } else if (routing.type == ROUTE_TYPE_OPT_BCAST) { params.push_back("*"); params.push_back(command); sent_cmd = "ENCAP"; } else if (routing.type == ROUTE_TYPE_OPT_UCAST) { TreeServer* sdest = FindServer(routing.serverdest); if (!sdest) { ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Trying to route ENCAP to nonexistant server %s", routing.serverdest.c_str()); return; } params.push_back(sdest->GetID()); params.push_back(command); sent_cmd = "ENCAP"; } else { Module* srcmodule = thiscmd->creator; Version ver = srcmodule->GetVersion(); if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator) { ServerInstance->Logs->Log("m_spanningtree", LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s", command.c_str(), srcmodule->ModuleSourceFile.c_str()); return; } } std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd); params.push_back(output_text); if (routing.type == ROUTE_TYPE_MESSAGE) { char pfx = 0; std::string dest = routing.serverdest; if (ServerInstance->Modes->FindPrefix(dest[0])) { pfx = dest[0]; dest = dest.substr(1); } if (dest[0] == '#') { Channel* c = ServerInstance->FindChan(dest); if (!c) return; TreeServerList list; // TODO OnBuildExemptList hook was here GetListOfServersForChannel(c,list,pfx, CUList()); std::string data = ":" + user->uuid + " " + sent_cmd; for (unsigned int x = 0; x < params.size(); x++) data += " " + params[x]; for (TreeServerList::iterator i = list.begin(); i != list.end(); i++) { TreeSocket* Sock = (*i)->GetSocket(); if (origin && origin->GetSocket() == Sock) continue; if (Sock) Sock->WriteLine(data); } } else if (dest[0] == '$') { if (origin) DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName()); else DoOneToMany(user->uuid, sent_cmd, params); } else { // user target? User* d = ServerInstance->FindNick(dest); if (!d) return; TreeServer* tsd = BestRouteTo(d->server); if (tsd == origin) // huh? no routing stuff around in a circle, please. return; DoOneToOne(user->uuid, sent_cmd, params, d->server); } } else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST) { if (origin) DoOneToAllButSender(user->uuid, sent_cmd, params, origin->GetName()); else DoOneToMany(user->uuid, sent_cmd, params); } else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST) { if (origin && routing.serverdest == origin->GetName()) return; DoOneToOne(user->uuid, sent_cmd, params, routing.serverdest); } }
void SpanningTreeUtilities::RouteCommand(TreeServer* origin, CommandBase* thiscmd, const CommandBase::Params& parameters, User* user) { const std::string& command = thiscmd->name; RouteDescriptor routing = thiscmd->GetRouting(user, parameters); if (routing.type == ROUTE_TYPE_LOCALONLY) return; const bool encap = ((routing.type == ROUTE_TYPE_OPT_BCAST) || (routing.type == ROUTE_TYPE_OPT_UCAST)); CmdBuilder params(user, encap ? "ENCAP" : command.c_str()); params.push_tags(parameters.GetTags()); TreeServer* sdest = NULL; if (routing.type == ROUTE_TYPE_OPT_BCAST) { params.push('*'); params.push_back(command); } else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST) { sdest = static_cast<TreeServer*>(routing.server); if (!sdest) { // Assume the command handler already validated routing.serverdest and have only returned success if the target is something that the // user executing the command is allowed to look up e.g. target is not an uuid if user is local. sdest = FindRouteTarget(routing.serverdest); if (!sdest) { ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Trying to route %s%s to nonexistent server %s", (encap ? "ENCAP " : ""), command.c_str(), routing.serverdest.c_str()); return; } } if (encap) { params.push_back(sdest->GetID()); params.push_back(command); } } else { Module* srcmodule = thiscmd->creator; Version ver = srcmodule->GetVersion(); if (!(ver.Flags & (VF_COMMON | VF_CORE)) && srcmodule != Creator) { ServerInstance->Logs.Log(MODNAME, LOG_DEFAULT, "Routed command %s from non-VF_COMMON module %s", command.c_str(), srcmodule->ModuleSourceFile.c_str()); return; } } std::string output_text = CommandParser::TranslateUIDs(thiscmd->translation, parameters, true, thiscmd); params.push_back(output_text); if (routing.type == ROUTE_TYPE_MESSAGE) { char pfx = 0; std::string dest = routing.serverdest; if (ServerInstance->Modes.FindPrefix(dest[0])) { pfx = dest[0]; dest.erase(dest.begin()); } if (dest[0] == '#') { Channel* c = ServerInstance->FindChan(dest); if (!c) return; // TODO OnBuildExemptList hook was here CUList exempts; std::string message; if (parameters.size() >= 2) message.assign(parameters[1]); SendChannelMessage(user->uuid, c, message, pfx, parameters.GetTags(), exempts, command.c_str(), origin ? origin->GetSocket() : NULL); } else if (dest[0] == '$') { params.Forward(origin); } else { // user target? User* d = ServerInstance->FindNick(dest); if (!d || IS_LOCAL(d)) return; TreeServer* tsd = TreeServer::Get(d)->GetRoute(); if (tsd == origin) // huh? no routing stuff around in a circle, please. return; params.Unicast(d); } } else if (routing.type == ROUTE_TYPE_BROADCAST || routing.type == ROUTE_TYPE_OPT_BCAST) { params.Forward(origin); } else if (routing.type == ROUTE_TYPE_UNICAST || routing.type == ROUTE_TYPE_OPT_UCAST) { params.Unicast(sdest->ServerUser); } }
bool ModuleManager::Load(const std::string& filename, bool defer) { /* Don't allow people to specify paths for modules, it doesn't work as expected */ if (filename.find('/') != std::string::npos) return false; char modfile[MAXBUF]; snprintf(modfile,MAXBUF,"%s/%s",ServerInstance->Config->ModPath.c_str(),filename.c_str()); if (!ServerConfig::FileExists(modfile)) { LastModuleError = "Module file could not be found: " + filename; ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } if (Modules.find(filename) != Modules.end()) { LastModuleError = "Module " + filename + " is already loaded, cannot load a module twice!"; ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } Module* newmod = NULL; DLLManager* newhandle = new DLLManager(modfile); try { newmod = newhandle->CallInit(); if (newmod) { newmod->ModuleSourceFile = filename; newmod->ModuleDLLManager = newhandle; newmod->dying = false; Modules[filename] = newmod; std::string version = newhandle->GetVersion(); if (defer) { ServerInstance->Logs->Log("MODULE", LOG_DEFAULT,"New module introduced: %s (Module version %s)", filename.c_str(), version.c_str()); } else { newmod->init(); Version v = newmod->GetVersion(); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT,"New module introduced: %s (Module version %s)%s", filename.c_str(), version.c_str(), (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]")); } } else { LastModuleError = "Unable to load " + filename + ": " + newhandle->LastError(); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); delete newhandle; return false; } } catch (CoreException& modexcept) { // failure in module constructor if (newmod) { DoSafeUnload(newmod); ServerInstance->GlobalCulls.AddItem(newhandle); } else delete newhandle; LastModuleError = "Unable to load " + filename + ": " + modexcept.GetReason(); ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, LastModuleError); return false; } this->ModCount++; if (defer) return true; FOREACH_MOD(I_OnLoadModule,OnLoadModule(newmod)); /* We give every module a chance to re-prioritize when we introduce a new one, * not just the one thats loading, as the new module could affect the preference * of others */ for(int tries = 0; tries < 20; tries++) { prioritizationState = tries > 0 ? PRIO_STATE_LAST : PRIO_STATE_FIRST; for (std::map<std::string, Module*>::iterator n = Modules.begin(); n != Modules.end(); ++n) n->second->Prioritize(); if (prioritizationState == PRIO_STATE_LAST) break; if (tries == 19) ServerInstance->Logs->Log("MODULE", LOG_DEFAULT, "Hook priority dependency loop detected while loading " + filename); } ServerInstance->ISupport.Build(); return true; }
ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) { if (modname.empty()) return MOD_ERR_PARAMS; if (FindModule(modname)) return MOD_ERR_EXISTS; Log(LOG_DEBUG) << "trying to load [" << modname << "]"; /* Generate the filename for the temporary copy of the module */ Anope::string pbuf = services_dir + "/modules/runtime/" + modname + ".so.XXXXXX"; /* Don't skip return value checking! -GD */ ModuleReturn ret = moduleCopyFile(modname, pbuf); if (ret != MOD_ERR_OK) return ret; dlerror(); void *handle = dlopen(pbuf.c_str(), RTLD_LAZY); const char *err = dlerror(); if (!handle && err && *err) { Log() << err; 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 && err && *err) { Log() << "No init function found, not an Anope module"; dlclose(handle); return MOD_ERR_NOLOAD; } if (!func) throw CoreException("Couldn't find constructor, yet moderror wasn't set?"); /* Create module. */ Anope::string nick; if (u) nick = u->nick; Module *m; try { m = func(modname, nick); } catch (const ModuleException &ex) { Log() << "Error while loading " << modname << ": " << ex.GetReason(); return MOD_ERR_EXCEPTION; } m->filename = pbuf; m->handle = handle; Version v = m->GetVersion(); 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::VersionMajor() << "." << Anope::VersionMinor(); DeleteModule(m); 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::VersionMajor() << "." << Anope::VersionMinor(); DeleteModule(m); return MOD_ERR_VERSION; } else if (v.GetBuild() < Anope::VersionBuild()) Log() << "Module " << modname << " is compiled against an older revision of Anope " << v.GetBuild() << ", this is " << Anope::VersionBuild(); else if (v.GetBuild() > Anope::VersionBuild()) Log() << "Module " << modname << " is compiled against a newer revision of Anope " << v.GetBuild() << ", this is " << Anope::VersionBuild(); else if (v.GetBuild() == Anope::VersionBuild()) Log(LOG_DEBUG) << "Module " << modname << " compiled against current version of Anope " << v.GetBuild(); if (m->type == PROTOCOL && ModuleManager::FindFirstOf(PROTOCOL) != m) { DeleteModule(m); Log() << "You cannot load two protocol modules"; return MOD_ERR_UNKNOWN; } FOREACH_MOD(I_OnModuleLoad, OnModuleLoad(u, m)); return MOD_ERR_OK; }
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]; }
ModuleReturn ModuleManager::LoadModule(const Anope::string &modname, User *u) { if (modname.empty()) return MOD_ERR_PARAMS; if (FindModule(modname)) return MOD_ERR_EXISTS; Log(LOG_DEBUG) << "Trying to load module: " << modname; #ifdef _WIN32 /* Generate the filename for the temporary copy of the module */ Anope::string pbuf = Anope::DataDir + "/runtime/" + modname + ".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)"; else if (ret == MOD_ERR_FILE_IO) Log(LOG_TERMINAL) << "Error while loading " << modname << " (file IO error, check file permissions and diskspace)"; return ret; } #else Anope::string pbuf = Anope::ModuleDir + "/modules/" + modname + ".so"; #endif dlerror(); void *handle = dlopen(pbuf.c_str(), RTLD_NOW); const char *err = dlerror(); if (!handle) { if (err && *err) Log() << err; 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; } /* Create module. */ Anope::string nick; if (u) nick = u->nick; Module *m; ModuleReturn moderr = MOD_ERR_OK; try { m = func(modname, nick); } catch (const ModuleException &ex) { Log() << "Error while loading " << modname << ": " << ex.GetReason(); moderr = MOD_ERR_EXCEPTION; } if (moderr != MOD_ERR_OK) { if (dlclose(handle)) Log() << dlerror(); return moderr; } m->filename = pbuf; m->handle = handle; ModuleVersion v = m->GetVersion(); 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(); DeleteModule(m); 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(); DeleteModule(m); 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(); DeleteModule(m); 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(); DeleteModule(m); return MOD_ERR_VERSION; } else Log(LOG_DEBUG_2) << "Module " << modname << " is compiled against current version of Anope " << Anope::VersionShort(); /* Initialize config */ try { m->OnReload(Config); } catch (const ModuleException &ex) { Log() << "Module " << modname << " couldn't load:" << ex.GetReason(); moderr = MOD_ERR_EXCEPTION; } catch (const ConfigException &ex) { Log() << "Module " << modname << " couldn't load due to configuration problems: " << ex.GetReason(); moderr = MOD_ERR_EXCEPTION; } catch (const NotImplementedException &ex) { } if (moderr != MOD_ERR_OK) { DeleteModule(m); 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); FOREACH_MOD(OnModuleLoad, (u, m)); return MOD_ERR_OK; }