[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