From: Timo Sirainen Date: Wed, 14 May 2003 18:23:40 +0000 (+0300) Subject: missing X-Git-Tag: 1.1.alpha1~4640 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=615f6231e6f3b30ae6eb038883ea6e8070224cd7;p=thirdparty%2Fdovecot%2Fcore.git missing --HG-- branch : HEAD --- diff --git a/src/lib/module-dir.c b/src/lib/module-dir.c new file mode 100644 index 0000000000..4a58d8f008 --- /dev/null +++ b/src/lib/module-dir.c @@ -0,0 +1,131 @@ +/* Copyright (C) 2003 Timo Sirainen */ + +#include "lib.h" +#include "module-dir.h" + +#ifdef HAVE_MODULES + +#include +#include +#include + +static void *get_symbol(const char *path, void *handle, const char *symbol) +{ + const char *error; + void *ret; + + /* get our init func */ + ret = dlsym(handle, symbol); + + error = dlerror(); + if (error != NULL) { + i_error("module %s: dlsym(%s) failed: %s", path, symbol, error); + ret = NULL; + } + + return ret; +} + +static struct module *module_load(const char *path, const char *name) +{ + void *handle; + void (*init)(void); + void (*deinit)(void); + struct module *module; + + handle = dlopen(path, RTLD_GLOBAL | RTLD_NOW); + if (handle == NULL) { + i_error("dlopen(%s) failed: %s", path, dlerror()); + return NULL; + } + + /* get our init func */ + init = get_symbol(path, handle, t_strconcat(name, "_init", NULL)); + deinit = init == NULL ? NULL : + get_symbol(path, handle, t_strconcat(name, "_deinit", NULL)); + + if (init == NULL || deinit == NULL) { + (void)dlclose(handle); + return NULL; + } + + init(); + + module = i_new(struct module, 1); + module->handle = handle; + module->deinit = deinit; + return module; +} + +struct module *module_dir_load(const char *dir) +{ + DIR *dirp; + struct dirent *d; + const char *name, *path, *p; + struct module *modules, *module; + + dirp = opendir(dir); + if (dirp == NULL) { + i_error("opendir(%s) failed: %m", dir); + return NULL; + } + + modules = NULL; + while ((d = readdir(dirp)) != NULL) { + name = d->d_name; + + if (name[0] == '.') + continue; + + p = strstr(name, ".so"); + if (p == NULL || strlen(p) != 3) + continue; + + if (strncmp(name, "lib", 3) == 0) + name += 3; + + t_push(); + name = t_strdup_until(d->d_name, p); + path = t_strconcat(dir, "/", d->d_name, NULL); + module = module_load(path, name); + t_pop(); + + if (module != NULL) { + module->next = modules; + modules = module; + } + } + + if (closedir(dirp) < 0) + i_error("closedir(%s) failed: %m", dir); + + return modules; +} + +void module_dir_unload(struct module *modules) +{ + struct module *next; + + while (modules != NULL) { + next = modules->next; + modules->deinit(); + if (dlclose(modules->handle) != 0) + i_error("dlclose() failed: %m"); + i_free(modules); + modules = next; + } +} + +#else + +struct module *module_dir_load(const char *dir __attr_unused__) +{ + i_error("Dynamically loadable module support not built in"); + return NULL; +} + +void module_dir_unload(struct module *modules __attr_unused__) +{ +} + +#endif diff --git a/src/lib/module-dir.h b/src/lib/module-dir.h new file mode 100644 index 0000000000..53b293c61b --- /dev/null +++ b/src/lib/module-dir.h @@ -0,0 +1,16 @@ +#ifndef __MODULE_DIR_H +#define __MODULE_DIR_H + +struct module { + void *handle; + void (*deinit)(void); + + struct module *next; +}; + +/* Load all modules in given directory. */ +struct module *module_dir_load(const char *dir); +/* Unload all modules */ +void module_dir_unload(struct module *modules); + +#endif