/*
Unix SMB/CIFS implementation.
- module loading system
- Copyright (C) Jelmer Vernooij 2002-2004
+ Copyright (C) Jelmer Vernooij 2005
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
*/
#include "includes.h"
+#include "system/dir.h"
-#ifdef HAVE_DLOPEN
-
-/* Load module (or directory with modules) recursively.
- * Includes running the init_module() function */
-NTSTATUS smb_load_module(const char *module_name)
+static void *load_module(TALLOC_CTX *mem_ctx, const char *dir, const char *name)
{
+ char *path;
void *handle;
- init_module_function init;
- NTSTATUS status;
- const char *error;
- struct stat st;
- DIR *dir;
- struct dirent *dirent;
-
- if(stat(module_name, &st) < 0) {
- DEBUG(0, ("Can't stat module '%s'\n", module_name));
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- /* If the argument is a directory, recursively load all files /
- * directories in it */
+ void *init_fn;
- /* How about symlinks pointing to themselves - wouldn't we rather
- * want to use wildcards here? */
- if(S_ISDIR(st.st_mode)) {
- dir = opendir(module_name);
- while ((dirent = readdir(dir))) {
- smb_load_module(dirent->d_name);
- }
- }
-
- /* Always try to use LAZY symbol resolving; if the plugin has
- * backwards compatibility, there might be symbols in the
- * plugin referencing to old (removed) functions
- */
- handle = sys_dlopen(module_name, RTLD_LAZY);
+ path = talloc_asprintf(mem_ctx, "%s/%s", dir, name);
- if(!handle) {
- DEBUG(0, ("Error loading module '%s': %s\n", module_name, sys_dlerror()));
- return NT_STATUS_UNSUCCESSFUL;
+ handle = dlopen(path, RTLD_NOW);
+ if (handle == NULL) {
+ DEBUG(0, ("Unable to open %s: %s\n", path, dlerror()));
+ talloc_free(path);
+ return NULL;
}
- init = (init_module_function)sys_dlsym(handle, "init_module");
+ init_fn = dlsym(handle, "init_module");
- /* we must check sys_dlerror() to determine if it worked, because
- sys_dlsym() can validly return NULL */
- error = sys_dlerror();
- if (error) {
- DEBUG(0, ("Error trying to resolve symbol 'init_module' in %s: %s\n", module_name, error));
- return NT_STATUS_UNSUCCESSFUL;
+ if (init_fn == NULL) {
+ DEBUG(0, ("Unable to find init_module() in %s: %s\n", path, dlerror()));
+ DEBUG(1, ("Loading module '%s' failed\n", path));
+ dlclose(handle);
+ talloc_free(path);
+ return NULL;
}
- status = init();
+ talloc_free(path);
- DEBUG(2, ("Module '%s' loaded\n", module_name));
-
- return status;
+ return init_fn;
}
-/* Load all modules in list and return number of
- * modules that has been successfully loaded */
-int smb_load_modules(const char **modules)
+init_module_fn *load_modules(TALLOC_CTX *mem_ctx, const char *path)
{
- int i;
+ DIR *dir;
+ struct dirent *entry;
int success = 0;
+ init_module_fn *ret = talloc_array(mem_ctx, init_module_fn, 2);
- for(i = 0; modules[i]; i++){
- if(NT_STATUS_IS_OK(smb_load_module(modules[i]))) {
- success++;
- }
+ ret[0] = NULL;
+
+ dir = opendir(path);
+ if (dir == NULL) {
+ talloc_free(ret);
+ return NULL;
}
- DEBUG(2, ("%d modules successfully loaded\n", success));
+ while((entry = readdir(dir))) {
+ if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
+ continue;
- return success;
-}
-
-#else /* HAVE_DLOPEN */
-
-NTSTATUS smb_load_module(const char *module_name)
-{
- DEBUG(0,("This samba executable has not been built with plugin support\n"));
- return NT_STATUS_NOT_SUPPORTED;
-}
-
-int smb_load_modules(const char **modules)
-{
- DEBUG(0,("This samba executable has not been built with plugin support\n"));
- return -1;
-}
-
-#endif /* HAVE_DLOPEN */
-
-void init_modules(void)
-{
- if(lp_preload_modules())
- smb_load_modules(lp_preload_modules());
-}
-
-struct subsystem {
- char *name;
- register_backend_function callback;
- struct subsystem *prev, *next;
-};
-
-static struct subsystem *subsystems = NULL;
-
-NTSTATUS register_subsystem(const char *name, register_backend_function callback)
-{
- struct subsystem *s;
- struct subsystem *t = subsystems;
-
- while(t) {
- if(!strcmp(name, t->name)) {
- /* its already registered! */
- DEBUG(0,("Subsystem '%s' already registered\n", name));
- return NT_STATUS_OBJECT_NAME_COLLISION;
+ ret[success] = load_module(mem_ctx, path, entry->d_name);
+ if (ret[success]) {
+ ret = talloc_realloc(mem_ctx, ret, init_module_fn, success+2);
+ success++;
+ ret[success] = NULL;
}
- t = t->next;
}
- s = smb_xmalloc(sizeof(struct subsystem));
-
- s->name = smb_xstrdup(name);
- s->callback = callback;
- s->prev = s->next = NULL;
-
- DLIST_ADD(subsystems, s);
+ closedir(dir);
- return NT_STATUS_OK;
+ return ret;
}
-NTSTATUS register_backend(const char *subsystem, const void *args)
+BOOL run_init_functions(NTSTATUS (**fns) (void))
{
- /* Find the specified subsystem */
- struct subsystem *s = subsystems;
-
- while(s) {
- if(!strcmp(subsystem, s->name)) return s->callback(args);
- s = s->next;
- }
+ int i;
+ BOOL ret;
+
+ if (fns == NULL)
+ return True;
- DEBUG(0, ("Unable to register backend for subsystem '%s'\n", subsystem));
+ for (i = 0; fns[i]; i++) { ret &= NT_STATUS_IS_OK(fns[i]()); }
- return NT_STATUS_NOT_IMPLEMENTED;
+ return ret;
}