From e99b0d654a56ccf5d80cc861639f6b6fb453285c Mon Sep 17 00:00:00 2001 From: Rick Bird Date: Sat, 2 Apr 2011 16:20:25 -0400 Subject: [PATCH] Module Core Code Phase 1 - @module - Lists Modules loaded @module/load - loads a module @module/unload - unloads a module netmud now linked using libtool's export-dynamic instead of straight gcc --- Makefile.SH | 2 +- hdrs/modules.h | 37 ++++++++++ src/Makefile.SH | 12 +-- src/SWITCHES | 2 + src/bsd.c | 3 + src/command.c | 1 + src/modules.c | 190 ++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 241 insertions(+), 6 deletions(-) create mode 100644 hdrs/modules.h create mode 100644 src/modules.c diff --git a/Makefile.SH b/Makefile.SH index 57996f9..d35e6ca 100644 --- a/Makefile.SH +++ b/Makefile.SH @@ -52,7 +52,7 @@ $make_set_make CC=$cc CCFLAGS=$optimize -I.. -I../hdrs -Wall -Wno-comment -Wno-parentheses -Wno-switch -Werror $ccflags $warnings LDFLAGS=$ldflags -CLIBS=$libs $cryptlib $libssl $libcrypto $libmysqlclient +CLIBS=-ltdl $libs $cryptlib $libssl $libcrypto $libmysqlclient INSTALL=$install INSTALLDIR=$installdir CP=$cp diff --git a/hdrs/modules.h b/hdrs/modules.h new file mode 100644 index 0000000..8664dc5 --- /dev/null +++ b/hdrs/modules.h @@ -0,0 +1,37 @@ +/* CobraMUSH Module System based upon cross-platform libldl */ +#ifndef _MODULES_H_ +#define _MODULES_H_ + +struct module_entry_t { + char *name; /* Name of module */ + char *info; /* Short Description */ + float version; /* Version of Module */ + int (*load)(struct module_entry_t *); /* Load Function */ + int (*unload)(struct module_entry_t *); /* Unload function */ + void *handle; + struct module_entry_t *next; +}; + +struct module_entry_t *module_entry_add(char *name); +int module_entry_del(struct module_entry_t *entry); +int modules_init(void); +int module_open(char *path, char *name); +int module_close(struct module_entry_t *m); +int modules_shutdown(void); + + +/* Iterate through Module List */ +#define MODULE_ITER(m) for(m = module_list ; m != NULL ; m = m->next) +/* Check and Free */ +#define MODULE_CAF(mem,check) if(mem != NULL) \ + mush_free(mem, check); +/* Retrieve Module Function */ +#define MODULE_FUNC(h, m, func, ...) \ + if((h = lt_dlsym(m, func))) { \ + h(__VAR_ARGS__) \ + } + +#define MODULE_FUNCRET(m, func) lt_dlsym(m, func); + + +#endif /* _MODULES_H_ */ diff --git a/src/Makefile.SH b/src/Makefile.SH index 337ed71..cd4612c 100644 --- a/src/Makefile.SH +++ b/src/Makefile.SH @@ -50,6 +50,7 @@ LINTFILT=egrep -v '(possible pointer|long assign|not yet im|:$$)' # Libs LIBS=$(CLIBS) $(RLIBS) $(ILIBS) +CC=libtool CFLAGS=$(CCFLAGS) $(RDEFS) $(IDEFS) @@ -64,7 +65,7 @@ C_FILES=access.c atr_tab.c attrib.c boolexp.c bsd.c bufferq.c \ extmail.c filecopy.c flaglocal.c flags.c funcrypt.c function.c \ fundb.c fundiv.c funlist.c funlocal.c funmath.c funmisc.c funstr.c funtime.c \ funufun.c game.c help.c htab.c ident.c local.c lock.c log.c look.c \ - malias.c match.c memcheck.c move.c mushlua.c mushlua_wrap.c mycrypt.c mymalloc.c mysocket.c \ + malias.c match.c memcheck.c move.c modules.c mushlua.c mushlua_wrap.c mycrypt.c mymalloc.c mysocket.c \ myssl.c notify.c parse.c pcre.c player.c plyrlist.c \ predicat.c privtab.c prog.o ptab.c rob.c rplog.c services.c set.c shs.c \ sig.c speech.c sql.c strdup.c strtree.c strutil.c tables.c timer.c unparse.c \ @@ -78,7 +79,7 @@ H_FILES = ../config.h ../confmagic.h ../hdrs/ansi.h ../hdrs/atr_tab.h \ ../hdrs/function.h ../hdrs/game.h ../hdrs/getpgsiz.h ../hdrs/help.h \ ../hdrs/htab.h ../hdrs/htab.h ../hdrs/ident.h ../hdrs/lock.h \ ../hdrs/log.h ../hdrs/log.h ../hdrs/malias.h ../hdrs/match.h \ - ../hdrs/mushdb.h ../hdrs/mushlua.h ../hdrs/mushtype.h \ + ../hdrs/modules.h ../hdrs/mushdb.h ../hdrs/mushlua.h ../hdrs/mushtype.h \ ../hdrs/mymalloc.h ../hdrs/mysocket.h ../hdrs/myssl.h \ ../hdrs/parse.h ../hdrs/pcre.h ../hdrs/privtab.h ../hdrs/ptab.h \ ../hdrs/strtree.h ../hdrs/version.h ../options.h ../hdrs/division.h ../hdrs/cron.h @@ -90,7 +91,7 @@ COMMON_O_FILES=access.o atr_tab.o attrib.o boolexp.o bufferq.o \ extmail.o filecopy.o flaglocal.o flags.o funcrypt.o function.o \ fundb.o funlist.o fundiv.o funlocal.o funmath.o funmisc.o funstr.o funtime.o \ funufun.o game.o help.o htab.o ident.o local.o lock.o log.o look.o \ - malias.o match.o memcheck.o move.o mushlua.o mushlua_wrap.o mycrypt.o mymalloc.o \ + malias.o match.o memcheck.o move.o modules.o mushlua.o mushlua_wrap.o mycrypt.o mymalloc.o \ mysocket.o myssl.o notify.o parse.o pcre.o player.o plyrlist.o predicat.o privtab.o \ prog.o ptab.o rob.o rplog.o services.o set.o shs.o sig.o speech.o sql.o strdup.o \ strtree.o strutil.o tables.o timer.o unparse.o utils.o version.o warnings.o \ @@ -110,12 +111,13 @@ all: $(OUTFILES) netmud: $(O_FILES) @echo "Making netmud." -mv -f netmud netmud~ - $(CC) $(LDFLAGS) $(CCFLAGS) -o netmud $(O_FILES) $(LIBS) + $(LIBTOOL) --mode=link $(CC) -export-dynamic $(LDFLAGS) $(CCFLAGS) -o netmud $(O_FILES) $(LIBS) console: $(CONSOLE_O_FILES) @echo "Making console." -mv -f console console~ - $(CC) $(LDFLAGS) $(CCFLAGS) -o console $(CONSOLE_O_FILES) $(LIBS) + $(LIBTOOL) --mode=link $(CC) -export-dynamic $(LDFLAGS) $(CCFLAGS) -o netmud $(O_FILES) $(LIBS) + # By default, db.c initially allocates enough space for 5000 objects, then # grows the space if needed. To change this value, include diff --git a/src/SWITCHES b/src/SWITCHES index ec68f3d..e99dcd4 100644 --- a/src/SWITCHES +++ b/src/SWITCHES @@ -70,6 +70,7 @@ JOIN LEAVE LETTER LIST +LOAD LOGOUT LOWERCASE LOCK @@ -147,6 +148,7 @@ THINGS TITLE TRACE TYPE +UNLOAD UNCLEAR UNHIDE UNGAG diff --git a/src/bsd.c b/src/bsd.c index 934399b..12ada57 100644 --- a/src/bsd.c +++ b/src/bsd.c @@ -125,6 +125,7 @@ #include "game.h" #include "dbio.h" #include "confmagic.h" +#include "modules.h" #include "lua.h" #include "mushlua.h" #ifdef HAS_WAITPID @@ -505,6 +506,8 @@ main(int argc, char **argv) #endif time(&mudtime); + /* Initialize Module interface */ + modules_init(); /* If we have setlocale, call it to set locale info * from environment variables diff --git a/src/command.c b/src/command.c index cb74d13..c6882ba 100644 --- a/src/command.c +++ b/src/command.c @@ -191,6 +191,7 @@ COMLIST commands[] = { #endif {"@MAP", "DELIMIT", cmd_map, CMD_T_ANY | CMD_T_EQSPLIT | CMD_T_RS_NOPARSE, NULL}, + {"@MODULE", "LOAD UNLOAD", cmd_module, CMD_T_ANY, "POWER^SITE"}, {"@MOTD", "CONNECT LIST DOWN FULL", cmd_motd, CMD_T_ANY | CMD_T_NOGAGGED, NULL}, {"@MVATTR", "CONVERT NOFLAGCOPY", cmd_mvattr, diff --git a/src/modules.c b/src/modules.c new file mode 100644 index 0000000..210ce58 --- /dev/null +++ b/src/modules.c @@ -0,0 +1,190 @@ +/* CobraMUSH Module/Plugin System - File created 3/31/11 + * + * Our Approach shall be one using the libtool library, mostly for the fact + * that is a cross-platform designed library. + */ + +#include +#include +#include + +#include "conf.h" +#include "externs.h" +#include "command.h" +#include "switches.h" +#include "mushtype.h" +#include "log.h" +#include "modules.h" + +struct module_entry_t *module_list = NULL; + +/* Ads a module entry and returns */ +struct module_entry_t *module_entry_add(char *name) { + struct module_entry_t *entry; + + entry = (struct module_entry_t *) mush_malloc(sizeof(struct module_entry_t), "MODULE_ENTRY"); + + if(!entry) { + return NULL; /* Should really panic here.. */ + } + + entry->name = mush_strdup(name, "MODULE_ENTRY.NAME"); + entry->info = NULL; + entry->load = NULL; + entry->unload = NULL; + entry->next = module_list; + module_list = entry; + + return entry; +} + +/* removes a module entry from the list */ +int module_entry_del(struct module_entry_t *entry) { + struct module_entry_t *m, *e = NULL; + + if(module_list == entry) + e = module_list; + else MODULE_ITER(m) + if(m->next != NULL && m->next == entry) { + e = m; + m->next = m->next->next; + break; + } + + if(e == NULL) + return 0; + + MODULE_CAF(e->name, "MODULE_ENTRY.NAME"); + MODULE_CAF(e->info, "MODULE_ENTRY.INFO"); + MODULE_CAF(e, "MODULE_ENTRY"); + + return 1; +} + +/* Initialize Module Interface */ +int modules_init() { + return lt_dlinit(); /* Initialize libltdl. 0 is good */ +} + +/* Load Module name */ +int module_open(char *path, char *name) { + char file[BUFFER_LEN]; + int (*module_loader)(struct module_entry_t *); + struct module_entry_t *module; + void *handle; + + memset(file, '\0', BUFFER_LEN); + snprintf(file, BUFFER_LEN, "%s/%s", path, name); + + handle = lt_dlopen(file); + + if(!handle) { + do_rawlog(LT_ERR, "Error Loading Module: %s | %s ", file, lt_dlerror()); + return 0; + } + + /* Some OSes may need symbols to be prefixed with _.. Will need to look into autoconfig code for this */ + module_loader = MODULE_FUNCRET(handle, "module_load"); + + if(!module_loader) { + do_rawlog(LT_ERR, "Error Loading Module: Could not call module_load | %s", file); + return 0; + } + + /* Add the module to the linked list */ + module = module_entry_add(name); + if(module == NULL) { + return 0; + } + module->handle = handle; + module->load = module_loader; + module->unload = MODULE_FUNCRET(handle, "module_unload"); + + /* Grab info and version from module & put it in */ + /* Success.. Call the module */ + return module_loader(module); +} + +/* Unload one Module */ +int module_close(struct module_entry_t *m) { + int ret; + + ret = m->unload(m); /* first run requierd unload code */ + + if(!ret) + return 0; + + /* next unload the modules for real */ + ret = lt_dlclose(m->handle); + + if(ret != 0) { + do_rawlog(LT_ERR, "Could not unload module: %s/%d | %s", __FILE__, __LINE__, lt_dlerror()); + return 0; + } + + if(!module_entry_del(m)) { + do_rawlog(LT_ERR, "Could not unload module: %s/%d ", __FILE__, __LINE__); + return 0; + } + + return 1; +} + +/* Unload all modules */ +int modules_shutdown() { + struct module_entry_t *m; + + MODULE_ITER(m) + m->unload(m); + + return lt_dlexit(); /* 0 is good */ +} + +/* MUSH Module Interface Portion... Much of this section will probably actually move to a module itself and become a resident module */ + + /* command will be restricted to Director player in nature from the command file */ +COMMAND(cmd_module) { + struct module_entry_t *m; + char tbuf1[BUFFER_LEN]; + int ret; + + if(SW_ISSET(sw, SWITCH_LOAD)) { + if(!arg_left) { + notify(player, "Requires at least one argument."); + return; + } + /* Load a Module By name in arg_left */ + (void) getcwd(tbuf1, BUFFER_LEN); + ret = module_open(tbuf1, arg_left); + if(ret) + notify(player, "module successfully loaded."); + else + notify(player, "module could not load."); + + } else if(module_list == NULL) { + notify_format(player, "Search-path: %s", lt_dlgetsearchpath()); + notify(player, "No modules loaded."); + return; + } else if(SW_ISSET(sw, SWITCH_UNLOAD)) { + /* This is after the no modules loaded one.. because you have to modules loaded in order to unload something */ + if(!arg_left) { + notify(player, "Reqiures at least one argument."); + return; + } + MODULE_ITER(m) + if(!strcasecmp(arg_left, m->name)) { + if(module_close(m)) + notify(player, "unloaded module"); + else + notify(player, "could not unload module"); + return; + } + } else { + /* No Switches.. Just view modules loaded */ + MODULE_ITER(m) { + notify_format(player, "Module-Name: %s", m->name); + } + } +} + + -- 2.30.2