/** * @file mce-modules.c * Module handling for MCE *

* Copyright © 2007-2009 Nokia Corporation and/or its subsidiary(-ies). * Copyright (C) 2012-2019 Jolla Ltd. *

* @author David Weinehall * @author Simo Piiroinen * * mce is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * mce is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with mce. If not, see . */ #include "mce-modules.h" #include "mce.h" #include "mce-log.h" #include "mce-conf.h" #include #include /** List of all loaded modules */ static GSList *modules = NULL; /** * Dump information about mce modules to stdout */ void mce_modules_dump_info(void) { GModule *module; gint i; for (i = 0; (module = g_slist_nth_data(modules, i)) != NULL; i++) { const gchar *modulename = g_module_name(module); module_info_struct *modinfo; gchar *tmp = NULL; gpointer mip; fprintf(stdout, "\n" "Module: %s\n", modulename); if (g_module_symbol(module, "module_info", &mip) == FALSE) { fprintf(stdout, " %-32s\n", "module lacks information"); continue; } modinfo = (module_info_struct *)mip; fprintf(stdout, " %-32s %s\n", "name:", modinfo->name ? modinfo->name : ""); if (modinfo->depends != NULL) tmp = g_strjoinv(",", (gchar **)(modinfo->depends)); fprintf(stdout, " %-32s %s\n", "depends:", tmp ? tmp : ""); g_free(tmp); tmp = NULL; if (modinfo->recommends != NULL) tmp = g_strjoinv(",", (gchar **)(modinfo->recommends)); fprintf(stdout, " %-32s %s\n", "recommends:", tmp ? tmp : ""); g_free(tmp); tmp = NULL; if (modinfo->provides != NULL) tmp = g_strjoinv(",", (gchar **)(modinfo->provides)); fprintf(stdout, " %-32s %s\n", "provides:", tmp ? tmp : ""); g_free(tmp); tmp = NULL; if (modinfo->enhances != NULL) tmp = g_strjoinv(",", (gchar **)(modinfo->enhances)); fprintf(stdout, " %-32s %s\n", "enhances:", tmp ? tmp : ""); g_free(tmp); tmp = NULL; if (modinfo->conflicts != NULL) tmp = g_strjoinv(",", (gchar **)(modinfo->conflicts)); fprintf(stdout, " %-32s %s\n", "conflicts:", tmp ? tmp : ""); g_free(tmp); tmp = NULL; if (modinfo->replaces != NULL) tmp = g_strjoinv(",", (gchar **)(modinfo->replaces)); fprintf(stdout, " %-32s %s\n", "replaces:", tmp ? tmp : ""); g_free(tmp); fprintf(stdout, " %-32s %d\n", "priority:", modinfo->priority); } } /** Construct path for named mce plugin * * @param directory Location of the plugin * @module_name Name of the plugin * * @return Path to shared object */ static gchar * mce_modules_build_path(const gchar *directory, const gchar *module_name) { return g_strdup_printf("%s/%s.so", directory, module_name); } /** * Init function for the mce-modules component * * @return TRUE on success, FALSE on failure */ gboolean mce_modules_init(void) { gchar **modlist = NULL; gsize length; gchar *path = NULL; /* Get the module path */ path = mce_conf_get_string(MCE_CONF_MODULES_GROUP, MCE_CONF_MODULES_PATH, DEFAULT_MCE_MODULE_PATH); /* Get the list modules to load */ modlist = mce_conf_get_string_list(MCE_CONF_MODULES_GROUP, MCE_CONF_MODULES_MODULES, &length); if (modlist != NULL) { gint i; for (i = 0; modlist[i]; i++) { GModule *module; gchar *tmp = mce_modules_build_path(path, modlist[i]); mce_log(LL_INFO, "Loading module: %s from %s", modlist[i], path); if ((module = g_module_open(tmp, 0)) != NULL) { /* XXX: check dependencies, conflicts, et al */ modules = g_slist_prepend(modules, module); } else { const char *err = g_module_error(); mce_log(LL_ERR, "%s", err ?: "unknown error"); mce_log(LL_ERR, "Failed to load module: %s; skipping", modlist[i]); } g_free(tmp); } g_strfreev(modlist); } g_free(path); return TRUE; } /** * Exit function for the mce-modules component */ void mce_modules_exit(void) { GModule *module; gint i; if (modules != NULL) { for (i = 0; (module = g_slist_nth_data(modules, i)) != NULL; i++) { if( mce_in_valgrind_mode() ) { /* Do not actually unmap the plugins so that * valgrind can still locate the symbols at * exit time. */ gpointer addr = 0; g_module_symbol(module, "g_module_unload", &addr); if( addr ) { mce_log(LL_WARN, "simulating module %s unload", g_module_name(module)); void (*unload)(GModule *) = addr; unload(module); } else { mce_log(LL_WARN, "skipping module %s unload", g_module_name(module)); } continue; } g_module_close(module); } g_slist_free(modules); modules = NULL; } return; }