diff options
Diffstat (limited to 'src/udiskslinuxdriveobject.c')
-rw-r--r-- | src/udiskslinuxdriveobject.c | 860 |
1 files changed, 860 insertions, 0 deletions
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; +} |