sometimes arrays are better than lists
[vlock.git] / src / module.c
blob0fd4f48265f239b550121bdb8eb400809668ac27
1 #if !defined(__FreeBSD__) && !defined(_GNU_SOURCE)
2 #define _GNU_SOURCE
3 #endif
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <errno.h>
10 #include <dlfcn.h>
12 #include <sys/types.h>
14 #include "list.h"
15 #include "util.h"
17 #include "plugin.h"
19 #include "module.h"
21 #define VLOCK_MODULE_DIR PREFIX "/lib/vlock/modules"
23 typedef bool (*vlock_hook_fn)(void **);
24 typedef vlock_hook_fn (*hook_dlsym_t)(void *, const char *);
26 struct module_context
28 void *dl_handle;
29 vlock_hook_fn hooks[nr_hooks];
32 static void close_module(struct plugin *m);
34 struct plugin *open_module(const char *name, char **error)
36 char *path;
37 struct plugin *m = __allocate_plugin(name);
38 struct module_context *context = ensure_malloc(sizeof (struct module_context));
40 if (asprintf(&path, "%s/%s.so", VLOCK_MODULE_DIR, name) < 0) {
41 *error = strdup("filename too long");
42 goto path_error;
45 if (access(path, R_OK) < 0) {
46 (void) asprintf(error, "%s: %s", path, strerror(errno));
47 goto file_error;
50 context->dl_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
52 if (context->dl_handle == NULL) {
53 *error = strdup(dlerror());
54 goto file_error;
57 free(path);
59 for (size_t i = 0; i < nr_hooks; i++)
60 *(void **) (&context->hooks[i]) = dlsym(context->dl_handle, hooks[i].name);
63 for (size_t i = 0; i < nr_dependencies; i++) {
64 const char *(*dependency)[] = dlsym(context->dl_handle, dependency_names[i]);
66 for (size_t j = 0; dependency != NULL && (*dependency)[j] != NULL; j++)
67 list_append(m->dependencies[i], strdup((*dependency)[j]));
70 m->context = context;
71 m->close = close_module;
73 return m;
75 file_error:
76 free(path);
78 path_error:
79 free(context);
80 __destroy_plugin(m);
81 return NULL;
84 static void close_module(struct plugin *m)
86 struct module_context *context = m->context;
87 dlclose(context->dl_handle);