X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fmodmanager_dynamic.cpp;h=05c9740632731a62b998b9d3c7c49d3d36ea2cd2;hb=ac83d3b0d607f2bdc373365bc2f08f0cde023bf3;hp=156105ad8db041a6801efe430dbc2a05f3ac3522;hpb=704c793d479f835180e9d89d82cd21a2c6c6521d;p=user%2Fhenk%2Fcode%2Finspircd.git diff --git a/src/modmanager_dynamic.cpp b/src/modmanager_dynamic.cpp index 156105ad8..05c974063 100644 --- a/src/modmanager_dynamic.cpp +++ b/src/modmanager_dynamic.cpp @@ -2,7 +2,7 @@ * | Inspire Internet Relay Chat Daemon | * +------------------------------------+ * - * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * InspIRCd: (C) 2002-2010 InspIRCd Development Team * See: http://wiki.inspircd.org/Credits * * This program is free but copyrighted software; see @@ -25,16 +25,16 @@ #ifndef PURE_STATIC -bool ModuleManager::Load(const char* filename) +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 (strchr(filename, '/')) + if (filename.find('/') != std::string::npos) return false; /* 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,'?'))) + if (strchr(filename.c_str(),'*') || (strchr(filename.c_str(),'?'))) { int n_match = 0; DIR* library = opendir(ServerInstance->Config->ModPath.c_str()); @@ -44,9 +44,11 @@ bool ModuleManager::Load(const char* filename) dirent* entry = NULL; while (0 != (entry = readdir(library))) { - if (InspIRCd::Match(entry->d_name, filename, ascii_case_insensitive_map)) + if (entry->d_name[0] == '.') + continue; + if (InspIRCd::Match(entry->d_name, filename.c_str(), ascii_case_insensitive_map)) { - if (!this->Load(entry->d_name)) + if (!this->Load(entry->d_name, defer)) n_match++; } } @@ -60,19 +62,18 @@ bool ModuleManager::Load(const char* filename) } char modfile[MAXBUF]; - snprintf(modfile,MAXBUF,"%s/%s",ServerInstance->Config->ModPath.c_str(),filename); - std::string filename_str = filename; + 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_str; + LastModuleError = "Module file could not be found: " + filename; ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); return false; } - if (Modules.find(filename_str) != Modules.end()) + if (Modules.find(filename) != Modules.end()) { - LastModuleError = "Module " + filename_str + " is already loaded, cannot load a module twice!"; + LastModuleError = "Module " + filename + " is already loaded, cannot load a module twice!"; ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); return false; } @@ -82,22 +83,29 @@ bool ModuleManager::Load(const char* filename) try { - newmod = newhandle->callInit(); + newmod = newhandle->CallInit(); if (newmod) { - newmod->ModuleSourceFile = filename_str; + newmod->ModuleSourceFile = filename; newmod->ModuleDLLManager = newhandle; - Version v = newmod->GetVersion(); - - ServerInstance->Logs->Log("MODULE", DEFAULT,"New module introduced: %s (Module version %s)%s", - filename, v.version.c_str(), (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]")); + Modules[filename] = newmod; + if (defer) + { + ServerInstance->Logs->Log("MODULE", DEFAULT,"New module introduced: %s", filename.c_str()); + } + else + { + newmod->init(); - Modules[filename_str] = newmod; + Version v = newmod->GetVersion(); + ServerInstance->Logs->Log("MODULE", DEFAULT,"New module introduced: %s (Module version %s)%s", + filename.c_str(), newhandle->GetVersion().c_str(), (!(v.Flags & VF_VENDOR) ? " [3rd Party]" : " [Vendor]")); + } } else { - LastModuleError = "Unable to load " + filename_str + ": " + newhandle->LastError(); + LastModuleError = "Unable to load " + filename + ": " + newhandle->LastError(); ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); delete newhandle; return false; @@ -106,16 +114,20 @@ bool ModuleManager::Load(const char* filename) catch (CoreException& modexcept) { // failure in module constructor - delete newmod; - delete newhandle; - LastModuleError = "Unable to load " + filename_str + ": " + modexcept.GetReason(); + if (newmod) + DoSafeUnload(newmod); + else + delete newhandle; + LastModuleError = "Unable to load " + filename + ": " + modexcept.GetReason(); ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); return false; } this->ModCount++; - FOREACH_MOD(I_OnLoadModule,OnLoadModule(newmod)); + 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 @@ -129,85 +141,13 @@ bool ModuleManager::Load(const char* filename) if (prioritizationState == PRIO_STATE_LAST) break; if (tries == 19) - ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected while loading " + filename_str); + ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected while loading " + filename); } ServerInstance->BuildISupport(); return true; } -bool ModuleManager::CanUnload(Module* mod) -{ - std::map::iterator modfind = Modules.find(mod->ModuleSourceFile); - - if (modfind == Modules.end() || modfind->second != mod) - { - LastModuleError = "Module " + mod->ModuleSourceFile + " is not loaded, cannot unload it!"; - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); - return false; - } - if (mod->GetVersion().Flags & VF_STATIC) - { - LastModuleError = "Module " + mod->ModuleSourceFile + " not unloadable (marked static)"; - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); - return false; - } - std::pair intercount = GetInterfaceInstanceCount(mod); - if (intercount.first > 0) - { - LastModuleError = "Failed to unload module " + mod->ModuleSourceFile + ", being used by " + ConvToStr(intercount.first) + " other(s) via interface '" + intercount.second + "'"; - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); - return false; - } - return true; -} - -void ModuleManager::DoSafeUnload(Module* mod) -{ - std::map::iterator modfind = Modules.find(mod->ModuleSourceFile); - - std::vector > items; - ServerInstance->Extensions.BeginUnregister(modfind->second, items); - /* Give the module a chance to tidy out all its metadata */ - for (chan_hash::iterator c = ServerInstance->chanlist->begin(); c != ServerInstance->chanlist->end(); c++) - { - mod->OnCleanup(TYPE_CHANNEL,c->second); - c->second->doUnhookExtensions(items); - const UserMembList* users = c->second->GetUsers(); - for(UserMembCIter mi = users->begin(); mi != users->end(); mi++) - mi->second->doUnhookExtensions(items); - } - for (user_hash::iterator u = ServerInstance->Users->clientlist->begin(); u != ServerInstance->Users->clientlist->end(); u++) - { - mod->OnCleanup(TYPE_USER,u->second); - u->second->doUnhookExtensions(items); - } - for(char m='A'; m <= 'z'; m++) - { - ModeHandler* mh; - mh = ServerInstance->Modes->FindMode(m, MODETYPE_USER); - if (mh && mh->creator == mod) - ServerInstance->Modes->DelMode(mh); - mh = ServerInstance->Modes->FindMode(m, MODETYPE_CHANNEL); - if (mh && mh->creator == mod) - ServerInstance->Modes->DelMode(mh); - } - - /* Tidy up any dangling resolvers */ - ServerInstance->Res->CleanResolvers(mod); - - FOREACH_MOD(I_OnUnloadModule,OnUnloadModule(mod)); - - DetachAll(mod); - - Modules.erase(modfind); - ServerInstance->GlobalCulls.AddItem(mod); - - ServerInstance->Logs->Log("MODULE", DEFAULT,"Module %s unloaded",mod->ModuleSourceFile.c_str()); - this->ModCount--; - ServerInstance->BuildISupport(); -} - namespace { struct UnloadAction : public HandlerBase0 { @@ -237,7 +177,8 @@ namespace { ServerInstance->GlobalCulls.Apply(); delete dll; bool rv = ServerInstance->Modules->Load(name.c_str()); - callback->Call(rv); + if (callback) + callback->Call(rv); ServerInstance->GlobalCulls.AddItem(this); } }; @@ -278,7 +219,7 @@ void ModuleManager::LoadAll() printf("."); fflush(stdout); - if (!Load(entry->d_name)) + if (!Load(entry->d_name, true)) { ServerInstance->Logs->Log("MODULE", DEFAULT, this->LastError()); printf_c("\n[\033[1;31m*\033[0m] %s\n\n", this->LastError().c_str()); @@ -297,13 +238,48 @@ void ModuleManager::LoadAll() std::string name = tag->getString("name"); printf_c("[\033[1;32m*\033[0m] Loading module:\t\033[1;32m%s\033[0m\n",name.c_str()); - if (!this->Load(name.c_str())) + if (!this->Load(name, true)) { ServerInstance->Logs->Log("MODULE", DEFAULT, this->LastError()); printf_c("\n[\033[1;31m*\033[0m] %s\n\n", this->LastError().c_str()); ServerInstance->Exit(EXIT_STATUS_MODULE); } } + + for(std::map::iterator i = Modules.begin(); i != Modules.end(); i++) + { + Module* mod = i->second; + try + { + mod->init(); + } + catch (CoreException& modexcept) + { + LastModuleError = "Unable to initialize " + mod->ModuleSourceFile + ": " + modexcept.GetReason(); + ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + printf_c("\n[\033[1;31m*\033[0m] %s\n\n", LastModuleError.c_str()); + ServerInstance->Exit(EXIT_STATUS_MODULE); + } + } + + /* 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::iterator n = Modules.begin(); n != Modules.end(); ++n) + n->second->Prioritize(); + + if (prioritizationState == PRIO_STATE_LAST) + break; + if (tries == 19) + { + ServerInstance->Logs->Log("MODULE", DEFAULT, "Hook priority dependency loop detected"); + ServerInstance->Exit(EXIT_STATUS_MODULE); + } + } } void ModuleManager::UnloadAll()