lib/eggdrop/module.c File Reference

#include <eggdrop/eggdrop.h>
#include <ltdl.h>
#include <unistd.h>

Go to the source code of this file.

Data Structures

struct  module_list

Defines

#define find_active_module(name)   find_module((name), module_list_head)
#define find_deleted_module(name)   find_module((name), deleted_head)

Typedefs

typedef struct module_list module_list_t

Functions

static int module_cleanup (void *ignored)
 Calls module_really_unload() for every module marked for unloading.
static module_list_tfind_module (const char *name, module_list_t *head)
int module_init (void)
int module_shutdown (void)
 Shuts down the module interface.
int module_add_dir (const char *moddir)
int module_load (const char *name)
 Load a module.
int module_unload (const char *name, int why)
 Unload a module.
static void module_really_unload (module_list_t *entry)
 Remove a module from the process's memory.
egg_module_tmodule_lookup (const char *name)
int module_loaded (const char *name)
void * module_get_api (const char *name, int major, int minor)
int module_addref (const char *name)
int module_decref (const char *name)
int module_list (const char ***names)

Variables

static const char rcsid [] = "$Id: module.c,v 1.15 2007-09-13 22:20:55 sven Exp $"
static module_list_tmodule_list_head = NULL
static module_list_tdeleted_head = NULL
static bind_table_tBT_load
static bind_table_tBT_unload


Define Documentation

#define find_active_module ( name   )     find_module((name), module_list_head)

#define find_deleted_module ( name   )     find_module((name), deleted_head)

Definition at line 42 of file module.c.

Referenced by module_load().


Typedef Documentation

typedef struct module_list module_list_t


Function Documentation

static module_list_t* find_module ( const char *  name,
module_list_t head 
) [static]

Definition at line 44 of file module.c.

References module_list::modinfo, egg_module::name, module_list::next, and NULL.

00045 {
00046   module_list_t *entry;
00047 
00048   for (entry = head; entry; entry = entry->next) {
00049     if (!strcasecmp(name, entry->modinfo.name)) return(entry);
00050   }
00051   return(NULL);
00052 }

int module_add_dir ( const char *  moddir  ) 

Definition at line 95 of file module.c.

References egg_mprintf().

Referenced by core_init().

00096 {
00097   char *fixed_moddir;
00098 
00099   if (*moddir != '/') {
00100     char cwd[1024];
00101 
00102     cwd[0] = 0;
00103     getcwd(cwd, sizeof(cwd));
00104     cwd[sizeof(cwd)-1] = 0;
00105     fixed_moddir = egg_mprintf("%s/%s", cwd, moddir);
00106   }
00107   else fixed_moddir = (char *)moddir;
00108 
00109   lt_dladdsearchdir(fixed_moddir);
00110   if (fixed_moddir != moddir) free(fixed_moddir);
00111   return(0);
00112 }

int module_addref ( const char *  name  ) 

Definition at line 320 of file module.c.

References find_active_module, and module_list::refcount.

00321 {
00322   module_list_t *entry;
00323 
00324   entry = find_active_module(name);
00325   if (!entry) return(-1);
00326   entry->refcount++;
00327   return(0);
00328 }

static int module_cleanup ( void *  ignored  )  [static]

Calls module_really_unload() for every module marked for unloading.

This function is called automatically by garbage_run() if a module has has been closed.

Returns:
Always 0.

Definition at line 287 of file module.c.

References deleted_head, and module_really_unload().

Referenced by module_unload().

00288 {
00289   while (deleted_head) module_really_unload(deleted_head);
00290 
00291   return 0;
00292 }

int module_decref ( const char *  name  ) 

Definition at line 330 of file module.c.

References find_active_module, and module_list::refcount.

00331 {
00332   module_list_t *entry;
00333 
00334   entry = find_active_module(name);
00335   if (!entry) return(-1);
00336   entry->refcount--;
00337   return(0);
00338 }

void* module_get_api ( const char *  name,
int  major,
int  minor 
)

Definition at line 310 of file module.c.

References find_active_module, module_list::modinfo, egg_module::module_api, NULL, and module_list::refcount.

Referenced by chanserv_init().

00311 {
00312   module_list_t *entry;
00313 
00314   entry = find_active_module(name);
00315   if (!entry) return(NULL);
00316   entry->refcount++;
00317   return entry->modinfo.module_api;
00318 }

int module_init ( void   ) 

Definition at line 54 of file module.c.

References bind_table_add(), BTN_LOAD_MODULE, BTN_UNLOAD_MODULE, and MATCH_MASK.

Referenced by eggdrop_init().

00055 {
00056   BT_load = bind_table_add(BTN_LOAD_MODULE, 1, "s", MATCH_MASK, 0);   /* DDD  */
00057   BT_unload = bind_table_add(BTN_UNLOAD_MODULE, 2, "ss", MATCH_MASK, 0);    /* DDD  */
00058   return(0);
00059 }

