summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordanieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7>2009-11-11 00:17:07 +0000
committerdanieldg <danieldg@e03df62e-2008-0410-955e-edbf42e46eb7>2009-11-11 00:17:07 +0000
commit19487dbebc520450e457472b97d9e7bcd5160c00 (patch)
tree5ba36439139db77ff11c549228a3dbf69727e9cc
parent316167b91713739d784cc4c640275ebe2a9f054a (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.h24
-rwxr-xr-xmake/calcdep.pl55
-rw-r--r--make/template/main.mk6
-rw-r--r--src/commands/cmd_clearcache.cpp6
-rw-r--r--src/commands/cmd_mode.cpp9
-rw-r--r--src/modmanager_dynamic.cpp328
-rw-r--r--src/modmanager_static.cpp127
-rw-r--r--src/modules.cpp304
-rw-r--r--src/modules/extra/m_mysql.cpp2
-rw-r--r--src/modules/extra/m_pgsql.cpp2
-rw-r--r--src/modules/extra/m_sqlite3.cpp2
-rw-r--r--src/modules/m_sqlv2.h4
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);
}