diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2016-09-28 18:49:08 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2016-09-29 15:43:05 +0200 |
commit | c4a584416ab4af81b6cae653625c78f9158de1e6 (patch) | |
tree | b76526a1b1eed1abc11a4a740b4e7c55261be54d /libmm-glib/mm-kernel-event-properties.c | |
parent | aa4577dfb9b5a7863a4939ec2409eae392e2fc0c (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.c | 454 |
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; +} |