int module_list ( const char ***  names  ) 

Definition at line 340 of file module.c.

References module_list::modinfo, egg_module::name, module_list::next, and NULL.

Referenced by party_modules().

00341 {
00342   module_list_t *entry;
00343   int i = 0;
00344 
00345   for (entry = module_list_head; entry; entry = entry->next) i++;
00346   *names = malloc((i + 1) * sizeof(char **));
00347   i = 0;
00348   for (entry = module_list_head; entry; entry = entry->next) {
00349     (*names)[i] = entry->modinfo.name;
00350     i++;
00351   }
00352   (*names)[i] = NULL;
00353   return(i);
00354 }

int module_load ( const char *  name  ) 

Load a module.

This function loads a module and executes its start function. If the module name does not contain a path the default paths will be searched. If it does have an extenteion the plattforms default library extentions will be added.

Parameters:
name The name of the module to load.
Returns:
0 on success. (This will be logged.)

-1 if the module is already loaded. (Nothing will be logged.)

-2 if the module could not be opened. (This will be logged.)

-3 if no start function is present. (Nothing will be logged.)

-4 if the start function returned an error. (Nothing will be logged.)

-5 if the module can't be loaded because it's marked for unloading. (Nothing will be logged.)

Definition at line 131 of file module.c.

References bind_check(), egg_mprintf(), find_active_module, find_deleted_module, module_list::hand, LOG_MISC, module_list::modinfo, module_list::next, NULL, module_list::prev, putlog(), and module_list::refcount.

Referenced by core_init(), and party_loadmod().

00132 {
00133   lt_dlhandle hand;
00134   module_list_t *entry;
00135   egg_start_func_t startfunc;
00136   char *startname;
00137 
00138 
00139   /* See if it's already loaded. */
00140   entry = find_active_module(name);
00141   if (entry) return(-1);
00142   entry = find_deleted_module(name);
00143   if (entry) return(-5);
00144 
00145   hand = lt_dlopenext(name);
00146   if (!hand) {
00147     const char *err = lt_dlerror();
00148     putlog(LOG_MISC, "*", "Error loading module %s: %s", name, err);
00149     return(-2);
00150   }
00151 
00152   startname = egg_mprintf("%s_LTX_start", name);
00153   startfunc = (egg_start_func_t)lt_dlsym(hand, startname);
00154   free(startname);
00155   if (!startfunc) {
00156     startfunc = (egg_start_func_t)lt_dlsym(hand, "start");
00157     if (!startfunc) {
00158       lt_dlclose(hand);
00159       return(-3);
00160     }
00161   }
00162 
00163   /* Create an entry for it. */
00164   entry = calloc(1, sizeof(*entry));
00165   entry->prev = NULL;
00166   entry->next = module_list_head;
00167   entry->refcount = 0;
00168   entry->hand = hand;
00169   module_list_head = entry;
00170 
00171   if (startfunc(&entry->modinfo)) {
00172     module_list_head = module_list_head->next;
00173     free(entry);
00174     return(-4);
00175   }
00176 
00177   putlog(LOG_MISC, "*", "Module loaded: %s", name);
00178   bind_check(BT_load, NULL, name, name);
00179 
00180   return(0);
00181 }

int module_loaded ( const char *  name  ) 

Definition at line 303 of file module.c.

References find_active_module, and NULL.

00304 {
00305   if (name == NULL) return 0;
00306 
00307   return (find_active_module(name) != NULL);
00308 }

egg_module_t* module_lookup ( const char *  name  ) 

Definition at line 294 of file module.c.

References find_active_module, module_list::modinfo, and NULL.

00295 {
00296   module_list_t *entry;
00297 
00298   entry = find_active_module(name);
00299   if (entry) return(&entry->modinfo);
00300   return(NULL);
00301 }

static void module_really_unload ( module_list_t entry  )  [static]

Remove a module from the process's memory.

Tis function will call the modules's unload function, remove all asyncronous events owned by this module and finally remove the module itself from memory.

Parameters:
entry The module to remove. This must be in the list of deleted modules.

Definition at line 247 of file module.c.

References deleted_head, egg_module::event_cleanup, module_list::hand, LOG_MISC, module_list::modinfo, egg_module::name, module_list::next, module_list::prev, putlog(), script_remove_events_by_owner(), and egg_module::unload_func.

Referenced by module_cleanup().

