00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] = "$Id: module.c,v 1.15 2007-09-13 22:20:55 sven Exp $";
00022 #endif
00023
00024 #include <eggdrop/eggdrop.h>
00025 #include <ltdl.h>
00026 #include <unistd.h>
00027
00028 typedef struct module_list {
00029 struct module_list *prev;
00030 struct module_list *next;
00031 egg_module_t modinfo;
00032 lt_dlhandle hand;
00033 int refcount;
00034 } module_list_t;
00035
00036 static module_list_t *module_list_head = NULL, *deleted_head = NULL;
00037 static bind_table_t *BT_load, *BT_unload;
00038
00039 static int module_cleanup(void *);
00040
00041 #define find_active_module(name) find_module((name), module_list_head)
00042 #define find_deleted_module(name) find_module((name), deleted_head)
00043
00044 static module_list_t *find_module(const char *name, module_list_t *head)
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 }
00053
00054 int module_init(void)
00055 {
00056 BT_load = bind_table_add(BTN_LOAD_MODULE, 1, "s", MATCH_MASK, 0);
00057 BT_unload = bind_table_add(BTN_UNLOAD_MODULE, 2, "ss", MATCH_MASK, 0);
00058 return(0);
00059 }
00060
00075 int module_shutdown(void)
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 }
00094
00095 int module_add_dir(const char *moddir)
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 }
00113
00131 int module_load(const char *name)
00132 {
00133 lt_dlhandle hand;
00134 module_list_t *entry;
00135 egg_start_func_t startfunc;
00136 char *startname;
00137
00138
00139
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
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 }
00182
00201 int module_unload(const char *name, int why)
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 }
00235
00247 static void module_really_unload(module_list_t *entry)
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 }
00277
00287 static int module_cleanup(void *ignored)
00288 {
00289 while (deleted_head) module_really_unload(deleted_head);
00290
00291 return 0;
00292 }
00293
00294 egg_module_t *module_lookup(const char *name)
00295 {
00296 module_list_t *entry;
00297
00298 entry = find_active_module(name);
00299 if (entry) return(&entry->modinfo);
00300 return(NULL);
00301 }
00302
00303 int module_loaded(const char *name)
00304 {
00305 if (name == NULL) return 0;
00306
00307 return (find_active_module(name) != NULL);
00308 }
00309
00310 void *module_get_api(const char *name, int major, int minor)
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 }
00319
00320 int module_addref(const char *name)
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 }
00329
00330 int module_decref(const char *name)
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 }
00339
00340 int module_list(const char ***names)
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 }