/* IRCfs - IRC FileServ for *nix. * Copyright (C) 2002 Nick 'Zaf' Clifford * For licensing details, refer to the LICENSE file in the source * code directory. */ #include "runtime.h" #include "module.h" #define MODULE_LIST(x) extern int module__ ## x ## __init(void); #include "modlist.h" static module_func_t module_init_funcs[] = { #undef MODULE_LIST #define MODULE_LIST(x) module__ ## x ## __init, #include "modlist.h" NULL }; #ifdef MODULE_POST #undef MODULE_POST #endif #define MODULE_POST(x) extern int x (void); #include "modpost.h" #undef MODULE_POST static module_func_t module_post_funcs[] = { #define MODULE_POST(x) x, #include "modpost.h" NULL }; enum module_status { mod_status_unloaded, mod_status_loading, mod_status_loaded, mod_status_failed, mod_status_unloading }; struct module_list { struct module *modinfo; enum module_status status; int load_order; struct module_list *next; }; static int load_module(struct module_list *ml); static int unload_module(struct module_list *ml, int force); static struct module_list *find_module(const char *name); struct module_list *head; static POOL pool; static int module_count; DEBUG module_debug; int load_modules() { int i; module_debug = debug_register("module"); pool = pool_new(NULL); for(i=0; module_init_funcs[i]; i++) { module_init_funcs[i](); } if (init_modules() == -1) return -1; for(i=0; module_post_funcs[i]; i++) { module_post_funcs[i](); } return 0; } int module_check_load(const char *name) { struct module_list *mt; mt = find_module(name); if (mt == NULL) { error(module_debug,"Can't find module '%s' which is " "required by a module " "calling module_check_load", name); return -1; } switch (mt->status) { case mod_status_unloaded: if (load_module(mt) == -1) { return -1; } break; case mod_status_loading: error(module_debug,"Circular dependancy. " "A module called module_check_load(%s) " "however, that module is in the process of " "loading. (Maybe use a postinit for this " "module?", mt->modinfo->name); return -1; case mod_status_loaded: break; default: error(module_debug,"Dependancy on failed module on '%s'", mt->modinfo->name); return -1; } return 0; } int unload_modules() { struct module_list *ml; int r=0; for(ml=head; ml != NULL; ml=ml->next) { if (ml->status != mod_status_loaded) continue; if (unload_module(ml,1) == -1) { r = -1; } } return r; } /* Load all unloaded modules */ int init_modules() { struct module_list *ml; for(ml=head; ml != NULL; ml=ml->next) { if (ml->status == mod_status_loaded) continue; if (load_module(ml) == -1) { return -1; } } return 0; } struct module_list *find_module(const char *name) { struct module_list *ml; for(ml=head; ml != NULL; ml=ml->next) { if (strcmp(ml->modinfo->name,name) == 0) return ml; } return NULL; } /* TODO * Rewrite, we are suppose to use load_order field to unload by, * not dependancies! */ int unload_module(struct module_list *ml, int force) { struct module_list *mt; const char *cp; int i; /* Go through dependancy list, check if those are * loaded */ ml->status = mod_status_unloading; info(module_debug, "unloading module: %s",ml->modinfo->name); for(i = 0; ml->modinfo->depends[i] != NULL; i++) { cp = ml->modinfo->depends[i]; if (*cp == 0) continue; mt = find_module(cp); if (mt == NULL) { error(module_debug,"Can't find module '%s' which is " "required by module '%s'", cp,ml->modinfo->name); ml->status = mod_status_failed; return -1; } switch (mt->status) { case mod_status_unloaded: break; case mod_status_unloading: if (!force) { error(module_debug,"Circular dependancy. Module '%s' requires " "module '%s'.", ml->modinfo->name, mt->modinfo->name); ml->status = mod_status_failed; } return -1; case mod_status_loaded: if (unload_module(mt,force) == -1 && !force) { ml->status = mod_status_loaded; return -1; } break; default: if (!force) { error(module_debug,"Dependancy on failed module '%s' by '%s'", mt->modinfo->name, ml->modinfo->name); ml->status = mod_status_failed; return -1; } } /* Module dependancy loaded */ } if (ml->modinfo->destroy && ml->modinfo->destroy() != 0) { if (!force) { error(module_debug,"module %s destroy() failed", ml->modinfo->name); ml->status = mod_status_failed; return -1; } } ml->status = mod_status_unloaded; ml->modinfo->loaded = 0; module_count--; return 0; } int load_module(struct module_list *ml) { struct module_list *mt; const char *cp; int i; /* Go through dependancy list, check if those are * loaded */ ml->status = mod_status_loading; info(module_debug, "loading module: %s",ml->modinfo->name); for(i = 0; ml->modinfo->depends[i] != NULL; i++) { cp = ml->modinfo->depends[i]; if (*cp == 0) continue; mt = find_module(cp); if (mt == NULL) { error(module_debug,"Can't find module '%s' which is " "required by module '%s'", ml->modinfo->name, cp); ml->status = mod_status_failed; return -1; } switch (mt->status) { case mod_status_unloaded: if (load_module(mt) == -1) { ml->status = mod_status_failed; return -1; } break; case mod_status_loading: error(module_debug,"Circular dependancy. Module '%s' requires " "module '%s'.", ml->modinfo->name, mt->modinfo->name); ml->status = mod_status_failed; return -1; case mod_status_loaded: break; default: error(module_debug,"Dependancy on failed module '%s' by '%s'", mt->modinfo->name, ml->modinfo->name); ml->status = mod_status_failed; return -1; } /* Module dependancy loaded */ } if (ml->modinfo->init && ml->modinfo->init() != 0) { ml->status = mod_status_failed; return -1; } ml->status = mod_status_loaded; ml->modinfo->loaded = 1; ml->load_order = module_count++; return 0; } void register_module(struct module *modinfo) { struct module_list *ml = XMALLOC(pool,struct module_list); ml->modinfo = modinfo; ml->status = mod_status_unloaded; ml->next = head; head = ml; }