[PATCH 08/10] base-manager: process initial kernel events from an input file

Aleksander Morgado aleksander at aleksander.es
Sat Aug 6 13:03:36 UTC 2016


In order to cope with devices already available in the system when the daemon
starts, we allow loading a list of kernel events from an input text file where
the kernel events were recorded since boot.

The file will contain one line per event, e.g.:
  action=add, name=wwan0,    subsystem=net
  action=add, name=cdc-wdm2, subsystem=usbmisc
---
 src/main.c            |   1 +
 src/mm-base-manager.c | 249 +++++++++++++++++++++++++++++++++-----------------
 src/mm-base-manager.h |   2 +
 src/mm-context.c      |  21 ++++-
 src/mm-context.h      |  19 ++--
 5 files changed, 199 insertions(+), 93 deletions(-)

diff --git a/src/main.c b/src/main.c
index 5e5628c..d83baaf 100644
--- a/src/main.c
+++ b/src/main.c
@@ -87,6 +87,7 @@ bus_acquired_cb (GDBusConnection *connection,
     manager = mm_base_manager_new (connection,
                                    mm_context_get_test_plugin_dir (),
                                    !mm_context_get_no_auto_scan (),
+                                   mm_context_get_initial_kernel_events (),
                                    mm_context_get_test_enable (),
                                    &error);
     if (!manager) {
diff --git a/src/mm-base-manager.c b/src/mm-base-manager.c
index 528c5e9..72f5ffc 100644
--- a/src/mm-base-manager.c
+++ b/src/mm-base-manager.c
@@ -53,6 +53,7 @@ enum {
     PROP_AUTO_SCAN,
     PROP_ENABLE_TEST,
     PROP_PLUGIN_DIR,
+    PROP_INITIAL_KERNEL_EVENTS,
     LAST_PROP
 };
 
@@ -65,6 +66,8 @@ struct _MMBaseManagerPrivate {
     gboolean enable_test;
     /* Path to look for plugins */
     gchar *plugin_dir;
+    /* Path to the list of initial kernel events */
+    gchar *initial_kernel_events;
     /* The authorization provider */
     MMAuthProvider *authp;
     GCancellable *authp_cancellable;
@@ -311,6 +314,57 @@ device_added (MMBaseManager  *manager,
     mm_device_grab_port (device, port);
 }
 
+static gboolean
+handle_kernel_event (MMBaseManager            *self,
+                     MMKernelEventProperties  *properties,
+                     GError                  **error)
+{
+    const gchar    *action;
+    MMKernelDevice *kernel_device;
+
+    action = mm_kernel_event_properties_get_action (properties);
+    if (g_strcmp0 (action, "add") != 0 && g_strcmp0 (action, "remove") != 0) {
+        g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Invalid action");
+        return FALSE;
+    }
+
+    mm_dbg ("Kernel event reported:");
+    mm_dbg ("  action:      %s",     action);
+    if (mm_kernel_event_properties_get_subsystem (properties))
+        mm_dbg ("  subsystem:   %s", mm_kernel_event_properties_get_subsystem (properties));
+    if (mm_kernel_event_properties_get_name (properties))
+        mm_dbg ("  name:        %s", mm_kernel_event_properties_get_name (properties));
+    if (mm_kernel_event_properties_get_driver (properties))
+        mm_dbg ("  driver:      %s", mm_kernel_event_properties_get_driver (properties));
+    if (mm_kernel_event_properties_get_physdev_uid (properties))
+        mm_dbg ("  physdev-uid: %s", mm_kernel_event_properties_get_physdev_uid (properties));
+    if (mm_kernel_event_properties_get_physdev_vid (properties))
+        mm_dbg ("  physdev-vid: 0x%04X", mm_kernel_event_properties_get_physdev_vid (properties));
+    if (mm_kernel_event_properties_get_physdev_pid (properties))
+        mm_dbg ("  physdev-pid: 0x%04X", mm_kernel_event_properties_get_physdev_pid (properties));
+    if (mm_kernel_event_properties_get_candidate (properties))
+        mm_dbg ("  candidate:   yes");
+
+#if WITH_UDEV
+    kernel_device = mm_kernel_device_udev_new_from_properties (properties, error);
+#else
+    kernel_device = mm_kernel_device_generic_new (properties, error);
+#endif
+
+    if (!kernel_device)
+        return FALSE;
+
+    if (g_strcmp0 (action, "add") == 0)
+        device_added (self, kernel_device, TRUE, TRUE);
+    else if (g_strcmp0 (action, "remove") == 0)
+        device_removed (self, kernel_device);
+    else
+        g_assert_not_reached ();
+    g_object_unref (kernel_device);
+
+    return TRUE;
+}
+
 #if WITH_UDEV
 
 static void
@@ -381,63 +435,116 @@ start_device_added (MMBaseManager *self,
     g_idle_add ((GSourceFunc)start_device_added_idle, ctx);
 }
 
+static void
+process_scan (MMBaseManager *self,
+              gboolean       manual_scan)
+{
+    GList *devices, *iter;
+
+    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);
+
+    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));
+    }
+    g_list_free (devices);
+
+    devices = g_udev_client_query_by_subsystem (self->priv->udev, "usb");
+    for (iter = devices; iter; iter = g_list_next (iter)) {
+        const gchar *name;
+
+        name = g_udev_device_get_name (G_UDEV_DEVICE (iter->data));
+        if (name && g_str_has_prefix (name, "cdc-wdm"))
+            start_device_added (self, G_UDEV_DEVICE (iter->data), manual_scan);
+        g_object_unref (G_OBJECT (iter->data));
+    }
+    g_list_free (devices);
+
+    /* Newer kernels report 'usbmisc' subsystem */
+    devices = g_udev_client_query_by_subsystem (self->priv->udev, "usbmisc");
+    for (iter = devices; iter; iter = g_list_next (iter)) {
+        const gchar *name;
+
+        name = g_udev_device_get_name (G_UDEV_DEVICE (iter->data));
+        if (name && g_str_has_prefix (name, "cdc-wdm"))
+            start_device_added (self, G_UDEV_DEVICE (iter->data), manual_scan);
+        g_object_unref (G_OBJECT (iter->data));
+    }
+    g_list_free (devices);
+}
+
 #endif
 
