src/module.c: rename VlockPlugin *object to *plugin
[vlock.git] / src / module.c
blobf6d0f16935e3852b69ff2641a2fb14fdf0a7c9b5
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), TYPE_VLOCK_MODULE, VlockModulePrivate))
43 /* A hook function as defined by a module. */
44 typedef bool (*module_hook_function)(void **);
46 struct _VlockModulePrivate
48 /* Handle returned by dlopen(). */
49 void *dl_handle;
51 /* Pointer to be used by the module's hooks. */
52 void *hook_context;
54 /* Array of hook functions befined by a single module. Stored in the same
55 * order as the global hooks. */
56 module_hook_function hooks[nr_hooks];
59 static bool vlock_module_open(VlockPlugin *plugin, GError **error)
61 VlockModule *self = VLOCK_MODULE(plugin);
63 g_assert(self->priv->dl_handle == NULL);
65 char *path = g_strdup_printf("%s/%s.so", VLOCK_MODULE_DIR, plugin->name);
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 gint error_code = (errno == ENOENT) ?
71 VLOCK_PLUGIN_ERROR_NOT_FOUND :
72 VLOCK_PLUGIN_ERROR_FAILED;
74 g_set_error(
75 error,
76 VLOCK_PLUGIN_ERROR,
77 error_code,
78 "could not open module '%s': %s",
79 plugin->name,
80 g_strerror(errno));
82 g_free(path);
83 return false;
86 /* Open the module as a shared library. */
87 void *dl_handle = self->priv->dl_handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
89 g_free(path);
91 if (dl_handle == NULL) {
92 g_set_error(
93 error,
94 VLOCK_PLUGIN_ERROR,
95 VLOCK_PLUGIN_ERROR_FAILED,
96 "could not open module '%s': %s",
97 plugin->name,
98 dlerror());
100 return false;
103 /* Load all the hooks. Unimplemented hooks are NULL and will not be called later. */
104 for (size_t i = 0; i < nr_hooks; i++)
105 *(void **) (&self->priv->hooks[i]) = dlsym(dl_handle, hooks[i].name);
107 /* Load all dependencies. Unspecified dependencies are NULL. */
108 for (size_t i = 0; i < nr_dependencies; i++) {
109 const char *(*dependency)[] = dlsym(dl_handle, dependency_names[i]);
111 /* Append array elements to list. */
112 for (size_t j = 0; dependency != NULL && (*dependency)[j] != NULL; j++) {
113 char *s = g_strdup((*dependency)[j]);
115 plugin->dependencies[i] = g_list_append(plugin->dependencies[i], s);
119 return true;
122 static bool vlock_module_call_hook(VlockPlugin *plugin, const gchar *hook_name)
124 VlockModule *self = VLOCK_MODULE(plugin);
126 /* Find the right hook index. */
127 for (size_t i = 0; i < nr_hooks; i++)
128 if (strcmp(hooks[i].name, hook_name) == 0) {
129 module_hook_function hook = self->priv->hooks[i];
131 if (hook != NULL)
132 return hook(&self->priv->hook_context);
135 return true;
138 /* Initialize plugin to default values. */
139 static void vlock_module_init(VlockModule *self)
141 self->priv = VLOCK_MODULE_GET_PRIVATE(self);
142 self->priv->dl_handle = NULL;
145 /* Destroy module object. */
146 static void vlock_module_finalize(GObject *object)
148 VlockModule *self = VLOCK_MODULE(object);
150 if (self->priv->dl_handle != NULL) {
151 dlclose(self->priv->dl_handle);
152 self->priv->dl_handle = NULL;
155 G_OBJECT_CLASS(vlock_module_parent_class)->finalize(object);
158 /* Initialize module class. */
159 static void vlock_module_class_init(VlockModuleClass *klass)
161 GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
162 VlockPluginClass *plugin_class = VLOCK_PLUGIN_CLASS(klass);
164 g_type_class_add_private(klass, sizeof(VlockModulePrivate));
166 /* Virtual methods. */
167 gobject_class->finalize = vlock_module_finalize;
169 plugin_class->open = vlock_module_open;
170 plugin_class->call_hook = vlock_module_call_hook;