diff --git a/Changes b/Changes index 55cda7d10..71a3624c1 100644 --- a/Changes +++ b/Changes @@ -968,3 +968,4 @@ seen. gmtime warning still there a Q:line. - Added HOOKTYPE_SERVER_CONNECT and HOOKTYPE_SERVER_QUIT for when servers connect and disconnect respectively +- Added module v3 code. Needs testing, and NO MODULES DOES NOT COMPILE diff --git a/include/modules.h b/include/modules.h index 6bdd8a043..9635493ba 100644 --- a/include/modules.h +++ b/include/modules.h @@ -19,11 +19,10 @@ * $Id$ */ -#define MOD_VERSION 2 -#define MAXMODULES 50 +#define MOD_VERSION "3.2-b5-1" +#define MOD_WE_SUPPORT "3.2-b5*" #define MAXHOOKTYPES 20 - #if defined(_WIN32) && !defined(STATIC_LINKING) #define DLLFUNC _declspec(dllexport) #define irc_dlopen(x,y) LoadLibrary(x) @@ -38,33 +37,63 @@ #define DLLFUNC #endif -#ifndef STATIC_LINKING -#define SymD(name, container,module) {#name, (vFP *) &container, module} -#else -#define SymD(name, container,module) {(void *)&name, (vFP *) &container} -#endif - -typedef struct moduleInfo ModuleInfo; -typedef struct msymboltable MSymbolTable; typedef void (*vFP)(); /* Void function pointer */ typedef int (*iFP)(); /* Integer function pointer */ typedef char (*cFP)(); /* char * function pointer */ -struct moduleInfo +/* + * For resolving symbols + * Look further down for definition of the structure + */ +typedef struct _mod_symboltable Mod_SymbolDepTable; + +/* + * Module header that every module must include, with the name of + * mod_header +*/ + +typedef struct _ModuleHeader { + char *name; + char *version; + char *description; + char *modversion; + Mod_SymbolDepTable *symdep; +} ModuleHeader; + +/* + * One piece of Borg ass.. +*/ +typedef struct _Module Module; + +typedef struct _ModuleChild { - short mversion; /* Written for module header version */ - char *name; /* Name of module */ - char *version; /* $Id$ */ - char *description; /* Small description */ + struct _ModuleChild *prev, *next; + Module *child; /* Aww. aint it cute? */ +} ModuleChild; + +/* + * What we use to keep track internally of the modules +*/ + +struct _Module +{ + struct _Module *prev, *next; + ModuleHeader *header; /* The module's header */ #ifdef _WIN32 HMODULE dll; /* Return value of LoadLibrary */ #else void *dll; /* Return value of dlopen */ -#endif - void (*unload)(); /* pointer to mod_unload */ +#endif + unsigned char flags; /* 8-bits for flags .. */ + ModuleChild *children; }; -struct msymboltable + +/* + * Symbol table +*/ + +struct _mod_symboltable { #ifndef STATIC_LINKING char *symbol; @@ -77,16 +106,22 @@ struct msymboltable #endif }; -extern ModuleInfo *module_buffer; +#ifndef STATIC_LINKING +#define MOD_Dep(name, container,module) {#name, (vFP *) &container, module} +#else +#define MOD_Dep(name, container,module) {(void *)&name, (vFP *) &container} +#endif + + extern Hook *Hooks[MAXHOOKTYPES]; extern Hook *global_i; -void module_init(void); -int load_module(char *module, int module_load); -int unload_module(char *name); -vFP module_sym(char *name); - - +void Module_Init(void); +char *Module_Load(char *path, int load); +int Module_Unload(char *name, int unload); +vFP Module_Sym(char *name); +vFP Module_SymX(char *name, Module **mptr); +int Module_free(Module *mod); #define add_Hook(hooktype, func) HookAddEx(hooktype, func, NULL) #define del_Hook(hooktype, func) HookDelEx(hooktype, func, NULL) @@ -123,3 +158,8 @@ void HookDelEx(int hooktype, int (*intfunc)(), void (*voidfunc)()); #define MODFLAG_NONE 0x0000 #define MODFLAG_LOADED 0x0001 /* (mod_load has been called and suceeded) */ +/* Module function return values */ +#define MOD_SUCCESS 1 +#define MOD_FAILED -1 +#define MOD_DELAY 2 + diff --git a/include/struct.h b/include/struct.h index 96cd2a5f3..ea849cb66 100644 --- a/include/struct.h +++ b/include/struct.h @@ -53,6 +53,7 @@ #include #include #include +#include #endif #include "auth.h" extern int sendanyways; diff --git a/src/modules.c b/src/modules.c index fa5c35ded..28e67fbc4 100644 --- a/src/modules.c +++ b/src/modules.c @@ -45,261 +45,249 @@ #define RTLD_NOW RTLD_LAZY #endif -ModuleInfo *Modules[MAXMODULES]; -unsigned char ModuleFlags[MAXMODULES]; Hook *Hooks[MAXHOOKTYPES]; Hook *global_i = NULL; +Module *Modules = NULL; -int modules_loaded = 0; +Module *Module_make(ModuleHeader *header, +#ifdef _WIN32 + HMODULE mod +#else + void *mod +#endif + ); -void module_init(void) +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) +Module *Module_Find(char *name) +{ + Module *p; + + for (p = Modules; p; p = p->next) + { + if (!strcmp(p->header->name, name)) + { + return (p); + } + } + return NULL; + +} + +/* + * Returns an error if insucessful .. yes NULL is OK! +*/ +char *Module_Load (char *path, int 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)) + HMODULE Mod; +#else /* _WIN32 */ + void *Mod; +#endif /* _WIN32 */ + int (*Mod_Init)(); + int (*Mod_Load)(); + int (*Mod_Unload)(); + static char errorbuf[1024]; + ModuleHeader *mod_header; + int ret = 0; + Module *mod = NULL; + Debug((DEBUG_DEBUG, "Attempting to load module from %s", + path)); + if (Mod = irc_dlopen(path, RTLD_NOW)) { - /* Succeed loading module */ - /* We check header */ - mod_header = irc_dlsym(Mod, "mod_header"); - if (!mod_header) + /* We have engaged the borg cube. Scan for lifesigns. */ + if (!(mod_header = irc_dlsym(Mod, "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; + return ("Unable to locate Mod_Header"); } - if (mod_header->mversion != MOD_VERSION) + if (!mod_header->modversion) { - 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; + return ("Lacking mod_header->modversion"); } - if (!mod_header->name || !mod_header->version - || !mod_header->description) + if (match(MOD_WE_SUPPORT, mod_header->modversion)) { - config_progress - ("Failed to load module %s: name/version/description missing", - module); + ircsprintf(errorbuf, "Unsupported version, we support %s, %s is %s", + MOD_WE_SUPPORT, path, mod_header->modversion); irc_dlclose(Mod); - return -1; + return(errorbuf); } - for (i = 0; i < MAXMODULES; i++) - if (Modules[i] && !strcmp(Modules[i]->name, mod_header->name)) + if (!mod_header->name || !mod_header->version || + !mod_header->description) + { + irc_dlclose(Mod); + return("Lacking sane header pointer"); + } + if (Module_Find(mod_header->name)) + { + irc_dlclose(Mod); + return ("Module already loaded"); + } + mod = (Module *)Module_make(mod_header, Mod); + if (!(Mod_Init = irc_dlsym(Mod, "Mod_Init"))) + { + Module_free(mod); + return ("Unable to locate Mod_Init"); + } + if ((ret = (*Mod_Init)(load)) < MOD_SUCCESS) + { + ircsprintf(errorbuf, "Mod_Init returned %i", + ret); + /* We EXPECT the module to have cleaned up it's mess */ + Module_free(mod); + return (errorbuf); + } + if (!(Mod_Unload = irc_dlsym(Mod, "Mod_Unload"))) + { + Module_free(mod); + return ("Unable to locate Mod_Unload"); + } + + if (load) + { + if (!(Mod_Load = irc_dlsym(Mod, "Mod_Load"))) { - Debug((DEBUG_DEBUG, "Module already loaded, duplicate")); - /* We will unload it without notice, its a duplicate */ - irc_dlclose(Mod); - return 1; + /* We cannot do delayed unloading if this happens */ + (*Mod_Unload)(); + Module_free(mod); + return ("Unable to locate Mod_Load"); } - for (i = 0; i < MAXMODULES; i++) - { - if (!Modules[i]) + if ((ret = (*Mod_Load)(load)) < MOD_SUCCESS) { - Modules[i] = mod_header; - modules_loaded++; + ircsprintf(errorbuf, "Mod_Load returned %i", + ret); + (*Mod_Unload)(); + Module_free(mod); + return (errorbuf); + } + } + if (load) + mod->flags |= MODFLAG_LOADED; + AddListItem(mod, Modules); + } + else + { + /* Return the error .. */ + return (strerror(ERRNO)); + } + + +#else /* !STATIC_LINKING */ + return "We don't support dynamic linking"; +#endif + +} + +Module *Module_make(ModuleHeader *header, +#ifdef _WIN32 + HMODULE mod +#else + void *mod +#endif + ) +{ + Module *modp = NULL; + + modp = (Module *)MyMallocEx(sizeof(Module)); + modp->header = header; + modp->dll = mod; + modp->flags = MODFLAG_NONE; + modp->children = NULL; + return (modp); +} + +/* + * Returns -1 if you cannot unload due to children still alive + * Returns 1 if successful + */ +int Module_free(Module *mod) +{ + Module *p; + ModuleChild *cp; + /* Do not kill parent if children still alive */ + + if (mod->children) + { + for (cp = mod->children; cp; cp = cp->next) + { + sendto_realops("Unloading child module %s", + cp->child->header->name); + Module_Unload(cp->child->header->name, 0); + } + } + for (p = Modules; p; p = p->next) + { + for (cp = p->children; cp; cp = cp->next) + { + if (cp->child == mod) + { + DelListItem(mod, p->children); + /* We can assume there can be only one. */ 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--; + DelListItem(mod, Modules); + irc_dlclose(mod->dll); + MyFree(mod); return 1; -#endif } -vFP module_sym(char *name) +/* + * Module_Unload () + * char *name Internal module name + * int unload If /module unload + * Returns: + * -1 Not able to locate module, severe failure, anything + * 1 Module unloaded + * 2 Module wishes delayed unloading, has placed event + */ +int Module_Unload(char *name, int unload) +{ + Module *m; + int (*Mod_Unload)(); + int ret; + for (m = Modules; m; m = m->next) + { + if (!strcmp(m->header->name, name)) + { + break; + } + } + if (!m) + return -1; + if (!(Mod_Unload = irc_dlsym(m->dll, "Mod_Unload"))) + { + return -1; + } + ret = (*Mod_Unload)(unload); + if (ret == MOD_DELAY) + { + return 2; + } + if (ret == MOD_FAILED) + { + return -1; + } + /* No more pain detected, let's unload */ + DelListItem(m, Modules); + Module_free(m); + return 1; +} + + +vFP Module_Sym(char *name) { #ifndef STATIC_LINKING vFP fp; char buf[512]; int i; - ModuleInfo *mi; + Module *mi; if (!name) return NULL; @@ -307,12 +295,8 @@ vFP module_sym(char *name) ircsprintf(buf, "_%s", name); /* Run through all modules and check for symbols */ - for (i = 0; i < MAXMODULES; i++) + for (mi = Modules; mi; mi = mi->next) { - mi = Modules[i]; - if (!mi) - continue; - if (fp = (vFP) irc_dlsym(mi->dll, name)) return (fp); if (fp = (vFP) irc_dlsym(mi->dll, buf)) @@ -322,13 +306,47 @@ vFP module_sym(char *name) #endif } +vFP Module_SymX(char *name, Module **mptr) +{ +#ifndef STATIC_LINKING + vFP fp; + char buf[512]; + int i; + Module *mi; + + if (!name) + return NULL; + + ircsprintf(buf, "_%s", name); + + /* Run through all modules and check for symbols */ + for (mi = Modules; mi; mi = mi->next) + { + if (fp = (vFP) irc_dlsym(mi->dll, name)) + { + *mptr = mi; + return (fp); + } + if (fp = (vFP) irc_dlsym(mi->dll, buf)) + { + *mptr = mi; + return (fp); + } + } + *mptr = NULL; + return NULL; +#endif +} + + + void module_loadall(int module_load) { #ifndef STATIC_LINKING iFP fp; int i; - ModuleInfo *mi; + Module *mi; if (!loop.ircd_booted) { @@ -336,12 +354,9 @@ void module_loadall(int module_load) return ; } /* Run through all modules and check for module load */ - for (i = 0; i < MAXMODULES; i++) + for (mi = Modules; mi; mi = mi->next) { - mi = Modules[i]; - if (!mi) - continue; - if (ModuleFlags[i] & MODFLAG_LOADED) + if (mi->flags & MODFLAG_LOADED) continue; if (fp = (iFP) irc_dlsym(mi->dll, "mod_load")) { @@ -358,39 +373,60 @@ void module_loadall(int module_load) /* Call the module_load */ if ((*fp)(module_load) < 0) { - config_error("cannot load module %s", mi->name); + config_error("cannot load module %s", mi->header->name); } else { - ModuleFlags[i] |= MODFLAG_LOADED; + mi->flags |= MODFLAG_LOADED; } } #endif } -int module_depend_resolve(MSymbolTable *dep) +inline int Module_IsAlreadyChild(Module *parent, Module *child) { - MSymbolTable *d = dep; + ModuleChild *mcp; + + for (mcp = parent->children; mcp; mcp = mcp->next) + { + if (mcp->child == child) + return 1; + } + return 0; +} + +inline void Module_AddAsChild(Module *parent, Module *child) +{ + ModuleChild *childp = NULL; + + childp = (ModuleChild *) MyMallocEx(sizeof(ModuleChild)); + childp->child = child; + AddListItem(childp, parent->children); +} + +int Module_Depend_Resolve(Module *p) +{ + Mod_SymbolDepTable *d = p->header->symdep; + Module *parental = NULL; #ifndef STATIC_LINKING while (d->pointer) { - *(d->pointer) = module_sym(d->symbol); + *(d->pointer) = Module_SymX(d->symbol, &parental); 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); + config_progress("Unable to resolve symbol %s, attempting to load %s to find it", d->symbol, d->module); + Module_Load(d->module,0); + *(d->pointer) = Module_SymX(d->symbol, &parental); if (!*(d->pointer)) { config_progress("module dependancy error: cannot resolve symbol %s", d->symbol); return -1; } - } + + } + if (!Module_IsAlreadyChild(parental, p)) + Module_AddAsChild(parental, p); d++; } return 0; @@ -406,8 +442,9 @@ d->symbol, d->module); int m_module(aClient *cptr, aClient *sptr, int parc, char *parv[]) { - int i; - ModuleInfo *mi; + int i; + char *ret; + Module *mi; if (!IsAdmin(sptr)) { @@ -428,9 +465,16 @@ int m_module(aClient *cptr, aClient *sptr, int parc, char *parv[]) me.name, parv[0], "MODULE LOAD"); return 0; } - sendto_realops("Trying to load module %s", parv[2]); - if (load_module(parv[2],1) == 1) + if (!(ret = Module_Load(parv[2], 1))) + { sendto_realops("Loaded module %s", parv[2]); + return; + } + else + { + sendto_realops("Module load of %s failed: %s", + parv[2], ret); + } } else if (!match(parv[1], "unload")) @@ -442,7 +486,7 @@ int m_module(aClient *cptr, aClient *sptr, int parc, char *parv[]) return 0; } sendto_realops("Trying to unload module %s", parv[2]); - i = unload_module(parv[2]); + i = Module_Unload(parv[2], 0); { if (i == 1) sendto_realops("Unloaded module %s", parv[2]); @@ -457,17 +501,16 @@ int m_module(aClient *cptr, aClient *sptr, int parc, char *parv[]) else if (!match(parv[1], "status")) { - if (modules_loaded == 0) + if (!Modules) { 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); - } + for (mi = Modules; mi; mi = mi->next) + { + sendto_one(sptr, ":%s NOTICE %s :*** %s - %s (%s)", me.name, sptr->name, + mi->header->name, mi->header->version, mi->header->description); + } } else { @@ -509,11 +552,15 @@ EVENT(e_unload_module_delayed) sendto_realops("Delayed unload of module %s in progress", name); - i = unload_module(name); + i = Module_Unload(name, 0); if (i == 2) { sendto_realops("Delayed unload of %s, again", name); + } + if (i == -2) + { + } if (i == -1) { @@ -525,3 +572,15 @@ EVENT(e_unload_module_delayed) } return; } + +void unload_all_modules(void) +{ + Module *m; + int (*Mod_Unload)(); + for (m = Modules; m; m = m->next) + { + Mod_Unload = irc_dlsym(m->dll, "Mod_Unload"); + if (Mod_Unload) + (*Mod_Unload)(0); + } +} \ No newline at end of file diff --git a/src/s_conf.c b/src/s_conf.c index 16873b67c..2f1e6db50 100644 --- a/src/s_conf.c +++ b/src/s_conf.c @@ -1249,7 +1249,7 @@ int _conf_loadmodule(ConfigFile *conf, ConfigEntry *ce) HANDLE hFind; WIN32_FIND_DATA FindData; #endif - + char *ret; if (!ce->ce_vardata) { config_status("%s:%i: loadmodule without filename", @@ -1270,10 +1270,10 @@ int _conf_loadmodule(ConfigFile *conf, ConfigEntry *ce) return -1; } for (i = 0; i < files.gl_pathc; i++) { - if (load_module(files.gl_pathv[i],0) != 1) { - config_status("%s:%i: loadmodule %s: failed to load", + if ((ret = Module_Load(files.gl_pathv[i],0))) { + config_status("%s:%i: loadmodule %s: failed to load: %s", ce->ce_fileptr->cf_filename, ce->ce_varlinenum, - files.gl_pathv[i]); + files.gl_pathv[i], ret); } } globfree(&files); @@ -1286,23 +1286,23 @@ int _conf_loadmodule(ConfigFile *conf, ConfigEntry *ce) FindClose(hFind); return -1; } - if (load_module(FindData.cFileName,0) != 1) { - config_status("%s:%i: loadmodule %s: failed to load", + if ((ret = Module_Load(FindData.cFileName,0))) { + config_status("%s:%i: loadmodule %s: failed to load: %s", ce->ce_fileptr->cf_filename, ce->ce_varlinenum, - FindData.cFileName); + FindData.cFileName), ret); } while (FindNextFile(hFind, &FindData) != 0) { - if (load_module(FindData.cFileName,0) != 1) - config_status("%s:%i: loadmodule %s: failed to load", + if (((ret = Module_Load(FindData.cFileName,0)))) + config_status("%s:%i: loadmodule %s: failed to load: %s", ce->ce_fileptr->cf_filename, ce->ce_varlinenum, - FindData.cFileName); + FindData.cFileName, ret); } FindClose(hFind); #else - if (load_module(ce->ce_vardata,0) != 1) { - config_status("%s:%i: loadmodule %s: failed to load", + if ((ret = Module_Load(ce->ce_vardata,0)))) { + config_status("%s:%i: loadmodule %s: failed to load: %s", ce->ce_fileptr->cf_filename, ce->ce_varlinenum, - ce->ce_vardata); + ce->ce_vardata, ret); return -1; } #endif diff --git a/src/s_err.c b/src/s_err.c index feacab510..0d3dc3c9d 100644 --- a/src/s_err.c +++ b/src/s_err.c @@ -1056,7 +1056,7 @@ static char *replies[] = { }; char *getreply(int numeric) { - if((numeric<0 || numeric>999) || !replies[numeric]) + if((numeric<0 || numeric>999) || !replies[numeric]) return(replies[ERR_NUMERICERR]); else return(replies[numeric]);