diff options
author | David Zeuthen <davidz@redhat.com> | 2011-08-16 10:50:33 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2011-08-16 10:50:33 -0400 |
commit | c12cd7a91ae56e937a13746a3a87db73cc300e84 (patch) | |
tree | 80b61f1472f254850459a1dc7b201421535819a1 | |
parent | 157b215bfccf469e729633e67e32a7ebc4590169 (diff) |
Factor out drive functionality into three separate types
Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r-- | doc/udisks2-docs.xml | 7 | ||||
-rw-r--r-- | doc/udisks2-sections.txt | 43 | ||||
-rw-r--r-- | doc/udisks2.types | 2 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/udisksdaemontypes.h | 6 | ||||
-rw-r--r-- | src/udiskslinuxblock.c | 8 | ||||
-rw-r--r-- | src/udiskslinuxdrive.c | 1093 | ||||
-rw-r--r-- | src/udiskslinuxdrive.h | 22 | ||||
-rw-r--r-- | src/udiskslinuxdriveata.c | 387 | ||||
-rw-r--r-- | src/udiskslinuxdriveata.h | 43 | ||||
-rw-r--r-- | src/udiskslinuxdriveobject.c | 860 | ||||
-rw-r--r-- | src/udiskslinuxdriveobject.h | 57 | ||||
-rw-r--r-- | src/udiskslinuxprovider.c | 80 |
13 files changed, 1531 insertions, 1079 deletions
diff --git a/doc/udisks2-docs.xml b/doc/udisks2-docs.xml index 854f37e..a6a7426 100644 --- a/doc/udisks2-docs.xml +++ b/doc/udisks2-docs.xml @@ -191,11 +191,16 @@ <xi:include href="xml/udisksspawnedjob.xml"/> </chapter> <chapter id="ref-daemon-linux"> - <title>Linux-specific implementation</title> + <title>Linux-specific objects and providers</title> <xi:include href="xml/udiskslinuxprovider.xml"/> + <xi:include href="xml/udiskslinuxdriveobject.xml"/> + </chapter> + <chapter id="ref-daemon-linux-ifaces"> + <title>Linux implementation of interfaces</title> <xi:include href="xml/udiskslinuxmanager.xml"/> <xi:include href="xml/udiskslinuxblock.xml"/> <xi:include href="xml/udiskslinuxdrive.xml"/> + <xi:include href="xml/udiskslinuxdriveata.xml"/> <xi:include href="xml/udiskslinuxfilesystem.xml"/> <xi:include href="xml/udiskslinuxencrypted.xml"/> <xi:include href="xml/udiskslinuxswapspace.xml"/> diff --git a/doc/udisks2-sections.txt b/doc/udisks2-sections.txt index 17cabce..4d5e48c 100644 --- a/doc/udisks2-sections.txt +++ b/doc/udisks2-sections.txt @@ -160,21 +160,50 @@ udisks_linux_block_get_type </SECTION> <SECTION> +<FILE>udiskslinuxdriveobject</FILE> +<TITLE>UDisksLinuxDriveObject</TITLE> +UDisksLinuxDriveObject +udisks_linux_drive_object_new +udisks_linux_drive_object_uevent +udisks_linux_drive_object_get_daemon +udisks_linux_drive_object_get_block +udisks_linux_drive_object_get_device +udisks_linux_drive_object_get_devices +udisks_linux_drive_object_housekeeping +<SUBSECTION Standard> +UDISKS_TYPE_LINUX_DRIVE_OBJECT +UDISKS_LINUX_DRIVE_OBJECT +UDISKS_IS_LINUX_DRIVE_OBJECT +<SUBSECTION Private> +udisks_linux_drive_object_get_type +udisks_linux_drive_object_should_include_device +</SECTION> + +<SECTION> <FILE>udiskslinuxdrive</FILE> -<TITLE>UDisksLinuxDrive</TITLE> UDisksLinuxDrive udisks_linux_drive_new -udisks_linux_drive_uevent -udisks_linux_drive_get_daemon -udisks_linux_drive_get_devices -udisks_linux_drive_housekeeping +udisks_linux_drive_update <SUBSECTION Standard> -UDISKS_TYPE_LINUX_DRIVE UDISKS_LINUX_DRIVE UDISKS_IS_LINUX_DRIVE +UDISKS_TYPE_LINUX_DRIVE <SUBSECTION Private> udisks_linux_drive_get_type -udisks_linux_drive_should_include_device +</SECTION> + +<SECTION> +<FILE>udiskslinuxdriveata</FILE> +UDisksLinuxDriveAta +udisks_linux_drive_ata_new +udisks_linux_drive_ata_update +udisks_linux_drive_ata_refresh_smart_sync +<SUBSECTION Standard> +UDISKS_LINUX_DRIVE_ATA +UDISKS_IS_LINUX_DRIVE_ATA +UDISKS_TYPE_LINUX_DRIVE_ATA +<SUBSECTION Private> +udisks_linux_drive_ata_get_type </SECTION> <SECTION> diff --git a/doc/udisks2.types b/doc/udisks2.types index 7b0ceee..c8de422 100644 --- a/doc/udisks2.types +++ b/doc/udisks2.types @@ -3,6 +3,8 @@ udisks_client_get_type udisks_daemon_get_type udisks_linux_block_get_type udisks_linux_drive_get_type +udisks_linux_drive_ata_get_type +udisks_linux_drive_object_get_type udisks_base_job_get_type udisks_spawned_job_get_type udisks_threaded_job_get_type diff --git a/src/Makefile.am b/src/Makefile.am index 962cf12..f628971 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -52,7 +52,9 @@ libudisks_daemon_la_SOURCES = \ udiskslinuxencrypted.h udiskslinuxencrypted.c \ udiskslinuxswapspace.h udiskslinuxswapspace.c \ udiskslinuxloop.h udiskslinuxloop.c \ + udiskslinuxdriveobject.h udiskslinuxdriveobject.c \ udiskslinuxdrive.h udiskslinuxdrive.c \ + udiskslinuxdriveata.h udiskslinuxdriveata.c \ udiskslinuxmanager.h udiskslinuxmanager.c \ udisksbasejob.h udisksbasejob.c \ udisksspawnedjob.h udisksspawnedjob.c \ diff --git a/src/udisksdaemontypes.h b/src/udisksdaemontypes.h index edf97c2..853fbc8 100644 --- a/src/udisksdaemontypes.h +++ b/src/udisksdaemontypes.h @@ -37,9 +37,15 @@ typedef struct _UDisksLinuxProvider UDisksLinuxProvider; struct _UDisksLinuxBlock; typedef struct _UDisksLinuxBlock UDisksLinuxBlock; +struct _UDisksLinuxDriveObject; +typedef struct _UDisksLinuxDriveObject UDisksLinuxDriveObject; + struct _UDisksLinuxDrive; typedef struct _UDisksLinuxDrive UDisksLinuxDrive; +struct _UDisksLinuxDriveAta; +typedef struct _UDisksLinuxDriveAta UDisksLinuxDriveAta; + struct _UDisksBaseJob; typedef struct _UDisksBaseJob UDisksBaseJob; diff --git a/src/udiskslinuxblock.c b/src/udiskslinuxblock.c index bec388d..b6b13a7 100644 --- a/src/udiskslinuxblock.c +++ b/src/udiskslinuxblock.c @@ -40,6 +40,7 @@ #include "udiskslinuxblock.h" #include "udisksmount.h" #include "udisksmountmonitor.h" +#include "udiskslinuxdriveobject.h" #include "udiskslinuxdrive.h" #include "udiskslinuxfilesystem.h" #include "udiskslinuxencrypted.h" @@ -1252,16 +1253,13 @@ find_drive (GDBusObjectManagerServer *object_manager, for (l = objects; l != NULL; l = l->next) { GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (l->data); - UDisksLinuxDrive *drive; GList *drive_devices; GList *j; - if (!UDISKS_IS_LINUX_DRIVE (object)) + if (!UDISKS_IS_LINUX_DRIVE_OBJECT (object)) continue; - drive = UDISKS_LINUX_DRIVE (object); - drive_devices = udisks_linux_drive_get_devices (drive); - + drive_devices = udisks_linux_drive_object_get_devices (UDISKS_LINUX_DRIVE_OBJECT (object)); for (j = drive_devices; j != NULL; j = j->next) { GUdevDevice *drive_device = G_UDEV_DEVICE (j->data); diff --git a/src/udiskslinuxdrive.c b/src/udiskslinuxdrive.c index df42c98..9a6db9a 100644 --- a/src/udiskslinuxdrive.c +++ b/src/udiskslinuxdrive.c @@ -21,25 +21,32 @@ #include "config.h" #include <glib/gi18n-lib.h> +#include <sys/types.h> +#include <pwd.h> +#include <grp.h> #include <string.h> #include <stdlib.h> #include <stdio.h> +#include <mntent.h> -#include <atasmart.h> +#include <glib/gstdio.h> #include "udiskslogging.h" -#include "udisksdaemon.h" -#include "udisksdaemonutil.h" #include "udiskslinuxprovider.h" +#include "udiskslinuxdriveobject.h" #include "udiskslinuxdrive.h" #include "udiskslinuxblock.h" +#include "udisksdaemon.h" +#include "udiskscleanup.h" +#include "udisksdaemonutil.h" /** * SECTION:udiskslinuxdrive * @title: UDisksLinuxDrive - * @short_description: Linux drives (ATA, SCSI, Software RAID, etc.) + * @short_description: Linux implementation of #UDisksDrive * - * Object corresponding to a Drive on Linux. + * This type provides an implementation of the #UDisksDrive interface + * on Linux. */ typedef struct _UDisksLinuxDriveClass UDisksLinuxDriveClass; @@ -47,409 +54,53 @@ typedef struct _UDisksLinuxDriveClass UDisksLinuxDriveClass; /** * UDisksLinuxDrive: * - * The #UDisksLinuxDrive structure contains only private data and - * should only be accessed using the provided API. + * The #UDisksLinuxDrive structure contains only private data and should + * only be accessed using the provided API. */ struct _UDisksLinuxDrive { - UDisksObjectSkeleton parent_instance; - - UDisksDaemon *daemon; - - /* list of GUdevDevice objects for block objects */ - GList *devices; - - /* interfaces */ - UDisksDrive *iface_drive; - UDisksDriveAta *iface_drive_ata; - - /* ATA Smart */ - guint64 ata_smart_updated; - gboolean ata_smart_failing; - gdouble ata_smart_temperature; - guint64 ata_smart_power_on_seconds; - - guint64 detection_time_at_construction; + UDisksDriveSkeleton parent_instance; }; -G_LOCK_DEFINE_STATIC (drive_lock); - struct _UDisksLinuxDriveClass { - UDisksObjectSkeletonClass parent_class; -}; - -enum -{ - PROP_0, - PROP_DAEMON, - PROP_DEVICE + UDisksDriveSkeletonClass parent_class; }; -G_DEFINE_TYPE (UDisksLinuxDrive, udisks_linux_drive, UDISKS_TYPE_OBJECT_SKELETON); - -static void -udisks_linux_drive_finalize (GObject *object) -{ - UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (object); - - /* note: we don't hold a ref to drive->daemon or drive->mount_monitor */ - g_list_foreach (drive->devices, (GFunc) g_object_unref, NULL); - g_list_free (drive->devices); - - if (drive->iface_drive != NULL) - g_object_unref (drive->iface_drive); - if (drive->iface_drive_ata != NULL) - g_object_unref (drive->iface_drive_ata); - - if (G_OBJECT_CLASS (udisks_linux_drive_parent_class)->finalize != NULL) - G_OBJECT_CLASS (udisks_linux_drive_parent_class)->finalize (object); -} - -static void -udisks_linux_drive_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (object); - - switch (prop_id) - { - case PROP_DAEMON: - g_value_set_object (value, udisks_linux_drive_get_daemon (drive)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -udisks_linux_drive_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (object); - - switch (prop_id) - { - case PROP_DAEMON: - g_assert (drive->daemon == NULL); - /* we don't take a reference to the daemon */ - drive->daemon = g_value_get_object (value); - break; +static void drive_iface_init (UDisksDriveIface *iface); - case PROP_DEVICE: - g_assert (drive->devices == NULL); - drive->devices = g_list_prepend (NULL, g_value_dup_object (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} +G_DEFINE_TYPE_WITH_CODE (UDisksLinuxDrive, udisks_linux_drive, UDISKS_TYPE_DRIVE_SKELETON, + G_IMPLEMENT_INTERFACE (UDISKS_TYPE_DRIVE, drive_iface_init)); +/* ---------------------------------------------------------------------------------------------------- */ static void udisks_linux_drive_init (UDisksLinuxDrive *drive) { -} - -static GObjectConstructParam * -find_construct_property (guint n_construct_properties, - GObjectConstructParam *construct_properties, - const gchar *name) -{ - guint n; - for (n = 0; n < n_construct_properties; n++) - if (g_strcmp0 (g_param_spec_get_name (construct_properties[n].pspec), name) == 0) - return &construct_properties[n]; - return NULL; -} - -/* unless given, compute object path from sysfs path */ -static GObject * -udisks_linux_drive_constructor (GType type, - guint n_construct_properties, - GObjectConstructParam *construct_properties) -{ - GObjectConstructParam *cp; - UDisksDaemon *daemon; - GUdevClient *client; - GUdevDevice *device; - - cp = find_construct_property (n_construct_properties, construct_properties, "daemon"); - g_assert (cp != NULL); - daemon = UDISKS_DAEMON (g_value_get_object (cp->value)); - g_assert (daemon != NULL); - - client = udisks_linux_provider_get_udev_client (udisks_daemon_get_linux_provider (daemon)); - - cp = find_construct_property (n_construct_properties, construct_properties, "device"); - g_assert (cp != NULL); - device = G_UDEV_DEVICE (g_value_get_object (cp->value)); - g_assert (device != NULL); - - if (!udisks_linux_drive_should_include_device (client, device, NULL)) - { - return NULL; - } - else - { - return G_OBJECT_CLASS (udisks_linux_drive_parent_class)->constructor (type, - n_construct_properties, - construct_properties); - } -} - -static void -strip_and_replace_with_uscore (gchar *s) -{ - guint n; - - if (s == NULL) - goto out; - - g_strstrip (s); - - for (n = 0; s != NULL && s[n] != '\0'; n++) - { - if (s[n] == ' ' || s[n] == '-') - s[n] = '_'; - } - - out: - ; -} - -static void -udisks_linux_drive_constructed (GObject *object) -{ - UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (object); - gchar *vendor; - gchar *model; - gchar *serial; - GString *str; - - /* initial coldplug */ - udisks_linux_drive_uevent (drive, "add", drive->devices->data); - - /* compute the object path */ - vendor = g_strdup (udisks_drive_get_vendor (drive->iface_drive)); - model = g_strdup (udisks_drive_get_model (drive->iface_drive)); - serial = g_strdup (udisks_drive_get_serial (drive->iface_drive)); - strip_and_replace_with_uscore (vendor); - strip_and_replace_with_uscore (model); - strip_and_replace_with_uscore (serial); - str = g_string_new ("/org/freedesktop/UDisks2/drives/"); - if (vendor == NULL && model == NULL && serial == NULL) - { - g_string_append (str, "drive"); - } - else - { - /* <VENDOR>_<MODEL>_<SERIAL> */ - if (vendor != NULL && strlen (vendor) > 0) - { - udisks_safe_append_to_object_path (str, vendor); - } - if (model != NULL && strlen (model) > 0) - { - if (str->str[str->len - 1] != '/') - g_string_append_c (str, '_'); - udisks_safe_append_to_object_path (str, model); - } - if (serial != NULL && strlen (serial) > 0) - { - if (str->str[str->len - 1] != '/') - g_string_append_c (str, '_'); - udisks_safe_append_to_object_path (str, serial); - } - } - g_free (vendor); - g_free (model); - g_free (serial); - g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (drive), str->str); - g_string_free (str, TRUE); - - if (G_OBJECT_CLASS (udisks_linux_drive_parent_class)->constructed != NULL) - G_OBJECT_CLASS (udisks_linux_drive_parent_class)->constructed (object); + g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (drive), + G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD); } static void udisks_linux_drive_class_init (UDisksLinuxDriveClass *klass) { - GObjectClass *gobject_class; - - gobject_class = G_OBJECT_CLASS (klass); - gobject_class->constructor = udisks_linux_drive_constructor; - gobject_class->finalize = udisks_linux_drive_finalize; - gobject_class->constructed = udisks_linux_drive_constructed; - gobject_class->set_property = udisks_linux_drive_set_property; - gobject_class->get_property = udisks_linux_drive_get_property; - - /** - * UDisksLinuxDrive:daemon: - * - * The #UDisksDaemon the object is for. - */ - g_object_class_install_property (gobject_class, - PROP_DAEMON, - g_param_spec_object ("daemon", - "Daemon", - "The daemon the object is for", - UDISKS_TYPE_DAEMON, - G_PARAM_READABLE | - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - /** - * UDisksLinuxDrive:device: - * - * The #GUdevDevice for the object. Connect to the #GObject::notify - * signal to get notified whenever this is updated. - */ - g_object_class_install_property (gobject_class, - PROP_DEVICE, - g_param_spec_object ("device", - "Device", - "The device for the object", - G_UDEV_TYPE_DEVICE, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - } /** * udisks_linux_drive_new: - * @daemon: A #UDisksDaemon. - * @device: The #GUdevDevice for the sysfs block device. - * - * Create a new drive object. - * - * Returns: A #UDisksLinuxDrive object or %NULL if @device does not represent a drive. Free with g_object_unref(). - */ -UDisksLinuxDrive * -udisks_linux_drive_new (UDisksDaemon *daemon, - GUdevDevice *device) -{ - GObject *object; - - g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL); - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); - - object = g_object_new (UDISKS_TYPE_LINUX_DRIVE, - "daemon", daemon, - "device", device, - NULL); - - if (object != NULL) - return UDISKS_LINUX_DRIVE (object); - else - return NULL; -} - -/** - * udisks_linux_drive_get_daemon: - * @drive: A #UDisksLinuxDrive. - * - * Gets the daemon used by @drive. * - * Returns: A #UDisksDaemon. Do not free, the object is owned by @drive. - */ -UDisksDaemon * -udisks_linux_drive_get_daemon (UDisksLinuxDrive *drive) -{ - g_return_val_if_fail (UDISKS_IS_LINUX_DRIVE (drive), NULL); - return drive->daemon; -} - -/** - * udisks_linux_drive_get_devices: - * @drive: A #UDisksLinuxDrive. - * - * Gets the current #GUdevDevice objects associated with @drive. + * Creates a new #UDisksLinuxDrive instance. * - * Returns: A list of #GUdevDevice objects. Free each element with - * g_object_unref(), then free the list with g_list_free(). + * Returns: A new #UDisksLinuxDrive. Free with g_object_unref(). */ -GList * -udisks_linux_drive_get_devices (UDisksLinuxDrive *drive) -{ - GList *ret; - g_return_val_if_fail (UDISKS_IS_LINUX_DRIVE (drive), NULL); - ret = g_list_copy (drive->devices); - g_list_foreach (ret, (GFunc) g_object_ref, NULL); - return ret; -} - -/* ---------------------------------------------------------------------------------------------------- */ - -typedef gboolean (*HasInterfaceFunc) (UDisksLinuxDrive *drive); -typedef void (*ConnectInterfaceFunc) (UDisksLinuxDrive *drive); -typedef void (*UpdateInterfaceFunc) (UDisksLinuxDrive *drive, - const gchar *uevent_action, - GDBusInterface *interface); - -static void -update_iface (UDisksLinuxDrive *drive, - const gchar *uevent_action, - HasInterfaceFunc has_func, - ConnectInterfaceFunc connect_func, - UpdateInterfaceFunc update_func, - GType skeleton_type, - gpointer _interface_pointer) +UDisksDrive * +udisks_linux_drive_new (void) { - gboolean has; - gboolean add; - GDBusInterface **interface_pointer = _interface_pointer; - - g_return_if_fail (drive != NULL); - g_return_if_fail (has_func != NULL); - g_return_if_fail (update_func != NULL); - g_return_if_fail (g_type_is_a (skeleton_type, G_TYPE_OBJECT)); - g_return_if_fail (g_type_is_a (skeleton_type, G_TYPE_DBUS_INTERFACE)); - g_return_if_fail (interface_pointer != NULL); - g_return_if_fail (*interface_pointer == NULL || G_IS_DBUS_INTERFACE (*interface_pointer)); - - add = FALSE; - has = has_func (drive); - if (*interface_pointer == NULL) - { - if (has) - { - *interface_pointer = g_object_new (skeleton_type, NULL); - if (connect_func != NULL) - connect_func (drive); - add = TRUE; - } - } - else - { - if (!has) - { - g_dbus_object_skeleton_remove_interface (G_DBUS_OBJECT_SKELETON (drive), G_DBUS_INTERFACE_SKELETON (*interface_pointer)); - g_object_unref (*interface_pointer); - *interface_pointer = NULL; - } - } - - if (*interface_pointer != NULL) - { - update_func (drive, uevent_action, G_DBUS_INTERFACE (*interface_pointer)); - if (add) - g_dbus_object_skeleton_add_interface (G_DBUS_OBJECT_SKELETON (drive), G_DBUS_INTERFACE_SKELETON (*interface_pointer)); - } + return UDISKS_DRIVE (g_object_new (UDISKS_TYPE_LINUX_DRIVE, + NULL)); } /* ---------------------------------------------------------------------------------------------------- */ -/* org.freedesktop.UDisks.Drive */ static const struct { @@ -539,9 +190,8 @@ ptr_str_array_compare (const gchar **a, } static void -drive_set_media (UDisksLinuxDrive *drive, - UDisksDrive *iface, - GUdevDevice *device) +set_media (UDisksDrive *iface, + GUdevDevice *device) { guint n; GPtrArray *media_compat_array; @@ -581,9 +231,8 @@ drive_set_media (UDisksLinuxDrive *drive, } static void -drive_set_rotation_rate (UDisksLinuxDrive *drive, - UDisksDrive *iface, - GUdevDevice *device) +set_rotation_rate (UDisksDrive *iface, + GUdevDevice *device) { gint rate; @@ -600,144 +249,9 @@ drive_set_rotation_rate (UDisksLinuxDrive *drive, udisks_drive_set_rotation_rate (iface, rate); } -static gboolean -drive_check (UDisksLinuxDrive *drive) -{ - return TRUE; -} - -/* TODO: ensure that returned object is for a physical device e.g. not multipath */ -static UDisksObject * -find_block_object (UDisksLinuxDrive *drive) -{ - GDBusObjectManagerServer *object_manager; - UDisksObject *ret; - GList *objects; - GList *l; - - ret = NULL; - - object_manager = udisks_daemon_get_object_manager (udisks_linux_drive_get_daemon (drive)); - objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager)); - for (l = objects; l != NULL; l = l->next) - { - GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (l->data); - UDisksBlockDevice *block; - GUdevDevice *device; - gboolean is_disk; - - if (!UDISKS_IS_LINUX_BLOCK (object)) - continue; - - device = udisks_linux_block_get_device (UDISKS_LINUX_BLOCK (object)); - is_disk = (g_strcmp0 (g_udev_device_get_devtype (device), "disk") == 0); - g_object_unref (device); - - if (!is_disk) - continue; - - block = udisks_object_peek_block_device (UDISKS_OBJECT (object)); - - if (g_strcmp0 (udisks_block_device_get_drive (block), - g_dbus_object_get_object_path (G_DBUS_OBJECT (drive))) == 0) - { - ret = g_object_ref (object); - goto out; - } - } - - out: - g_list_foreach (objects, (GFunc) g_object_unref, NULL); - g_list_free (objects); - return ret; -} - -static gboolean -on_eject (UDisksDrive *drive_iface, - GDBusMethodInvocation *invocation, - GVariant *options, - gpointer user_data) -{ - UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (user_data); - UDisksObject *block_object; - UDisksBlockDevice *block; - UDisksDaemon *daemon; - const gchar *action_id; - gchar *error_message; - - daemon = NULL; - block = NULL; - error_message = NULL; - - daemon = udisks_linux_drive_get_daemon (drive); - block_object = find_block_object (drive); - if (block_object == NULL) - { - g_dbus_method_invocation_return_error (invocation, - UDISKS_ERROR, - UDISKS_ERROR_FAILED, - "Unable to find physical block device for drive"); - goto out; - } - block = udisks_object_peek_block_device (block_object); - - /* TODO: is it a good idea to overload modify-device? */ - action_id = "org.freedesktop.udisks2.modify-device"; - if (udisks_block_device_get_hint_system (block)) - action_id = "org.freedesktop.udisks2.modify-device-system"; - - /* Check that the user is actually authorized */ - if (!udisks_daemon_util_check_authorization_sync (daemon, - block_object, - action_id, - options, - N_("Authentication is required to eject $(udisks2.device)"), - invocation)) - goto out; - - if (!udisks_daemon_launch_spawned_job_sync (daemon, - NULL, /* GCancellable */ - 0, /* uid_t run_as_uid */ - 0, /* uid_t run_as_euid */ - NULL, /* gint *out_status */ - &error_message, - NULL, /* input_string */ - "eject \"%s\"", - udisks_block_device_get_device (block))) - { - g_dbus_method_invocation_return_error (invocation, - UDISKS_ERROR, - UDISKS_ERROR_FAILED, - "Error eject %s: %s", - udisks_block_device_get_device (block), - error_message); - goto out; - } - - udisks_drive_complete_eject (drive_iface, invocation); - - out: - if (block_object != NULL) - g_object_unref (block_object); - g_free (error_message); - return TRUE; /* returning TRUE means that we handled the method invocation */ -} - -static void -drive_connect (UDisksLinuxDrive *drive) -{ - g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (drive->iface_drive), - G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD); - g_signal_connect (drive->iface_drive, - "handle-eject", - G_CALLBACK (on_eject), - drive); -} - static void -drive_set_connection_bus (UDisksLinuxDrive *drive, - UDisksDrive *iface, - GUdevDevice *device) +set_connection_bus (UDisksDrive *iface, + GUdevDevice *device) { GUdevDevice *parent; @@ -767,20 +281,25 @@ drive_set_connection_bus (UDisksLinuxDrive *drive, } -static void -drive_update (UDisksLinuxDrive *drive, - const gchar *uevent_action, - GDBusInterface *_iface) +/** + * udisks_linux_drive_update: + * @drive: A #UDisksLinuxDrive. + * @object: The enclosing #UDisksLinuxDriveObject instance. + * + * Updates the interface. + */ +void +udisks_linux_drive_update (UDisksLinuxDrive *drive, + UDisksLinuxDriveObject *object) { - UDisksDrive *iface = UDISKS_DRIVE (_iface); + UDisksDrive *iface = UDISKS_DRIVE (drive); GUdevDevice *device; gchar *sort_key; - if (drive->devices == NULL) + device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */); + if (device == NULL) goto out; - device = G_UDEV_DEVICE (drive->devices->data); - /* this is the _almost_ the same for both ATA and SCSI devices (cf. udev's ata_id and scsi_id) * but we special case since there are subtle differences... */ @@ -916,9 +435,9 @@ drive_update (UDisksLinuxDrive *drive, /* common bits go here */ udisks_drive_set_media_removable (iface, g_udev_device_get_sysfs_attr_as_boolean (device, "removable")); udisks_drive_set_size (iface, udisks_daemon_util_block_get_size (device)); - drive_set_media (drive, iface, device); - drive_set_rotation_rate (drive, iface, device); - drive_set_connection_bus (drive, iface, device); + set_media (iface, device); + set_rotation_rate (iface, device); + set_connection_bus (iface, device); #if 0 /* This ensures that devices are shown in the order they are detected */ @@ -931,129 +450,43 @@ drive_update (UDisksLinuxDrive *drive, { GUdevClient *client; GUdevDevice *ns_device; - client = udisks_linux_provider_get_udev_client (udisks_daemon_get_linux_provider (drive->daemon)); + client = g_udev_client_new (NULL); ns_device = g_udev_client_query_by_sysfs_path (client, g_udev_device_get_sysfs_path (device)); sort_key = g_strdup_printf ("%" G_GUINT64_FORMAT, time (NULL) * G_USEC_PER_SEC - g_udev_device_get_usec_since_initialized (ns_device)); g_object_unref (ns_device); + g_object_unref (client); } #endif udisks_drive_set_sort_key (iface, sort_key); g_free (sort_key); out: - ; + if (device != NULL) + g_object_unref (device); } /* ---------------------------------------------------------------------------------------------------- */ -static void drive_ata_smart_update (UDisksLinuxDrive *drive); - -static gboolean -update_smart (UDisksLinuxDrive *drive, - gboolean nowakeup, - GError **error) -{ - gboolean ret; - SkDisk *d; - SkBool awake; - SkBool good; - uint64_t temp_mkelvin; - uint64_t power_on_msec; - GUdevDevice *device; - - d = NULL; - ret = FALSE; - - device = G_UDEV_DEVICE (drive->devices->data); - - if (sk_disk_open (g_udev_device_get_device_file (device), &d) != 0) - { - g_set_error (error, - UDISKS_ERROR, - UDISKS_ERROR_FAILED, - "sk_disk_open: %m"); - goto out; - } - - if (sk_disk_check_sleep_mode (d, &awake) != 0) - { - g_set_error (error, - UDISKS_ERROR, - UDISKS_ERROR_FAILED, - "sk_disk_check_sleep_mode: %m"); - goto out; - } - - /* don't wake up disk unless specically asked to */ - if (nowakeup && !awake) - { - g_set_error (error, - UDISKS_ERROR, - UDISKS_ERROR_WOULD_WAKEUP, - "Disk is in sleep mode and the nowakeup option was passed"); - goto out; - } - - if (sk_disk_smart_read_data (d) != 0) - { - g_set_error (error, - UDISKS_ERROR, - UDISKS_ERROR_FAILED, - "sk_disk_smart_read_data: %m"); - goto out; - } - - if (sk_disk_smart_status (d, &good) != 0) - { - g_set_error (error, - UDISKS_ERROR, - UDISKS_ERROR_FAILED, - "sk_disk_smart_status: %m"); - goto out; - } - - /* don't care if these are failing or not */ - temp_mkelvin = 0; - sk_disk_smart_get_temperature (d, &temp_mkelvin); - power_on_msec = 0; - sk_disk_smart_get_power_on (d, &power_on_msec); - - G_LOCK (drive_lock); - drive->ata_smart_updated = time (NULL); - drive->ata_smart_failing = !good; - drive->ata_smart_temperature = temp_mkelvin / 1000.0; - drive->ata_smart_power_on_seconds = power_on_msec / 1000.0; - G_UNLOCK (drive_lock); - - drive_ata_smart_update (drive); - - ret = TRUE; - - out: - if (d != NULL) - sk_disk_free (d); - return ret; -} - static gboolean -on_smart_update (UDisksDriveAta *drive_ata_iface, - GDBusMethodInvocation *invocation, - GVariant *options, - gpointer user_data) +handle_eject (UDisksDrive *_drive, + GDBusMethodInvocation *invocation, + GVariant *options) { - UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (user_data); - UDisksObject *block_object; + UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (_drive); + UDisksLinuxDriveObject *object; + UDisksLinuxBlock *block_object; UDisksBlockDevice *block; UDisksDaemon *daemon; const gchar *action_id; - gboolean nowakeup; - GError *error; + gchar *error_message; daemon = NULL; block = NULL; + error_message = NULL; - daemon = udisks_linux_drive_get_daemon (drive); - block_object = find_block_object (drive); + object = UDISKS_LINUX_DRIVE_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (drive))); + daemon = udisks_linux_drive_object_get_daemon (object); + block_object = udisks_linux_drive_object_get_block (object, TRUE); if (block_object == NULL) { g_dbus_method_invocation_return_error (invocation, @@ -1062,12 +495,7 @@ on_smart_update (UDisksDriveAta *drive_ata_iface, "Unable to find physical block device for drive"); goto out; } - block = udisks_object_peek_block_device (block_object); - - g_variant_lookup (options, - "nowakeup", - "b", - &nowakeup); + block = udisks_object_peek_block_device (UDISKS_OBJECT (block_object)); /* TODO: is it a good idea to overload modify-device? */ action_id = "org.freedesktop.udisks2.modify-device"; @@ -1076,396 +504,45 @@ on_smart_update (UDisksDriveAta *drive_ata_iface, /* Check that the user is actually authorized */ if (!udisks_daemon_util_check_authorization_sync (daemon, - block_object, + UDISKS_OBJECT (block_object), action_id, options, - N_("Authentication is required to update SMART from $(udisks2.device)"), + N_("Authentication is required to eject $(udisks2.device)"), invocation)) goto out; - if (!udisks_drive_ata_get_smart_supported (drive_ata_iface)) - { - g_dbus_method_invocation_return_error (invocation, - UDISKS_ERROR, - UDISKS_ERROR_FAILED, - "SMART is not supported"); - goto out; - } - - if (!udisks_drive_ata_get_smart_enabled (drive_ata_iface)) + if (!udisks_daemon_launch_spawned_job_sync (daemon, + NULL, /* GCancellable */ + 0, /* uid_t run_as_uid */ + 0, /* uid_t run_as_euid */ + NULL, /* gint *out_status */ + &error_message, + NULL, /* input_string */ + "eject \"%s\"", + udisks_block_device_get_device (block))) { g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED, - "SMART is not enabled"); - goto out; - } - - error = NULL; - if (!update_smart (drive, nowakeup, &error)) - { - udisks_warning ("Error updating ATA smart for %s: %s (%s, %d)", - g_dbus_object_get_object_path (G_DBUS_OBJECT (drive)), - error->message, g_quark_to_string (error->domain), error->code); - g_dbus_method_invocation_take_error (invocation, error); + "Error eject %s: %s", + udisks_block_device_get_device (block), + error_message); goto out; } - udisks_drive_ata_complete_smart_update (drive_ata_iface, invocation); + udisks_drive_complete_eject (UDISKS_DRIVE (drive), invocation); out: if (block_object != NULL) g_object_unref (block_object); + g_free (error_message); return TRUE; /* returning TRUE means that we handled the method invocation */ } -static gboolean -drive_ata_check (UDisksLinuxDrive *drive) -{ - gboolean ret; - GUdevDevice *device; - - ret = FALSE; - if (drive->devices == NULL) - goto out; - - device = G_UDEV_DEVICE (drive->devices->data); - if (!g_udev_device_get_property_as_boolean (device, "ID_ATA")) - goto out; - - ret = TRUE; - - out: - return ret; -} - -static void -drive_ata_connect (UDisksLinuxDrive *drive) -{ - g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (drive->iface_drive_ata), - G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD); - g_signal_connect (drive->iface_drive_ata, - "handle-smart-update", - G_CALLBACK (on_smart_update), - drive); -} - -/* also called from *any* thread when the SMART data has been updated */ -static void -drive_ata_smart_update (UDisksLinuxDrive *drive) -{ - GUdevDevice *device; - gboolean supported; - gboolean enabled; - guint64 updated; - gboolean failing; - gdouble temperature; - guint64 power_on_seconds; - - device = G_UDEV_DEVICE (drive->devices->data); - - supported = g_udev_device_get_property_as_boolean (device, "ID_ATA_FEATURE_SET_SMART"); - enabled = g_udev_device_get_property_as_boolean (device, "ID_ATA_FEATURE_SET_SMART_ENABLED"); - updated = 0; - failing = FALSE; - temperature = 0.0; - power_on_seconds = 0; - - G_LOCK (drive_lock); - if (drive->ata_smart_updated > 0) - { - updated = drive->ata_smart_updated; - failing = drive->ata_smart_failing; - temperature = drive->ata_smart_temperature; - power_on_seconds = drive->ata_smart_power_on_seconds; - } - G_UNLOCK (drive_lock); - - g_object_freeze_notify (G_OBJECT (drive->iface_drive_ata)); - udisks_drive_ata_set_smart_supported (drive->iface_drive_ata, supported); - udisks_drive_ata_set_smart_enabled (drive->iface_drive_ata, enabled); - udisks_drive_ata_set_smart_updated (drive->iface_drive_ata, updated); - udisks_drive_ata_set_smart_failing (drive->iface_drive_ata, failing); - udisks_drive_ata_set_smart_temperature (drive->iface_drive_ata, temperature); - udisks_drive_ata_set_smart_power_on_seconds (drive->iface_drive_ata, power_on_seconds); - g_object_thaw_notify (G_OBJECT (drive->iface_drive_ata)); -} - -static void -drive_ata_update (UDisksLinuxDrive *drive, - const gchar *uevent_action, - GDBusInterface *_iface) -{ - drive_ata_smart_update (drive); -} - -/* ---------------------------------------------------------------------------------------------------- */ - -static GList * -find_link_for_sysfs_path (UDisksLinuxDrive *drive, - const gchar *sysfs_path) -{ - GList *l; - GList *ret; - ret = NULL; - for (l = drive->devices; l != NULL; l = l->next) - { - GUdevDevice *device = G_UDEV_DEVICE (l->data); - if (g_strcmp0 (g_udev_device_get_sysfs_path (device), sysfs_path) == 0) - { - ret = l; - goto out; - } - } - out: - return ret; -} - -/** - * udisks_linux_drive_uevent: - * @drive: A #UDisksLinuxDrive. - * @action: Uevent action or %NULL - * @device: A new #GUdevDevice device object or %NULL if the device hasn't changed. - * - * Updates all information on interfaces on @drive. - */ -void -udisks_linux_drive_uevent (UDisksLinuxDrive *drive, - const gchar *action, - GUdevDevice *device) -{ - GList *link; - - g_return_if_fail (UDISKS_IS_LINUX_DRIVE (drive)); - g_return_if_fail (G_UDEV_IS_DEVICE (device)); - - link = find_link_for_sysfs_path (drive, g_udev_device_get_sysfs_path (device)); - if (g_strcmp0 (action, "remove") == 0) - { - if (link != NULL) - { - g_object_unref (G_UDEV_DEVICE (link->data)); - drive->devices = g_list_delete_link (drive->devices, link); - } - else - { - udisks_warning ("Drive doesn't have device with sysfs path %s on remove event", - g_udev_device_get_sysfs_path (device)); - } - } - else - { - if (link != NULL) - { - g_object_unref (G_UDEV_DEVICE (link->data)); - link->data = g_object_ref (device); - } - else - { - drive->devices = g_list_append (drive->devices, g_object_ref (device)); - } - } - - update_iface (drive, action, drive_check, drive_connect, drive_update, - UDISKS_TYPE_DRIVE_SKELETON, &drive->iface_drive); - update_iface (drive, action, drive_ata_check, drive_ata_connect, drive_ata_update, - UDISKS_TYPE_DRIVE_ATA_SKELETON, &drive->iface_drive_ata); -} - -/* ---------------------------------------------------------------------------------------------------- */ - -static gchar * -check_for_vpd (GUdevDevice *device) -{ - gchar *ret; - const gchar *serial; - const gchar *wwn; - - g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); - - ret = NULL; - - /* prefer WWN to serial */ - serial = g_udev_device_get_property (device, "ID_SERIAL"); - wwn = g_udev_device_get_property (device, "ID_WWN_WITH_EXTENSION"); - if (wwn != NULL && strlen (wwn) > 0) - { - ret = g_strdup (wwn); - } - else if (serial != NULL && strlen (serial) > 0) - { - ret = g_strdup (serial); - } - return ret; -} - -/* <internal> - * udisks_linux_drive_should_include_device: - * @client: A #GUdevClient. - * @device: A #GUdevDevice. - * @out_vpd: Return location for unique ID or %NULL. - * - * Checks if we should even construct a #UDisksLinuxDrive for @device. - * - * Returns: %TRUE if we should construct an object, %FALSE otherwise. - */ -gboolean -udisks_linux_drive_should_include_device (GUdevClient *client, - GUdevDevice *device, - gchar **out_vpd) -{ - gboolean ret; - gchar *vpd; - - ret = FALSE; - vpd = NULL; - - /* The 'block' subsystem encompasses several objects with varying - * DEVTYPE including - * - * - disk - * - partition - * - * and we are only interested in the first. - */ - if (g_strcmp0 (g_udev_device_get_devtype (device), "disk") != 0) - goto out; - - vpd = check_for_vpd (device); - - if (vpd == NULL) - { - const gchar *name; - GUdevDevice *parent; - - name = g_udev_device_get_name (device); - - /* workaround for missing serial/wwn on virtio-blk */ - if (g_str_has_prefix (name, "vd")) - { - vpd = g_strdup (name); - goto found; - } - - /* workaround for missing serial/wwn on firewire devices */ - parent = g_udev_device_get_parent_with_subsystem (device, "firewire", NULL); - if (parent != NULL) - { - vpd = g_strdup (name); - g_object_unref (parent); - goto found; - } - - /* dm-multipath */ - const gchar *dm_name; - dm_name = g_udev_device_get_sysfs_attr (device, "dm/name"); - if (dm_name != NULL && g_str_has_prefix (dm_name, "mpath")) - { - gchar **slaves; - guint n; - slaves = udisks_daemon_util_resolve_links (g_udev_device_get_sysfs_path (device), "slaves"); - for (n = 0; slaves[n] != NULL; n++) - { - GUdevDevice *slave; - slave = g_udev_client_query_by_sysfs_path (client, slaves[n]); - if (slave != NULL) - { - vpd = check_for_vpd (slave); - if (vpd != NULL) - { - g_object_unref (slave); - g_strfreev (slaves); - goto found; - } - g_object_unref (slave); - } - } - g_strfreev (slaves); - } - } - - found: - if (vpd != NULL) - { - if (out_vpd != NULL) - { - *out_vpd = vpd; - vpd = NULL; - } - ret = TRUE; - } - - out: - g_free (vpd); - return ret; -} - /* ---------------------------------------------------------------------------------------------------- */ -/** - * udisks_linux_drive_housekeeping: - * @drive: A #UDisksLinuxDrive. - * @secs_since_last: Number of seconds sincex the last housekeeping or 0 if the first housekeeping ever. - * @cancellable: A %GCancellable or %NULL. - * @error: Return location for error or %NULL. - * - * Called periodically (every ten minutes or so) to perform - * housekeeping tasks such as refreshing ATA SMART data. - * - * The function runs in a dedicated thread and is allowed to perform - * blocking I/O. - * - * Long-running tasks should periodically check @cancellable to see if - * they have been cancelled. - * - * Returns: %TRUE if the operation succeeded, %FALSE if @error is set. - */ -gboolean -udisks_linux_drive_housekeeping (UDisksLinuxDrive *drive, - guint secs_since_last, - GCancellable *cancellable, - GError **error) +static void +drive_iface_init (UDisksDriveIface *iface) { - gboolean ret; - - ret = FALSE; - - if (drive->iface_drive_ata != NULL && - udisks_drive_ata_get_smart_supported (drive->iface_drive_ata) && - udisks_drive_ata_get_smart_enabled (drive->iface_drive_ata)) - { - GError *local_error; - gboolean nowakeup; - - /* Wake-up only on start-up */ - nowakeup = TRUE; - if (secs_since_last == 0) - nowakeup = FALSE; - - udisks_info ("Refreshing SMART data on %s (nowakeup=%d)", - g_dbus_object_get_object_path (G_DBUS_OBJECT (drive)), - nowakeup); - - local_error = NULL; - if (!update_smart (drive, nowakeup, &local_error)) - { - if (nowakeup && (local_error->domain == UDISKS_ERROR && - local_error->code == UDISKS_ERROR_WOULD_WAKEUP)) - { - udisks_info ("Drive %s is in a sleep state", - g_dbus_object_get_object_path (G_DBUS_OBJECT (drive))); - g_error_free (local_error); - } - else - { - g_propagate_prefixed_error (error, local_error, "Error updating SMART data: "); - goto out; - } - } - } - - ret = TRUE; - - out: - return ret; + iface->handle_eject = handle_eject; } diff --git a/src/udiskslinuxdrive.h b/src/udiskslinuxdrive.h index e287ebb..084a68d 100644 --- a/src/udiskslinuxdrive.h +++ b/src/udiskslinuxdrive.h @@ -22,7 +22,6 @@ #define __UDISKS_LINUX_DRIVE_H__ #include "udisksdaemontypes.h" -#include <gudev/gudev.h> G_BEGIN_DECLS @@ -30,23 +29,10 @@ G_BEGIN_DECLS #define UDISKS_LINUX_DRIVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UDISKS_TYPE_LINUX_DRIVE, UDisksLinuxDrive)) #define UDISKS_IS_LINUX_DRIVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UDISKS_TYPE_LINUX_DRIVE)) -GType udisks_linux_drive_get_type (void) G_GNUC_CONST; -UDisksLinuxDrive *udisks_linux_drive_new (UDisksDaemon *daemon, - GUdevDevice *device); -void udisks_linux_drive_uevent (UDisksLinuxDrive *drive, - const gchar *action, - GUdevDevice *device); -UDisksDaemon *udisks_linux_drive_get_daemon (UDisksLinuxDrive *drive); -GList *udisks_linux_drive_get_devices (UDisksLinuxDrive *drive); - -gboolean udisks_linux_drive_housekeeping (UDisksLinuxDrive *drive, - guint secs_since_last, - GCancellable *cancellable, - GError **error); - -gboolean udisks_linux_drive_should_include_device (GUdevClient *client, - GUdevDevice *device, - gchar **out_vpd); +GType udisks_linux_drive_get_type (void) G_GNUC_CONST; +UDisksDrive *udisks_linux_drive_new (void); +void udisks_linux_drive_update (UDisksLinuxDrive *drive, + UDisksLinuxDriveObject *object); G_END_DECLS diff --git a/src/udiskslinuxdriveata.c b/src/udiskslinuxdriveata.c new file mode 100644 index 0000000..00104f3 --- /dev/null +++ b/src/udiskslinuxdriveata.c @@ -0,0 +1,387 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com> + * + * 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 <glib/gi18n-lib.h> + +#include <sys/types.h> +#include <pwd.h> +#include <grp.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <mntent.h> + +#include <glib/gstdio.h> + +#include <atasmart.h> + +#include "udiskslogging.h" +#include "udiskslinuxprovider.h" +#include "udiskslinuxdriveobject.h" +#include "udiskslinuxdriveata.h" +#include "udiskslinuxblock.h" +#include "udisksdaemon.h" +#include "udiskscleanup.h" +#include "udisksdaemonutil.h" + +/** + * SECTION:udiskslinuxdriveata + * @title: UDisksLinuxDriveAta + * @short_description: Linux implementation of #UDisksDriveAta + * + * This type provides an implementation of the #UDisksDriveAta + * interface on Linux. + */ + +typedef struct _UDisksLinuxDriveAtaClass UDisksLinuxDriveAtaClass; + +/** + * UDisksLinuxDriveAta: + * + * The #UDisksLinuxDriveAta structure contains only private data and should + * only be accessed using the provided API. + */ +struct _UDisksLinuxDriveAta +{ + UDisksDriveAtaSkeleton parent_instance; + + guint64 smart_updated; + gboolean smart_failing; + gdouble smart_temperature; + guint64 smart_power_on_seconds; +}; + +struct _UDisksLinuxDriveAtaClass +{ + UDisksDriveAtaSkeletonClass parent_class; +}; + +static void drive_ata_iface_init (UDisksDriveAtaIface *iface); + +G_DEFINE_TYPE_WITH_CODE (UDisksLinuxDriveAta, udisks_linux_drive_ata, UDISKS_TYPE_DRIVE_ATA_SKELETON, + G_IMPLEMENT_INTERFACE (UDISKS_TYPE_DRIVE_ATA, drive_ata_iface_init)); + +G_LOCK_DEFINE_STATIC (object_lock); + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +udisks_linux_drive_ata_init (UDisksLinuxDriveAta *drive_ata) +{ + g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (drive_ata), + G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD); +} + +static void +udisks_linux_drive_ata_class_init (UDisksLinuxDriveAtaClass *klass) +{ +} + +/** + * udisks_linux_drive_ata_new: + * + * Creates a new #UDisksLinuxDriveAta instance. + * + * Returns: A new #UDisksLinuxDriveAta. Free with g_object_unref(). + */ +UDisksDriveAta * +udisks_linux_drive_ata_new (void) +{ + return UDISKS_DRIVE_ATA (g_object_new (UDISKS_TYPE_LINUX_DRIVE_ATA, + NULL)); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/* may be called from *any* thread when the SMART data has been updated */ +static void +update_smart (UDisksLinuxDriveAta *drive, + GUdevDevice *device) +{ + gboolean supported; + gboolean enabled; + guint64 updated; + gboolean failing; + gdouble temperature; + guint64 power_on_seconds; + + supported = g_udev_device_get_property_as_boolean (device, "ID_ATA_FEATURE_SET_SMART"); + enabled = g_udev_device_get_property_as_boolean (device, "ID_ATA_FEATURE_SET_SMART_ENABLED"); + updated = 0; + failing = FALSE; + temperature = 0.0; + power_on_seconds = 0; + + G_LOCK (object_lock); + if (drive->smart_updated > 0) + { + updated = drive->smart_updated; + failing = drive->smart_failing; + temperature = drive->smart_temperature; + power_on_seconds = drive->smart_power_on_seconds; + } + G_UNLOCK (object_lock); + + g_object_freeze_notify (G_OBJECT (drive)); + udisks_drive_ata_set_smart_supported (UDISKS_DRIVE_ATA (drive), supported); + udisks_drive_ata_set_smart_enabled (UDISKS_DRIVE_ATA (drive), enabled); + udisks_drive_ata_set_smart_updated (UDISKS_DRIVE_ATA (drive), updated); + udisks_drive_ata_set_smart_failing (UDISKS_DRIVE_ATA (drive), failing); + udisks_drive_ata_set_smart_temperature (UDISKS_DRIVE_ATA (drive), temperature); + udisks_drive_ata_set_smart_power_on_seconds (UDISKS_DRIVE_ATA (drive), power_on_seconds); + g_object_thaw_notify (G_OBJECT (drive)); +} + +/** + * udisks_linux_drive_ata_update: + * @drive: A #UDisksLinuxDriveAta. + * @object: The enclosing #UDisksLinuxDriveObject instance. + * + * Updates the interface. + */ +void +udisks_linux_drive_ata_update (UDisksLinuxDriveAta *drive, + UDisksLinuxDriveObject *object) +{ + GUdevDevice *device; + device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */); + if (device == NULL) + goto out; + update_smart (drive, device); + out: + if (device != NULL) + g_object_unref (device); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * udisks_linux_drive_ata_refresh_smart_sync: + * @drive: The #UDisksLinuxDriveAta to refresh. + * @nowakeup: If %TRUE, will not wake up the disk if asleep. + * @cancellable: A #GCancellable or %NULL. + * @error: Return location for error. + * + * Synchronously refreshes ATA S.M.A.R.T. data on @drive using one of + * the physical drives associated with it. The calling thread is + * blocked until the data has been obtained. + * + * If @nowake is %TRUE and the disk is in a sleep state this fails + * with %UDISKS_ERROR_WOULD_WAKEUP. + * + * This may only be called if @drive has been associated with a + * #UDisksLinuxDriveObject instance. + * + * This method may be called from any thread. + * + * Returns: %TRUE if the operation succeeded, %FALSE if @error is set. + */ +gboolean +udisks_linux_drive_ata_refresh_smart_sync (UDisksLinuxDriveAta *drive, + gboolean nowakeup, + GCancellable *cancellable, + GError **error) +{ + UDisksLinuxDriveObject *object; + GUdevDevice *device; + gboolean ret; + SkDisk *d; + SkBool awake; + SkBool good; + uint64_t temp_mkelvin; + uint64_t power_on_msec; + + object = UDISKS_LINUX_DRIVE_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (drive))); + device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */); + g_assert (device != NULL); + + /* TODO: use cancellable */ + + d = NULL; + ret = FALSE; + + if (sk_disk_open (g_udev_device_get_device_file (device), &d) != 0) + { + g_set_error (error, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "sk_disk_open: %m"); + goto out; + } + + if (sk_disk_check_sleep_mode (d, &awake) != 0) + { + g_set_error (error, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "sk_disk_check_sleep_mode: %m"); + goto out; + } + + /* don't wake up disk unless specically asked to */ + if (nowakeup && !awake) + { + g_set_error (error, + UDISKS_ERROR, + UDISKS_ERROR_WOULD_WAKEUP, + "Disk is in sleep mode and the nowakeup option was passed"); + goto out; + } + + if (sk_disk_smart_read_data (d) != 0) + { + g_set_error (error, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "sk_disk_smart_read_data: %m"); + goto out; + } + + if (sk_disk_smart_status (d, &good) != 0) + { + g_set_error (error, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "sk_disk_smart_status: %m"); + goto out; + } + + /* don't care if these are failing or not */ + temp_mkelvin = 0; + sk_disk_smart_get_temperature (d, &temp_mkelvin); + power_on_msec = 0; + sk_disk_smart_get_power_on (d, &power_on_msec); + + G_LOCK (object_lock); + drive->smart_updated = time (NULL); + drive->smart_failing = !good; + drive->smart_temperature = temp_mkelvin / 1000.0; + drive->smart_power_on_seconds = power_on_msec / 1000.0; + G_UNLOCK (object_lock); + + update_smart (drive, device); + + ret = TRUE; + + out: + g_object_unref (device); + if (d != NULL) + sk_disk_free (d); + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gboolean +handle_smart_update (UDisksDriveAta *_drive, + GDBusMethodInvocation *invocation, + GVariant *options) +{ + UDisksLinuxDriveAta *drive = UDISKS_LINUX_DRIVE_ATA (_drive); + UDisksLinuxDriveObject *object; + UDisksLinuxBlock *block_object; + UDisksBlockDevice *block; + UDisksDaemon *daemon; + const gchar *action_id; + gboolean nowakeup; + GError *error; + + daemon = NULL; + block = NULL; + + object = UDISKS_LINUX_DRIVE_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (drive))); + daemon = udisks_linux_drive_object_get_daemon (object); + block_object = udisks_linux_drive_object_get_block (object, TRUE); + if (block_object == NULL) + { + g_dbus_method_invocation_return_error (invocation, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "Unable to find physical block device for drive"); + goto out; + } + block = udisks_object_peek_block_device (UDISKS_OBJECT (block_object)); + + g_variant_lookup (options, + "nowakeup", + "b", + &nowakeup); + + /* TODO: is it a good idea to overload modify-device? */ + action_id = "org.freedesktop.udisks2.modify-device"; + if (udisks_block_device_get_hint_system (block)) + action_id = "org.freedesktop.udisks2.modify-device-system"; + + /* Check that the user is actually authorized */ + if (!udisks_daemon_util_check_authorization_sync (daemon, + UDISKS_OBJECT (block_object), + action_id, + options, + N_("Authentication is required to update S.M.A.R.T. data from $(udisks2.device)"), + invocation)) + goto out; + + if (!udisks_drive_ata_get_smart_supported (UDISKS_DRIVE_ATA (drive))) + { + g_dbus_method_invocation_return_error (invocation, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "SMART is not supported"); + goto out; + } + + if (!udisks_drive_ata_get_smart_enabled (UDISKS_DRIVE_ATA (drive))) + { + g_dbus_method_invocation_return_error (invocation, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "SMART is not enabled"); + goto out; + } + + error = NULL; + if (!udisks_linux_drive_ata_refresh_smart_sync (drive, + nowakeup, + NULL /* cancellable */, + &error)) + { + udisks_warning ("Error updating ATA smart for %s: %s (%s, %d)", + g_dbus_object_get_object_path (G_DBUS_OBJECT (drive)), + error->message, g_quark_to_string (error->domain), error->code); + g_dbus_method_invocation_take_error (invocation, error); + goto out; + } + + udisks_drive_ata_complete_smart_update (UDISKS_DRIVE_ATA (drive), invocation); + + out: + if (block_object != NULL) + g_object_unref (block_object); + return TRUE; /* returning TRUE means that we handled the method invocation */ +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +drive_ata_iface_init (UDisksDriveAtaIface *iface) +{ + iface->handle_smart_update = handle_smart_update; +} diff --git a/src/udiskslinuxdriveata.h b/src/udiskslinuxdriveata.h new file mode 100644 index 0000000..31d5676 --- /dev/null +++ b/src/udiskslinuxdriveata.h @@ -0,0 +1,43 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com> + * + * 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 __UDISKS_LINUX_DRIVE_ATA_H__ +#define __UDISKS_LINUX_DRIVE_ATA_H__ + +#include "udisksdaemontypes.h" + +G_BEGIN_DECLS + +#define UDISKS_TYPE_LINUX_DRIVE_ATA (udisks_linux_drive_ata_get_type ()) +#define UDISKS_LINUX_DRIVE_ATA(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UDISKS_TYPE_LINUX_DRIVE_ATA, UDisksLinuxDriveAta)) +#define UDISKS_IS_LINUX_DRIVE_ATA(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UDISKS_TYPE_LINUX_DRIVE_ATA)) + +GType udisks_linux_drive_ata_get_type (void) G_GNUC_CONST; +UDisksDriveAta *udisks_linux_drive_ata_new (void); +void udisks_linux_drive_ata_update (UDisksLinuxDriveAta *drive, + UDisksLinuxDriveObject *object); +gboolean udisks_linux_drive_ata_refresh_smart_sync (UDisksLinuxDriveAta *drive, + gboolean nowakeup, + GCancellable *cancellable, + GError **error); + +G_END_DECLS + +#endif /* __UDISKS_LINUX_DRIVE_ATA_H__ */ diff --git a/src/udiskslinuxdriveobject.c b/src/udiskslinuxdriveobject.c new file mode 100644 index 0000000..0956419 --- /dev/null +++ b/src/udiskslinuxdriveobject.c @@ -0,0 +1,860 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com> + * + * 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 <glib/gi18n-lib.h> + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "udiskslogging.h" +#include "udisksdaemon.h" +#include "udisksdaemonutil.h" +#include "udiskslinuxprovider.h" +#include "udiskslinuxdriveobject.h" +#include "udiskslinuxdrive.h" +#include "udiskslinuxdriveata.h" +#include "udiskslinuxblock.h" + +/** + * SECTION:udiskslinuxdriveobject + * @title: UDisksLinuxDriveObject + * @short_description: Object representing a drive on Linux + * + * Object corresponding to a drive on Linux. + */ + +typedef struct _UDisksLinuxDriveObjectClass UDisksLinuxDriveObjectClass; + +/** + * UDisksLinuxDriveObject: + * + * The #UDisksLinuxDriveObject structure contains only private data and + * should only be accessed using the provided API. + */ +struct _UDisksLinuxDriveObject +{ + UDisksObjectSkeleton parent_instance; + + UDisksDaemon *daemon; + + /* list of GUdevDevice objects for block objects */ + GList *devices; + + /* interfaces */ + UDisksDrive *iface_drive; + UDisksDriveAta *iface_drive_ata; +}; + +// G_LOCK_DEFINE_STATIC (drive_object_lock); + +struct _UDisksLinuxDriveObjectClass +{ + UDisksObjectSkeletonClass parent_class; +}; + +enum +{ + PROP_0, + PROP_DAEMON, + PROP_DEVICE +}; + +G_DEFINE_TYPE (UDisksLinuxDriveObject, udisks_linux_drive_object, UDISKS_TYPE_OBJECT_SKELETON); + +static void +udisks_linux_drive_object_finalize (GObject *_object) +{ + UDisksLinuxDriveObject *object = UDISKS_LINUX_DRIVE_OBJECT (_object); + + /* note: we don't hold a ref to drive_object->daemon or drive_object->mount_monitor */ + g_list_foreach (object->devices, (GFunc) g_object_unref, NULL); + g_list_free (object->devices); + + if (object->iface_drive != NULL) + g_object_unref (object->iface_drive); + if (object->iface_drive_ata != NULL) + g_object_unref (object->iface_drive_ata); + + if (G_OBJECT_CLASS (udisks_linux_drive_object_parent_class)->finalize != NULL) + G_OBJECT_CLASS (udisks_linux_drive_object_parent_class)->finalize (_object); +} + +static void +udisks_linux_drive_object_get_property (GObject *_object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + UDisksLinuxDriveObject *object = UDISKS_LINUX_DRIVE_OBJECT (_object); + + switch (prop_id) + { + case PROP_DAEMON: + g_value_set_object (value, udisks_linux_drive_object_get_daemon (object)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec); + break; + } +} + +static void +udisks_linux_drive_object_set_property (GObject *_object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + UDisksLinuxDriveObject *object = UDISKS_LINUX_DRIVE_OBJECT (_object); + + switch (prop_id) + { + case PROP_DAEMON: + g_assert (object->daemon == NULL); + /* we don't take a reference to the daemon */ + object->daemon = g_value_get_object (value); + break; + + case PROP_DEVICE: + g_assert (object->devices == NULL); + object->devices = g_list_prepend (NULL, g_value_dup_object (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec); + break; + } +} + + +static void +udisks_linux_drive_object_init (UDisksLinuxDriveObject *object) +{ +} + +static GObjectConstructParam * +find_construct_property (guint n_construct_properties, + GObjectConstructParam *construct_properties, + const gchar *name) +{ + guint n; + for (n = 0; n < n_construct_properties; n++) + if (g_strcmp0 (g_param_spec_get_name (construct_properties[n].pspec), name) == 0) + return &construct_properties[n]; + return NULL; +} + +/* unless given, compute object path from sysfs path */ +static GObject * +udisks_linux_drive_object_constructor (GType type, + guint n_construct_properties, + GObjectConstructParam *construct_properties) +{ + GObjectConstructParam *cp; + UDisksDaemon *daemon; + GUdevClient *client; + GUdevDevice *device; + + cp = find_construct_property (n_construct_properties, construct_properties, "daemon"); + g_assert (cp != NULL); + daemon = UDISKS_DAEMON (g_value_get_object (cp->value)); + g_assert (daemon != NULL); + + client = udisks_linux_provider_get_udev_client (udisks_daemon_get_linux_provider (daemon)); + + cp = find_construct_property (n_construct_properties, construct_properties, "device"); + g_assert (cp != NULL); + device = G_UDEV_DEVICE (g_value_get_object (cp->value)); + g_assert (device != NULL); + + if (!udisks_linux_drive_object_should_include_device (client, device, NULL)) + { + return NULL; + } + else + { + return G_OBJECT_CLASS (udisks_linux_drive_object_parent_class)->constructor (type, + n_construct_properties, + construct_properties); + } +} + +static void +strip_and_replace_with_uscore (gchar *s) +{ + guint n; + + if (s == NULL) + goto out; + + g_strstrip (s); + + for (n = 0; s != NULL && s[n] != '\0'; n++) + { + if (s[n] == ' ' || s[n] == '-') + s[n] = '_'; + } + + out: + ; +} + +static void +udisks_linux_drive_object_constructed (GObject *_object) +{ + UDisksLinuxDriveObject *object = UDISKS_LINUX_DRIVE_OBJECT (_object); + gchar *vendor; + gchar *model; + gchar *serial; + GString *str; + + /* initial coldplug */ + udisks_linux_drive_object_uevent (object, "add", object->devices->data); + + /* compute the object path */ + vendor = g_strdup (udisks_drive_get_vendor (object->iface_drive)); + model = g_strdup (udisks_drive_get_model (object->iface_drive)); + serial = g_strdup (udisks_drive_get_serial (object->iface_drive)); + strip_and_replace_with_uscore (vendor); + strip_and_replace_with_uscore (model); + strip_and_replace_with_uscore (serial); + str = g_string_new ("/org/freedesktop/UDisks2/drives/"); + if (vendor == NULL && model == NULL && serial == NULL) + { + g_string_append (str, "drive"); + } + else + { + /* <VENDOR>_<MODEL>_<SERIAL> */ + if (vendor != NULL && strlen (vendor) > 0) + { + udisks_safe_append_to_object_path (str, vendor); + } + if (model != NULL && strlen (model) > 0) + { + if (str->str[str->len - 1] != '/') + g_string_append_c (str, '_'); + udisks_safe_append_to_object_path (str, model); + } + if (serial != NULL && strlen (serial) > 0) + { + if (str->str[str->len - 1] != '/') + g_string_append_c (str, '_'); + udisks_safe_append_to_object_path (str, serial); + } + } + g_free (vendor); + g_free (model); + g_free (serial); + g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (object), str->str); + g_string_free (str, TRUE); + + if (G_OBJECT_CLASS (udisks_linux_drive_object_parent_class)->constructed != NULL) + G_OBJECT_CLASS (udisks_linux_drive_object_parent_class)->constructed (_object); +} + +static void +udisks_linux_drive_object_class_init (UDisksLinuxDriveObjectClass *klass) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (klass); + gobject_class->constructor = udisks_linux_drive_object_constructor; + gobject_class->finalize = udisks_linux_drive_object_finalize; + gobject_class->constructed = udisks_linux_drive_object_constructed; + gobject_class->set_property = udisks_linux_drive_object_set_property; + gobject_class->get_property = udisks_linux_drive_object_get_property; + + /** + * UDisksLinuxDriveObject:daemon: + * + * The #UDisksDaemon the object is for. + */ + g_object_class_install_property (gobject_class, + PROP_DAEMON, + g_param_spec_object ("daemon", + "Daemon", + "The daemon the object is for", + UDISKS_TYPE_DAEMON, + G_PARAM_READABLE | + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /** + * UDisksLinuxDriveObject:device: + * + * The #GUdevDevice for the object. Connect to the #GObject::notify + * signal to get notified whenever this is updated. + */ + g_object_class_install_property (gobject_class, + PROP_DEVICE, + g_param_spec_object ("device", + "Device", + "The device for the object", + G_UDEV_TYPE_DEVICE, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + +} + +/** + * udisks_linux_drive_object_new: + * @daemon: A #UDisksDaemon. + * @device: The #GUdevDevice for the sysfs block device. + * + * Create a new drive object. + * + * Returns: A #UDisksLinuxDriveObject object or %NULL if @device does not represent a drive. Free with g_object_unref(). + */ +UDisksLinuxDriveObject * +udisks_linux_drive_object_new (UDisksDaemon *daemon, + GUdevDevice *device) +{ + GObject *object; + + g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL); + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), NULL); + + object = g_object_new (UDISKS_TYPE_LINUX_DRIVE_OBJECT, + "daemon", daemon, + "device", device, + NULL); + + if (object != NULL) + return UDISKS_LINUX_DRIVE_OBJECT (object); + else + return NULL; +} + +/** + * udisks_linux_drive_object_get_daemon: + * @object: A #UDisksLinuxDriveObject. + * + * Gets the daemon used by @object. + * + * Returns: A #UDisksDaemon. Do not free, the object is owned by @object. + */ +UDisksDaemon * +udisks_linux_drive_object_get_daemon (UDisksLinuxDriveObject *object) +{ + g_return_val_if_fail (UDISKS_IS_LINUX_DRIVE_OBJECT (object), NULL); + return object->daemon; +} + +/** + * udisks_linux_drive_object_get_devices: + * @object: A #UDisksLinuxDriveObject. + * + * Gets the current #GUdevDevice objects associated with @object. + * + * Returns: A list of #GUdevDevice objects. Free each element with + * g_object_unref(), then free the list with g_list_free(). + */ +GList * +udisks_linux_drive_object_get_devices (UDisksLinuxDriveObject *object) +{ + GList *ret; + g_return_val_if_fail (UDISKS_IS_LINUX_DRIVE_OBJECT (object), NULL); + ret = g_list_copy (object->devices); + g_list_foreach (ret, (GFunc) g_object_ref, NULL); + return ret; +} + +/** + * udisks_linux_drive_object_get_device: + * @object: A #UDisksLinuxDriveObject. + * @get_hw: If the drive is multipath, set to %TRUE to get a path device instead of the multipath device. + * + * Gets one of the #GUdevDevice object associated with @object. + * + * If @get_hw is %TRUE and @object represents a multipath device then + * one of the paths is returned rather than the multipath device. This + * is useful if you e.g. need to configure the physical hardware. + * + * Returns: A #GUdevDevice or %NULL. The returned object must be freed + * with g_object_unref(). + */ +GUdevDevice * +udisks_linux_drive_object_get_device (UDisksLinuxDriveObject *object, + gboolean get_hw) +{ + GUdevDevice *ret; + /* TODO: actually look at @get_hw */ + ret = object->devices->data; + if (ret != NULL) + g_object_ref (ret); + return ret; +} + +/** + * udisks_linux_drive_object_get_block: + * @object: A #UDisksLinuxDriveObject. + * @get_hw: If the drive is multipath, set to %TRUE to get a path device instead of the multipath device. + * + * Gets a #UDisksLinuxBlockObject representing a block device associated with @object. + * + * Returns: A #UDisksLinuxBlockObject or %NULL. The returned object + * must be freed with g_object_unref(). + */ +UDisksLinuxBlock * +udisks_linux_drive_object_get_block (UDisksLinuxDriveObject *object, + gboolean get_hw) +{ + GDBusObjectManagerServer *object_manager; + UDisksLinuxBlock *ret; + GList *objects; + GList *l; + + /* TODO: actually look at @get_hw */ + + ret = NULL; + + object_manager = udisks_daemon_get_object_manager (object->daemon); + objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager)); + for (l = objects; l != NULL; l = l->next) + { + GDBusObjectSkeleton *iter_object = G_DBUS_OBJECT_SKELETON (l->data); + UDisksBlockDevice *block; + GUdevDevice *device; + gboolean is_disk; + + if (!UDISKS_IS_LINUX_BLOCK (iter_object)) + continue; + + device = udisks_linux_block_get_device (UDISKS_LINUX_BLOCK (iter_object)); + is_disk = (g_strcmp0 (g_udev_device_get_devtype (device), "disk") == 0); + g_object_unref (device); + + if (!is_disk) + continue; + + block = udisks_object_peek_block_device (UDISKS_OBJECT (iter_object)); + if (g_strcmp0 (udisks_block_device_get_drive (block), + g_dbus_object_get_object_path (G_DBUS_OBJECT (object))) == 0) + { + ret = g_object_ref (iter_object); + goto out; + } + } + + out: + g_list_foreach (objects, (GFunc) g_object_unref, NULL); + g_list_free (objects); + return ret; + +} + +/* ---------------------------------------------------------------------------------------------------- */ + +typedef gboolean (*HasInterfaceFunc) (UDisksLinuxDriveObject *object); +typedef void (*ConnectInterfaceFunc) (UDisksLinuxDriveObject *object); +typedef void (*UpdateInterfaceFunc) (UDisksLinuxDriveObject *object, + const gchar *uevent_action, + GDBusInterface *interface); + +static void +update_iface (UDisksLinuxDriveObject *object, + const gchar *uevent_action, + HasInterfaceFunc has_func, + ConnectInterfaceFunc connect_func, + UpdateInterfaceFunc update_func, + GType skeleton_type, + gpointer _interface_pointer) +{ + gboolean has; + gboolean add; + GDBusInterface **interface_pointer = _interface_pointer; + + g_return_if_fail (object != NULL); + g_return_if_fail (has_func != NULL); + g_return_if_fail (update_func != NULL); + g_return_if_fail (g_type_is_a (skeleton_type, G_TYPE_OBJECT)); + g_return_if_fail (g_type_is_a (skeleton_type, G_TYPE_DBUS_INTERFACE)); + g_return_if_fail (interface_pointer != NULL); + g_return_if_fail (*interface_pointer == NULL || G_IS_DBUS_INTERFACE (*interface_pointer)); + + add = FALSE; + has = has_func (object); + if (*interface_pointer == NULL) + { + if (has) + { + *interface_pointer = g_object_new (skeleton_type, NULL); + if (connect_func != NULL) + connect_func (object); + add = TRUE; + } + } + else + { + if (!has) + { + g_dbus_object_skeleton_remove_interface (G_DBUS_OBJECT_SKELETON (object), + G_DBUS_INTERFACE_SKELETON (*interface_pointer)); + g_object_unref (*interface_pointer); + *interface_pointer = NULL; + } + } + + if (*interface_pointer != NULL) + { + update_func (object, uevent_action, G_DBUS_INTERFACE (*interface_pointer)); + if (add) + g_dbus_object_skeleton_add_interface (G_DBUS_OBJECT_SKELETON (object), + G_DBUS_INTERFACE_SKELETON (*interface_pointer)); + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gboolean +drive_check (UDisksLinuxDriveObject *object) +{ + return TRUE; +} + +static void +drive_connect (UDisksLinuxDriveObject *object) +{ +} + +static void +drive_update (UDisksLinuxDriveObject *object, + const gchar *uevent_action, + GDBusInterface *_iface) +{ + udisks_linux_drive_update (UDISKS_LINUX_DRIVE (object->iface_drive), object); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gboolean +drive_ata_check (UDisksLinuxDriveObject *object) +{ + gboolean ret; + GUdevDevice *device; + + ret = FALSE; + if (object->devices == NULL) + goto out; + + device = G_UDEV_DEVICE (object->devices->data); + if (!g_udev_device_get_property_as_boolean (device, "ID_ATA")) + goto out; + + ret = TRUE; + + out: + return ret; +} + +static void +drive_ata_connect (UDisksLinuxDriveObject *object) +{ + +} + +static void +drive_ata_update (UDisksLinuxDriveObject *object, + const gchar *uevent_action, + GDBusInterface *_iface) +{ + udisks_linux_drive_ata_update (UDISKS_LINUX_DRIVE_ATA (object->iface_drive_ata), object); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static GList * +find_link_for_sysfs_path (UDisksLinuxDriveObject *object, + const gchar *sysfs_path) +{ + GList *l; + GList *ret; + ret = NULL; + for (l = object->devices; l != NULL; l = l->next) + { + GUdevDevice *device = G_UDEV_DEVICE (l->data); + if (g_strcmp0 (g_udev_device_get_sysfs_path (device), sysfs_path) == 0) + { + ret = l; + goto out; + } + } + out: + return ret; +} + +/** + * udisks_linux_drive_object_uevent: + * @object: A #UDisksLinuxDriveObject. + * @action: Uevent action or %NULL + * @device: A #GUdevDevice device object or %NULL if the device hasn't changed. + * + * Updates all information on interfaces on @drive. + */ +void +udisks_linux_drive_object_uevent (UDisksLinuxDriveObject *object, + const gchar *action, + GUdevDevice *device) +{ + GList *link; + + g_return_if_fail (UDISKS_IS_LINUX_DRIVE_OBJECT (object)); + g_return_if_fail (device == NULL || G_UDEV_IS_DEVICE (device)); + + link = NULL; + if (device != NULL) + link = find_link_for_sysfs_path (object, g_udev_device_get_sysfs_path (device)); + if (g_strcmp0 (action, "remove") == 0) + { + if (link != NULL) + { + g_object_unref (G_UDEV_DEVICE (link->data)); + object->devices = g_list_delete_link (object->devices, link); + } + else + { + udisks_warning ("Drive doesn't have device with sysfs path %s on remove event", + g_udev_device_get_sysfs_path (device)); + } + } + else + { + if (link != NULL) + { + g_object_unref (G_UDEV_DEVICE (link->data)); + link->data = g_object_ref (device); + } + else + { + object->devices = g_list_append (object->devices, g_object_ref (device)); + } + } + + update_iface (object, action, drive_check, drive_connect, drive_update, + UDISKS_TYPE_LINUX_DRIVE, &object->iface_drive); + update_iface (object, action, drive_ata_check, drive_ata_connect, drive_ata_update, + UDISKS_TYPE_LINUX_DRIVE_ATA, &object->iface_drive_ata); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static gchar * +check_for_vpd (GUdevDevice *device) +{ + gchar *ret; + const gchar *serial; + const gchar *wwn; + + g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); + + ret = NULL; + + /* prefer WWN to serial */ + serial = g_udev_device_get_property (device, "ID_SERIAL"); + wwn = g_udev_device_get_property (device, "ID_WWN_WITH_EXTENSION"); + if (wwn != NULL && strlen (wwn) > 0) + { + ret = g_strdup (wwn); + } + else if (serial != NULL && strlen (serial) > 0) + { + ret = g_strdup (serial); + } + return ret; +} + +/* <internal> + * udisks_linux_drive_object_should_include_device: + * @client: A #GUdevClient. + * @device: A #GUdevDevice. + * @out_vpd: Return location for unique ID or %NULL. + * + * Checks if we should even construct a #UDisksLinuxDriveObject for @device. + * + * Returns: %TRUE if we should construct an object, %FALSE otherwise. + */ +gboolean +udisks_linux_drive_object_should_include_device (GUdevClient *client, + GUdevDevice *device, + gchar **out_vpd) +{ + gboolean ret; + gchar *vpd; + + ret = FALSE; + vpd = NULL; + + /* The 'block' subsystem encompasses several objects with varying + * DEVTYPE including + * + * - disk + * - partition + * + * and we are only interested in the first. + */ + if (g_strcmp0 (g_udev_device_get_devtype (device), "disk") != 0) + goto out; + + vpd = check_for_vpd (device); + + if (vpd == NULL) + { + const gchar *name; + GUdevDevice *parent; + + name = g_udev_device_get_name (device); + + /* workaround for missing serial/wwn on virtio-blk */ + if (g_str_has_prefix (name, "vd")) + { + vpd = g_strdup (name); + goto found; + } + + /* workaround for missing serial/wwn on firewire devices */ + parent = g_udev_device_get_parent_with_subsystem (device, "firewire", NULL); + if (parent != NULL) + { + vpd = g_strdup (name); + g_object_unref (parent); + goto found; + } + + /* dm-multipath */ + const gchar *dm_name; + dm_name = g_udev_device_get_sysfs_attr (device, "dm/name"); + if (dm_name != NULL && g_str_has_prefix (dm_name, "mpath")) + { + gchar **slaves; + guint n; + slaves = udisks_daemon_util_resolve_links (g_udev_device_get_sysfs_path (device), "slaves"); + for (n = 0; slaves[n] != NULL; n++) + { + GUdevDevice *slave; + slave = g_udev_client_query_by_sysfs_path (client, slaves[n]); + if (slave != NULL) + { + vpd = check_for_vpd (slave); + if (vpd != NULL) + { + g_object_unref (slave); + g_strfreev (slaves); + goto found; + } + g_object_unref (slave); + } + } + g_strfreev (slaves); + } + } + + found: + if (vpd != NULL) + { + if (out_vpd != NULL) + { + *out_vpd = vpd; + vpd = NULL; + } + ret = TRUE; + } + + out: + g_free (vpd); + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * udisks_linux_drive_object_housekeeping: + * @object: A #UDisksLinuxDriveObject. + * @secs_since_last: Number of seconds sincex the last housekeeping or 0 if the first housekeeping ever. + * @cancellable: A %GCancellable or %NULL. + * @error: Return location for error or %NULL. + * + * Called periodically (every ten minutes or so) to perform + * housekeeping tasks such as refreshing ATA SMART data. + * + * The function runs in a dedicated thread and is allowed to perform + * blocking I/O. + * + * Long-running tasks should periodically check @cancellable to see if + * they have been cancelled. + * + * Returns: %TRUE if the operation succeeded, %FALSE if @error is set. + */ +gboolean +udisks_linux_drive_object_housekeeping (UDisksLinuxDriveObject *object, + guint secs_since_last, + GCancellable *cancellable, + GError **error) +{ + gboolean ret; + + ret = FALSE; + + if (object->iface_drive_ata != NULL && + udisks_drive_ata_get_smart_supported (object->iface_drive_ata) && + udisks_drive_ata_get_smart_enabled (object->iface_drive_ata)) + { + GError *local_error; + gboolean nowakeup; + + /* Wake-up only on start-up */ + nowakeup = TRUE; + if (secs_since_last == 0) + nowakeup = FALSE; + + udisks_info ("Refreshing SMART data on %s (nowakeup=%d)", + g_dbus_object_get_object_path (G_DBUS_OBJECT (object)), + nowakeup); + + local_error = NULL; + if (!udisks_linux_drive_ata_refresh_smart_sync (UDISKS_LINUX_DRIVE_ATA (object->iface_drive_ata), + nowakeup, + cancellable, + &local_error)) + { + if (nowakeup && (local_error->domain == UDISKS_ERROR && + local_error->code == UDISKS_ERROR_WOULD_WAKEUP)) + { + udisks_info ("Drive %s is in a sleep state", + g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); + g_error_free (local_error); + } + else + { + g_propagate_prefixed_error (error, local_error, "Error updating SMART data: "); + goto out; + } + } + } + + ret = TRUE; + + out: + return ret; +} diff --git a/src/udiskslinuxdriveobject.h b/src/udiskslinuxdriveobject.h new file mode 100644 index 0000000..289bffc --- /dev/null +++ b/src/udiskslinuxdriveobject.h @@ -0,0 +1,57 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com> + * + * 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 __UDISKS_LINUX_DRIVE_OBJECT_H__ +#define __UDISKS_LINUX_DRIVE_OBJECT_H__ + +#include "udisksdaemontypes.h" +#include <gudev/gudev.h> + +G_BEGIN_DECLS + +#define UDISKS_TYPE_LINUX_DRIVE_OBJECT (udisks_linux_drive_object_get_type ()) +#define UDISKS_LINUX_DRIVE_OBJECT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UDISKS_TYPE_LINUX_DRIVE_OBJECT, UDisksLinuxDriveObject)) +#define UDISKS_IS_LINUX_DRIVE_OBJECT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UDISKS_TYPE_LINUX_DRIVE_OBJECT)) + +GType udisks_linux_drive_object_get_type (void) G_GNUC_CONST; +UDisksLinuxDriveObject *udisks_linux_drive_object_new (UDisksDaemon *daemon, + GUdevDevice *device); +void udisks_linux_drive_object_uevent (UDisksLinuxDriveObject *object, + const gchar *action, + GUdevDevice *device); +UDisksDaemon *udisks_linux_drive_object_get_daemon (UDisksLinuxDriveObject *object); +GList *udisks_linux_drive_object_get_devices (UDisksLinuxDriveObject *object); +GUdevDevice *udisks_linux_drive_object_get_device (UDisksLinuxDriveObject *object, + gboolean get_hw); +UDisksLinuxBlock *udisks_linux_drive_object_get_block (UDisksLinuxDriveObject *object, + gboolean get_hw); + +gboolean udisks_linux_drive_object_housekeeping (UDisksLinuxDriveObject *object, + guint secs_since_last, + GCancellable *cancellable, + GError **error); + +gboolean udisks_linux_drive_object_should_include_device (GUdevClient *client, + GUdevDevice *device, + gchar **out_vpd); + +G_END_DECLS + +#endif /* __UDISKS_LINUX_DRIVE_OBJECT_H__ */ diff --git a/src/udiskslinuxprovider.c b/src/udiskslinuxprovider.c index 39d599d..9a0fbca 100644 --- a/src/udiskslinuxprovider.c +++ b/src/udiskslinuxprovider.c @@ -28,7 +28,7 @@ #include "udisksprovider.h" #include "udiskslinuxprovider.h" #include "udiskslinuxblock.h" -#include "udiskslinuxdrive.h" +#include "udiskslinuxdriveobject.h" #include "udiskslinuxmanager.h" #include "udiskscleanup.h" @@ -38,7 +38,7 @@ * @short_description: Provider of Linux-specific objects * * This object is used to add/remove Linux specific objects. Right now - * it handles #UDisksLinuxBlock and #UDisksLinuxDrive objects. + * it handles #UDisksLinuxBlock and #UDisksLinuxDriveObject instances. */ typedef struct _UDisksLinuxProviderClass UDisksLinuxProviderClass; @@ -60,7 +60,7 @@ struct _UDisksLinuxProvider /* maps from sysfs path to UDisksLinuxBlock objects */ GHashTable *sysfs_to_block; - /* maps from VPD (serial, wwn) and sysfs_path to UDisksLinuxDrive objects */ + /* maps from VPD (serial, wwn) and sysfs_path to UDisksLinuxDriveObject instances */ GHashTable *vpd_to_drive; GHashTable *sysfs_path_to_drive; @@ -287,16 +287,16 @@ perform_initial_housekeeping_for_drive (GIOSchedulerJob *job, GCancellable *cancellable, gpointer user_data) { - UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (user_data); + UDisksLinuxDriveObject *object = UDISKS_LINUX_DRIVE_OBJECT (user_data); GError *error; error = NULL; - if (!udisks_linux_drive_housekeeping (drive, 0, - NULL, /* TODO: cancellable */ - &error)) + if (!udisks_linux_drive_object_housekeeping (object, 0, + NULL, /* TODO: cancellable */ + &error)) { udisks_warning ("Error performing initial housekeeping for drive %s: %s (%s, %d)", - g_dbus_object_get_object_path (G_DBUS_OBJECT (drive)), + g_dbus_object_get_object_path (G_DBUS_OBJECT (object)), error->message, g_quark_to_string (error->domain), error->code); g_error_free (error); } @@ -309,7 +309,7 @@ handle_block_uevent_for_drive (UDisksLinuxProvider *provider, const gchar *action, GUdevDevice *device) { - UDisksLinuxDrive *drive; + UDisksLinuxDriveObject *object; UDisksDaemon *daemon; const gchar *sysfs_path; gchar *vpd; @@ -320,22 +320,22 @@ handle_block_uevent_for_drive (UDisksLinuxProvider *provider, if (g_strcmp0 (action, "remove") == 0) { - drive = g_hash_table_lookup (provider->sysfs_path_to_drive, sysfs_path); - if (drive != NULL) + object = g_hash_table_lookup (provider->sysfs_path_to_drive, sysfs_path); + if (object != NULL) { GList *devices; - udisks_linux_drive_uevent (drive, action, device); + udisks_linux_drive_object_uevent (object, action, device); g_warn_if_fail (g_hash_table_remove (provider->sysfs_path_to_drive, sysfs_path)); - devices = udisks_linux_drive_get_devices (drive); + devices = udisks_linux_drive_object_get_devices (object); if (devices == NULL) { const gchar *vpd; - vpd = g_object_get_data (G_OBJECT (drive), "x-vpd"); + vpd = g_object_get_data (G_OBJECT (object), "x-vpd"); g_dbus_object_manager_server_unexport (udisks_daemon_get_object_manager (daemon), - g_dbus_object_get_object_path (G_DBUS_OBJECT (drive))); + g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); g_warn_if_fail (g_hash_table_remove (provider->vpd_to_drive, vpd)); } g_list_foreach (devices, (GFunc) g_object_unref, NULL); @@ -344,7 +344,7 @@ handle_block_uevent_for_drive (UDisksLinuxProvider *provider, } else { - if (!udisks_linux_drive_should_include_device (provider->gudev_client, device, &vpd)) + if (!udisks_linux_drive_object_should_include_device (provider->gudev_client, device, &vpd)) goto out; if (vpd == NULL) @@ -353,29 +353,29 @@ handle_block_uevent_for_drive (UDisksLinuxProvider *provider, g_udev_device_get_sysfs_path (device)); goto out; } - drive = g_hash_table_lookup (provider->vpd_to_drive, vpd); - if (drive != NULL) + object = g_hash_table_lookup (provider->vpd_to_drive, vpd); + if (object != NULL) { if (g_hash_table_lookup (provider->sysfs_path_to_drive, sysfs_path) == NULL) - g_hash_table_insert (provider->sysfs_path_to_drive, g_strdup (sysfs_path), drive); - udisks_linux_drive_uevent (drive, action, device); + g_hash_table_insert (provider->sysfs_path_to_drive, g_strdup (sysfs_path), object); + udisks_linux_drive_object_uevent (object, action, device); } else { - drive = udisks_linux_drive_new (daemon, device); - if (drive != NULL) + object = udisks_linux_drive_object_new (daemon, device); + if (object != NULL) { - g_object_set_data_full (G_OBJECT (drive), "x-vpd", g_strdup (vpd), g_free); + g_object_set_data_full (G_OBJECT (object), "x-vpd", g_strdup (vpd), g_free); g_dbus_object_manager_server_export_uniquely (udisks_daemon_get_object_manager (daemon), - G_DBUS_OBJECT_SKELETON (drive)); - g_hash_table_insert (provider->vpd_to_drive, g_strdup (vpd), drive); - g_hash_table_insert (provider->sysfs_path_to_drive, g_strdup (sysfs_path), drive); + G_DBUS_OBJECT_SKELETON (object)); + g_hash_table_insert (provider->vpd_to_drive, g_strdup (vpd), object); + g_hash_table_insert (provider->sysfs_path_to_drive, g_strdup (sysfs_path), object); /* schedule initial housekeeping for the drive unless coldplugging */ if (!provider->coldplug) { g_io_scheduler_push_job (perform_initial_housekeeping_for_drive, - g_object_ref (drive), + g_object_ref (object), (GDestroyNotify) g_object_unref, G_PRIORITY_DEFAULT, NULL); @@ -434,7 +434,7 @@ handle_block_uevent (UDisksLinuxProvider *provider, const gchar *action, GUdevDevice *device) { - /* We use the sysfs block device for both Drive and BlockDevice + /* We use the sysfs block device for both UDisksLinuxDriveObject and BlockDevice * objects. Ensure that drive are added before and removed after * BlockDevice */ @@ -486,34 +486,34 @@ static void housekeeping_all_drives (UDisksLinuxProvider *provider, guint secs_since_last) { - GList *drives; + GList *objects; GList *l; G_LOCK (provider_lock); - drives = g_hash_table_get_values (provider->vpd_to_drive); - g_list_foreach (drives, (GFunc) g_object_ref, NULL); + objects = g_hash_table_get_values (provider->vpd_to_drive); + g_list_foreach (objects, (GFunc) g_object_ref, NULL); G_UNLOCK (provider_lock); - for (l = drives; l != NULL; l = l->next) + for (l = objects; l != NULL; l = l->next) { - UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (l->data); + UDisksLinuxDriveObject *object = UDISKS_LINUX_DRIVE_OBJECT (l->data); GError *error; error = NULL; - if (!udisks_linux_drive_housekeeping (drive, - secs_since_last, - NULL, /* TODO: cancellable */ - &error)) + if (!udisks_linux_drive_object_housekeeping (object, + secs_since_last, + NULL, /* TODO: cancellable */ + &error)) { udisks_warning ("Error performing housekeeping for drive %s: %s (%s, %d)", - g_dbus_object_get_object_path (G_DBUS_OBJECT (drive)), + g_dbus_object_get_object_path (G_DBUS_OBJECT (object)), error->message, g_quark_to_string (error->domain), error->code); g_error_free (error); } } - g_list_foreach (drives, (GFunc) g_object_unref, NULL); - g_list_free (drives); + g_list_foreach (objects, (GFunc) g_object_unref, NULL); + g_list_free (objects); } /* ---------------------------------------------------------------------------------------------------- */ |