-void
-mm_base_manager_start (MMBaseManager *manager,
-                       gboolean       manual_scan)
+static void
+process_initial_kernel_events (MMBaseManager *self)
 {
-    g_return_if_fail (manager != NULL);
-    g_return_if_fail (MM_IS_BASE_MANAGER (manager));
+    gchar *contents = NULL;
+    gchar *line;
+    GError *error = NULL;
 
-    if (!manager->priv->auto_scan && !manual_scan)
+    if (!self->priv->initial_kernel_events)
         return;
 
-#if WITH_UDEV
-    {
-        GList *devices, *iter;
+    if (!g_file_get_contents (self->priv->initial_kernel_events, &contents, NULL, &error)) {
+        g_warning ("Couldn't load initial kernel events: %s", error->message);
+        g_error_free (error);
+        return;
+    }
 
-        mm_dbg ("Starting %s device scan...", manual_scan ? "manual" : "automatic");
+    line = contents;
+    while (line) {
+        gchar *next;
 
-        devices = g_udev_client_query_by_subsystem (manager->priv->udev, "tty");
-        for (iter = devices; iter; iter = g_list_next (iter)) {
-            start_device_added (manager, G_UDEV_DEVICE (iter->data), manual_scan);
-            g_object_unref (G_OBJECT (iter->data));
+        next = strchr (line, '\n');
+        if (next) {
+            *next = '\0';
+            next++;
         }
-        g_list_free (devices);
 
-        devices = g_udev_client_query_by_subsystem (manager->priv->udev, "net");
-        for (iter = devices; iter; iter = g_list_next (iter)) {
-            start_device_added (manager, G_UDEV_DEVICE (iter->data), manual_scan);
-            g_object_unref (G_OBJECT (iter->data));
+        /* ignore empty lines */
+        if (line[0] != '\0') {
+            MMKernelEventProperties *properties;
+
+            properties = mm_kernel_event_properties_new_from_string (line, &error);
+            if (!properties) {
+                g_warning ("Couldn't parse line '%s' as initial kernel event %s", line, error->message);
+                g_clear_error (&error);
+            } else if (!handle_kernel_event (self, properties, &error)) {
+                g_warning ("Couldn't process line '%s' as initial kernel event %s", line, error->message);
+                g_clear_error (&error);
+            } else
+                g_debug ("Processed initial kernel event:' %s'", line);
         }
-        g_list_free (devices);
 
-        devices = g_udev_client_query_by_subsystem (manager->priv->udev, "usb");
-        for (iter = devices; iter; iter = g_list_next (iter)) {
-            const gchar *name;
-
-            name = g_udev_device_get_name (G_UDEV_DEVICE (iter->data));
-            if (name && g_str_has_prefix (name, "cdc-wdm"))
-                start_device_added (manager, G_UDEV_DEVICE (iter->data), manual_scan);
-            g_object_unref (G_OBJECT (iter->data));
-        }
-        g_list_free (devices);
+        line = next;
+    }
 
-        /* Newer kernels report 'usbmisc' subsystem */
-        devices = g_udev_client_query_by_subsystem (manager->priv->udev, "usbmisc");
-        for (iter = devices; iter; iter = g_list_next (iter)) {
-            const gchar *name;
+    g_free (contents);
+}
 
-            name = g_udev_device_get_name (G_UDEV_DEVICE (iter->data));
-            if (name && g_str_has_prefix (name, "cdc-wdm"))
-                start_device_added (manager, G_UDEV_DEVICE (iter->data), manual_scan);
-            g_object_unref (G_OBJECT (iter->data));
-        }
-        g_list_free (devices);
+void
+mm_base_manager_start (MMBaseManager *self,
+                       gboolean       manual_scan)
+{
+    g_return_if_fail (self != NULL);
+    g_return_if_fail (MM_IS_BASE_MANAGER (self));
 
-        mm_dbg ("Finished device scan...");
+    if (!self->priv->auto_scan && !manual_scan) {
+        /* If we have a list of initial kernel events, process it now */
+        process_initial_kernel_events (self);
+        return;
     }
+
+#if WITH_UDEV
+    mm_dbg ("Starting %s device scan...", manual_scan ? "manual" : "automatic");
+    process_scan (self, manual_scan);
+    mm_dbg ("Finished device scan...");
 #else
     mm_dbg ("Unsupported %s device scan...", manual_scan ? "manual" : "automatic");
 #endif
@@ -677,8 +784,6 @@ report_kernel_event_auth_ready (MMAuthProvider           *authp,
 {
     GError                  *error = NULL;
     MMKernelEventProperties *properties = NULL;
-    MMKernelDevice          *kernel_device;
-    const gchar             *action;
 
     if (!mm_auth_provider_authorize_finish (authp, res, &error))
         goto out;
@@ -696,45 +801,7 @@ report_kernel_event_auth_ready (MMAuthProvider           *authp,
     if (!properties)
         goto out;
 
-    action = mm_kernel_event_properties_get_action (properties);
-    if (g_strcmp0 (action, "add") != 0 && g_strcmp0 (action, "remove") != 0) {
-        error = g_error_new_literal (MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Invalid action");
-        goto out;
-    }
-
-    mm_dbg ("Kernel event reported:");
-    mm_dbg ("  action:      %s",     action);
-    if (mm_kernel_event_properties_get_subsystem (properties))
-        mm_dbg ("  subsystem:   %s", mm_kernel_event_properties_get_subsystem (properties));
-    if (mm_kernel_event_properties_get_name (properties))
-        mm_dbg ("  name:        %s", mm_kernel_event_properties_get_name (properties));
-    if (mm_kernel_event_properties_get_driver (properties))
-        mm_dbg ("  driver:      %s", mm_kernel_event_properties_get_driver (properties));
-    if (mm_kernel_event_properties_get_physdev_uid (properties))
-        mm_dbg ("  physdev-uid: %s", mm_kernel_event_properties_get_physdev_uid (properties));
-    if (mm_kernel_event_properties_get_physdev_vid (properties))
-        mm_dbg ("  physdev-vid: 0x%04X", mm_kernel_event_properties_get_physdev_vid (properties));
-    if (mm_kernel_event_properties_get_physdev_pid (properties))
-        mm_dbg ("  physdev-pid: 0x%04X", mm_kernel_event_properties_get_physdev_pid (properties));
-    if (mm_kernel_event_properties_get_candidate (properties))
-        mm_dbg ("  candidate:   yes");
-
-#if WITH_UDEV
-    kernel_device = mm_kernel_device_udev_new_from_properties (properties, &error);
-#else
-    kernel_device = mm_kernel_device_generic_new (properties, &error);
-#endif
-
-    if (!kernel_device)
-        goto out;
-
-    if (g_strcmp0 (action, "add") == 0)
-        device_added (ctx->self, kernel_device, TRUE, TRUE);
-    else if (g_strcmp0 (action, "remove") == 0)
-        device_removed (ctx->self, kernel_device);
-    else
-        g_assert_not_reached ();
-    g_object_unref (kernel_device);
+    handle_kernel_event (ctx->self, properties, &error);
 
 out:
     if (error)
@@ -840,6 +907,7 @@ MMBaseManager *
 mm_base_manager_new (GDBusConnection *connection,
                      const gchar *plugin_dir,
                      gboolean auto_scan,
+                     const gchar *initial_kernel_events,
                      gboolean enable_test,
                      GError **error)
 {
@@ -851,6 +919,7 @@ mm_base_manager_new (GDBusConnection *connection,
                            MM_BASE_MANAGER_CONNECTION, connection,
                            MM_BASE_MANAGER_PLUGIN_DIR, plugin_dir,
                            MM_BASE_MANAGER_AUTO_SCAN, auto_scan,
+                           MM_BASE_MANAGER_INITIAL_KERNEL_EVENTS, initial_kernel_events,
                            MM_BASE_MANAGER_ENABLE_TEST, enable_test,
                            NULL);
 }
@@ -896,6 +965,10 @@ set_property (GObject *object,
         g_free (priv->plugin_dir);
         priv->plugin_dir = g_value_dup_string (value);
         break;
+    case PROP_INITIAL_KERNEL_EVENTS:
+        g_free (priv->initial_kernel_events);
+        priv->initial_kernel_events = g_value_dup_string (value);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         break;
@@ -923,6 +996,9 @@ get_property (GObject *object,
     case PROP_PLUGIN_DIR:
         g_value_set_string (value, priv->plugin_dir);
         break;
+    case PROP_INITIAL_KERNEL_EVENTS:
+        g_value_set_string (value, priv->initial_kernel_events);
+        break;
     default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         break;
@@ -1031,6 +1107,7 @@ finalize (GObject *object)
 {
     MMBaseManagerPrivate *priv = MM_BASE_MANAGER (object)->priv;
 
+    g_free (priv->initial_kernel_events);
     g_free (priv->plugin_dir);
 
     g_hash_table_destroy (priv->devices);
@@ -1112,4 +1189,12 @@ mm_base_manager_class_init (MMBaseManagerClass *manager_class)
                               "Where to look for plugins",
                               NULL,
                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+    g_object_class_install_property
+        (object_class, PROP_INITIAL_KERNEL_EVENTS,
+         g_param_spec_string (MM_BASE_MANAGER_INITIAL_KERNEL_EVENTS,
+                              "Initial kernel events",
+                              "Path to a file with the list of initial kernel events",
+                              NULL,
+                              G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
diff --git a/src/mm-base-manager.h b/src/mm-base-manager.h
index 43e7cae..56b3016 100644
--- a/src/mm-base-manager.h
+++ b/src/mm-base-manager.h
@@ -34,6 +34,7 @@
 #define MM_BASE_MANAGER_AUTO_SCAN   "auto-scan"   /* Construct-only */
 #define MM_BASE_MANAGER_ENABLE_TEST "enable-test" /* Construct-only */
 #define MM_BASE_MANAGER_PLUGIN_DIR  "plugin-dir"  /* Construct-only */
+#define MM_BASE_MANAGER_INITIAL_KERNEL_EVENTS "initial-kernel-events" /* Construct-only */
 
 typedef struct _MMBaseManagerPrivate MMBaseManagerPrivate;
 
@@ -51,6 +52,7 @@ GType mm_base_manager_get_type (void);
 MMBaseManager   *mm_base_manager_new         (GDBusConnection *bus,
                                               const gchar *plugin_dir,
                                               gboolean auto_scan,
+                                              const gchar *initial_kernel_events,
                                               gboolean enable_test,
                                               GError **error);
 
diff --git a/src/mm-context.c b/src/mm-context.c
index b6af1a3..9c0b3d0 100644
--- a/src/mm-context.c
+++ b/src/mm-context.c
@@ -27,7 +27,7 @@ static const gchar *log_level;
 static const gchar *log_file;
 static gboolean show_ts;
 static gboolean rel_ts;
-
+static const gchar *initial_kernel_events;
 #if WITH_UDEV
 static gboolean no_auto_scan;
 #endif
@@ -41,6 +41,9 @@ static const GOptionEntry entries[] = {
     { "relative-timestamps", 0, 0, G_OPTION_ARG_NONE, &rel_ts, "Use relative timestamps (from MM start)", NULL },
 #if WITH_UDEV
     { "no-auto-scan", 0, 0, G_OPTION_ARG_NONE, &no_auto_scan, "Don't auto-scan looking for devices", NULL },
+    { "initial-kernel-events", 0, 0, G_OPTION_ARG_FILENAME, &initial_kernel_events, "Path to initial kernel events file (requires --no-auto-scan)", "[PATH]" },
+#else
+    { "initial-kernel-events", 0, 0, G_OPTION_ARG_FILENAME, &initial_kernel_events, "Path to initial kernel events file", "[PATH]" },
 #endif
     { NULL }
 };
@@ -75,6 +78,12 @@ mm_context_get_relative_timestamps (void)
     return rel_ts;
 }
 
+const gchar *
+mm_context_get_initial_kernel_events (void)
+{
+    return initial_kernel_events;
+}
+
 gboolean
 mm_context_get_no_auto_scan (void)
 {
@@ -159,7 +168,7 @@ mm_context_init (gint argc,
     g_option_context_add_group (ctx, test_get_option_group ());
 
     if (!g_option_context_parse (ctx, &argc, &argv, &error)) {
-        g_warning ("%s\n", error->message);
+        g_warning ("error: %s", error->message);
         g_error_free (error);
         exit (1);
     }
@@ -176,4 +185,12 @@ mm_context_init (gint argc,
     /* If just version requested, print and exit */
     if (version_flag)
         print_version ();
+
+    /* Initial kernel events processing may only be used if autoscan is disabled */
+#if WITH_UDEV
+    if (!no_auto_scan && initial_kernel_events) {
+        g_warning ("error: --initial-kernel-events must be used only if --no-auto-scan is also used");
+        exit (1);
+    }
+#endif
 }
diff --git a/src/mm-context.h b/src/mm-context.h
index b2ba07f..63a8ec4 100644
--- a/src/mm-context.h
+++ b/src/mm-context.h
@@ -26,16 +26,17 @@
 void mm_context_init (gint argc,
                       gchar **argv);
 
-gboolean     mm_context_get_debug               (void);
-const gchar *mm_context_get_log_level           (void);
-const gchar *mm_context_get_log_file            (void);
-gboolean     mm_context_get_timestamps          (void);
-gboolean     mm_context_get_relative_timestamps (void);
-gboolean     mm_context_get_no_auto_scan        (void);
+gboolean     mm_context_get_debug                 (void);
+const gchar *mm_context_get_log_level             (void);
+const gchar *mm_context_get_log_file              (void);
+gboolean     mm_context_get_timestamps            (void);
+gboolean     mm_context_get_relative_timestamps   (void);
+const gchar *mm_context_get_initial_kernel_events (void);
+gboolean     mm_context_get_no_auto_scan          (void);
 
 /* Testing support */
-gboolean     mm_context_get_test_session        (void);
-gboolean     mm_context_get_test_enable         (void);
-const gchar *mm_context_get_test_plugin_dir     (void);
+gboolean     mm_context_get_test_session    (void);
+gboolean     mm_context_get_test_enable     (void);
+const gchar *mm_context_get_test_plugin_dir (void);
 
 #endif /* MM_CONTEXT_H */
-- 
2.9.0



More information about the ModemManager-devel mailing list