rename modules/blank.c to modules/ttyblank.c
[vlock.git] / src / module.c
blobf327098007b7a9a4a19e02841440dd5f7e3042f2
1 /* module.c -- module routines for vlock, the VT locking program for linux
3 * This program is copyright (C) 2007 Frank Benkstein, and is free
4 * software which is freely distributable under the terms of the
5 * GNU General Public License version 2, included as the file COPYING in this
6 * distribution. It is NOT public domain software, and any
7 * redistribution not permitted by the GNU General Public License is
8 * expressly forbidden without prior written permission from
9 * the author.
13 /* Modules are shared objects that are loaded into vlock's address space. */
14 /* They can define certain functions that are called through vlock's plugin
15 * mechanism. They should also define dependencies if they depend on other
16 * plugins of have to be called before or after other plugins. */
18 #if !defined(__FreeBSD__) && !defined(_GNU_SOURCE)
19 #define _GNU_SOURCE
20 #endif
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <dlfcn.h>
29 #include <sys/types.h>
31 #include "list.h"
32 #include "util.h"
34 #include "plugin.h"
36 /* A hook function as defined by a module. */
37 typedef bool (*module_hook_function)(void **);
39 struct module_context
41 /* Handle returned by dlopen(). */
42 void *dl_handle;
43 /* Pointer to be used by the modules. */
44 void *module_data;
45 /* Array of hook functions befined by a single module. Stored in the same
46 * order as the global hooks. */
47 module_hook_function hooks[nr_hooks];
50 static void close_module(struct plugin *m);
51 static bool call_module_hook(struct plugin *m, const char *hook_name);
53 /* Create a new module type plugin. */
54 struct plugin *open_module(const char *name, char **error)
56 char *path;
57 struct plugin *m = __allocate_plugin(name);
58 struct module_context *context = ensure_malloc(sizeof *context);
60 context->module_data = NULL;
62 if (asprintf(&path, "%s/%s.so", VLOCK_MODULE_DIR, name) < 0) {
63 *error = strdup("filename too long");
64 goto path_error;
67 /* Test for access. This must be done manually because vlock most likely
68 * runs as a setuid executable and would otherwise override restrictions. */
69 if (access(path, R_OK) < 0) {
70 (void) asprintf(error, "%s: %s", path, strerror(errno));
71 goto access_error;
74 /* Open the module as a shared library. */
75 context->dl_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
77 if (context->dl_handle == NULL) {
78 *error = strdup(dlerror());
79 goto dlopen_error;
82 free(path);
84 /* Load all the hooks. Unimplemented hooks are NULL and will not be called later. */
85 for (size_t i = 0; i < nr_hooks; i++)
86 *(void **) (&context->hooks[i]) = dlsym(context->dl_handle, hooks[i].name);
89 /* Load all dependencies. Unspecified dependencies are NULL. */
90 for (size_t i = 0; i < nr_dependencies; i++) {
91 const char *(*dependency)[] = dlsym(context->dl_handle, dependency_names[i]);
93 for (size_t j = 0; dependency != NULL && (*dependency)[j] != NULL; j++)
94 list_append(m->dependencies[i], ensure_not_null(strdup((*dependency)[j]), "failed to copy string"));
97 m->context = context;
98 m->close = close_module;
99 m->call_hook = call_module_hook;
101 return m;
103 dlopen_error:
104 access_error:
105 free(path);
107 path_error:
108 free(context);
109 __destroy_plugin(m);
110 return NULL;
113 static void close_module(struct plugin *m)
115 struct module_context *context = m->context;
116 dlclose(context->dl_handle);
117 free(context);
120 static bool call_module_hook(struct plugin *m, const char *hook_name)
122 bool result = true;
124 /* Find the right hook index. */
125 for (size_t i = 0; i < nr_hooks; i++)
126 if (strcmp(hooks[i].name, hook_name) == 0) {
127 struct module_context *context = m->context;
128 module_hook_function hook = context->hooks[i];
130 if (hook != NULL)
131 result = context->hooks[i](&context->module_data);
133 break;
136 return result;