Allow static build of inspircd without module support

git-svn-id: http://svn.inspircd.org/repository/trunk/inspircd@12083 e03df62e-2008-0410-955e-edbf42e46eb7
This commit is contained in:
danieldg 2009-11-11 00:17:07 +00:00
parent 316167b917
commit 19487dbebc
12 changed files with 540 additions and 329 deletions

View File

@ -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

View File

@ -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_.*)/#) {

View File

@ -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

View File

@ -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)

View File

@ -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
*/

328
src/modmanager_dynamic.cpp Normal file
View File

@ -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

127
src/modmanager_static.cpp Normal file
View File

@ -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

View File

@ -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())

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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);
}