2 * kmscon - Module handling
4 * Copyright (c) 2012-2013 David Herrmann <dh.herrmann@googlemail.com>
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files
8 * (the "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
21 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 #include <sys/types.h>
33 #include "kmscon_module.h"
34 #include "kmscon_module_interface.h"
35 #include "shl_dlist.h"
36 #include "shl_githead.h"
40 #define LOG_SUBSYSTEM "module"
42 static struct shl_dlist module_list = SHL_DLIST_INIT(module_list);
44 int kmscon_module_open(struct kmscon_module **out, const char *file)
47 struct kmscon_module *module;
53 log_debug("opening module %s", file);
55 handle = dlopen(file, RTLD_NOW);
57 log_error("cannot open module %s (%d): %s",
58 file, errno, dlerror());
62 module = dlsym(handle, "module");
64 log_error("cannot find module-info for %s", file);
69 if (strcmp(module->info.githead, shl_git_head)) {
70 log_error("incompatible module %s (%s != %s)",
71 file, module->info.githead, shl_git_head);
76 if (module->ref != 0) {
77 log_error("module %s already loaded (%ld)",
83 log_debug("Initializing module: %s", file);
86 module->loaded = false;
87 module->handle = handle;
89 module->file = strdup(file);
95 log_debug(" Date: %s %s", module->info.date, module->info.time);
96 log_debug(" GIT: %s", module->info.githead);
97 log_debug(" Hooks: %p %p %p %p",
103 if (module->info.init) {
104 ret = module->info.init();
106 log_error("loading module %s failed: %d",
122 void kmscon_module_ref(struct kmscon_module *module)
124 if (!module || !module->ref)
130 void kmscon_module_unref(struct kmscon_module *module)
132 if (!module || !module->ref || --module->ref)
135 log_debug("closing module %s", module->file);
137 if (module->info.exit)
141 dlclose(module->handle);
144 int kmscon_module_load(struct kmscon_module *module)
154 log_debug("loading module %s", module->file);
156 if (module->info.load)
157 ret = module->info.load();
164 module->loaded = true;
168 void kmscon_module_unload(struct kmscon_module *module)
170 if (!module || !module->loaded)
173 log_debug("unloading module %s", module->file);
175 if (module->info.unload)
176 module->info.unload();
177 module->loaded = false;
180 void kmscon_load_modules(void)
184 struct dirent *buf = NULL, *de;
186 struct kmscon_module *mod;
188 log_debug("loading global modules from %s", BUILD_MODULE_DIR);
190 if (!shl_dlist_empty(&module_list)) {
191 log_error("trying to load global modules twice");
195 ent = opendir(BUILD_MODULE_DIR);
197 if (errno == ENOTDIR || errno == ENOENT)
198 log_debug("module directory %s not available",
201 log_error("cannot open module directory %s (%d): %m",
202 BUILD_MODULE_DIR, errno);
206 ret = shl_dirent(BUILD_MODULE_DIR, &buf);
208 log_error("cannot allocate dirent object");
214 ret = readdir_r(ent, buf, &de);
216 log_error("cannot read directory %s: %d",
217 BUILD_MODULE_DIR, ret);
223 if (de->d_type == DT_DIR)
226 if (de->d_type != DT_REG &&
227 de->d_type != DT_LNK &&
228 de->d_type != DT_UNKNOWN) {
229 log_warning("non-module file %s in module dir %s",
230 de->d_name, BUILD_MODULE_DIR);
234 if (!shl_ends_with(de->d_name, ".so"))
237 ret = asprintf(&file, "%s/%s", BUILD_MODULE_DIR, de->d_name);
239 log_error("cannot allocate memory for module file name");
243 ret = kmscon_module_open(&mod, file);
249 ret = kmscon_module_load(mod);
251 kmscon_module_unref(mod);
255 shl_dlist_link(&module_list, &mod->list);
262 void kmscon_unload_modules(void)
264 struct kmscon_module *module;
266 log_debug("unloading modules");
268 while (!shl_dlist_empty(&module_list)) {
269 module = shl_dlist_entry(module_list.prev, struct kmscon_module,
271 shl_dlist_unlink(&module->list);
272 kmscon_module_unload(module);
273 kmscon_module_unref(module);