1
0
mirror of https://github.com/unrealircd/unrealircd.git synced 2026-06-27 15:26:39 +02:00
Files
unrealircd/src/modules.c
T
2001-11-19 20:30:30 +00:00

528 lines
10 KiB
C

/************************************************************************
* UnrealIRCd - Unreal Internet Relay Chat Daemon - src/modules.c
* (C) 2001 Carsten Munk (Techie/Stskeeps) <stskeeps@tspre.org>
*
* See file AUTHORS in IRC package for additional names of
* the programmers.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 1, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "struct.h"
#include "common.h"
#include "sys.h"
#include "numeric.h"
#include "msg.h"
#include "channel.h"
#include "version.h"
#include <time.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#include <io.h>
#define RTLD_NOW 0
#else
#include <dlfcn.h>
#endif
#include <fcntl.h>
#include "h.h"
#ifndef RTLD_NOW
#define RTLD_NOW RTLD_LAZY
#endif
ModuleInfo *Modules[MAXMODULES];
unsigned char ModuleFlags[MAXMODULES];
Hook *Hooks[MAXHOOKTYPES];
Hook *global_i = NULL;
int modules_loaded = 0;
void module_init(void)
{
bzero(Modules, sizeof(Modules));
bzero(Hooks, sizeof(Hooks));
bzero(ModuleFlags, sizeof(ModuleFlags));
modules_loaded = 0;
}
int load_module(char *module, int module_load)
{
#ifndef STATIC_LINKING
#ifdef _WIN32
HMODULE Mod;
#else
void *Mod;
#endif
int (*mod_init) ();
int (*mod_load) ();
void (*mod_unload) ();
MSymbolTable *mod_dep;
ModuleInfo *mod_header;
int i;
Debug((DEBUG_DEBUG, "Attemping to load %s",
module));
if (Mod = irc_dlopen(module, RTLD_NOW))
{
/* Succeed loading module */
/* We check header */
mod_header = irc_dlsym(Mod, "mod_header");
if (!mod_header)
{
Debug((DEBUG_DEBUG, "Didn't find mod_header, trying _mod_header"));
mod_header = irc_dlsym(Mod, "_mod_header");
}
if (!mod_header)
{
config_progress("%s: cannot load, no module header",
module);
irc_dlclose(Mod);
return -1;
}
if (mod_header->mversion != MOD_VERSION)
{
config_progress
("Failed to load module %s: mversion is %i, not %i as we require",
module, mod_header->mversion, MOD_VERSION);
irc_dlclose(Mod);
return -1;
}
if (!mod_header->name || !mod_header->version
|| !mod_header->description)
{
config_progress
("Failed to load module %s: name/version/description missing",
module);
irc_dlclose(Mod);
return -1;
}
for (i = 0; i < MAXMODULES; i++)
if (Modules[i] && !strcmp(Modules[i]->name, mod_header->name))
{
Debug((DEBUG_DEBUG, "Module already loaded, duplicate"));
/* We will unload it without notice, its a duplicate */
irc_dlclose(Mod);
return 1;
}
for (i = 0; i < MAXMODULES; i++)
{
if (!Modules[i])
{
Modules[i] = mod_header;
modules_loaded++;
break;
}
}
if (i == MAXMODULES)
{
config_progress
("Failed to load module %s: Too many modules loaded");
Modules[i] = NULL;
irc_dlclose(Mod);
return -1;
}
/* Locate mod_depend */
mod_dep = irc_dlsym(Mod, "mod_depend");
if (!mod_dep)
mod_dep = irc_dlsym(Mod, "_mod_depend");
if (mod_dep)
{
if (module_depend_resolve(mod_dep) == -1)
{
config_progress("%s: cannot load, missing dependancy",
module);
Modules[i] = NULL;
irc_dlclose(Mod);
return -1;
}
}
/* Locate mod_init function */
mod_init = irc_dlsym(Mod, "mod_init");
if (!mod_init)
{
mod_init = irc_dlsym(Mod, "_mod_init");
if (!mod_init)
{
config_progress
("Failed to load module %s: Could not locate mod_init",
module);
Modules[i] = NULL;
irc_dlclose(Mod);
return -1;
}
}
mod_unload = irc_dlsym(Mod, "mod_unload");
if (!mod_unload)
{
mod_unload = irc_dlsym(Mod, "_mod_unload");
if (!mod_unload)
{
config_progress
("Failed to load module %s: Could not locate mod_unload",
module);
Modules[i] = NULL;
irc_dlclose(Mod);
return -1;
}
}
mod_header->dll = Mod;
mod_header->unload = mod_unload;
if ((*mod_init)(module_load) < 0)
{
config_progress
("Failed to load module %s: mod_init failed",
module);
Modules[i] = NULL;
irc_dlclose(Mod);
return -1;
}
ModuleFlags[i] = 0;
if (module_load)
{
mod_load = irc_dlsym(Mod, "mod_load");
if (!mod_load)
{
mod_load = irc_dlsym(Mod, "_mod_load");
if (mod_load)
{
(*mod_load)(module_load);
ModuleFlags[i] |= MODFLAG_LOADED;
}
}
}
return 1;
}
#ifndef _WIN32
else
{
const char *err = irc_dlerror();
if (err)
{
config_progress("Failed to load module %s: %s",
module, err);
}
return -1;
}
#endif
#endif
}
void unload_all_modules(void)
{
#ifndef STATIC_LINKING
int i;
for (i = 0; i < MAXMODULES; i++)
if (Modules[i])
{
/* Call unload */
(*Modules[i]->unload)();
irc_dlclose(Modules[i]->dll);
Modules[i] = NULL;
ModuleFlags[i] = MODFLAG_NONE;
modules_loaded--;
}
#endif
return;
}
int unload_module(char *name)
{
#ifndef STATIC_LINKING
int i;
int (*mod_delay)();
for (i = 0; i < MAXMODULES; i++)
if (Modules[i])
if (!strcmp(Modules[i]->name, name))
break;
if (i == MAXMODULES)
return -1;
mod_delay = irc_dlsym(Modules[i]->dll, "mod_delay");
if (mod_delay)
{
/*
* We are to question the modules mod_delay() if to unload or not
* 1 if we are to delay, 0 if not ..
* The module MUST queue a module unload event
*/
if ((*mod_delay)() == 1)
{
/* Return */
return 2;
}
}
/* Call unload */
(*Modules[i]->unload)();
irc_dlclose(Modules[i]->dll);
Modules[i] = NULL;
ModuleFlags[i] = MODFLAG_NONE;
modules_loaded--;
return 1;
#endif
}
vFP module_sym(char *name)
{
#ifndef STATIC_LINKING
vFP fp;
char buf[512];
int i;
ModuleInfo *mi;
if (!name)
return NULL;
ircsprintf(buf, "_%s", name);
/* Run through all modules and check for symbols */
for (i = 0; i < MAXMODULES; i++)
{
mi = Modules[i];
if (!mi)
continue;
if (fp = (vFP) irc_dlsym(mi->dll, name))
return (fp);
if (fp = (vFP) irc_dlsym(mi->dll, buf))
return (fp);
}
return NULL;
#endif
}
void module_loadall(int module_load)
{
#ifndef STATIC_LINKING
iFP fp;
int i;
ModuleInfo *mi;
if (!loop.ircd_booted)
{
sendto_realops("Ehh, !loop.ircd_booted in module_loadall()");
return ;
}
/* Run through all modules and check for module load */
for (i = 0; i < MAXMODULES; i++)
{
mi = Modules[i];
if (!mi)
continue;
if (ModuleFlags[i] & MODFLAG_LOADED)
continue;
if (fp = (iFP) irc_dlsym(mi->dll, "mod_load"))
{
}
else
if (fp = (iFP) irc_dlsym(mi->dll, "_mod_load"))
{
}
else
{
/* else, we didn't find it */
continue;
}
/* Call the module_load */
if ((*fp)(module_load) < 0)
{
config_error("cannot load module %s", mi->name);
}
else
{
ModuleFlags[i] |= MODFLAG_LOADED;
}
}
#endif
}
int module_depend_resolve(MSymbolTable *dep)
{
MSymbolTable *d = dep;
#ifndef STATIC_LINKING
while (d->pointer)
{
*(d->pointer) = module_sym(d->symbol);
if (!*(d->pointer))
{
/* config_progress("module dependancy error: cannot resolve symbol %s",
d->symbol);*/
config_progress("Unable to resolve symbol %s, attempting to load %s to find it",
d->symbol, d->module);
load_module(d->module,0);
*(d->pointer) = module_sym(d->symbol);
if (!*(d->pointer)) {
config_progress("module dependancy error: cannot resolve symbol %s",
d->symbol);
return -1;
}
}
d++;
}
return 0;
#else
while (d->pointer)
{
*((vFP *)d->pointer) = (vFP) d->realfunc;
d++;
}
#endif
}
int m_module(aClient *cptr, aClient *sptr, int parc, char *parv[])
{
int i;
ModuleInfo *mi;
if (!IsAdmin(sptr))
{
sendto_one(sptr, err_str(ERR_NOPRIVILEGES), me.name, parv[0]);
return 0;
}
if (parc < 2)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "MODULE");
return 0;
}
if (!match(parv[1], "load"))
{
if (parc < 3)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "MODULE LOAD");
return 0;
}
sendto_realops("Trying to load module %s", parv[2]);
if (load_module(parv[2],1) == 1)
sendto_realops("Loaded module %s", parv[2]);
}
else
if (!match(parv[1], "unload"))
{
if (parc < 3)
{
sendto_one(sptr, err_str(ERR_NEEDMOREPARAMS),
me.name, parv[0], "MODULE UNLOAD");
return 0;
}
sendto_realops("Trying to unload module %s", parv[2]);
i = unload_module(parv[2]);
{
if (i == 1)
sendto_realops("Unloaded module %s", parv[2]);
else if (i == 2)
sendto_realops("Delaying module unload of %s",
parv[2]);
else if (i == -1)
sendto_realops("Couldn't unload module %s",
parv[2]);
}
}
else
if (!match(parv[1], "status"))
{
if (modules_loaded == 0)
{
sendto_one(sptr, ":%s NOTICE %s :*** No modules loaded", me.name, sptr->name);
return 1;
}
for (i = 0; i < MAXMODULES; i++)
if (mi = Modules[i])
{
sendto_one(sptr, ":%s NOTICE %s :*** %s - %s (%s)", me.name, sptr->name,
mi->name, mi->version, mi->description);
}
}
else
{
sendto_one(sptr, ":%s NOTICE %s :*** Syntax: /module load|unload|status",
me.name, sptr->name);
}
return 1;
}
void HookAddEx(int hooktype, int (*func)(), void (*vfunc)())
{
Hook *p;
p = (Hook *) MyMallocEx(sizeof(Hook));
if (func)
p->func.intfunc = func;
if (vfunc)
p->func.voidfunc = vfunc;
add_ConfigItem((ConfigItem *) p, (ConfigItem **) &Hooks[hooktype]);
}
void HookDelEx(int hooktype, int (*func)(), void (*vfunc)())
{
Hook *p;
for (p = Hooks[hooktype]; p; p = p->next)
if ((func && (p->func.intfunc == func)) ||
(vfunc && (p->func.voidfunc == vfunc)))
{
del_ConfigItem((ConfigItem *) p, (ConfigItem **) &Hooks[hooktype]);
return;
}
}
EVENT(e_unload_module_delayed)
{
char *name = (char *) data;
int i;
sendto_realops("Delayed unload of module %s in progress",
name);
i = unload_module(name);
if (i == 2)
{
sendto_realops("Delayed unload of %s, again",
name);
}
if (i == -1)
{
sendto_realops("Failed to unload '%s'", name);
}
if (i == 1)
{
sendto_realops("Unloaded module %s", name);
}
return;
}