00248 {
00249   int errors;
00250   const char *error;
00251   module_list_t *m;
00252 
00253   if (entry->prev) entry->prev->next = entry->next;
00254   else deleted_head = entry->next;
00255   if (entry->next) entry->next->prev = entry->prev;
00256 
00257   if (entry->modinfo.unload_func) entry->modinfo.unload_func();
00258 
00259   script_remove_events_by_owner(&entry->modinfo, 0);
00260 
00261   for (m = module_list_head; m; m = m->next) {
00262     if (m->modinfo.event_cleanup) m->modinfo.event_cleanup(&entry->modinfo);
00263   }
00264   
00265   for (m = deleted_head; m; m = m->next) {
00266     if (m->modinfo.event_cleanup) m->modinfo.event_cleanup(&entry->modinfo);
00267   }
00268   
00269   errors = lt_dlclose(entry->hand);
00270   if (errors) {
00271     putlog(LOG_MISC, "*", "Error unloading %s!", entry->modinfo.name);
00272     while ((error = lt_dlerror())) putlog(LOG_MISC, "*", "ltdlerror: %s", error);
00273   }
00274 
00275   free(entry);
00276 }

int module_shutdown ( void   ) 

Shuts down the module interface.

This function unloads all loaded modules and deletes the load and unload bind tables.

The module_unload() function is called for every module that is currently loaded. If there is still a module loaded, for example because of dependencies, module_unload() is called again. This is done until either all modules have been unloaded or no more modules could be unloaded.

Returns:
Always 0.

Definition at line 75 of file module.c.

References bind_table_del(), garbage_run(), module_list::modinfo, MODULE_RESTART, module_unload(), egg_module::name, and module_list::next.

Referenced by eggdrop_shutdown().

00076 {
00077   int unloaded;
00078   module_list_t *entry, *next;
00079 
00080   do {
00081     unloaded = 0;
00082     for (entry = module_list_head; entry; entry = next) {
00083       next = entry->next;
00084       if (!module_unload(entry->modinfo.name, MODULE_RESTART)) unloaded = 1;
00085     }
00086   } while (unloaded);
00087 
00088   bind_table_del(BT_load);
00089   bind_table_del(BT_unload);
00090 
00091   garbage_run();
00092   return (0);
00093 }

int module_unload ( const char *  name,
int  why 
)

Unload a module.

If a module's reference count is 0 its closing function will be executed. If the closing function did not veto the unloading it will be removed from the list of active modules, the "unload" bind is triggered and a cleanup run is sceduled.

Parameters:
name The name of the module to unload.
why The reason this function was called: MODULE_USER, MODULE_RESTART or MODULE_SHUTDOWN.
Returns:
0 on success. (This will be logged.)

-1 if the module is not loaded. (Nothing will be logged.)

-2 if the module is in use by another module. (Nothing will be logged.)

-3 if the module's closing function vetoed. (Nothing will be logged.)

Definition at line 201 of file module.c.

References bind_check(), egg_module::close_func, deleted_head, find_active_module, garbage_add(), GARBAGE_ONCE, LOG_MISC, module_list::modinfo, module_cleanup(), MODULE_SHUTDOWN, MODULE_USER, module_list::next, NULL, module_list::prev, putlog(), and module_list::refcount.

Referenced by module_shutdown(), party_unloadmod(), and script_module_unload().

00202 {
00203   module_list_t *entry;
00204   int retval;
00205 
00206   entry = find_active_module(name);
00207   if (!entry) return(-1);
00208   if (entry->refcount > 0) return(-2);
00209   if (entry->modinfo.close_func) {
00210     retval = entry->modinfo.close_func(why);
00211     if (retval) return(-3);
00212   }
00213 
00214   if (entry->prev) entry->prev->next = entry->next;
00215   else module_list_head = entry->next;
00216   if (entry->next) entry->next->prev = entry->prev;
00217 
00218   entry->next = NULL;
00219   if (!deleted_head) {
00220     deleted_head = entry;
00221     entry->prev = NULL;
00222   } else {
00223     module_list_t *tail;
00224 
00225     for (tail = deleted_head; tail->next; tail = tail->next);
00226     tail->next = entry;
00227     entry->prev = tail;
00228   }
00229 
00230   bind_check(BT_unload, NULL, name, name, why == MODULE_USER ? "request" : why == MODULE_SHUTDOWN ? "shutdown" : "restart");
00231   putlog(LOG_MISC, "*", "Module unloaded: %s", name);
00232   garbage_add(module_cleanup, NULL, GARBAGE_ONCE);
00233   return 0;
00234 }


Variable Documentation

bind_table_t* BT_load [static]

Definition at line 37 of file module.c.

bind_table_t * BT_unload [static]

Definition at line 37 of file module.c.

module_list_t * deleted_head = NULL [static]

Definition at line 36 of file module.c.

Referenced by module_cleanup(), module_really_unload(), and module_unload().

module_list_t* module_list_head = NULL [static]

Definition at line 36 of file module.c.

const char rcsid[] = "$Id: module.c,v 1.15 2007-09-13 22:20:55 sven Exp $" [static]

Definition at line 21 of file module.c.


Generated on Sun Nov 30 18:43:34 2008 for eggdrop1.9 by  doxygen 1.5.6