diff options
author | danieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7> | 2009-11-11 00:17:07 +0000 |
---|---|---|
committer | danieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7> | 2009-11-11 00:17:07 +0000 |
commit | 19487dbebc520450e457472b97d9e7bcd5160c00 (patch) | |
tree | 5ba36439139db77ff11c549228a3dbf69727e9cc | |
parent | 316167b91713739d784cc4c640275ebe2a9f054a (diff) |
Allow static build of inspircd without module support
git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@12083 e03df62e-2008-0410-955e-edbf42e46eb7
-rw-r--r-- | include/modules.h | 24 | ||||
-rwxr-xr-x | make/calcdep.pl | 55 | ||||
-rw-r--r-- | make/template/main.mk | 6 | ||||
-rw-r--r-- | src/commands/cmd_clearcache.cpp | 6 | ||||
-rw-r--r-- | src/commands/cmd_mode.cpp | 9 | ||||
-rw-r--r-- | src/modmanager_dynamic.cpp | 328 | ||||
-rw-r--r-- | src/modmanager_static.cpp | 127 | ||||
-rw-r--r-- | src/modules.cpp | 304 | ||||
-rw-r--r-- | src/modules/extra/m_mysql.cpp | 2 | ||||
-rw-r--r-- | src/modules/extra/m_pgsql.cpp | 2 | ||||
-rw-r--r-- | src/modules/extra/m_sqlite3.cpp | 2 | ||||
-rw-r--r-- | src/modules/m_sqlv2.h | 4 |
12 files changed, 540 insertions, 329 deletions
diff --git a/include/modules.h b/include/modules.h index dc59abdd9..3efee83dc 100644 --- a/include/modules.h +++ b/include/modules.h @@ -1696,6 +1696,28 @@ class CoreExport ModuleManager #define MODULE_INIT_SYM_FN_2(x) MODULE_INIT_SYM_FN_1(x) #define MODULE_INIT_SYM_FN_1(x) inspircd_module_ ## x +#ifdef PURE_STATIC + +struct AllCommandList { + typedef Command* (*fn)(Module*); + AllCommandList(fn cmd); +}; +#define COMMAND_INIT(x) static Command* MK_ ## x(Module* m) { return new x(m); } \ + static const AllCommandList PREP_ ## x(&MK_ ## x); + +struct AllModuleList { + typedef Module* (*fn)(); + fn init; + std::string name; + AllModuleList(fn mod, const std::string& Name); +}; + +#define MODULE_INIT(x) static Module* MK_ ## x() { return new x; } \ + static const AllModuleList PREP_ ## x(&MK_ ## x, #x); + + +#else + /** This definition is used as shorthand for the various classes * and functions needed to make a module loadable by the OS. * It defines the class factory and external init_module function. @@ -1730,3 +1752,5 @@ class CoreExport ModuleManager #define COMMAND_INIT(c) MODULE_INIT(CommandModule<c>) #endif + +#endif diff --git a/make/calcdep.pl b/make/calcdep.pl index 81a7759d3..587bd64de 100755 --- a/make/calcdep.pl +++ b/make/calcdep.pl @@ -3,7 +3,7 @@ use strict; use warnings; use POSIX qw(getcwd); -sub find_output($); +sub find_output; sub gendep($); sub dep_cpp($$); sub dep_dir($); @@ -28,6 +28,16 @@ sub run() { open MAKE, '>real.mk' or die "Could not write real.mk: $!"; chdir "$ENV{SOURCEPATH}/src"; + if ($ENV{PURE_STATIC}) { + run_static(); + } else { + run_dynamic(); + } + close MAKE; +} + +sub run_dynamic() { + my $build = $ENV{BUILDPATH}; print MAKE <<END; # DO NOT EDIT THIS FILE # It is autogenerated by make/calcdep.pl, and will be overwritten @@ -95,11 +105,48 @@ modules: $mods END } -sub find_output($) { - my $file = shift; +sub run_static() { + print MAKE <<END; +# DO NOT EDIT THIS FILE +# It is autogenerated by make/calcdep.pl, and will be overwritten +# every time you rerun make in the main directory +VPATH = \$(SOURCEPATH)/src + +bad-target: + \@echo "This Makefile must be run by a sub-make from the source" + \@echo "in order to set the correct environment variables" + \@exit 1 + +all: inspircd + +END + my @deps; + for my $file (<*.cpp>, <modes/*.cpp>, <socketengines/*.cpp>, <commands/*.cpp>, + <modules/*.cpp>, <modules/m_*/*.cpp>, "threadengines/threadengine_pthread.cpp") { + my $out = find_output $file, 1; + dep_cpp $file, $out; + next if $file =~ m#^socketengines/# && $file ne "socketengines/$ENV{SOCKETENGINE}.cpp"; + push @deps, $out; + } + + my $core_mk = join ' ', @deps; + print MAKE <<END; + +bin/inspircd: $core_mk + \$(RUNCC) -o \$\@ \$(CORELDFLAGS) \$(LDLIBS) \$^ \$> + +inspircd: bin/inspircd + +.PHONY: all bad-target inspircd + +END +} + +sub find_output { + my($file, $static) = @_; my($path,$base) = $file =~ m#^((?:.*/)?)([^/]+)\.cpp# or die "Bad file $file"; if ($path eq 'modules/' || $path eq 'commands/') { - return "modules/$base.so"; + return $static ? "obj/$base.o" : "modules/$base.so"; } elsif ($path eq '' || $path eq 'modes/' || $path =~ /^[a-z]+engines\/$/) { return "obj/$base.o"; } elsif ($path =~ m#modules/(m_.*)/#) { diff --git a/make/template/main.mk b/make/template/main.mk index 666104d1b..c06e92fea 100644 --- a/make/template/main.mk +++ b/make/template/main.mk @@ -74,7 +74,11 @@ CXXFLAGS += -Iinclude RUNCC = perl $(SOURCEPATH)/make/run-cc.pl $(CC) @ENDIF -@DO_EXPORT RUNCC CXXFLAGS CC LDLIBS PICLDFLAGS VERBOSE SOCKETENGINE CORELDFLAGS +@IFDEF PURE_STATIC + CXXFLAGS += -DPURE_STATIC +@ENDIF + +@DO_EXPORT RUNCC CXXFLAGS CC LDLIBS PICLDFLAGS VERBOSE SOCKETENGINE CORELDFLAGS PURE_STATIC @DO_EXPORT BASE CONPATH MODPATH BINPATH SOURCEPATH BUILDPATH # Default target diff --git a/src/commands/cmd_clearcache.cpp b/src/commands/cmd_clearcache.cpp index 2334e597c..1fc8a1241 100644 --- a/src/commands/cmd_clearcache.cpp +++ b/src/commands/cmd_clearcache.cpp @@ -13,9 +13,6 @@ #include "inspircd.h" -#ifndef __CMD_ADMIN_H__ -#define __CMD_ADMIN_H__ - #include "users.h" #include "channels.h" #include "ctables.h" @@ -40,9 +37,6 @@ class CommandClearcache : public Command CmdResult Handle(const std::vector<std::string>& parameters, User *user); }; -#endif - - /** Handle /CLEARCACHE */ CmdResult CommandClearcache::Handle (const std::vector<std::string>& parameters, User *user) diff --git a/src/commands/cmd_mode.cpp b/src/commands/cmd_mode.cpp index 3cfc58263..5bc55e895 100644 --- a/src/commands/cmd_mode.cpp +++ b/src/commands/cmd_mode.cpp @@ -13,13 +13,6 @@ #include "inspircd.h" -#ifndef __CMD_ADMIN_H__ -#define __CMD_ADMIN_H__ - -#include "users.h" -#include "channels.h" -#include "ctables.h" - /** Handle /MODE. These command handlers can be reloaded by the core, * and handle basic RFC1459 commands. Commands within modules work * the same way, however, they can be fully unloaded, where these @@ -40,8 +33,6 @@ class CommandMode : public Command CmdResult Handle(const std::vector<std::string>& parameters, User *user); }; -#endif - /** Handle /MODE */ diff --git a/src/modmanager_dynamic.cpp b/src/modmanager_dynamic.cpp new file mode 100644 index 000000000..b4a1d5906 --- /dev/null +++ b/src/modmanager_dynamic.cpp @@ -0,0 +1,328 @@ +/* +------------------------------------+ + * | Inspire Internet Relay Chat Daemon | + * +------------------------------------+ + * + * InspIRCd: (C) 2002-2009 InspIRCd Development Team + * See: http://wiki.inspircd.org/Credits + * + * This program is free but copyrighted software; see + * the file COPYING for details. + * + * --------------------------------------------------- + */ + +#include "inspircd.h" +#include "xline.h" +#include "socket.h" +#include "socketengine.h" +#include "command_parse.h" +#include "dns.h" +#include "exitcodes.h" + +#ifndef PURE_STATIC + +bool ModuleManager::Load(const char* filename) +{ + /* Don't allow people to specify paths for modules, it doesn't work as expected */ + if (strchr(filename, '/')) + 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,'?'))) + { + int n_match = 0; + DIR* library = opendir(ServerInstance->Config->ModPath.c_str()); + if (library) + { + /* Try and locate and load all modules matching the pattern */ + dirent* entry = NULL; + while (0 != (entry = readdir(library))) + { + if (InspIRCd::Match(entry->d_name, filename, ascii_case_insensitive_map)) + { + if (!this->Load(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 ? false : true); + } + + char modfile[MAXBUF]; + snprintf(modfile,MAXBUF,"%s/%s",ServerInstance->Config->ModPath.c_str(),filename); + std::string filename_str = filename; + + if (!ServerConfig::FileExists(modfile)) + { + LastModuleError = "Module file could not be found: " + filename_str; + ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + return false; + } + + if (Modules.find(filename_str) != Modules.end()) + { + LastModuleError = "Module " + filename_str + " is already loaded, cannot load a module twice!"; + ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + return false; + } + + Module* newmod = NULL; + DLLManager* newhandle = new DLLManager(modfile); + + try + { + newmod = newhandle->callInit(); + + if (newmod) + { + newmod->ModuleSourceFile = filename_str; + 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_str] = newmod; + } + else + { + LastModuleError = "Unable to load " + filename_str + ": " + newhandle->LastError(); + ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + delete newhandle; + return false; + } + } + catch (CoreException& modexcept) + { + // failure in module constructor + delete newmod; + delete newhandle; + LastModuleError = "Unable to load " + filename_str + ": " + modexcept.GetReason(); + ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); + return false; + } + + this->ModCount++; + 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", DEFAULT, "Hook priority dependency loop detected while loading " + filename_str); + } + + ServerInstance->BuildISupport(); + return true; +} + +bool ModuleManager::CanUnload(Module* mod) +{ + std::map<std::string, Module*>::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<int,std::string> 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<std::string, Module*>::iterator modfind = Modules.find(mod->ModuleSourceFile); + + std::vector<reference<ExtensionItem> > 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<void> + { + Module* const mod; + UnloadAction(Module* m) : mod(m) {} + void Call() + { + DLLManager* dll = mod->ModuleDLLManager; + ServerInstance->Modules->DoSafeUnload(mod); + ServerInstance->GlobalCulls.Apply(); + delete dll; + ServerInstance->GlobalCulls.AddItem(this); + } + }; + + struct ReloadAction : public HandlerBase0<void> + { + Module* const mod; + HandlerBase1<void, bool>* const callback; + ReloadAction(Module* m, HandlerBase1<void, bool>* c) + : mod(m), callback(c) {} + void Call() + { + DLLManager* dll = mod->ModuleDLLManager; + std::string name = mod->ModuleSourceFile; + ServerInstance->Modules->DoSafeUnload(mod); + ServerInstance->GlobalCulls.Apply(); + delete dll; + bool rv = ServerInstance->Modules->Load(name.c_str()); + callback->Call(rv); + ServerInstance->GlobalCulls.AddItem(this); + } + }; +} + +bool ModuleManager::Unload(Module* mod) +{ + if (!CanUnload(mod)) + return false; + ServerInstance->AtomicActions.AddAction(new UnloadAction(mod)); + return true; +} + +void ModuleManager::Reload(Module* mod, HandlerBase1<void, bool>* callback) +{ + if (CanUnload(mod)) + ServerInstance->AtomicActions.AddAction(new ReloadAction(mod, callback)); + else + callback->Call(false); +} + +/* We must load the modules AFTER initializing the socket engine, now */ +void ModuleManager::LoadAll() +{ + ModCount = 0; + + printf("\nLoading core commands"); + fflush(stdout); + + DIR* library = opendir(ServerInstance->Config->ModPath.c_str()); + if (library) + { + dirent* entry = NULL; + while (0 != (entry = readdir(library))) + { + if (InspIRCd::Match(entry->d_name, "cmd_*.so", ascii_case_insensitive_map)) + { + printf("."); + fflush(stdout); + + if (!Load(entry->d_name)) + { + 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); + } + } + } + closedir(library); + printf("\n"); + } + + ConfigTagList tags = ServerInstance->Config->ConfTags("module"); + for(ConfigIter i = tags.first; i != tags.second; ++i) + { + ConfigTag* tag = i->second; + 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())) + { + 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); + } + } +} + +void ModuleManager::UnloadAll() +{ + /* We do this more than once, so that any service providers get a + * chance to be unhooked by the modules using them, but then get + * a chance to be removed themsleves. + * + * Note: this deliberately does NOT delete the DLLManager objects + */ + for (int tries = 0; tries < 4; tries++) + { + std::map<std::string, Module*>::iterator i = Modules.begin(); + while (i != Modules.end()) + { + std::map<std::string, Module*>::iterator me = i++; + if (CanUnload(me->second)) + { + DoSafeUnload(me->second); + } + } + ServerInstance->GlobalCulls.Apply(); + } +} + +#endif diff --git a/src/modmanager_static.cpp b/src/modmanager_static.cpp new file mode 100644 index 000000000..e09310a13 --- /dev/null +++ b/src/modmanager_static.cpp @@ -0,0 +1,127 @@ +#include "inspircd.h" + +#ifdef PURE_STATIC + +static std::vector<AllCommandList::fn>* cmdlist = NULL; +static std::vector<AllModuleList*>* modlist = NULL; + +AllCommandList::AllCommandList(fn cmd) +{ + if (!cmdlist) + cmdlist = new std::vector<AllCommandList::fn>(); + cmdlist->push_back(cmd); +} + +AllModuleList::AllModuleList(AllModuleList::fn mod, const std::string& Name) : init(mod), name(Name) +{ + if (!modlist) + modlist = new std::vector<AllModuleList*>(); + modlist->push_back(this); +} + +class AllModule : public Module +{ + std::vector<Command*> cmds; + public: + AllModule() + { + if (!cmdlist) + return; + try + { + cmds.reserve(cmdlist->size()); + for(std::vector<AllCommandList::fn>::iterator i = cmdlist->begin(); i != cmdlist->end(); ++i) + { + Command* c = (*i)(this); + cmds.push_back(c); + ServerInstance->AddCommand(c); + } + } + catch (...) + { + this->AllModule::~AllModule(); + throw; + } + } + + ~AllModule() + { + for(std::vector<Command*>::iterator i = cmds.begin(); i != cmds.end(); ++i) + delete *i; + } + + Version GetVersion() + { + return Version("All commands", VF_VENDOR|VF_CORE); + } +}; + +MODULE_INIT(AllModule) + +bool ModuleManager::Load(const char* filename) +{ + return false; +} + +bool ModuleManager::CanUnload(Module* mod) +{ + return false; +} + +void ModuleManager::DoSafeUnload(Module* mod) +{ +} + +bool ModuleManager::Unload(Module* mod) +{ + return false; +} + +void ModuleManager::Reload(Module* mod, HandlerBase1<void, bool>* callback) +{ + callback->Call(false); +} + +void ModuleManager::LoadAll() +{ + ModCount = 0; + for(std::vector<AllModuleList*>::iterator i = modlist->begin(); i != modlist->end(); ++i) + { + try + { + Module* c = (*(**i).init)(); + c->ModuleSourceFile = (**i).name; + Modules[(**i).name] = c; + FOREACH_MOD(I_OnLoadModule,OnLoadModule(c)); + } + catch (CoreException& modexcept) + { + ServerInstance->Logs->Log("MODULE", DEFAULT, "Unable to load " + (**i).name + ": " + modexcept.GetReason()); + } + } + + /* 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", DEFAULT, "Hook priority dependency loop detected"); + } + + ServerInstance->BuildISupport(); +} + +void ModuleManager::UnloadAll() +{ + // TODO don't really need this, who cares if we leak on exit? +} + +#endif diff --git a/src/modules.cpp b/src/modules.cpp index b3aabf284..a2c4aa6ea 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -322,310 +322,6 @@ std::string& ModuleManager::LastError() return LastModuleError; } -bool ModuleManager::Load(const char* filename) -{ - /* Don't allow people to specify paths for modules, it doesn't work as expected */ - if (strchr(filename, '/')) - 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,'?'))) - { - int n_match = 0; - DIR* library = opendir(ServerInstance->Config->ModPath.c_str()); - if (library) - { - /* Try and locate and load all modules matching the pattern */ - dirent* entry = NULL; - while (0 != (entry = readdir(library))) - { - if (InspIRCd::Match(entry->d_name, filename, ascii_case_insensitive_map)) - { - if (!this->Load(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 ? false : true); - } - - char modfile[MAXBUF]; - snprintf(modfile,MAXBUF,"%s/%s",ServerInstance->Config->ModPath.c_str(),filename); - std::string filename_str = filename; - - if (!ServerConfig::FileExists(modfile)) - { - LastModuleError = "Module file could not be found: " + filename_str; - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); - return false; - } - - if (Modules.find(filename_str) != Modules.end()) - { - LastModuleError = "Module " + filename_str + " is already loaded, cannot load a module twice!"; - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); - return false; - } - - Module* newmod = NULL; - DLLManager* newhandle = new DLLManager(modfile); - - try - { - newmod = newhandle->callInit(); - - if (newmod) - { - newmod->ModuleSourceFile = filename_str; - 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_str] = newmod; - } - else - { - LastModuleError = "Unable to load " + filename_str + ": " + newhandle->LastError(); - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); - delete newhandle; - return false; - } - } - catch (CoreException& modexcept) - { - // failure in module constructor - delete newmod; - delete newhandle; - LastModuleError = "Unable to load " + filename_str + ": " + modexcept.GetReason(); - ServerInstance->Logs->Log("MODULE", DEFAULT, LastModuleError); - return false; - } - - this->ModCount++; - 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", DEFAULT, "Hook priority dependency loop detected while loading " + filename_str); - } - - ServerInstance->BuildISupport(); - return true; -} - -bool ModuleManager::CanUnload(Module* mod) -{ - std::map<std::string, Module*>::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<int,std::string> 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<std::string, Module*>::iterator modfind = Modules.find(mod->ModuleSourceFile); - - std::vector<reference<ExtensionItem> > 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<void> - { - Module* const mod; - UnloadAction(Module* m) : mod(m) {} - void Call() - { - DLLManager* dll = mod->ModuleDLLManager; - ServerInstance->Modules->DoSafeUnload(mod); - ServerInstance->GlobalCulls.Apply(); - delete dll; - ServerInstance->GlobalCulls.AddItem(this); - } - }; - - struct ReloadAction : public HandlerBase0<void> - { - Module* const mod; - HandlerBase1<void, bool>* const callback; - ReloadAction(Module* m, HandlerBase1<void, bool>* c) - : mod(m), callback(c) {} - void Call() - { - DLLManager* dll = mod->ModuleDLLManager; - std::string name = mod->ModuleSourceFile; - ServerInstance->Modules->DoSafeUnload(mod); - ServerInstance->GlobalCulls.Apply(); - delete dll; - bool rv = ServerInstance->Modules->Load(name.c_str()); - callback->Call(rv); - ServerInstance->GlobalCulls.AddItem(this); - } - }; -} - -bool ModuleManager::Unload(Module* mod) -{ - if (!CanUnload(mod)) - return false; - ServerInstance->AtomicActions.AddAction(new UnloadAction(mod)); - return true; -} - -void ModuleManager::Reload(Module* mod, HandlerBase1<void, bool>* callback) -{ - if (CanUnload(mod)) - ServerInstance->AtomicActions.AddAction(new ReloadAction(mod, callback)); - else - callback->Call(false); -} - -/* We must load the modules AFTER initializing the socket engine, now */ -void ModuleManager::LoadAll() -{ - ModCount = 0; - - printf("\nLoading core commands"); - fflush(stdout); - - DIR* library = opendir(ServerInstance->Config->ModPath.c_str()); - if (library) - { - dirent* entry = NULL; - while (0 != (entry = readdir(library))) - { - if (InspIRCd::Match(entry->d_name, "cmd_*.so", ascii_case_insensitive_map)) - { - printf("."); - fflush(stdout); - - if (!Load(entry->d_name)) - { - 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); - } - } - } - closedir(library); - printf("\n"); - } - - ConfigTagList tags = ServerInstance->Config->ConfTags("module"); - for(ConfigIter i = tags.first; i != tags.second; ++i) - { - ConfigTag* tag = i->second; - 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())) - { - 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); - } - } -} - -void ModuleManager::UnloadAll() -{ - /* We do this more than once, so that any service providers get a - * chance to be unhooked by the modules using them, but then get - * a chance to be removed themsleves. - * - * Note: this deliberately does NOT delete the DLLManager objects - */ - for (int tries = 0; tries < 4; tries++) - { - std::map<std::string, Module*>::iterator i = Modules.begin(); - while (i != Modules.end()) - { - std::map<std::string, Module*>::iterator me = i++; - if (CanUnload(me->second)) - { - DoSafeUnload(me->second); - } - } - ServerInstance->GlobalCulls.Apply(); - } -} - bool ModuleManager::PublishFeature(const std::string &FeatureName, Module* Mod) { if (Features.find(FeatureName) == Features.end()) diff --git a/src/modules/extra/m_mysql.cpp b/src/modules/extra/m_mysql.cpp index 47de25ee4..358f5e992 100644 --- a/src/modules/extra/m_mysql.cpp +++ b/src/modules/extra/m_mysql.cpp @@ -70,7 +70,7 @@ class DispatcherThread; typedef std::map<std::string, SQLConnection*> ConnMap; typedef std::deque<SQLresult*> ResultQueue; -unsigned long count(const char * const str, char a) +static unsigned long count(const char * const str, char a) { unsigned long n = 0; for (const char *p = str; *p; ++p) diff --git a/src/modules/extra/m_pgsql.cpp b/src/modules/extra/m_pgsql.cpp index b5beea0b0..f362125cb 100644 --- a/src/modules/extra/m_pgsql.cpp +++ b/src/modules/extra/m_pgsql.cpp @@ -44,7 +44,7 @@ typedef std::map<std::string, SQLConn*> ConnMap; */ enum SQLstatus { CREAD, CWRITE, WREAD, WWRITE, RREAD, RWRITE }; -unsigned long count(const char * const str, char a) +static unsigned long count(const char * const str, char a) { unsigned long n = 0; for (const char *p = str; *p; ++p) diff --git a/src/modules/extra/m_sqlite3.cpp b/src/modules/extra/m_sqlite3.cpp index 89f61b652..e5693b61f 100644 --- a/src/modules/extra/m_sqlite3.cpp +++ b/src/modules/extra/m_sqlite3.cpp @@ -31,7 +31,7 @@ typedef std::map<std::string, SQLConn*> ConnMap; typedef std::deque<classbase*> paramlist; typedef std::deque<SQLite3Result*> ResultQueue; -unsigned long count(const char * const str, char a) +static unsigned long count(const char * const str, char a) { unsigned long n = 0; for (const char *p = str; *p; ++p) diff --git a/src/modules/m_sqlv2.h b/src/modules/m_sqlv2.h index 05079a8e6..7d1cb78f2 100644 --- a/src/modules/m_sqlv2.h +++ b/src/modules/m_sqlv2.h @@ -457,13 +457,13 @@ class SQLhost /** Overload operator== for two SQLhost objects for easy comparison. */ -bool operator== (const SQLhost& l, const SQLhost& r) +inline bool operator== (const SQLhost& l, const SQLhost& r) { return (l.id == r.id && l.host == r.host && l.port == r.port && l.name == r.name && l.user == r.user && l.pass == r.pass && l.ssl == r.ssl); } /** Overload operator!= for two SQLhost objects for easy comparison. */ -bool operator!= (const SQLhost& l, const SQLhost& r) +inline bool operator!= (const SQLhost& l, const SQLhost& r) { return (l.id != r.id || l.host != r.host || l.port != r.port || l.name != r.name || l.user != r.user || l.pass != r.pass || l.ssl != r.ssl); } |