aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cli/Makefile.am2
-rw-r--r--cli/mmcli-manager.c148
-rw-r--r--data/tests/org.freedesktop.ModemManager1.service.in2
-rw-r--r--docs/reference/libmm-glib/libmm-glib-docs.xml1
-rw-r--r--docs/reference/libmm-glib/libmm-glib-sections.txt38
-rw-r--r--introspection/org.freedesktop.ModemManager1.xml74
-rw-r--r--libmm-glib/Makefile.am3
-rw-r--r--libmm-glib/libmm-glib.h1
-rw-r--r--libmm-glib/mm-kernel-event-properties.c454
-rw-r--r--libmm-glib/mm-kernel-event-properties.h97
-rw-r--r--libmm-glib/mm-manager.c124
-rw-r--r--libmm-glib/mm-manager.h14
-rw-r--r--src/kerneldevice/mm-kernel-device-udev.c221
-rw-r--r--src/kerneldevice/mm-kernel-device-udev.h9
-rw-r--r--src/main.c3
-rw-r--r--src/mm-base-manager.c266
-rw-r--r--src/mm-base-manager.h2
-rw-r--r--src/mm-context.c32
-rw-r--r--src/mm-context.h19
19 files changed, 1437 insertions, 73 deletions
diff --git a/cli/Makefile.am b/cli/Makefile.am
index d2573dbc..7915f289 100644
--- a/cli/Makefile.am
+++ b/cli/Makefile.am
@@ -2,6 +2,7 @@ bin_PROGRAMS = mmcli
mmcli_CPPFLAGS = \
$(MMCLI_CFLAGS) \
+ $(GUDEV_CFLAGS) \
-I$(top_srcdir) \
-I$(top_srcdir)/include \
-I$(top_builddir)/include \
@@ -34,6 +35,7 @@ mmcli_SOURCES = \
$(NULL)
mmcli_LDADD = \
+ $(GUDEV_LIBS) \
$(MMCLI_LIBS) \
$(top_builddir)/libmm-glib/libmm-glib.la \
$(NULL)
diff --git a/cli/mmcli-manager.c b/cli/mmcli-manager.c
index 9960412e..4e078f17 100644
--- a/cli/mmcli-manager.c
+++ b/cli/mmcli-manager.c
@@ -15,8 +15,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
- * Copyright (C) 2011 Aleksander Morgado <aleksander@gnu.org>
* Copyright (C) 2011 Google, Inc.
+ * Copyright (C) 2011-2016 Aleksander Morgado <aleksander@aleksander.es>
*/
#include "config.h"
@@ -29,6 +29,8 @@
#include <glib.h>
#include <gio/gio.h>
+#include <gudev/gudev.h>
+
#define _LIBMM_INSIDE_MMCLI
#include "libmm-glib.h"
@@ -39,6 +41,7 @@
typedef struct {
MMManager *manager;
GCancellable *cancellable;
+ GUdevClient *udev;
} Context;
static Context *ctx;
@@ -47,6 +50,8 @@ static gboolean list_modems_flag;
static gboolean monitor_modems_flag;
static gboolean scan_modems_flag;
static gchar *set_logging_str;
+static gchar *report_kernel_event_str;
+static gboolean report_kernel_event_auto_scan;
static GOptionEntry entries[] = {
{ "set-logging", 'G', 0, G_OPTION_ARG_STRING, &set_logging_str,
@@ -65,6 +70,14 @@ static GOptionEntry entries[] = {
"Request to re-scan looking for modems",
NULL
},
+ { "report-kernel-event", 'K', 0, G_OPTION_ARG_STRING, &report_kernel_event_str,
+ "Report kernel event",
+ "[\"key=value,...\"]"
+ },
+ { "report-kernel-event-auto-scan", 0, 0, G_OPTION_ARG_NONE, &report_kernel_event_auto_scan,
+ "Automatically report kernel events based on udev notifications",
+ NULL
+ },
{ NULL }
};
@@ -96,7 +109,9 @@ mmcli_manager_options_enabled (void)
n_actions = (list_modems_flag +
monitor_modems_flag +
scan_modems_flag +
- !!set_logging_str);
+ !!set_logging_str +
+ !!report_kernel_event_str +
+ report_kernel_event_auto_scan);
if (n_actions > 1) {
g_printerr ("error: too many manager actions requested\n");
@@ -106,6 +121,9 @@ mmcli_manager_options_enabled (void)
if (monitor_modems_flag)
mmcli_force_async_operation ();
+ if (report_kernel_event_auto_scan)
+ mmcli_force_async_operation ();
+
checked = TRUE;
return !!n_actions;
}
@@ -116,6 +134,8 @@ context_free (Context *ctx)
if (!ctx)
return;
+ if (ctx->udev)
+ g_object_unref (ctx->udev);
if (ctx->manager)
g_object_unref (ctx->manager);
if (ctx->cancellable)
@@ -130,6 +150,47 @@ mmcli_manager_shutdown (void)
}
static void
+report_kernel_event_process_reply (gboolean result,
+ const GError *error)
+{
+ if (!result) {
+ g_printerr ("error: couldn't report kernel event: '%s'\n",
+ error ? error->message : "unknown error");
+ exit (EXIT_FAILURE);
+ }
+
+ g_print ("successfully reported kernel event\n");
+}
+
+static void
+report_kernel_event_ready (MMManager *manager,
+ GAsyncResult *result)
+{
+ gboolean operation_result;
+ GError *error = NULL;
+
+ operation_result = mm_manager_report_kernel_event_finish (manager, result, &error);
+ report_kernel_event_process_reply (operation_result, error);
+
+ mmcli_async_operation_done ();
+}
+
+static MMKernelEventProperties *
+build_kernel_event_properties_from_input (const gchar *properties_string)
+{
+ GError *error = NULL;
+ MMKernelEventProperties *properties;
+
+ properties = mm_kernel_event_properties_new_from_string (properties_string, &error);
+ if (!properties) {
+ g_printerr ("error: cannot parse properties string: '%s'\n", error->message);
+ exit (EXIT_FAILURE);
+ }
+
+ return properties;
+}
+
+static void
set_logging_process_reply (gboolean result,
const GError *error)
{
@@ -248,6 +309,22 @@ cancelled (GCancellable *cancellable)
}
static void
+handle_uevent (GUdevClient *client,
+ const char *action,
+ GUdevDevice *device,
+ gpointer none)
+{
+ MMKernelEventProperties *properties;
+
+ properties = mm_kernel_event_properties_new ();
+ mm_kernel_event_properties_set_action (properties, action);
+ mm_kernel_event_properties_set_subsystem (properties, g_udev_device_get_subsystem (device));
+ mm_kernel_event_properties_set_name (properties, g_udev_device_get_name (device));
+ mm_manager_report_kernel_event (ctx->manager, properties, NULL, NULL, NULL);
+ g_object_unref (properties);
+}
+
+static void
get_manager_ready (GObject *source,
GAsyncResult *result,
gpointer none)
@@ -276,6 +353,54 @@ get_manager_ready (GObject *source,
return;
}
+ /* Request to report kernel event? */
+ if (report_kernel_event_str) {
+ MMKernelEventProperties *properties;
+
+ properties = build_kernel_event_properties_from_input (report_kernel_event_str);
+ mm_manager_report_kernel_event (ctx->manager,
+ properties,
+ ctx->cancellable,
+ (GAsyncReadyCallback)report_kernel_event_ready,
+ NULL);
+ g_object_unref (properties);
+ return;
+ }
+
+ if (report_kernel_event_auto_scan) {
+ const gchar *subsys[] = { "tty", "usbmisc", "net", NULL };
+ guint i;
+
+ ctx->udev = g_udev_client_new (subsys);
+ g_signal_connect (ctx->udev, "uevent", G_CALLBACK (handle_uevent), NULL);
+
+ for (i = 0; subsys[i]; i++) {
+ GList *list, *iter;
+
+ list = g_udev_client_query_by_subsystem (ctx->udev, subsys[i]);
+ for (iter = list; iter; iter = g_list_next (iter)) {
+ MMKernelEventProperties *properties;
+ GUdevDevice *device;
+
+ device = G_UDEV_DEVICE (iter->data);
+ properties = mm_kernel_event_properties_new ();
+ mm_kernel_event_properties_set_action (properties, "add");
+ mm_kernel_event_properties_set_subsystem (properties, subsys[i]);
+ mm_kernel_event_properties_set_name (properties, g_udev_device_get_name (device));
+ mm_manager_report_kernel_event (ctx->manager, properties, NULL, NULL, NULL);
+ g_object_unref (properties);
+ }
+ g_list_free_full (list, (GDestroyNotify) g_object_unref);
+ }
+
+ /* If we get cancelled, operation done */
+ g_cancellable_connect (ctx->cancellable,
+ G_CALLBACK (cancelled),
+ NULL,
+ NULL);
+ return;
+ }
+
/* Request to monitor modems? */
if (monitor_modems_flag) {
g_signal_connect (ctx->manager,
@@ -332,6 +457,11 @@ mmcli_manager_run_synchronous (GDBusConnection *connection)
exit (EXIT_FAILURE);
}
+ if (report_kernel_event_auto_scan) {
+ g_printerr ("error: monitoring udev events cannot be done synchronously\n");
+ exit (EXIT_FAILURE);
+ }
+
/* Initialize context */
ctx = g_new0 (Context, 1);
ctx->manager = mmcli_get_manager_sync (connection);
@@ -362,6 +492,20 @@ mmcli_manager_run_synchronous (GDBusConnection *connection)
return;
}
+ /* Request to report kernel event? */
+ if (report_kernel_event_str) {
+ MMKernelEventProperties *properties;
+ gboolean result;
+
+ properties = build_kernel_event_properties_from_input (report_kernel_event_str);
+ result = mm_manager_report_kernel_event_sync (ctx->manager,
+ properties,
+ NULL,
+ &error);
+ report_kernel_event_process_reply (result, error);
+ return;
+ }
+
/* Request to list modems? */
if (list_modems_flag) {
list_current_modems (ctx->manager);
diff --git a/data/tests/org.freedesktop.ModemManager1.service.in b/data/tests/org.freedesktop.ModemManager1.service.in
index ee8bdead..d7c1a007 100644
--- a/data/tests/org.freedesktop.ModemManager1.service.in
+++ b/data/tests/org.freedesktop.ModemManager1.service.in
@@ -2,4 +2,4 @@
[D-BUS Service]
Name=org.freedesktop.ModemManager1
-Exec=@abs_top_builddir@/src/ModemManager --test-session --test-no-auto-scan --test-enable --test-plugin-dir="@abs_top_builddir@/plugins/.libs" --debug
+Exec=@abs_top_builddir@/src/ModemManager --test-session --no-auto-scan --test-enable --test-plugin-dir="@abs_top_builddir@/plugins/.libs" --debug
diff --git a/docs/reference/libmm-glib/libmm-glib-docs.xml b/docs/reference/libmm-glib/libmm-glib-docs.xml
index 4e1d7fec..f611b72d 100644
--- a/docs/reference/libmm-glib/libmm-glib-docs.xml
+++ b/docs/reference/libmm-glib/libmm-glib-docs.xml
@@ -72,6 +72,7 @@
<chapter>
<title>The Manager object</title>
<xi:include href="xml/mm-manager.xml"/>
+ <xi:include href="xml/mm-kernel-event-properties.xml"/>
</chapter>
<chapter>
diff --git a/docs/reference/libmm-glib/libmm-glib-sections.txt b/docs/reference/libmm-glib/libmm-glib-sections.txt
index 27a98cda..250ae712 100644
--- a/docs/reference/libmm-glib/libmm-glib-sections.txt
+++ b/docs/reference/libmm-glib/libmm-glib-sections.txt
@@ -20,6 +20,9 @@ mm_manager_scan_devices_sync
mm_manager_set_logging
mm_manager_set_logging_finish
mm_manager_set_logging_sync
+mm_manager_report_kernel_event
+mm_manager_report_kernel_event_finish
+mm_manager_report_kernel_event_sync
<SUBSECTION Standard>
MMManagerClass
MMManagerPrivate
@@ -33,6 +36,37 @@ mm_manager_get_type
</SECTION>
<SECTION>
+<FILE>mm-kernel-event-properties</FILE>
+<TITLE>MMKernelEventProperties</TITLE>
+MMKernelEventProperties
+<SUBSECTION Methods>
+mm_kernel_event_properties_new
+mm_kernel_event_properties_get_action
+mm_kernel_event_properties_set_action
+mm_kernel_event_properties_get_name
+mm_kernel_event_properties_set_name
+mm_kernel_event_properties_get_subsystem
+mm_kernel_event_properties_set_subsystem
+mm_kernel_event_properties_get_uid
+mm_kernel_event_properties_set_uid
+<SUBSECTION Private>
+mm_kernel_event_properties_new_from_string
+mm_kernel_event_properties_new_from_dictionary
+mm_kernel_event_properties_dup
+mm_kernel_event_properties_get_dictionary
+<SUBSECTION Standard>
+MMKernelEventPropertiesClass
+MMKernelEventPropertiesPrivate
+MM_KERNEL_EVENT_PROPERTIES
+MM_KERNEL_EVENT_PROPERTIES_CLASS
+MM_KERNEL_EVENT_PROPERTIES_GET_CLASS
+MM_IS_KERNEL_EVENT_PROPERTIES
+MM_IS_KERNEL_EVENT_PROPERTIES_CLASS
+MM_TYPE_KERNEL_EVENT_PROPERTIES
+mm_kernel_event_properties_get_type
+</SECTION>
+
+<SECTION>
<FILE>mm-object</FILE>
<TITLE>MMObject</TITLE>
MMObject
@@ -1555,10 +1589,14 @@ mm_gdbus_org_freedesktop_modem_manager1_call_scan_devices_sync
mm_gdbus_org_freedesktop_modem_manager1_call_set_logging
mm_gdbus_org_freedesktop_modem_manager1_call_set_logging_finish
mm_gdbus_org_freedesktop_modem_manager1_call_set_logging_sync
+mm_gdbus_org_freedesktop_modem_manager1_call_report_kernel_event
+mm_gdbus_org_freedesktop_modem_manager1_call_report_kernel_event_finish
+mm_gdbus_org_freedesktop_modem_manager1_call_report_kernel_event_sync
<SUBSECTION Private>
mm_gdbus_org_freedesktop_modem_manager1_override_properties
mm_gdbus_org_freedesktop_modem_manager1_complete_scan_devices
mm_gdbus_org_freedesktop_modem_manager1_complete_set_logging
+mm_gdbus_org_freedesktop_modem_manager1_complete_report_kernel_event
mm_gdbus_org_freedesktop_modem_manager1_interface_info
<SUBSECTION Standard>
MM_GDBUS_IS_ORG_FREEDESKTOP_MODEM_MANAGER1
diff --git a/introspection/org.freedesktop.ModemManager1.xml b/introspection/org.freedesktop.ModemManager1.xml
index 2ecd026e..4eccbc97 100644
--- a/introspection/org.freedesktop.ModemManager1.xml
+++ b/introspection/org.freedesktop.ModemManager1.xml
@@ -37,5 +37,79 @@
<arg name="level" type="s" direction="in" />
</method>
+ <!--
+ ReportKernelEvent:
+ @properties: event properties.
+
+ Reports a kernel event to ModemManager.
+
+ This method is only available if udev is not being used to report kernel
+ events.
+
+ The @properties dictionary is composed of key/value string pairs. The
+ possible keys are:
+
+ <variablelist>
+
+ <varlistentry><term><literal>action</literal></term>
+ <listitem>
+ <para>
+ The type of action, given as a string value (signature
+ <literal>"s"</literal>).
+ This parameter is MANDATORY.
+ </para>
+ <variablelist>
+ <varlistentry><term><literal>add</literal></term>
+ <listitem>
+ A new kernel device has been added.
+ </listitem>
+ </varlistentry>
+ <varlistentry><term><literal>remove</literal></term>
+ <listitem>
+ An existing kernel device has been removed.
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><literal>name</literal></term>
+ <listitem>
+ <para>
+ The device name, given as a string value (signature
+ <literal>"s"</literal>).
+ This parameter is MANDATORY.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><literal>subsystem</literal></term>
+ <listitem>
+ <para>
+ The device subsystem, given as a string value (signature
+ <literal>"s"</literal>).
+ This parameter is MANDATORY.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry><term><literal>uid</literal></term>
+ <listitem>
+ <para>
+ The unique ID of the physical device, given as a string value
+ (signature <literal>"s"</literal>).
+ This parameter is OPTIONAL, if not given the sysfs path of the
+ physical device will be used. This parameter must be the same
+ for all devices exposed by the same physical device.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ -->
+ <method name="ReportKernelEvent">
+ <arg name="properties" type="a{sv}" direction="in" />
+ </method>
+
</interface>
</node>
diff --git a/libmm-glib/Makefile.am b/libmm-glib/Makefile.am
index e257d6f0..64bca40e 100644
--- a/libmm-glib/Makefile.am
+++ b/libmm-glib/Makefile.am
@@ -81,6 +81,8 @@ libmm_glib_la_SOURCES = \
mm-cdma-manual-activation-properties.c \
mm-signal.h \
mm-signal.c \
+ mm-kernel-event-properties.h \
+ mm-kernel-event-properties.c \
$(NULL)
libmm_glib_la_CPPFLAGS = \
@@ -149,6 +151,7 @@ include_HEADERS = \
mm-firmware-properties.h \
mm-cdma-manual-activation-properties.h \
mm-signal.h \
+ mm-kernel-event-properties.h \
$(NULL)
CLEANFILES =
diff --git a/libmm-glib/libmm-glib.h b/libmm-glib/libmm-glib.h
index fa4c7e2f..53f0a196 100644
--- a/libmm-glib/libmm-glib.h
+++ b/libmm-glib/libmm-glib.h
@@ -72,6 +72,7 @@
#include <mm-firmware-properties.h>
#include <mm-cdma-manual-activation-properties.h>
#include <mm-signal.h>
+#include <mm-kernel-event-properties.h>
/* generated */
#include <mm-errors-types.h>
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;
+}
diff --git a/libmm-glib/mm-kernel-event-properties.h b/libmm-glib/mm-kernel-event-properties.h
new file mode 100644
index 00000000..576e356b
--- /dev/null
+++ b/libmm-glib/mm-kernel-event-properties.h
@@ -0,0 +1,97 @@
+/* -*- 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.
+ */
+
+#ifndef MM_KERNEL_EVENT_PROPERTIES_H
+#define MM_KERNEL_EVENT_PROPERTIES_H
+
+#if !defined (__LIBMM_GLIB_H_INSIDE__) && !defined (LIBMM_GLIB_COMPILATION)
+#error "Only <libmm-glib.h> can be included directly."
+#endif
+
+#include <ModemManager.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define MM_TYPE_KERNEL_EVENT_PROPERTIES (mm_kernel_event_properties_get_type ())
+#define MM_KERNEL_EVENT_PROPERTIES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_KERNEL_EVENT_PROPERTIES, MMKernelEventProperties))
+#define MM_KERNEL_EVENT_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_KERNEL_EVENT_PROPERTIES, MMKernelEventPropertiesClass))
+#define MM_IS_KERNEL_EVENT_PROPERTIES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_KERNEL_EVENT_PROPERTIES))
+#define MM_IS_KERNEL_EVENT_PROPERTIES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_KERNEL_EVENT_PROPERTIES))
+#define MM_KERNEL_EVENT_PROPERTIES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_KERNEL_EVENT_PROPERTIES, MMKernelEventPropertiesClass))
+
+typedef struct _MMKernelEventProperties MMKernelEventProperties;
+typedef struct _MMKernelEventPropertiesClass MMKernelEventPropertiesClass;
+typedef struct _MMKernelEventPropertiesPrivate MMKernelEventPropertiesPrivate;
+
+/**
+ * MMKernelEventProperties:
+ *
+ * The #MMKernelEventProperties structure contains private data and should only be
+ * accessed using the provided API.
+ */
+struct _MMKernelEventProperties {
+ /*< private >*/
+ GObject parent;
+ MMKernelEventPropertiesPrivate *priv;
+};
+
+struct _MMKernelEventPropertiesClass {
+ /*< private >*/
+ GObjectClass parent;
+};
+
+GType mm_kernel_event_properties_get_type (void);
+
+MMKernelEventProperties *mm_kernel_event_properties_new (void);
+
+void mm_kernel_event_properties_set_action (MMKernelEventProperties *self,
+ const gchar *action);
+const gchar *mm_kernel_event_properties_get_action (MMKernelEventProperties *self);
+
+void mm_kernel_event_properties_set_subsystem (MMKernelEventProperties *self,
+ const gchar *subsystem);
+const gchar *mm_kernel_event_properties_get_subsystem (MMKernelEventProperties *self);
+
+void mm_kernel_event_properties_set_name (MMKernelEventProperties *self,
+ const gchar *name);
+const gchar *mm_kernel_event_properties_get_name (MMKernelEventProperties *self);
+
+void mm_kernel_event_properties_set_uid (MMKernelEventProperties *self,
+ const gchar *uid);
+const gchar *mm_kernel_event_properties_get_uid (MMKernelEventProperties *self);
+
+/*****************************************************************************/
+/* ModemManager/libmm-glib/mmcli specific methods */
+
+#if defined (_LIBMM_INSIDE_MM) || \
+ defined (_LIBMM_INSIDE_MMCLI) || \
+ defined (LIBMM_GLIB_COMPILATION)
+
+MMKernelEventProperties *mm_kernel_event_properties_new_from_string (const gchar *str,
+ GError **error);
+
+MMKernelEventProperties *mm_kernel_event_properties_new_from_dictionary (GVariant *dictionary,
+ GError **error);
+
+MMKernelEventProperties *mm_kernel_event_properties_dup (MMKernelEventProperties *orig);
+
+GVariant *mm_kernel_event_properties_get_dictionary (MMKernelEventProperties *self);
+
+#endif
+
+G_END_DECLS
+
+#endif /* MM_KERNEL_EVENT_PROPERTIES_H */
diff --git a/libmm-glib/mm-manager.c b/libmm-glib/mm-manager.c
index cb196b3f..6a9ce5dd 100644
--- a/libmm-glib/mm-manager.c
+++ b/libmm-glib/mm-manager.c
@@ -497,6 +497,130 @@ mm_manager_scan_devices_sync (MMManager *manager,
/*****************************************************************************/
+/**
+ * mm_manager_report_kernel_event_finish:
+ * @manager: A #MMManager.
+ * @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to mm_manager_report_kernel_event().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with mm_manager_report_kernel_event().
+ *
+ * Returns: %TRUE if the operation succeded, %FALSE if @error is set.
+ */
+gboolean
+mm_manager_report_kernel_event_finish (MMManager *manager,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static void
+report_kernel_event_ready (MmGdbusOrgFreedesktopModemManager1 *manager_iface_proxy,
+ GAsyncResult *res,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (!mm_gdbus_org_freedesktop_modem_manager1_call_report_kernel_event_finish (
+ manager_iface_proxy,
+ res,
+ &error))
+ g_task_return_error (task, error);
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+/**
+ * mm_manager_report_kernel_event:
+ * @manager: A #MMManager.
+ * @properties: the properties of the kernel event.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL.
+ * @user_data: User data to pass to @callback.
+ *
+ * Asynchronously report kernel event.
+ *
+ * When the operation is finished, @callback will be invoked in the
+ * <link linkend="g-main-context-push-thread-default">thread-default main loop</link>
+ * of the thread you are calling this method from. You can then call
+ * mm_manager_report_kernel_event_finish() to get the result of the operation.
+ *
+ * See mm_manager_report_kernel_event_sync() for the synchronous, blocking version of this method.
+ */
+void
+mm_manager_report_kernel_event (MMManager *manager,
+ MMKernelEventProperties *properties,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ GError *inner_error = NULL;
+ GVariant *dictionary;
+
+ g_return_if_fail (MM_IS_MANAGER (manager));
+
+ task = g_task_new (manager, cancellable, callback, user_data);
+
+ if (!ensure_modem_manager1_proxy (manager, &inner_error)) {
+ g_task_return_error (task, inner_error);
+ g_object_unref (task);
+ return;
+ }
+
+ dictionary = mm_kernel_event_properties_get_dictionary (properties);
+ mm_gdbus_org_freedesktop_modem_manager1_call_report_kernel_event (
+ manager->priv->manager_iface_proxy,
+ dictionary,
+ cancellable,
+ (GAsyncReadyCallback)report_kernel_event_ready,
+ task);
+ g_variant_unref (dictionary);
+}
+
+/**
+ * mm_manager_report_kernel_event_sync:
+ * @manager: A #MMManager.
+ * @properties: the properties of the kernel event.
+ * @cancellable: (allow-none): A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Synchronously report kernel event.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * See mm_manager_report_kernel_event() for the asynchronous version of this method.
+ *
+ * Returns: %TRUE if the operation succeded, %FALSE if @error is set.
+ */
+gboolean
+mm_manager_report_kernel_event_sync (MMManager *manager,
+ MMKernelEventProperties *properties,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVariant *dictionary;
+ gboolean result;
+
+ g_return_val_if_fail (MM_IS_MANAGER (manager), FALSE);
+
+ if (!ensure_modem_manager1_proxy (manager, error))
+ return FALSE;
+
+ dictionary = mm_kernel_event_properties_get_dictionary (properties);
+ result = (mm_gdbus_org_freedesktop_modem_manager1_call_report_kernel_event_sync (
+ manager->priv->manager_iface_proxy,
+ dictionary,
+ cancellable,
+ error));
+ g_variant_unref (dictionary);
+ return result;
+}
+
+/*****************************************************************************/
+
static void
register_dbus_errors (void)
{
diff --git a/libmm-glib/mm-manager.h b/libmm-glib/mm-manager.h
index 96c3066a..57a129f5 100644
--- a/libmm-glib/mm-manager.h
+++ b/libmm-glib/mm-manager.h
@@ -33,6 +33,7 @@
#include <ModemManager.h>
#include "mm-gdbus-modem.h"
+#include "mm-kernel-event-properties.h"
G_BEGIN_DECLS
@@ -108,6 +109,19 @@ gboolean mm_manager_scan_devices_sync (MMManager *manager,
GCancellable *cancellable,
GError **error);
+void mm_manager_report_kernel_event (MMManager *manager,
+ MMKernelEventProperties *properties,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean mm_manager_report_kernel_event_finish (MMManager *manager,
+ GAsyncResult *res,
+ GError **error);
+gboolean mm_manager_report_kernel_event_sync (MMManager *manager,
+ MMKernelEventProperties *properties,
+ GCancellable *cancellable,
+ GError **error);
+
G_END_DECLS
#endif /* _MM_MANAGER_H_ */
diff --git a/src/kerneldevice/mm-kernel-device-udev.c b/src/kerneldevice/mm-kernel-device-udev.c
index 4953f48f..f4b47d88 100644
--- a/src/kerneldevice/mm-kernel-device-udev.c
+++ b/src/kerneldevice/mm-kernel-device-udev.c
@@ -21,11 +21,15 @@
#include "mm-kernel-device-udev.h"
#include "mm-log.h"
-G_DEFINE_TYPE (MMKernelDeviceUdev, mm_kernel_device_udev, MM_TYPE_KERNEL_DEVICE)
+static void initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_EXTENDED (MMKernelDeviceUdev, mm_kernel_device_udev, MM_TYPE_KERNEL_DEVICE, 0,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, initable_iface_init))
enum {
PROP_0,
PROP_UDEV_DEVICE,
+ PROP_PROPERTIES,
PROP_LAST
};
@@ -37,6 +41,8 @@ struct _MMKernelDeviceUdevPrivate {
GUdevDevice *physdev;
guint16 vendor;
guint16 product;
+
+ MMKernelEventProperties *properties;
};
/*****************************************************************************/
@@ -153,8 +159,11 @@ ensure_device_ids (MMKernelDeviceUdev *self)
if (self->priv->vendor || self->priv->product)
return;
+ if (!self->priv->device)
+ return;
+
if (!get_device_ids (self->priv->device, &self->priv->vendor, &self->priv->product))
- mm_dbg ("(%s/%s) could not get vendor/product ID",
+ mm_dbg ("(%s/%s) could not get vendor/product id",
g_udev_device_get_subsystem (self->priv->device),
g_udev_device_get_name (self->priv->device));
}
@@ -240,25 +249,42 @@ ensure_physdev (MMKernelDeviceUdev *self)
{
if (self->priv->physdev)
return;
- self->priv->physdev = find_physical_gudevdevice (self->priv->device);
+ if (self->priv->device)
+ self->priv->physdev = find_physical_gudevdevice (self->priv->device);
}
/*****************************************************************************/
static const gchar *
-kernel_device_get_subsystem (MMKernelDevice *self)
+kernel_device_get_subsystem (MMKernelDevice *_self)
{
- g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (self), NULL);
+ MMKernelDeviceUdev *self;
+
+ g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), NULL);
+
+ self = MM_KERNEL_DEVICE_UDEV (_self);
+
+ if (self->priv->device)
+ return g_udev_device_get_subsystem (self->priv->device);
- return g_udev_device_get_subsystem (MM_KERNEL_DEVICE_UDEV (self)->priv->device);
+ g_assert (self->priv->properties);
+ return mm_kernel_event_properties_get_subsystem (self->priv->properties);
}
static const gchar *
-kernel_device_get_name (MMKernelDevice *self)
+kernel_device_get_name (MMKernelDevice *_self)
{
- g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (self), NULL);
+ MMKernelDeviceUdev *self;
+
+ g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), NULL);
+
+ self = MM_KERNEL_DEVICE_UDEV (_self);
- return g_udev_device_get_name (MM_KERNEL_DEVICE_UDEV (self)->priv->device);
+ if (self->priv->device)
+ return g_udev_device_get_name (self->priv->device);
+
+ g_assert (self->priv->properties);
+ return mm_kernel_event_properties_get_name (self->priv->properties);
}
static const gchar *
@@ -271,6 +297,9 @@ kernel_device_get_driver (MMKernelDevice *_self)
self = MM_KERNEL_DEVICE_UDEV (_self);
+ if (!self->priv->device)
+ return NULL;
+
driver = g_udev_device_get_driver (self->priv->device);
if (!driver) {
GUdevDevice *parent;
@@ -308,6 +337,9 @@ kernel_device_get_sysfs_path (MMKernelDevice *self)
{
g_return_val_if_fail (MM_IS_KERNEL_DEVICE (self), NULL);
+ if (!MM_KERNEL_DEVICE_UDEV (self)->priv->device)
+ return NULL;
+
return g_udev_device_get_sysfs_path (MM_KERNEL_DEVICE_UDEV (self)->priv->device);
}
@@ -320,14 +352,20 @@ kernel_device_get_physdev_uid (MMKernelDevice *_self)
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), NULL);
self = MM_KERNEL_DEVICE_UDEV (_self);
- ensure_physdev (self);
- if (!self->priv->physdev)
- return NULL;
+ /* Prefer the one coming in the properties, if any */
+ if (self->priv->properties)
+ uid = mm_kernel_event_properties_get_uid (MM_KERNEL_DEVICE_UDEV (self)->priv->properties);
- uid = g_udev_device_get_property (self->priv->physdev, "ID_MM_PHYSDEV_UID");
- if (!uid)
- uid = g_udev_device_get_sysfs_path (self->priv->physdev);
+ if (!uid) {
+ ensure_physdev (self);
+ if (!self->priv->physdev)
+ return NULL;
+
+ uid = g_udev_device_get_property (self->priv->physdev, "ID_MM_PHYSDEV_UID");
+ if (!uid)
+ uid = g_udev_device_get_sysfs_path (self->priv->physdev);
+ }
return uid;
}
@@ -364,7 +402,8 @@ kernel_device_get_parent_sysfs_path (MMKernelDevice *_self)
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), 0);
self = MM_KERNEL_DEVICE_UDEV (_self);
- if (!self->priv->parent)
+
+ if (!self->priv->parent && self->priv->device)
self->priv->parent = g_udev_device_get_parent (self->priv->device);
return (self->priv->parent ? g_udev_device_get_sysfs_path (self->priv->parent) : NULL);
}
@@ -382,6 +421,9 @@ kernel_device_is_candidate (MMKernelDevice *_self,
self = MM_KERNEL_DEVICE_UDEV (_self);
+ if (!self->priv->device)
+ return FALSE;
+
name = g_udev_device_get_name (self->priv->device);
subsys = g_udev_device_get_subsystem (self->priv->device);
@@ -455,17 +497,22 @@ kernel_device_cmp (MMKernelDevice *_a,
a = MM_KERNEL_DEVICE_UDEV (_a);
b = MM_KERNEL_DEVICE_UDEV (_b);
- if (g_udev_device_has_property (a->priv->device, "DEVPATH_OLD") &&
- g_str_has_suffix (g_udev_device_get_sysfs_path (b->priv->device),
- g_udev_device_get_property (a->priv->device, "DEVPATH_OLD")))
- return TRUE;
+ if (a->priv->device && b->priv->device) {
+ if (g_udev_device_has_property (a->priv->device, "DEVPATH_OLD") &&
+ g_str_has_suffix (g_udev_device_get_sysfs_path (b->priv->device),
+ g_udev_device_get_property (a->priv->device, "DEVPATH_OLD")))
+ return TRUE;
- if (g_udev_device_has_property (b->priv->device, "DEVPATH_OLD") &&
- g_str_has_suffix (g_udev_device_get_sysfs_path (a->priv->device),
- g_udev_device_get_property (b->priv->device, "DEVPATH_OLD")))
- return TRUE;
+ if (g_udev_device_has_property (b->priv->device, "DEVPATH_OLD") &&
+ g_str_has_suffix (g_udev_device_get_sysfs_path (a->priv->device),
+ g_udev_device_get_property (b->priv->device, "DEVPATH_OLD")))
+ return TRUE;
+
+ return !g_strcmp0 (g_udev_device_get_sysfs_path (a->priv->device), g_udev_device_get_sysfs_path (b->priv->device));
+ }
- return !g_strcmp0 (g_udev_device_get_sysfs_path (a->priv->device), g_udev_device_get_sysfs_path (b->priv->device));
+ return (!g_strcmp0 (mm_kernel_device_get_subsystem (_a), mm_kernel_device_get_subsystem (_b)) &&
+ !g_strcmp0 (mm_kernel_device_get_name (_a), mm_kernel_device_get_name (_b)));
}
static gboolean
@@ -477,6 +524,10 @@ kernel_device_has_property (MMKernelDevice *_self,
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), FALSE);
self = MM_KERNEL_DEVICE_UDEV (_self);
+
+ if (!self->priv->device)
+ return FALSE;
+
return g_udev_device_has_property (self->priv->device, property);
}
@@ -489,6 +540,10 @@ kernel_device_get_property (MMKernelDevice *_self,
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), NULL);
self = MM_KERNEL_DEVICE_UDEV (_self);
+
+ if (!self->priv->device)
+ return NULL;
+
return g_udev_device_get_property (self->priv->device, property);
}
@@ -501,6 +556,10 @@ kernel_device_get_property_as_boolean (MMKernelDevice *_self,
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), FALSE);
self = MM_KERNEL_DEVICE_UDEV (_self);
+
+ if (!self->priv->device)
+ return FALSE;
+
return g_udev_device_get_property_as_boolean (self->priv->device, property);
}
@@ -513,6 +572,10 @@ kernel_device_get_property_as_int (MMKernelDevice *_self,
g_return_val_if_fail (MM_IS_KERNEL_DEVICE_UDEV (_self), -1);
self = MM_KERNEL_DEVICE_UDEV (_self);
+
+ if (!self->priv->device)
+ return -1;
+
return g_udev_device_get_property_as_int (self->priv->device, property);
}
@@ -521,11 +584,31 @@ kernel_device_get_property_as_int (MMKernelDevice *_self,
MMKernelDevice *
mm_kernel_device_udev_new (GUdevDevice *udev_device)
{
+ GError *error = NULL;
+ MMKernelDevice *self;
+
g_return_val_if_fail (G_UDEV_IS_DEVICE (udev_device), NULL);
- return MM_KERNEL_DEVICE (g_object_new (MM_TYPE_KERNEL_DEVICE_UDEV,
- "udev-device", udev_device,
- NULL));
+ self = MM_KERNEL_DEVICE (g_initable_new (MM_TYPE_KERNEL_DEVICE_UDEV,
+ NULL,
+ &error,
+ "udev-device", udev_device,
+ NULL));
+ g_assert_no_error (error);
+ return self;
+}
+
+/*****************************************************************************/
+
+MMKernelDevice *
+mm_kernel_device_udev_new_from_properties (MMKernelEventProperties *properties,
+ GError **error)
+{
+ return MM_KERNEL_DEVICE (g_initable_new (MM_TYPE_KERNEL_DEVICE_UDEV,
+ NULL,
+ error,
+ "properties", properties,
+ NULL));
}
/*****************************************************************************/
@@ -550,6 +633,10 @@ set_property (GObject *object,
g_assert (!self->priv->device);
self->priv->device = g_value_dup_object (value);
break;
+ case PROP_PROPERTIES:
+ g_assert (!self->priv->properties);
+ self->priv->properties = g_value_dup_object (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -568,12 +655,73 @@ get_property (GObject *object,
case PROP_UDEV_DEVICE:
g_value_set_object (value, self->priv->device);
break;
+ case PROP_PROPERTIES:
+ g_value_set_object (value, self->priv->properties);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
+static gboolean
+initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ MMKernelDeviceUdev *self = MM_KERNEL_DEVICE_UDEV (initable);
+ const gchar *subsystem;
+ const gchar *name;
+
+ /* When created from a GUdevDevice, we're done */
+ if (self->priv->device)
+ return TRUE;
+
+ /* Otherwise, we do need properties with subsystem and name */
+ if (!self->priv->properties) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "missing properties in kernel device");
+ return FALSE;
+ }
+
+ subsystem = mm_kernel_event_properties_get_subsystem (self->priv->properties);
+ if (!subsystem) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "subsystem is mandatory in kernel device");
+ return FALSE;
+ }
+
+ name = mm_kernel_event_properties_get_name (self->priv->properties);
+ if (!mm_kernel_device_get_name (MM_KERNEL_DEVICE (self))) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "name is mandatory in kernel device");
+ return FALSE;
+ }
+
+ /* On remove events, we don't look for the GUdevDevice */
+ if (g_strcmp0 (mm_kernel_event_properties_get_action (self->priv->properties), "remove")) {
+ GUdevClient *client;
+ GUdevDevice *device;
+
+ client = g_udev_client_new (NULL);
+ device = g_udev_client_query_by_subsystem_and_name (client, subsystem, name);
+ if (!device) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "device %s/%s not found",
+ subsystem,
+ name);
+ g_object_unref (client);
+ return FALSE;
+ }
+
+ /* Store device */
+ self->priv->device = device;
+ g_object_unref (client);
+ }
+
+ return TRUE;
+}
+
static void
dispose (GObject *object)
{
@@ -582,11 +730,18 @@ dispose (GObject *object)
g_clear_object (&self->priv->physdev);
g_clear_object (&self->priv->parent);
g_clear_object (&self->priv->device);
+ g_clear_object (&self->priv->properties);
G_OBJECT_CLASS (mm_kernel_device_udev_parent_class)->dispose (object);
}
static void
+initable_iface_init (GInitableIface *iface)
+{
+ iface->init = initable_init;
+}
+
+static void
mm_kernel_device_udev_class_init (MMKernelDeviceUdevClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
@@ -618,6 +773,14 @@ mm_kernel_device_udev_class_init (MMKernelDeviceUdevClass *klass)
"udev device",
"Device object as reported by GUdev",
G_UDEV_TYPE_DEVICE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ G_PARAM_READWRITE);
g_object_class_install_property (object_class, PROP_UDEV_DEVICE, properties[PROP_UDEV_DEVICE]);
+
+ properties[PROP_PROPERTIES] =
+ g_param_spec_object ("properties",
+ "Properties",
+ "Generic kernel event properties",
+ MM_TYPE_KERNEL_EVENT_PROPERTIES,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY);
+ g_object_class_install_property (object_class, PROP_PROPERTIES, properties[PROP_PROPERTIES]);
}
diff --git a/src/kerneldevice/mm-kernel-device-udev.h b/src/kerneldevice/mm-kernel-device-udev.h
index ed83159b..9096ca71 100644
--- a/src/kerneldevice/mm-kernel-device-udev.h
+++ b/src/kerneldevice/mm-kernel-device-udev.h
@@ -20,6 +20,9 @@
#include <glib-object.h>
#include <gudev/gudev.h>
+#define _LIBMM_INSIDE_MM
+#include <libmm-glib.h>
+
#include "mm-kernel-device.h"
#define MM_TYPE_KERNEL_DEVICE_UDEV (mm_kernel_device_udev_get_type ())
@@ -42,7 +45,9 @@ struct _MMKernelDeviceUdevClass {
MMKernelDeviceClass parent;
};
-GType mm_kernel_device_udev_get_type (void);
-MMKernelDevice *mm_kernel_device_udev_new (GUdevDevice *udev_device);
+GType mm_kernel_device_udev_get_type (void);
+MMKernelDevice *mm_kernel_device_udev_new (GUdevDevice *udev_device);
+MMKernelDevice *mm_kernel_device_udev_new_from_properties (MMKernelEventProperties *properties,
+ GError **error);
#endif /* MM_KERNEL_DEVICE_UDEV_H */
diff --git a/src/main.c b/src/main.c
index 8a3ebaba..d83baaf9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -86,7 +86,8 @@ bus_acquired_cb (GDBusConnection *connection,
g_assert (!manager);
manager = mm_base_manager_new (connection,
mm_context_get_test_plugin_dir (),
- !mm_context_get_test_no_auto_scan (),
+ !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 9da38960..3e03d552 100644
--- a/src/mm-base-manager.c
+++ b/src/mm-base-manager.c
@@ -47,6 +47,7 @@ enum {
PROP_AUTO_SCAN,
PROP_ENABLE_TEST,
PROP_PLUGIN_DIR,
+ PROP_INITIAL_KERNEL_EVENTS,
LAST_PROP
};
@@ -59,6 +60,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 UDev client */
GUdevClient *udev;
/* The authorization provider */
@@ -238,6 +241,11 @@ device_added (MMBaseManager *manager,
g_return_if_fail (port != NULL);
+ mm_dbg ("(%s/%s): adding device at sysfs path: %s",
+ mm_kernel_device_get_subsystem (port),
+ mm_kernel_device_get_name (port),
+ mm_kernel_device_get_sysfs_path (port));
+
if (!mm_kernel_device_is_candidate (port, manual_scan)) {
/* This could mean that device changed, losing its ID_MM_CANDIDATE
* flags (such as Bluetooth RFCOMM devices upon disconnect.
@@ -267,6 +275,11 @@ device_added (MMBaseManager *manager,
if (!device) {
FindDeviceSupportContext *ctx;
+ mm_dbg ("(%s/%s): first port in device %s",
+ mm_kernel_device_get_subsystem (port),
+ mm_kernel_device_get_name (port),
+ physdev_uid);
+
/* Keep the device listed in the Manager */
device = mm_device_new (physdev_uid, hotplugged, FALSE);
g_hash_table_insert (manager->priv->devices,
@@ -282,12 +295,73 @@ device_added (MMBaseManager *manager,
device,
(GAsyncReadyCallback) device_support_check_ready,
ctx);
- }
+ } else
+ mm_dbg ("(%s/%s): additional port in device %s",
+ mm_kernel_device_get_subsystem (port),
+ mm_kernel_device_get_name (port),
+ physdev_uid);
/* Grab the port in the existing device. */
mm_device_grab_port (device, port);
}
+static gboolean
+handle_kernel_event (MMBaseManager *self,
+ MMKernelEventProperties *properties,
+ GError **error)
+{
+ MMKernelDevice *kernel_device;
+ const gchar *action;
+ const gchar *subsystem;
+ const gchar *name;
+ const gchar *uid;
+
+ action = mm_kernel_event_properties_get_action (properties);
+ if (!action) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Missing mandatory parameter 'action'");
+ return FALSE;
+ }
+ 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' parameter given: '%s' (expected 'add' or 'remove')", action);
+ return FALSE;
+ }
+
+ subsystem = mm_kernel_event_properties_get_subsystem (properties);
+ if (!subsystem) {
+ g_set_error (error, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS, "Missing mandatory parameter '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'");
+ return FALSE;
+ }
+
+ uid = mm_kernel_event_properties_get_uid (properties);
+
+ mm_dbg ("Kernel event reported:");
+ mm_dbg (" action: %s", action);
+ mm_dbg (" subsystem: %s", subsystem);
+ mm_dbg (" name: %s", name);
+ mm_dbg (" uid: %s", uid ? uid : "n/a");
+
+ kernel_device = mm_kernel_device_udev_new_from_properties (properties, error);
+
+ 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;
+}
+
static void
handle_uevent (GUdevClient *client,
const char *action,
@@ -356,57 +430,112 @@ start_device_added (MMBaseManager *self,
g_idle_add ((GSourceFunc)start_device_added_idle, ctx);
}
-void
-mm_base_manager_start (MMBaseManager *manager,
- gboolean manual_scan)
+static void
+process_scan (MMBaseManager *self,
+ gboolean manual_scan)
{
GList *devices, *iter;
- g_return_if_fail (manager != NULL);
- g_return_if_fail (MM_IS_BASE_MANAGER (manager));
-
- if (!manager->priv->auto_scan && !manual_scan)
- return;
-
- mm_dbg ("Starting %s device scan...", manual_scan ? "manual" : "automatic");
-
- devices = g_udev_client_query_by_subsystem (manager->priv->udev, "tty");
+ devices = g_udev_client_query_by_subsystem (self->priv->udev, "tty");
for (iter = devices; iter; iter = g_list_next (iter)) {
- start_device_added (manager, G_UDEV_DEVICE (iter->data), manual_scan);
+ 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 (manager->priv->udev, "net");
+ devices = g_udev_client_query_by_subsystem (self->priv->udev, "net");
for (iter = devices; iter; iter = g_list_next (iter)) {
- start_device_added (manager, G_UDEV_DEVICE (iter->data), manual_scan);
+ 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 (manager->priv->udev, "usb");
+ 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 (manager, G_UDEV_DEVICE (iter->data), manual_scan);
+ 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 (manager->priv->udev, "usbmisc");
+ 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 (manager, G_UDEV_DEVICE (iter->data), manual_scan);
+ start_device_added (self, G_UDEV_DEVICE (iter->data), manual_scan);
g_object_unref (G_OBJECT (iter->data));
}
g_list_free (devices);
+}
+
+static void
+process_initial_kernel_events (MMBaseManager *self)
+{
+ gchar *contents = NULL;
+ gchar *line;
+ GError *error = NULL;
+
+ if (!self->priv->initial_kernel_events)
+ return;
+
+ 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;
+ }
+
+ line = contents;
+ while (line) {
+ gchar *next;
+
+ next = strchr (line, '\n');
+ if (next) {
+ *next = '\0';
+ next++;
+ }
+
+ /* 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);
+ }
+
+ line = next;
+ }
+
+ g_free (contents);
+}
+
+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));
+
+ 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;
+ }
+ mm_dbg ("Starting %s device scan...", manual_scan ? "manual" : "automatic");
+ process_scan (self, manual_scan);
mm_dbg ("Finished device scan...");
}
@@ -615,6 +744,81 @@ handle_scan_devices (MmGdbusOrgFreedesktopModemManager1 *manager,
}
/*****************************************************************************/
+
+typedef struct {
+ MMBaseManager *self;
+ GDBusMethodInvocation *invocation;
+ GVariant *dictionary;
+} ReportKernelEventContext;
+
+static void
+report_kernel_event_context_free (ReportKernelEventContext *ctx)
+{
+ g_object_unref (ctx->invocation);
+ g_object_unref (ctx->self);
+ g_variant_unref (ctx->dictionary);
+ g_slice_free (ReportKernelEventContext, ctx);
+}
+
+static void
+report_kernel_event_auth_ready (MMAuthProvider *authp,
+ GAsyncResult *res,
+ ReportKernelEventContext *ctx)
+{
+ GError *error = NULL;
+ MMKernelEventProperties *properties = NULL;
+
+ if (!mm_auth_provider_authorize_finish (authp, res, &error))
+ goto out;
+
+ if (ctx->self->priv->auto_scan) {
+ error = g_error_new_literal (MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
+ "Cannot report kernel event: "
+ "udev monitoring already in place");
+ goto out;
+ }
+
+ properties = mm_kernel_event_properties_new_from_dictionary (ctx->dictionary, &error);
+ if (!properties)
+ goto out;
+
+ handle_kernel_event (ctx->self, properties, &error);
+
+out:
+ if (error)
+ g_dbus_method_invocation_take_error (ctx->invocation, error);
+ else
+ mm_gdbus_org_freedesktop_modem_manager1_complete_report_kernel_event (
+ MM_GDBUS_ORG_FREEDESKTOP_MODEM_MANAGER1 (ctx->self),
+ ctx->invocation);
+
+ if (properties)
+ g_object_unref (properties);
+ report_kernel_event_context_free (ctx);
+}
+
+static gboolean
+handle_report_kernel_event (MmGdbusOrgFreedesktopModemManager1 *manager,
+ GDBusMethodInvocation *invocation,
+ GVariant *dictionary)
+{
+ ReportKernelEventContext *ctx;
+
+ ctx = g_slice_new0 (ReportKernelEventContext);
+ ctx->self = g_object_ref (manager);
+ ctx->invocation = g_object_ref (invocation);
+ ctx->dictionary = g_variant_ref (dictionary);
+
+ mm_auth_provider_authorize (ctx->self->priv->authp,
+ invocation,
+ MM_AUTHORIZATION_MANAGER_CONTROL,
+ ctx->self->priv->authp_cancellable,
+ (GAsyncReadyCallback)report_kernel_event_auth_ready,
+ ctx);
+ return TRUE;
+}
+
+/*****************************************************************************/
/* Test profile setup */
static gboolean
@@ -684,6 +888,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)
{
@@ -695,6 +900,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);
}
@@ -740,6 +946,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;
@@ -767,6 +977,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;
@@ -812,6 +1025,10 @@ mm_base_manager_init (MMBaseManager *manager)
"handle-scan-devices",
G_CALLBACK (handle_scan_devices),
NULL);
+ g_signal_connect (manager,
+ "handle-report-kernel-event",
+ G_CALLBACK (handle_report_kernel_event),
+ NULL);
}
static gboolean
@@ -864,6 +1081,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);
@@ -943,4 +1161,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 43e7cae0..56b3016e 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 df8d07c7..cf8025bc 100644
--- a/src/mm-context.c
+++ b/src/mm-context.c
@@ -26,6 +26,8 @@ static const gchar *log_level;
static const gchar *log_file;
static gboolean show_ts;
static gboolean rel_ts;
+static const gchar *initial_kernel_events;
+static gboolean no_auto_scan;
static const GOptionEntry entries[] = {
{ "version", 'V', 0, G_OPTION_ARG_NONE, &version_flag, "Print version", NULL },
@@ -34,6 +36,8 @@ static const GOptionEntry entries[] = {
{ "log-file", 0, 0, G_OPTION_ARG_FILENAME, &log_file, "Path to log file", "[PATH]" },
{ "timestamps", 0, 0, G_OPTION_ARG_NONE, &show_ts, "Show timestamps in log output", NULL },
{ "relative-timestamps", 0, 0, G_OPTION_ARG_NONE, &rel_ts, "Use relative timestamps (from MM start)", NULL },
+ { "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]" },
{ NULL }
};
@@ -67,17 +71,27 @@ 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)
+{
+ return no_auto_scan;
+}
+
/*****************************************************************************/
/* Test context */
static gboolean test_session;
-static gboolean test_no_auto_scan;
static gboolean test_enable;
static gchar *test_plugin_dir;
static const GOptionEntry test_entries[] = {
{ "test-session", 0, 0, G_OPTION_ARG_NONE, &test_session, "Run in session DBus", NULL },
- { "test-no-auto-scan", 0, 0, G_OPTION_ARG_NONE, &test_no_auto_scan, "Don't auto-scan looking for devices", NULL },
{ "test-enable", 0, 0, G_OPTION_ARG_NONE, &test_enable, "Enable the Test interface in the daemon", NULL },
{ "test-plugin-dir", 0, 0, G_OPTION_ARG_FILENAME, &test_plugin_dir, "Path to look for plugins", "[PATH]" },
{ NULL }
@@ -104,12 +118,6 @@ mm_context_get_test_session (void)
}
gboolean
-mm_context_get_test_no_auto_scan (void)
-{
- return test_no_auto_scan;
-}
-
-gboolean
mm_context_get_test_enable (void)
{
return test_enable;
@@ -149,7 +157,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);
}
@@ -166,4 +174,10 @@ 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 (!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);
+ }
}
diff --git a/src/mm-context.h b/src/mm-context.h
index 6627a601..63a8ec4c 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_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_no_auto_scan (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 */