From: David Zeuthen Date: Tue, 8 Jun 2010 19:46:33 +0000 (-0400) Subject: Updates X-Git-Tag: upstream/2.1.2~480^2~244 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ca191a944635ceafa40a628ad651f4e8fef132c4;p=platform%2Fupstream%2Fudisks2.git Updates --- diff --git a/src/Makefile.am b/src/Makefile.am index 7f1a780..6b54b5b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -34,6 +34,7 @@ BUILT_SOURCES = \ generated-bindings.h \ generated-daemon.h generated-daemon.c \ generated-device.h generated-device.c \ + generated-marshallers.list \ generated-marshallers.h generated-marshallers.c \ generated-typemappers.h \ $(NULL) @@ -45,6 +46,7 @@ udisks_daemon_SOURCES = \ error.h error.c \ main.c \ linuxdaemon.h linuxdaemon.c \ + linuxdevice.h linuxdevice.c \ private.h \ profile.h \ $(BUILT_SOURCES) \ diff --git a/src/linuxdaemon.c b/src/linuxdaemon.c index 8af5adb..685673d 100644 --- a/src/linuxdaemon.c +++ b/src/linuxdaemon.c @@ -23,23 +23,89 @@ #include #include "linuxdaemon.h" +#include "linuxdevice.h" struct _LinuxDaemonPrivate { + GDBusConnection *connection; + GUdevClient *udev_client; + + GHashTable *map_sysfs_path_to_object; +}; + +enum +{ + PROP_0, + PROP_CONNECTION, }; +/* ---------------------------------------------------------------------------------------------------- */ + +static void linux_daemon_coldplug (LinuxDaemon *daemon); + +static void on_uevent (GUdevClient *client, + const gchar *action, + GUdevDevice *device, + gpointer user_data); + static void daemon_iface_init (DaemonIface *iface); + +/* ---------------------------------------------------------------------------------------------------- */ + G_DEFINE_TYPE_WITH_CODE (LinuxDaemon, linux_daemon, TYPE_DAEMON_STUB, G_IMPLEMENT_INTERFACE (TYPE_DAEMON, daemon_iface_init)); +/* ---------------------------------------------------------------------------------------------------- */ + +static void +linux_daemon_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + LinuxDaemon *daemon = LINUX_DAEMON (object); + + switch (prop_id) + { + case PROP_CONNECTION: + g_value_set_object (value, daemon->priv->connection); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +linux_daemon_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + LinuxDaemon *daemon = LINUX_DAEMON (object); + + switch (prop_id) + { + case PROP_CONNECTION: + daemon->priv->connection = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} static void linux_daemon_finalize (GObject *object) { LinuxDaemon *daemon = LINUX_DAEMON (object); + g_object_unref (daemon->priv->connection); g_object_unref (daemon->priv->udev_client); + g_hash_table_unref (daemon->priv->map_sysfs_path_to_object); if (G_OBJECT_CLASS (linux_daemon_parent_class)->finalize != NULL) G_OBJECT_CLASS (linux_daemon_parent_class)->finalize (object); @@ -52,7 +118,27 @@ linux_daemon_init (LinuxDaemon *daemon) daemon->priv = G_TYPE_INSTANCE_GET_PRIVATE (daemon, TYPE_LINUX_DAEMON, LinuxDaemonPrivate); + daemon->priv->map_sysfs_path_to_object = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_object_unref); + daemon->priv->udev_client = g_udev_client_new (subsystems); + g_signal_connect (daemon->priv->udev_client, + "uevent", + G_CALLBACK (on_uevent), + daemon); +} + +static void +linux_daemon_constructed (GObject *object) +{ + LinuxDaemon *daemon = LINUX_DAEMON (object); + + linux_daemon_coldplug (daemon); + + if (G_OBJECT_CLASS (linux_daemon_parent_class)->constructed != NULL) + G_OBJECT_CLASS (linux_daemon_parent_class)->constructed (object); } static void @@ -61,13 +147,189 @@ linux_daemon_class_init (LinuxDaemonClass *klass) GObjectClass *gobject_class; gobject_class = G_OBJECT_CLASS (klass); - gobject_class->finalize = linux_daemon_finalize; + gobject_class->get_property = linux_daemon_get_property; + gobject_class->set_property = linux_daemon_set_property; + gobject_class->finalize = linux_daemon_finalize; + gobject_class->constructed = linux_daemon_constructed; + + g_object_class_install_property (gobject_class, + PROP_CONNECTION, + g_param_spec_object ("connection", + "Connection", + "The GDBusConnection to use", + G_TYPE_DBUS_CONNECTION, + G_PARAM_READABLE | + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB | + G_PARAM_STATIC_NICK)); + g_type_class_add_private (klass, sizeof (LinuxDaemonPrivate)); } /* ---------------------------------------------------------------------------------------------------- */ +/* returns TRUE if a change was made */ +static gboolean +maybe_export_unexport_object (LinuxDaemon *daemon, + LinuxDevice *device, + gboolean visible) +{ + guint daemon_export_id; + gboolean ret; + + ret = FALSE; + + daemon_export_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (device), "daemon-export-id")); + if (visible) + { + if (daemon_export_id == 0) + { + GError *error; + guint id; + error = NULL; + id = device_register_object (DEVICE (device), + daemon->priv->connection, + linux_device_get_object_path (device), + &error); + if (id == 0) + { + g_printerr ("Error registering object: %s\n", + error->message); + g_error_free (error); + } + g_object_set_data (G_OBJECT (device), "daemon-export-id", GUINT_TO_POINTER (id)); + ret = TRUE; + } + else + { + /* all good, is already exported */ + } + } + else + { + if (daemon_export_id > 0) + { + g_dbus_connection_unregister_object (daemon->priv->connection, daemon_export_id); + g_object_set_data (G_OBJECT (device), "daemon-export-id", GUINT_TO_POINTER (0)); + ret = TRUE; + } + else + { + /* all good, wasn't previously exported */ + } + } + + return ret; +} + +static void +emit_added (LinuxDaemon *daemon, + LinuxDevice *device) +{ + daemon_emit_device_added (DAEMON (daemon), linux_device_get_object_path (device)); +} + +static void +emit_removed (LinuxDaemon *daemon, + LinuxDevice *device) +{ + daemon_emit_device_removed (DAEMON (daemon), linux_device_get_object_path (device)); +} + +static void +handle_device_uevent (LinuxDaemon *daemon, + const gchar *action, + GUdevDevice *udev_device) +{ + LinuxDevice *device; + const gchar *sysfs_path; + + sysfs_path = g_udev_device_get_sysfs_path (udev_device); + if (g_strcmp0 (action, "remove") == 0) + { + device = g_hash_table_lookup (daemon->priv->map_sysfs_path_to_object, sysfs_path); + if (device != NULL) + { + if (maybe_export_unexport_object (daemon, device, FALSE)) + emit_removed (daemon, device); + + g_hash_table_remove (daemon->priv->map_sysfs_path_to_object, sysfs_path); + g_print ("removed object with sysfs path `%s'\n", sysfs_path); + } + } + else + { + device = g_hash_table_lookup (daemon->priv->map_sysfs_path_to_object, sysfs_path); + if (device != NULL) + { + gboolean visible; + + linux_device_set_udev_device (device, udev_device); + linux_device_update (device); + visible = linux_device_get_visible (device); + if (maybe_export_unexport_object (daemon, device, visible)) + { + if (visible) + emit_added (daemon, device); + else + emit_removed (daemon, device); + } + g_print ("handled %s uevent for object with sysfs path `%s'\n", action, sysfs_path); + } + else + { + const gchar *object_path; + gboolean visible; + + device = linux_device_new (udev_device); + object_path = linux_device_get_object_path (device); + visible = linux_device_get_visible (device); + + g_hash_table_insert (daemon->priv->map_sysfs_path_to_object, + g_strdup (sysfs_path), + device); + + if (maybe_export_unexport_object (daemon, device, visible)) + emit_added (daemon, device); + + /* TODO: connect to notify:visible to handle changes */ + + g_print ("added object with sysfs path `%s'\n", sysfs_path); + } + } +} + +/* Called on startup */ +static void +linux_daemon_coldplug (LinuxDaemon *daemon) +{ + GList *devices; + GList *l; + + /* TODO: maybe do two loops to properly handle dependency SNAFU? */ + devices = g_udev_client_query_by_subsystem (daemon->priv->udev_client, "block"); + for (l = devices; l != NULL; l = l->next) + handle_device_uevent (daemon, "add", G_UDEV_DEVICE (l->data)); + g_list_foreach (devices, (GFunc) g_object_unref, NULL); + g_list_free (devices); +} + +/* Called when an uevent happens on a device */ +static void +on_uevent (GUdevClient *client, + const gchar *action, + GUdevDevice *device, + gpointer user_data) +{ + LinuxDaemon *daemon = LINUX_DAEMON (user_data); + handle_device_uevent (daemon, action, device); +} + +/* ---------------------------------------------------------------------------------------------------- */ + static gboolean handle_enumerate_device_files (Daemon *_daemon, GDBusMethodInvocation *invocation) diff --git a/src/linuxdevice.c b/src/linuxdevice.c new file mode 100644 index 0000000..1da8918 --- /dev/null +++ b/src/linuxdevice.c @@ -0,0 +1,287 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" + +#include +#include + +#include "linuxdevice.h" + +struct _LinuxDevicePrivate +{ + GUdevDevice *udev_device; + gboolean visible; + gchar *object_path; +}; + +enum +{ + PROP_0, + PROP_UDEV_DEVICE, + PROP_VISIBLE, + PROP_OBJECT_PATH, +}; + +/* ---------------------------------------------------------------------------------------------------- */ + +static void device_iface_init (DeviceIface *iface); + +/* ---------------------------------------------------------------------------------------------------- */ + +G_DEFINE_TYPE_WITH_CODE (LinuxDevice, linux_device, TYPE_DEVICE_STUB, + G_IMPLEMENT_INTERFACE (TYPE_DEVICE, device_iface_init)); + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +linux_device_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + LinuxDevice *device = LINUX_DEVICE (object); + + switch (prop_id) + { + case PROP_UDEV_DEVICE: + g_value_set_object (value, linux_device_get_udev_device (device)); + break; + + case PROP_VISIBLE: + g_value_set_boolean (value, linux_device_get_visible (device)); + break; + + case PROP_OBJECT_PATH: + g_value_set_string (value, linux_device_get_object_path (device)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +linux_device_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + LinuxDevice *device = LINUX_DEVICE (object); + + switch (prop_id) + { + case PROP_UDEV_DEVICE: + linux_device_set_udev_device (device, g_value_get_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +linux_device_finalize (GObject *object) +{ + LinuxDevice *device = LINUX_DEVICE (object); + + if (device->priv->udev_device != NULL) + g_object_unref (device->priv->udev_device); + g_free (device->priv->object_path); + + if (G_OBJECT_CLASS (linux_device_parent_class)->finalize != NULL) + G_OBJECT_CLASS (linux_device_parent_class)->finalize (object); +} + +static void +linux_device_init (LinuxDevice *device) +{ + device->priv = G_TYPE_INSTANCE_GET_PRIVATE (device, TYPE_LINUX_DEVICE, LinuxDevicePrivate); +} + +static void +linux_device_constructed (GObject *object) +{ + LinuxDevice *device = LINUX_DEVICE (object); + + linux_device_update (device); + + if (G_OBJECT_CLASS (linux_device_parent_class)->constructed != NULL) + G_OBJECT_CLASS (linux_device_parent_class)->constructed (object); +} + +static void +linux_device_class_init (LinuxDeviceClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->get_property = linux_device_get_property; + gobject_class->set_property = linux_device_set_property; + gobject_class->constructed = linux_device_constructed; + gobject_class->finalize = linux_device_finalize; + + g_type_class_add_private (klass, sizeof (LinuxDevicePrivate)); + + g_object_class_install_property (gobject_class, + PROP_UDEV_DEVICE, + g_param_spec_object ("udev-device", + "UDev Device", + "The underlying GUdevDevice", + G_UDEV_TYPE_DEVICE, + G_PARAM_READABLE | + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB | + G_PARAM_STATIC_NICK)); + + g_object_class_install_property (gobject_class, + PROP_VISIBLE, + g_param_spec_boolean ("visible", + "Visible", + "Whether the device should be exported on D-Bus", + TRUE, + G_PARAM_READABLE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB | + G_PARAM_STATIC_NICK)); + + g_object_class_install_property (gobject_class, + PROP_OBJECT_PATH, + g_param_spec_string ("object-path", + "Object Path", + "The D-Bus object path to use for exporting the device", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_NAME | + G_PARAM_STATIC_BLURB | + G_PARAM_STATIC_NICK)); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +LinuxDevice * +linux_device_new (GUdevDevice *udev_device) +{ + return LINUX_DEVICE (g_object_new (TYPE_LINUX_DEVICE, + "udev-device", udev_device, + NULL)); +} + +GUdevDevice * +linux_device_get_udev_device (LinuxDevice *device) +{ + g_return_val_if_fail (IS_LINUX_DEVICE (device), NULL); + return device->priv->udev_device; +} + +void +linux_device_set_udev_device (LinuxDevice *device, + GUdevDevice *udev_device) +{ + g_return_if_fail (IS_LINUX_DEVICE (device)); + g_return_if_fail (G_UDEV_IS_DEVICE (udev_device)); + + if (device->priv->udev_device != NULL) + g_object_unref (device->priv->udev_device); + device->priv->udev_device = g_object_ref (udev_device); +} + +gboolean +linux_device_get_visible (LinuxDevice *device) +{ + g_return_val_if_fail (IS_LINUX_DEVICE (device), FALSE); + return device->priv->visible; +} + +const gchar * +linux_device_get_object_path (LinuxDevice *device) +{ + g_return_val_if_fail (IS_LINUX_DEVICE (device), NULL); + return device->priv->object_path; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +device_iface_init (DeviceIface *iface) +{ + /* TODO */ +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gchar * +util_compute_object_path (const gchar *path) +{ + const gchar *basename; + GString *s; + guint n; + + g_return_val_if_fail (path != NULL, NULL); + + basename = strrchr (path, '/'); + if (basename != NULL) + basename++; + else + basename = path; + + s = g_string_new ("/org/freedesktop/UDisks/devices/"); + for (n = 0; basename[n] != '\0'; n++) + { + gint c = basename[n]; + + /* D-Bus spec sez: + * + * Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_" + */ + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9')) + { + g_string_append_c (s, c); + } + else + { + /* Escape bytes not in [A-Z][a-z][0-9] as _ */ + g_string_append_printf (s, "_%02x", c); + } + } + + return g_string_free (s, FALSE); +} + +void +linux_device_update (LinuxDevice *device) +{ + g_return_if_fail (IS_LINUX_DEVICE (device)); + + device_set_native_path (DEVICE (device), (gchar *) g_udev_device_get_sysfs_path (device->priv->udev_device)); + + /* TODO */ + device->priv->visible = TRUE; + device->priv->object_path = util_compute_object_path (device_get_native_path (DEVICE (device))); + + device_set_device_detection_time (DEVICE (device), device_get_device_detection_time (DEVICE (device)) + 1); + device_set_device_media_detection_time (DEVICE (device), device_get_device_media_detection_time (DEVICE (device)) + 2); +} + +/* ---------------------------------------------------------------------------------------------------- */ diff --git a/src/linuxdevice.h b/src/linuxdevice.h new file mode 100644 index 0000000..4ca2273 --- /dev/null +++ b/src/linuxdevice.h @@ -0,0 +1,61 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2008 David Zeuthen + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __LINUX_DEVICE_H__ +#define __LINUX_DEVICE_H__ + +#include "types.h" +#include + +G_BEGIN_DECLS + +#define TYPE_LINUX_DEVICE (linux_device_get_type ()) +#define LINUX_DEVICE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_LINUX_DEVICE, LinuxDevice)) +#define LINUX_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TYPE_DEVICE, LinuxDeviceClass)) +#define IS_LINUX_DEVICE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_LINUX_DEVICE)) +#define IS_LINUX_DEVICE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TYPE_LINUX_DEVICE)) +#define LINUX_DEVICE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TYPE_LINUX_DEVICE, LinuxDeviceClass)) + +typedef struct _LinuxDeviceClass LinuxDeviceClass; +typedef struct _LinuxDevicePrivate LinuxDevicePrivate; + +struct _LinuxDevice +{ + DeviceStub parent; + LinuxDevicePrivate *priv; +}; + +struct _LinuxDeviceClass +{ + DeviceStubClass parent_class; +}; + +GType linux_device_get_type (void) G_GNUC_CONST; +LinuxDevice *linux_device_new (GUdevDevice *udev_device); +GUdevDevice *linux_device_get_udev_device (LinuxDevice *device); +void linux_device_set_udev_device (LinuxDevice *device, + GUdevDevice *udev_device); +void linux_device_update (LinuxDevice *device); +gboolean linux_device_get_visible (LinuxDevice *device); +const gchar *linux_device_get_object_path (LinuxDevice *device); + +G_END_DECLS + +#endif /* __LINUX_DEVICE_H__ */ diff --git a/src/main.c b/src/main.c index ee74327..857c3ce 100644 --- a/src/main.c +++ b/src/main.c @@ -49,6 +49,7 @@ on_bus_acquired (GDBusConnection *connection, g_assert (the_daemon == NULL); the_daemon = g_object_new (TYPE_LINUX_DAEMON, "daemon-version", PACKAGE_VERSION, + "connection", connection, NULL); error = NULL; diff --git a/src/types.h b/src/types.h index e93ee8e..9e08f3c 100644 --- a/src/types.h +++ b/src/types.h @@ -27,6 +27,7 @@ G_BEGIN_DECLS typedef struct _LinuxDaemon LinuxDaemon; +typedef struct _LinuxDevice LinuxDevice; typedef struct Mount Mount; typedef struct MountMonitor MountMonitor;