diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/kerneldevice/mm-kernel-device-udev.c | 221 | ||||
-rw-r--r-- | src/kerneldevice/mm-kernel-device-udev.h | 9 | ||||
-rw-r--r-- | src/main.c | 3 | ||||
-rw-r--r-- | src/mm-base-manager.c | 266 | ||||
-rw-r--r-- | src/mm-base-manager.h | 2 | ||||
-rw-r--r-- | src/mm-context.c | 32 | ||||
-rw-r--r-- | src/mm-context.h | 19 |
7 files changed, 482 insertions, 70 deletions
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 */ @@ -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 */ |