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>
36 /* A hook function as defined by a module. */
37 typedef bool (*module_hook_function
)(void **);
41 /* Handle returned by dlopen(). */
43 /* Pointer to be used by the modules. */
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
)
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");
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
));
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());
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"));
98 m
->close
= close_module
;
99 m
->call_hook
= call_module_hook
;
113 static void close_module(struct plugin
*m
)
115 struct module_context
*context
= m
->context
;
116 dlclose(context
->dl_handle
);
120 static bool call_module_hook(struct plugin
*m
, const char *hook_name
)
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
];
131 result
= context
->hooks
[i
](&context
->module_data
);