aboutsummaryrefslogtreecommitdiff
path: root/libmm-glib/mm-kernel-event-properties.c
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2016-09-28 18:49:08 +0200
committerAleksander Morgado <aleksander@aleksander.es>2016-09-29 15:43:05 +0200
commitc4a584416ab4af81b6cae653625c78f9158de1e6 (patch)
treeb76526a1b1eed1abc11a4a740b4e7c55261be54d /libmm-glib/mm-kernel-event-properties.c
parentaa4577dfb9b5a7863a4939ec2409eae392e2fc0c (diff)
core: allow disabling auto-scan and notifying ports one by one via API
This commit enables a new core ModemManager daemon option, so that automatic detection of available modems is totally disabled: '--no-auto-scan'. Note that this option also replaces the previously used '--test-no-auto-scan' option, which was only used during tests. Along with the new ModemManager option, a new ReportKernelEvent() method in the API is defined, which allows notifying the daemon of which interfaces it should be accessing, as well as the main details of each interface. The only mandatory parameters in the new method are 'action' (add/remove), 'name' (the name of the interface) and 'subsystem' (the subsystem of the interface). The mmcli tool has support for using the new api method via several new options: * The '--report-kernel-event' option allows specifying device ports one by one, and is a direct mapping of the ReportKernelEvent() method: $ sudo mmcli --report-kernel-event="action=add,name=wwan0,subsystem=net" $ sudo mmcli --report-kernel-event="action=add,name=cdc-wdm0,subsystem=usbmisc" * The '--report-kernel-event-auto-scan' option uses udev monitoring to notify events automatically to the daemon. This allows to operate in a way equivalent to the default daemon operation (with implicit auto-scan). Worth noting that the ReportKernelEvent() method is only usable when '--no-auto-scan' is explicitly used in the daemon. An error will be reported if the method is tried while standard udev monitoring is enabled (implicit if auto scan isn't explicitly disabled in the daemon). If mmcli is going to be used only to report 'real time' events, an optional '--initial-kernel-events=[PATH]' may be given in the ModemManager call to automatically process a set of port kernel events one by one on boot. The file may e.g. contain: action=add,name=wwan0,subsystem=net action=add,name=cdc-wdm0,subsystem=usbmisc
Diffstat (limited to 'libmm-glib/mm-kernel-event-properties.c')
-rw-r--r--libmm-glib/mm-kernel-event-properties.c454
1 files changed, 454 insertions, 0 deletions
diff --git a/libmm-glib/mm-kernel-event-properties.c b/libmm-glib/mm-kernel-event-properties.c
new file mode 100644
index 00000000..6782fbf7
--- /dev/null
+++ b/libmm-glib/mm-kernel-event-properties.c
@@ -0,0 +1,454 @@
+/* -*- 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) 2016 Velocloud, Inc.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include "mm-errors-types.h"
+#include "mm-enums-types.h"
+#include "mm-common-helpers.h"
+#include "mm-kernel-event-properties.h"
+
+/**
+ * SECTION: mm-kernel-event-properties
+ * @title: MMKernelEventProperties
+ * @short_description: Helper object to handle kernel event properties.
+ *
+ * The #MMKernelEventProperties is an object handling the properties to be set
+ * in reported kernel events.
+ *
+ * This object is created by the user and passed to ModemManager with either
+ * mm_manager_report_kernel_event() or mm_manager_report_kernel_event_sync().
+ */
+
+G_DEFINE_TYPE (MMKernelEventProperties, mm_kernel_event_properties, G_TYPE_OBJECT)
+
+#define PROPERTY_ACTION "action"
+#define PROPERTY_SUBSYSTEM "subsystem"
+#define PROPERTY_NAME "name"
+#define PROPERTY_UID "uid"
+
+struct _MMKernelEventPropertiesPrivate {
+ gchar *action;
+ gchar *subsystem;
+ gchar *name;
+ gchar *uid;
+};
+
+/*****************************************************************************/
+
+/**
+ * mm_kernel_event_properties_set_action:
+ * @self: A #MMKernelEventProperties.
+ * @action: The action to set.
+ *
+ * Sets the action.
+ */
+void
+mm_kernel_event_properties_set_action (MMKernelEventProperties *self,
+ const gchar *action)
+{
+ g_return_if_fail (MM_IS_KERNEL_EVENT_PROPERTIES (self));
+
+ g_free (self->priv->action);
+ self->priv->action = g_strdup (action);
+}
+
+/**
+ * mm_kernel_event_properties_get_action:
+ * @self: A #MMKernelEventProperties.
+ *
+ * Gets the action.
+ *
+ * Returns: (transfer none): The action. Do not free the returned value, it is owned by @self.
+ */
+const gchar *
+mm_kernel_event_properties_get_action (MMKernelEventProperties *self)
+{
+ g_return_val_if_fail (MM_IS_KERNEL_EVENT_PROPERTIES (self), NULL);
+
+ return self->priv->action;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_kernel_event_properties_set_subsystem:
+ * @self: A #MMKernelEventProperties.
+ * @subsystem: The subsystem to set.
+ *
+ * Sets the subsystem.
+ */
+void
+mm_kernel_event_properties_set_subsystem (MMKernelEventProperties *self,
+ const gchar *subsystem)
+{
+ g_return_if_fail (MM_IS_KERNEL_EVENT_PROPERTIES (self));
+
+ g_free (self->priv->subsystem);
+ self->priv->subsystem = g_strdup (subsystem);
+}
+
+/**
+ * mm_kernel_event_properties_get_subsystem:
+ * @self: A #MMKernelEventProperties.
+ *
+ * Gets the subsystem.
+ *
+ * Returns: (transfer none): The subsystem. Do not free the returned value, it is owned by @self.
+ */
+const gchar *
+mm_kernel_event_properties_get_subsystem (MMKernelEventProperties *self)
+{
+ g_return_val_if_fail (MM_IS_KERNEL_EVENT_PROPERTIES (self), NULL);
+
+ return self->priv->subsystem;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_kernel_event_properties_set_name:
+ * @self: A #MMKernelEventProperties.
+ * @name: The name to set.
+ *
+ * Sets the name.
+ */
+void
+mm_kernel_event_properties_set_name (MMKernelEventProperties *self,
+ const gchar *name)
+{
+ g_return_if_fail (MM_IS_KERNEL_EVENT_PROPERTIES (self));
+
+ g_free (self->priv->name);
+ self->priv->name = g_strdup (name);
+}
+
+/**
+ * mm_kernel_event_properties_get_name:
+ * @self: A #MMKernelEventProperties.
+ *
+ * Gets the name.
+ *
+ * Returns: (transfer none): The name. Do not free the returned value, it is owned by @self.
+ */
+const gchar *
+mm_kernel_event_properties_get_name (MMKernelEventProperties *self)
+{
+ g_return_val_if_fail (MM_IS_KERNEL_EVENT_PROPERTIES (self), NULL);
+
+ return self->priv->name;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_kernel_event_properties_set_uid:
+ * @self: A #MMKernelEventProperties.
+ * @uid: The uid to set.
+ *
+ * Sets the unique ID of the physical device.
+ */
+void
+mm_kernel_event_properties_set_uid (MMKernelEventProperties *self,
+ const gchar *uid)
+{
+ g_return_if_fail (MM_IS_KERNEL_EVENT_PROPERTIES (self));
+
+ g_free (self->priv->uid);
+ self->priv->uid = g_strdup (uid);
+}
+
+/**
+ * mm_kernel_event_properties_get_uid:
+ * @self: A #MMKernelEventProperties.
+ *
+ * Gets the unique ID of the physical device.
+ *
+ * Returns: (transfer none): The uid. Do not free the returned value, it is owned by @self.
+ */
+const gchar *
+mm_kernel_event_properties_get_uid (MMKernelEventProperties *self)
+{
+ g_return_val_if_fail (MM_IS_KERNEL_EVENT_PROPERTIES (self), NULL);
+
+ return self->priv->uid;
+}
+
+/*****************************************************************************/
+
+GVariant *
+mm_kernel_event_properties_get_dictionary (MMKernelEventProperties *self)
+{
+ GVariantBuilder builder;
+
+ /* We do allow NULL */
+ if (!self)
+ return NULL;
+
+ g_return_val_if_fail (MM_IS_KERNEL_EVENT_PROPERTIES (self), NULL);
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ if (self->priv->action)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_ACTION,
+ g_variant_new_string (self->priv->action));
+
+ if (self->priv->subsystem)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_SUBSYSTEM,
+ g_variant_new_string (self->priv->subsystem));
+
+ if (self->priv->name)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_NAME,
+ g_variant_new_string (self->priv->name));
+
+ if (self->priv->uid)
+ g_variant_builder_add (&builder,
+ "{sv}",
+ PROPERTY_UID,
+ g_variant_new_string (self->priv->uid));
+
+ return g_variant_ref_sink (g_variant_builder_end (&builder));
+}
+
+/*****************************************************************************/
+
+static gboolean
+consume_string (MMKernelEventProperties *self,
+ const gchar *key,
+ const gchar *value,
+ GError **error)
+{
+ if (g_str_equal (key, PROPERTY_ACTION))
+ mm_kernel_event_properties_set_action (self, value);
+ else if (g_str_equal (key, PROPERTY_SUBSYSTEM))
+ mm_kernel_event_properties_set_subsystem (self, value);
+ else if (g_str_equal (key, PROPERTY_NAME))
+ mm_kernel_event_properties_set_name (self, value);
+ else if (g_str_equal (key, PROPERTY_UID))
+ mm_kernel_event_properties_set_uid (self, value);
+ else {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid properties string, unexpected key '%s'",
+ key);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+typedef struct {
+ MMKernelEventProperties *properties;
+ GError *error;
+} ParseKeyValueContext;
+
+static gboolean
+key_value_foreach (const gchar *key,
+ const gchar *value,
+ ParseKeyValueContext *ctx)
+{
+ return consume_string (ctx->properties,
+ key,
+ value,
+ &ctx->error);
+}
+
+MMKernelEventProperties *
+mm_kernel_event_properties_new_from_string (const gchar *str,
+ GError **error)
+{
+ ParseKeyValueContext ctx;
+
+ ctx.properties = mm_kernel_event_properties_new ();
+ ctx.error = NULL;
+
+ mm_common_parse_key_value_string (str,
+ &ctx.error,
+ (MMParseKeyValueForeachFn) key_value_foreach,
+ &ctx);
+
+ /* If error, destroy the object */
+ if (ctx.error) {
+ g_propagate_error (error, ctx.error);
+ g_object_unref (ctx.properties);
+ ctx.properties = NULL;
+ }
+
+ return ctx.properties;
+}
+
+/*****************************************************************************/
+
+static gboolean
+consume_variant (MMKernelEventProperties *properties,
+ const gchar *key,
+ GVariant *value,
+ GError **error)
+{
+ if (g_str_equal (key, PROPERTY_ACTION))
+ mm_kernel_event_properties_set_action (
+ properties,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_SUBSYSTEM))
+ mm_kernel_event_properties_set_subsystem (
+ properties,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_NAME))
+ mm_kernel_event_properties_set_name (
+ properties,
+ g_variant_get_string (value, NULL));
+ else if (g_str_equal (key, PROPERTY_UID))
+ mm_kernel_event_properties_set_uid (
+ properties,
+ g_variant_get_string (value, NULL));
+ else {
+ /* Set error */
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid properties dictionary, unexpected key '%s'",
+ key);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+MMKernelEventProperties *
+mm_kernel_event_properties_new_from_dictionary (GVariant *dictionary,
+ GError **error)
+{
+ GError *inner_error = NULL;
+ GVariantIter iter;
+ gchar *key;
+ GVariant *value;
+ MMKernelEventProperties *properties;
+
+ properties = mm_kernel_event_properties_new ();
+ if (!dictionary)
+ return properties;
+
+ if (!g_variant_is_of_type (dictionary, G_VARIANT_TYPE ("a{sv}"))) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Cannot create kernel event properties from dictionary: "
+ "invalid variant type received");
+ g_object_unref (properties);
+ return NULL;
+ }
+
+ g_variant_iter_init (&iter, dictionary);
+ while (!inner_error &&
+ g_variant_iter_next (&iter, "{sv}", &key, &value)) {
+ consume_variant (properties,
+ key,
+ value,
+ &inner_error);
+ g_free (key);
+ g_variant_unref (value);
+ }
+
+ /* If error, destroy the object */
+ if (inner_error) {
+ g_propagate_error (error, inner_error);
+ g_object_unref (properties);
+ properties = NULL;
+ }
+
+ return properties;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_kernel_event_properties_dup:
+ * @orig: a #MMKernelEventProperties
+ *
+ * Returns a copy of @orig.
+ *
+ * Returns: (transfer full): a #MMKernelEventProperties
+ */
+MMKernelEventProperties *
+mm_kernel_event_properties_dup (MMKernelEventProperties *orig)
+{
+ GVariant *dict;
+ MMKernelEventProperties *copy;
+ GError *error = NULL;
+
+ g_return_val_if_fail (MM_IS_KERNEL_EVENT_PROPERTIES (orig), NULL);
+
+ dict = mm_kernel_event_properties_get_dictionary (orig);
+ copy = mm_kernel_event_properties_new_from_dictionary (dict, &error);
+ g_assert_no_error (error);
+ g_variant_unref (dict);
+
+ return copy;
+}
+
+/*****************************************************************************/
+
+/**
+ * mm_kernel_event_properties_new:
+ *
+ * Creates a new empty #MMKernelEventProperties.
+ *
+ * Returns: (transfer full): a #MMKernelEventProperties. The returned value should be freed with g_object_unref().
+ */
+MMKernelEventProperties *
+mm_kernel_event_properties_new (void)
+{
+ return (MM_KERNEL_EVENT_PROPERTIES (g_object_new (MM_TYPE_KERNEL_EVENT_PROPERTIES, NULL)));
+}
+
+static void
+mm_kernel_event_properties_init (MMKernelEventProperties *self)
+{
+ self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
+ MM_TYPE_KERNEL_EVENT_PROPERTIES,
+ MMKernelEventPropertiesPrivate);
+}
+
+static void
+finalize (GObject *object)
+{
+ MMKernelEventProperties *self = MM_KERNEL_EVENT_PROPERTIES (object);
+
+ g_free (self->priv->action);
+ g_free (self->priv->subsystem);
+ g_free (self->priv->name);
+ g_free (self->priv->uid);
+
+ G_OBJECT_CLASS (mm_kernel_event_properties_parent_class)->finalize (object);
+}
+
+static void
+mm_kernel_event_properties_class_init (MMKernelEventPropertiesClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (object_class, sizeof (MMKernelEventPropertiesPrivate));
+
+ object_class->finalize = finalize;
+}