base-manager: automatic required subsystem detection

Instead of assuming we require a fixed set of subsystems to monitor,
compile the full list based on what the plugins have requested
themselves.
This commit is contained in:
Aleksander Morgado
2020-11-13 08:57:06 +00:00
parent 950abbf8ee
commit 71f5c97543
5 changed files with 101 additions and 63 deletions
+24 -34
View File
@@ -368,6 +368,11 @@ handle_kernel_event (MMBaseManager *self,
return FALSE;
}
if (!g_strv_contains (mm_plugin_manager_get_subsystems (self->priv->plugin_manager), subsystem)) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Invalid 'subsystem' parameter given: '%s'", subsystem);
return FALSE;
}
name = mm_kernel_event_properties_get_name (properties);
if (!name) {
g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Missing mandatory parameter 'name'");
@@ -457,28 +462,19 @@ static void
process_scan (MMBaseManager *self,
gboolean manual_scan)
{
GList *devices, *iter;
const gchar **subsystems;
guint i;
devices = g_udev_client_query_by_subsystem (self->priv->udev, "tty");
for (iter = devices; iter; iter = g_list_next (iter)) {
start_device_added (self, G_UDEV_DEVICE (iter->data), manual_scan);
g_object_unref (G_OBJECT (iter->data));
}
g_list_free (devices);
subsystems = mm_plugin_manager_get_subsystems (self->priv->plugin_manager);
for (i = 0; subsystems[i]; i++) {
GList *devices;
GList *iter;
devices = g_udev_client_query_by_subsystem (self->priv->udev, "net");
for (iter = devices; iter; iter = g_list_next (iter)) {
start_device_added (self, G_UDEV_DEVICE (iter->data), manual_scan);
g_object_unref (G_OBJECT (iter->data));
devices = g_udev_client_query_by_subsystem (self->priv->udev, subsystems[i]);
for (iter = devices; iter; iter = g_list_next (iter))
start_device_added (self, G_UDEV_DEVICE (iter->data), manual_scan);
g_list_free_full (devices, g_object_unref);
}
g_list_free (devices);
devices = g_udev_client_query_by_subsystem (self->priv->udev, "usbmisc");
for (iter = devices; iter; iter = g_list_next (iter)) {
start_device_added (self, G_UDEV_DEVICE (iter->data), manual_scan);
g_object_unref (G_OBJECT (iter->data));
}
g_list_free (devices);
}
#endif
@@ -1365,15 +1361,6 @@ mm_base_manager_init (MMBaseManager *self)
/* Setup internal list of inhibited devices */
self->priv->inhibited_devices = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)inhibited_device_info_free);
#if defined WITH_UDEV
{
const gchar *subsys[5] = { "tty", "net", "usbmisc", NULL };
/* Setup UDev client */
self->priv->udev = g_udev_client_new (subsys);
}
#endif
/* By default, enable autoscan */
self->priv->auto_scan = TRUE;
@@ -1399,12 +1386,6 @@ initable_init (GInitable *initable,
{
MMBaseManager *self = MM_BASE_MANAGER (initable);
#if defined WITH_UDEV
/* If autoscan enabled, list for udev events */
if (self->priv->auto_scan)
g_signal_connect_swapped (self->priv->udev, "uevent", G_CALLBACK (handle_uevent), initable);
#endif
/* Create filter */
self->priv->filter = mm_filter_new (self->priv->filter_policy, error);
if (!self->priv->filter)
@@ -1415,6 +1396,15 @@ initable_init (GInitable *initable,
if (!self->priv->plugin_manager)
return FALSE;
#if defined WITH_UDEV
/* Create udev client based on the subsystems requested by the plugins */
self->priv->udev = g_udev_client_new (mm_plugin_manager_get_subsystems (self->priv->plugin_manager));
/* If autoscan enabled, list for udev events */
if (self->priv->auto_scan)
g_signal_connect_swapped (self->priv->udev, "uevent", G_CALLBACK (handle_uevent), initable);
#endif
/* Export the manager interface */
if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (initable),
self->priv->connection,
+69 -29
View File
@@ -62,6 +62,9 @@ struct _MMPluginManagerPrivate {
/* List of ongoing device support checks */
GList *device_contexts;
/* Full list of subsystems requested by the registered plugins */
gchar **subsystems;
};
/*****************************************************************************/
@@ -1601,6 +1604,14 @@ mm_plugin_manager_peek_plugin (MMPluginManager *self,
/*****************************************************************************/
const gchar **
mm_plugin_manager_get_subsystems (MMPluginManager *self)
{
return (const gchar **) self->priv->subsystems;
}
/*****************************************************************************/
static void
register_plugin_whitelist_tags (MMPluginManager *self,
MMPlugin *plugin)
@@ -1765,15 +1776,17 @@ out:
}
static gboolean
load_plugins (MMPluginManager *self,
GError **error)
load_plugins (MMPluginManager *self,
GError **error)
{
GDir *dir = NULL;
const gchar *fname;
gchar *plugindir_display = NULL;
GList *shared_paths = NULL;
GList *plugin_paths = NULL;
GList *l;
GDir *dir = NULL;
const gchar *fname;
GList *shared_paths = NULL;
GList *plugin_paths = NULL;
GList *l;
GPtrArray *subsystems = NULL;
g_autofree gchar *subsystems_str = NULL;
g_autofree gchar *plugindir_display = NULL;
if (!g_module_supported ()) {
g_set_error (error,
@@ -1811,21 +1824,41 @@ load_plugins (MMPluginManager *self,
load_shared (self, (const gchar *)(l->data));
/* Load all plugins */
subsystems = g_ptr_array_new ();
for (l = plugin_paths; l; l = g_list_next (l)) {
MMPlugin *plugin;
MMPlugin *plugin;
const gchar **plugin_subsystems;
guint i;
plugin = load_plugin (self, (const gchar *)(l->data));
if (!plugin)
continue;
/* Ignore plugins that don't specify subsystems */
plugin_subsystems = mm_plugin_get_allowed_subsystems (plugin);
if (!plugin_subsystems) {
mm_obj_warn (self, "plugin '%s' doesn't specify allowed subsystems: ignored",
mm_plugin_get_name (plugin));
continue;
}
/* Process generic plugin */
if (mm_plugin_is_generic (plugin)) {
if (self->priv->generic)
mm_obj_warn (self, "cannot register more than one generic plugin");
else
self->priv->generic = plugin;
if (self->priv->generic) {
mm_obj_warn (self, "plugin '%s' is generic and another one is already registered: ignored",
mm_plugin_get_name (plugin));
continue;
}
self->priv->generic = plugin;
} else
self->priv->plugins = g_list_append (self->priv->plugins, plugin);
/* Track required subsystems, avoiding duplicates in the list */
for (i = 0; plugin_subsystems[i]; i++) {
if (!g_ptr_array_find_with_equal_func (subsystems, plugin_subsystems[i], g_str_equal, NULL))
g_ptr_array_add (subsystems, g_strdup (plugin_subsystems[i]));
}
/* Register plugin whitelist rules in filter, if any */
register_plugin_whitelist_tags (self, plugin);
register_plugin_whitelist_vendor_ids (self, plugin);
@@ -1846,15 +1879,28 @@ load_plugins (MMPluginManager *self,
goto out;
}
mm_obj_dbg (self, "successfully loaded %u plugins",
g_list_length (self->priv->plugins) + !!self->priv->generic);
/* Validate required subsystems */
if (!subsystems->len) {
g_set_error (error,
MM_CORE_ERROR,
MM_CORE_ERROR_NO_PLUGINS,
"empty list of subsystems required by plugins");
goto out;
}
/* Add trailing NULL and store as GStrv */
g_ptr_array_add (subsystems, NULL);
self->priv->subsystems = (gchar **) g_ptr_array_free (subsystems, FALSE);
subsystems_str = g_strjoinv (", ", self->priv->subsystems);
mm_obj_dbg (self, "successfully loaded %u plugins registering %u subsystems: %s",
g_list_length (self->priv->plugins) + !!self->priv->generic,
g_strv_length (self->priv->subsystems), subsystems_str);
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);
/* Return TRUE if at least one plugin found */
return (self->priv->plugins || self->priv->generic);
@@ -1884,12 +1930,12 @@ mm_plugin_manager_new (const gchar *plugin_dir,
}
static void
mm_plugin_manager_init (MMPluginManager *manager)
mm_plugin_manager_init (MMPluginManager *self)
{
/* Initialize opaque pointer to private data */
manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
MM_TYPE_PLUGIN_MANAGER,
MMPluginManagerPrivate);
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
MM_TYPE_PLUGIN_MANAGER,
MMPluginManagerPrivate);
}
static void
@@ -1949,17 +1995,11 @@ dispose (GObject *object)
{
MMPluginManager *self = MM_PLUGIN_MANAGER (object);
/* Cleanup list of plugins */
if (self->priv->plugins) {
g_list_free_full (self->priv->plugins, g_object_unref);
self->priv->plugins = NULL;
}
g_list_free_full (g_steal_pointer (&self->priv->plugins), g_object_unref);
g_clear_object (&self->priv->generic);
g_free (self->priv->plugin_dir);
self->priv->plugin_dir = NULL;
g_clear_pointer (&self->priv->plugin_dir, g_free);
g_clear_object (&self->priv->filter);
g_clear_pointer (&self->priv->subsystems, g_strfreev);
G_OBJECT_CLASS (mm_plugin_manager_parent_class)->dispose (object);
}
+1
View File
@@ -65,5 +65,6 @@ MMPlugin * mm_plugin_manager_device_support_check_finish (MMPluginManager
GError **error);
MMPlugin *mm_plugin_manager_peek_plugin (MMPluginManager *self,
const gchar *plugin_name);
const gchar **mm_plugin_manager_get_subsystems (MMPluginManager *self);
#endif /* MM_PLUGIN_MANAGER_H */
+6
View File
@@ -146,6 +146,12 @@ mm_plugin_get_name (MMPlugin *self)
return self->priv->name;
}
const gchar **
mm_plugin_get_allowed_subsystems (MMPlugin *self)
{
return (const gchar **) self->priv->subsystems;
}
const gchar **
mm_plugin_get_allowed_udev_tags (MMPlugin *self)
{
+1
View File
@@ -126,6 +126,7 @@ GType mm_plugin_get_type (void);
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMPlugin, g_object_unref)
const gchar *mm_plugin_get_name (MMPlugin *self);
const gchar **mm_plugin_get_allowed_subsystems (MMPlugin *self);
const gchar **mm_plugin_get_allowed_udev_tags (MMPlugin *self);
const guint16 *mm_plugin_get_allowed_vendor_ids (MMPlugin *self);
const mm_uint16_pair *mm_plugin_get_allowed_product_ids (MMPlugin *self);