document the change in prompt timeout handling
[vlock.git] / src / module.c
blob71b96b3f5791f4c2a75be919a05bdd0f6561d049
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 <glib.h>
32 #include <glib-object.h>
34 #include "util.h"
36 #include "plugin.h"
37 #include "module.h"
39 G_DEFINE_TYPE(VlockModule, vlock_module, TYPE_VLOCK_PLUGIN)
41 #define VLOCK_MODULE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj),\
42 TYPE_VLOCK_MODULE,\
43 VlockModulePrivate))
45 /* A hook function as defined by a module. */
46 typedef bool (*module_hook_function)(void **);
48 struct _VlockModulePrivate
50 /* Handle returned by dlopen(). */
51 void *dl_handle;
53 /* Pointer to be used by the module's hooks. */
54 void *hook_context;
56 /* Array of hook functions befined by a single module. Stored in the same
57 * order as the global hooks. */
58 module_hook_function hooks[nr_hooks];
61 static bool vlock_module_open(VlockPlugin *plugin, GError **error)
63 VlockModule *self = VLOCK_MODULE(plugin);
65 g_assert(self->priv->dl_handle == NULL);
67 char *path = g_strdup_printf("%s/%s.so", VLOCK_MODULE_DIR, plugin->name);
69 /* Test for access. This must be done manually because vlock most likely
70 * runs as a setuid executable and would otherwise override restrictions. */
71 if (access(path, R_OK) < 0) {
72 gint error_code = (errno == ENOENT) ?
73 VLOCK_PLUGIN_ERROR_NOT_FOUND :
74 VLOCK_PLUGIN_ERROR_FAILED;
76 g_set_error(
77 error,
78 VLOCK_PLUGIN_ERROR,
79 error_code,
80 "could not open module '%s': %s",
81 plugin->name,
82 g_strerror(errno));
84 g_free(path);
85 return false;
88 /* Open the module as a shared library. */
89 void *dl_handle = self->priv->dl_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
91 g_free(path);
93 if (dl_handle == NULL) {
94 g_set_error(
95 error,
96 VLOCK_PLUGIN_ERROR,
97 VLOCK_PLUGIN_ERROR_FAILED,
98 "could not open module '%s': %s",
99 plugin->name,
100 dlerror());
102 return false;
105 /* Load all the hooks. Unimplemented hooks are NULL and will not be called later. */
106 for (size_t i = 0; i < nr_hooks; i++)
107 *(void **)(&self->priv->hooks[i]) = dlsym(dl_handle, hooks[i].name);
109 /* Load all dependencies. Unspecified dependencies are NULL. */
110 for (size_t i = 0; i < nr_dependencies; i++) {
111 const char *(*dependency)[] = dlsym(dl_handle, dependency_names[i]);
113 /* Append array elements to list. */
114 for (size_t j = 0; dependency != NULL && (*dependency)[j] != NULL; j++) {
115 char *s = g_strdup((*dependency)[j]);
117 plugin->dependencies[i] = g_list_append(plugin->dependencies[i], s);
121 return true;
124 static bool vlock_module_call_hook(VlockPlugin *plugin, const gchar *hook_name)
126 VlockModule *self = VLOCK_MODULE(plugin);
128 /* Find the right hook index. */
129 for (size_t i = 0; i < nr_hooks; i++)
130 if (strcmp(hooks[i].name, hook_name) == 0) {
131 module_hook_function hook = self->priv->hooks[i];
133 if (hook != NULL)
134 return hook(&self->priv->hook_context);
137 return true;
140 /* Initialize plugin to default values. */
141 static void vlock_module_init(VlockModule *self)
143 self->priv = VLOCK_MODULE_GET_PRIVATE(self);
144 self->priv->dl_handle = NULL;
147 /* Destroy module object. */
148 static void vlock_module_finalize(GObject *object)
150 VlockModule *self = VLOCK_MODULE(object);
152 if (self->priv->dl_handle != NULL) {
153 dlclose(self->priv->dl_handle);
154 self->priv->dl_handle = NULL;
157 G_OBJECT_CLASS(vlock_module_parent_class)->finalize(object);
160 /* Initialize module class. */
161 static void vlock_module_class_init(VlockModuleClass *klass)
163 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
164 VlockPluginClass *plugin_class = VLOCK_PLUGIN_CLASS(klass);
166 g_type_class_add_private(klass, sizeof(VlockModulePrivate));
168 /* Virtual methods. */
169 gobject_class->finalize = vlock_module_finalize;
171 plugin_class->open = vlock_module_open;
172 plugin_class->call_hook = vlock_module_call_hook;