Factor out drive functionality into three separate types
authorDavid Zeuthen <davidz@redhat.com>
Tue, 16 Aug 2011 14:50:33 +0000 (10:50 -0400)
committerDavid Zeuthen <davidz@redhat.com>
Tue, 16 Aug 2011 14:50:33 +0000 (10:50 -0400)
Signed-off-by: David Zeuthen <davidz@redhat.com>
13 files changed:
doc/udisks2-docs.xml
doc/udisks2-sections.txt
doc/udisks2.types
src/Makefile.am
src/udisksdaemontypes.h
src/udiskslinuxblock.c
src/udiskslinuxdrive.c
src/udiskslinuxdrive.h
src/udiskslinuxdriveata.c [new file with mode: 0644]
src/udiskslinuxdriveata.h [new file with mode: 0644]
src/udiskslinuxdriveobject.c [new file with mode: 0644]
src/udiskslinuxdriveobject.h [new file with mode: 0644]
src/udiskslinuxprovider.c

index 854f37e..a6a7426 100644 (file)
       <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"/>
index 17cabce..4d5e48c 100644 (file)
@@ -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>
index 7b0ceee..c8de422 100644 (file)
@@ -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
index 962cf12..f628971 100644 (file)
@@ -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              \
index edf97c2..853fbc8 100644 (file)
@@ -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;
 
index bec388d..b6b13a7 100644 (file)
@@ -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);
index df42c98..9a6db9a 100644 (file)
 #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;
 }
index e287ebb..084a68d 100644 (file)
@@ -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 (file)
index 0000000..00104f3
--- /dev/null
@@ -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 (file)
index 0000000..31d5676
--- /dev/null
@@ -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 (file)
index 0000000..0956419
--- /dev/null
@@ -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 (file)
index 0000000..289bffc
--- /dev/null
@@ -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__ */
index 39d599d..9a0fbca 100644 (file)
@@ -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);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */