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
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)
29 #include <sys/types.h>
32 #include <glib-object.h>
39 G_DEFINE_TYPE(VlockModule
, vlock_module
, TYPE_VLOCK_PLUGIN
)
41 #define VLOCK_MODULE_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj),\
45 /* A hook function as defined by a module. */
46 typedef bool (*module_hook_function
)(void **);
48 struct _VlockModulePrivate
50 /* Handle returned by dlopen(). */
53 /* Pointer to be used by the module's hooks. */
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
;
80 "could not open module '%s': %s",
88 /* Open the module as a shared library. */
89 void *dl_handle
= self
->priv
->dl_handle
= dlopen(path
, RTLD_NOW
| RTLD_LOCAL
);
93 if (dl_handle
== NULL
) {
97 VLOCK_PLUGIN_ERROR_FAILED
,
98 "could not open module '%s': %s",
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
);
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
];
134 return hook(&self
->priv
->hook_context
);
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
;