diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2019-11-17 13:45:07 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2019-11-27 14:34:26 +0100 |
commit | b65f902861f168085a8fc0d3525d11996438fb17 (patch) | |
tree | ba2236eee7aa45b59c32e402926fab250d4eb2c4 | |
parent | ec85ea32cb01c4e4c3922fb586b5cd9c143bcba2 (diff) |
plugin-manager: dynamically load 'shared' util libraries
(cherry picked from commit b1c3f1eb1c740975b3ea387ae5e08dc426643c8b)
-rw-r--r-- | plugins/Makefile.am | 8 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/mm-plugin-manager.c | 91 | ||||
-rw-r--r-- | src/mm-shared.h | 35 |
4 files changed, 124 insertions, 11 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index ffc0c0ec..38dd460e 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -37,6 +37,14 @@ AM_CFLAGS += $(MBIM_CFLAGS) AM_LDFLAGS += $(MBIM_LIBS) endif +# Common compiler/linker flags for shared utils +SHARED_COMMON_COMPILER_FLAGS = \ + $(NULL) +SHARED_COMMON_LINKER_FLAGS = \ + -module \ + -avoid-version \ + $(NULL) + # Common compiler/linker flags for plugins PLUGIN_COMMON_COMPILER_FLAGS = \ $(NULL) diff --git a/src/Makefile.am b/src/Makefile.am index 8f46d2c5..21086c47 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -350,6 +350,7 @@ ModemManager_SOURCES = \ mm-port-probe-at.c \ mm-plugin.c \ mm-plugin.h \ + mm-shared.h \ $(NULL) nodist_ModemManager_SOURCES = $(DAEMON_ENUMS_GENERATED) diff --git a/src/mm-plugin-manager.c b/src/mm-plugin-manager.c index b46b3a6f..ed484cd9 100644 --- a/src/mm-plugin-manager.c +++ b/src/mm-plugin-manager.c @@ -12,8 +12,8 @@ * * Copyright (C) 2008 - 2009 Novell, Inc. * Copyright (C) 2009 - 2012 Red Hat, Inc. - * Copyright (C) 2011 - 2012 Aleksander Morgado <aleksander@gnu.org> * Copyright (C) 2012 Google, Inc. + * Copyright (C) 2011 - 2019 Aleksander Morgado <aleksander@gnu.org> */ #include <string.h> @@ -27,8 +27,12 @@ #include "mm-plugin-manager.h" #include "mm-plugin.h" +#include "mm-shared.h" #include "mm-log.h" +#define SHARED_PREFIX "libmm-shared" +#define PLUGIN_PREFIX "libmm-plugin" + static void initable_iface_init (GInitableIface *iface); G_DEFINE_TYPE_EXTENDED (MMPluginManager, mm_plugin_manager, G_TYPE_OBJECT, 0, @@ -1585,9 +1589,10 @@ load_plugin (const gchar *path) } plugin = (*plugin_create_func) (); - if (plugin) + if (plugin) { + mm_dbg ("[plugin manager] loaded plugin '%s' from '%s'", mm_plugin_get_name (plugin), path_display); g_object_weak_ref (G_OBJECT (plugin), (GWeakNotify) g_module_close, module); - else + } else mm_warn ("[plugin manager] could not load plugin '%s': initialization failed", path_display); out: @@ -1599,6 +1604,60 @@ out: return plugin; } +static void +load_shared (const gchar *path) +{ + GModule *module; + gchar *path_display; + const gchar **shared_name = NULL; + gint *major_shared_version; + gint *minor_shared_version; + + /* Get printable UTF-8 string of the path */ + path_display = g_filename_display_name (path); + + module = g_module_open (path, G_MODULE_BIND_LAZY); + if (!module) { + mm_warn ("[plugin manager] could not load shared '%s': %s", path_display, g_module_error ()); + goto out; + } + + if (!g_module_symbol (module, "mm_shared_major_version", (gpointer *) &major_shared_version)) { + mm_warn ("[plugin manager] could not load shared '%s': Missing major version info", path_display); + goto out; + } + + if (*major_shared_version != MM_SHARED_MAJOR_VERSION) { + mm_warn ("[plugin manager] could not load shared '%s': Shared major version %d, %d is required", + path_display, *major_shared_version, MM_SHARED_MAJOR_VERSION); + goto out; + } + + if (!g_module_symbol (module, "mm_shared_minor_version", (gpointer *) &minor_shared_version)) { + mm_warn ("[plugin manager] could not load shared '%s': Missing minor version info", path_display); + goto out; + } + + if (*minor_shared_version != MM_SHARED_MINOR_VERSION) { + mm_warn ("[plugin manager] could not load shared '%s': Shared minor version %d, %d is required", + path_display, *minor_shared_version, MM_SHARED_MINOR_VERSION); + goto out; + } + + if (!g_module_symbol (module, "mm_shared_name", (gpointer *) &shared_name)) { + mm_warn ("[plugin manager] could not load shared '%s': Missing name", path_display); + goto out; + } + + mm_dbg ("[plugin manager] loaded shared '%s' utils from '%s'", *shared_name, path_display); + +out: + if (module && !(*shared_name)) + g_module_close (module); + + g_free (path_display); +} + static gboolean load_plugins (MMPluginManager *self, GError **error) @@ -1606,6 +1665,9 @@ load_plugins (MMPluginManager *self, GDir *dir = NULL; const gchar *fname; gchar *plugindir_display = NULL; + GList *shared_paths = NULL; + GList *plugin_paths = NULL; + GList *l; if (!g_module_supported ()) { g_set_error (error, @@ -1630,21 +1692,26 @@ load_plugins (MMPluginManager *self, } while ((fname = g_dir_read_name (dir)) != NULL) { - gchar *path; - MMPlugin *plugin; - if (!g_str_has_suffix (fname, G_MODULE_SUFFIX)) continue; + if (g_str_has_prefix (fname, SHARED_PREFIX)) + shared_paths = g_list_prepend (shared_paths, g_module_build_path (self->priv->plugin_dir, fname)); + else if (g_str_has_prefix (fname, PLUGIN_PREFIX)) + plugin_paths = g_list_prepend (plugin_paths, g_module_build_path (self->priv->plugin_dir, fname)); + } - path = g_module_build_path (self->priv->plugin_dir, fname); - plugin = load_plugin (path); - g_free (path); + /* Load all shared utils */ + for (l = shared_paths; l; l = g_list_next (l)) + load_shared ((const gchar *)(l->data)); + /* Load all plugins */ + for (l = plugin_paths; l; l = g_list_next (l)) { + MMPlugin *plugin; + + plugin = load_plugin ((const gchar *)(l->data)); if (!plugin) continue; - mm_dbg ("[plugin manager] loaded plugin '%s'", mm_plugin_get_name (plugin)); - if (g_str_equal (mm_plugin_get_name (plugin), MM_PLUGIN_GENERIC_NAME)) /* Generic plugin */ self->priv->generic = plugin; @@ -1675,6 +1742,8 @@ load_plugins (MMPluginManager *self, g_list_length (self->priv->plugins) + !!self->priv->generic); out: + g_list_free_full (shared_paths, g_free); + g_list_free_full (plugin_paths, g_free); if (dir) g_dir_close (dir); g_free (plugindir_display); diff --git a/src/mm-shared.h b/src/mm-shared.h new file mode 100644 index 00000000..4fc7cef5 --- /dev/null +++ b/src/mm-shared.h @@ -0,0 +1,35 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details: + * + * Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es> + */ + +#ifndef MM_SHARED_H +#define MM_SHARED_H + +#include <glib.h> +#include <glib-object.h> + +#define MM_SHARED_MAJOR_VERSION 1 +#define MM_SHARED_MINOR_VERSION 0 + +#if defined (G_HAVE_GNUC_VISIBILITY) +#define VISIBILITY __attribute__((visibility("protected"))) +#else +#define VISIBILITY +#endif + +#define MM_SHARED_DEFINE_MAJOR_VERSION VISIBILITY int mm_shared_major_version = MM_SHARED_MAJOR_VERSION; +#define MM_SHARED_DEFINE_MINOR_VERSION VISIBILITY int mm_shared_minor_version = MM_SHARED_MINOR_VERSION; +#define MM_SHARED_DEFINE_NAME(NAME) VISIBILITY const char *mm_shared_name = #NAME; + +#endif /* MM_SHARED_H */ |