Factor block devices into separate types
authorDavid Zeuthen <davidz@redhat.com>
Tue, 16 Aug 2011 16:36:42 +0000 (12:36 -0400)
committerDavid Zeuthen <davidz@redhat.com>
Tue, 16 Aug 2011 16:36:42 +0000 (12:36 -0400)
Signed-off-by: David Zeuthen <davidz@redhat.com>
22 files changed:
doc/udisks2-docs.xml
doc/udisks2-sections.txt
doc/udisks2.types
src/Makefile.am
src/udisksdaemontypes.h
src/udiskslinuxblock.c
src/udiskslinuxblock.h
src/udiskslinuxblockobject.c [new file with mode: 0644]
src/udiskslinuxblockobject.h [new file with mode: 0644]
src/udiskslinuxdrive.c
src/udiskslinuxdriveata.c
src/udiskslinuxdriveobject.c
src/udiskslinuxdriveobject.h
src/udiskslinuxencrypted.c
src/udiskslinuxencrypted.h
src/udiskslinuxfilesystem.c
src/udiskslinuxfilesystem.h
src/udiskslinuxloop.c
src/udiskslinuxloop.h
src/udiskslinuxprovider.c
src/udiskslinuxswapspace.c
src/udiskslinuxswapspace.h

index a6a7426..bfbaba5 100644 (file)
 
   <part id="ref-daemon">
     <title>Daemon Implementation Details</title>
-    <xi:include href="xml/udisksdaemon.xml"/>
-    <xi:include href="xml/udisksdaemonutil.xml"/>
-    <xi:include href="xml/udiskslogging.xml"/>
-    <xi:include href="xml/udisksmount.xml"/>
-    <xi:include href="xml/udisksmountmonitor.xml"/>
-    <xi:include href="xml/udisksfstabentry.xml"/>
-    <xi:include href="xml/udisksfstabmonitor.xml"/>
-    <xi:include href="xml/udiskscrypttabentry.xml"/>
-    <xi:include href="xml/udiskscrypttabmonitor.xml"/>
-    <xi:include href="xml/udiskspersistentstore.xml"/>
-    <xi:include href="xml/udiskscleanup.xml"/>
-    <xi:include href="xml/udisksprovider.xml"/>
+    <chapter id="ref-daemon-core">
+      <title>Core</title>
+      <xi:include href="xml/udisksdaemonutil.xml"/>
+      <xi:include href="xml/udiskslogging.xml"/>
+      <xi:include href="xml/udisksdaemon.xml"/>
+      <xi:include href="xml/udisksprovider.xml"/>
+      <xi:include href="xml/udiskscleanup.xml"/>
+      <xi:include href="xml/udiskspersistentstore.xml"/>
+    </chapter>
+    <chapter id="ref-daemon-monitoring">
+      <title>State and Configuration</title>
+      <xi:include href="xml/udisksmountmonitor.xml"/>
+      <xi:include href="xml/udisksmount.xml"/>
+      <xi:include href="xml/udisksfstabmonitor.xml"/>
+      <xi:include href="xml/udisksfstabentry.xml"/>
+      <xi:include href="xml/udiskscrypttabmonitor.xml"/>
+      <xi:include href="xml/udiskscrypttabentry.xml"/>
+    </chapter>
     <chapter id="ref-daemon-jobs">
       <title>Jobs</title>
       <xi:include href="xml/udisksbasejob.xml"/>
       <xi:include href="xml/udisksthreadedjob.xml"/>
       <xi:include href="xml/udisksspawnedjob.xml"/>
     </chapter>
-    <chapter id="ref-daemon-linux">
-      <title>Linux-specific objects and providers</title>
-      <xi:include href="xml/udiskslinuxprovider.xml"/>
+    <chapter id="ref-daemon-drives">
+      <title>Drives on Linux</title>
       <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"/>
+    </chapter>
+    <chapter id="ref-daemon-block-devices">
+      <title>Block devices on Linux</title>
+      <xi:include href="xml/udiskslinuxblockobject.xml"/>
+      <xi:include href="xml/udiskslinuxblock.xml"/>
       <xi:include href="xml/udiskslinuxfilesystem.xml"/>
       <xi:include href="xml/udiskslinuxencrypted.xml"/>
       <xi:include href="xml/udiskslinuxswapspace.xml"/>
       <xi:include href="xml/udiskslinuxloop.xml"/>
     </chapter>
+    <chapter id="ref-daemon-linux-ifaces">
+      <title>Other Linux-specific interfaces</title>
+      <xi:include href="xml/udiskslinuxprovider.xml"/>
+      <xi:include href="xml/udiskslinuxmanager.xml"/>
+    </chapter>
   </part>
 
   <part id="tools-fileformats">
index 4d5e48c..b26c12c 100644 (file)
@@ -144,22 +144,6 @@ udisks_simple_job_get_type
 </SECTION>
 
 <SECTION>
-<FILE>udiskslinuxblock</FILE>
-<TITLE>UDisksLinuxBlock</TITLE>
-UDisksLinuxBlock
-udisks_linux_block_new
-udisks_linux_block_uevent
-udisks_linux_block_get_daemon
-udisks_linux_block_get_device
-<SUBSECTION Standard>
-UDISKS_TYPE_LINUX_BLOCK
-UDISKS_LINUX_BLOCK
-UDISKS_IS_LINUX_BLOCK
-<SUBSECTION Private>
-udisks_linux_block_get_type
-</SECTION>
-
-<SECTION>
 <FILE>udiskslinuxdriveobject</FILE>
 <TITLE>UDisksLinuxDriveObject</TITLE>
 UDisksLinuxDriveObject
@@ -336,9 +320,39 @@ udisks_daemon_util_setup_by_user
 </SECTION>
 
 <SECTION>
+<FILE>udiskslinuxblockobject</FILE>
+<TITLE>UDisksLinuxBlockObject</TITLE>
+UDisksLinuxBlockObject
+udisks_linux_block_object_new
+udisks_linux_block_object_uevent
+udisks_linux_block_object_get_daemon
+udisks_linux_block_object_get_device
+<SUBSECTION Standard>
+UDISKS_TYPE_LINUX_BLOCK_OBJECT
+UDISKS_LINUX_BLOCK_OBJECT
+UDISKS_IS_LINUX_BLOCK_OBJECT
+<SUBSECTION Private>
+udisks_linux_block_object_get_type
+</SECTION>
+
+<SECTION>
+<FILE>udiskslinuxblock</FILE>
+UDisksLinuxBlock
+udisks_linux_block_new
+udisks_linux_block_update
+<SUBSECTION Standard>
+UDISKS_LINUX_BLOCK
+UDISKS_IS_LINUX_BLOCK
+UDISKS_TYPE_LINUX_BLOCK
+<SUBSECTION Private>
+udisks_linux_block_get_type
+</SECTION>
+
+<SECTION>
 <FILE>udiskslinuxfilesystem</FILE>
 UDisksLinuxFilesystem
 udisks_linux_filesystem_new
+udisks_linux_filesystem_update
 <SUBSECTION Standard>
 UDISKS_LINUX_FILESYSTEM
 UDISKS_IS_LINUX_FILESYSTEM
@@ -351,6 +365,7 @@ udisks_linux_filesystem_get_type
 <FILE>udiskslinuxencrypted</FILE>
 UDisksLinuxEncrypted
 udisks_linux_encrypted_new
+udisks_linux_encrypted_update
 <SUBSECTION Standard>
 UDISKS_LINUX_ENCRYPTED
 UDISKS_IS_LINUX_ENCRYPTED
@@ -363,6 +378,7 @@ udisks_linux_encrypted_get_type
 <FILE>udiskslinuxswapspace</FILE>
 UDisksLinuxSwapspace
 udisks_linux_swapspace_new
+udisks_linux_swapspace_update
 <SUBSECTION Standard>
 UDISKS_LINUX_SWAPSPACE
 UDISKS_IS_LINUX_SWAPSPACE
@@ -372,6 +388,19 @@ udisks_linux_swapspace_get_type
 </SECTION>
 
 <SECTION>
+<FILE>udiskslinuxloop</FILE>
+UDisksLinuxLoop
+udisks_linux_loop_new
+udisks_linux_loop_update
+<SUBSECTION Standard>
+UDISKS_LINUX_LOOP
+UDISKS_IS_LINUX_LOOP
+UDISKS_TYPE_LINUX_LOOP
+<SUBSECTION Private>
+udisks_linux_loop_get_type
+</SECTION>
+
+<SECTION>
 <FILE>UDisksObject</FILE>
 <TITLE>UDisksObject</TITLE>
 UDisksObject
@@ -968,18 +997,6 @@ udisks_linux_manager_get_type
 </SECTION>
 
 <SECTION>
-<FILE>udiskslinuxloop</FILE>
-UDisksLinuxLoop
-udisks_linux_loop_new
-<SUBSECTION Standard>
-UDISKS_LINUX_LOOP
-UDISKS_IS_LINUX_LOOP
-UDISKS_TYPE_LINUX_LOOP
-<SUBSECTION Private>
-udisks_linux_loop_get_type
-</SECTION>
-
-<SECTION>
 <FILE>UDisksLoop</FILE>
 UDisksLoop
 UDisksLoopIface
index c8de422..994a6a1 100644 (file)
@@ -1,10 +1,11 @@
 udisks_client_get_type
 
 udisks_daemon_get_type
+udisks_linux_block_object_get_type
 udisks_linux_block_get_type
+udisks_linux_drive_object_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 f628971..01faace 100644 (file)
@@ -47,6 +47,7 @@ libudisks_daemon_la_SOURCES =                                         \
        udisksdaemon.h                  udisksdaemon.c                  \
        udisksprovider.h                udisksprovider.c                \
        udiskslinuxprovider.h           udiskslinuxprovider.c           \
+       udiskslinuxblockobject.h        udiskslinuxblockobject.c        \
        udiskslinuxblock.h              udiskslinuxblock.c              \
        udiskslinuxfilesystem.h         udiskslinuxfilesystem.c         \
        udiskslinuxencrypted.h          udiskslinuxencrypted.c          \
index 853fbc8..86238a9 100644 (file)
@@ -34,6 +34,9 @@ typedef struct _UDisksDaemon UDisksDaemon;
 struct _UDisksLinuxProvider;
 typedef struct _UDisksLinuxProvider UDisksLinuxProvider;
 
+struct _UDisksLinuxBlockObject;
+typedef struct _UDisksLinuxBlockObject UDisksLinuxBlockObject;
+
 struct _UDisksLinuxBlock;
 typedef struct _UDisksLinuxBlock UDisksLinuxBlock;
 
index b6b13a7..41a950e 100644 (file)
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
 #include <pwd.h>
 #include <grp.h>
-#include <mntent.h>
-
 #include <string.h>
 #include <stdlib.h>
+#include <errno.h>
+#include <mntent.h>
+
 #include <glib/gstdio.h>
 
 #include "udiskslogging.h"
-#include "udisksdaemon.h"
-#include "udisksdaemonutil.h"
 #include "udiskslinuxblock.h"
-#include "udisksmount.h"
-#include "udisksmountmonitor.h"
+#include "udiskslinuxblockobject.h"
 #include "udiskslinuxdriveobject.h"
-#include "udiskslinuxdrive.h"
-#include "udiskslinuxfilesystem.h"
-#include "udiskslinuxencrypted.h"
-#include "udiskslinuxswapspace.h"
-#include "udiskslinuxloop.h"
-#include "udiskspersistentstore.h"
+#include "udisksdaemon.h"
+#include "udiskscleanup.h"
+#include "udisksdaemonutil.h"
 #include "udiskslinuxprovider.h"
 #include "udisksfstabmonitor.h"
 #include "udisksfstabentry.h"
 /**
  * SECTION:udiskslinuxblock
  * @title: UDisksLinuxBlock
- * @short_description: Linux block devices
+ * @short_description: Block devices on Linux
  *
- * Object corresponding to a Linux block device.
+ * This type provides an implementation of the #UDisksBlock
+ * interface on Linux.
  */
 
 typedef struct _UDisksLinuxBlockClass   UDisksLinuxBlockClass;
@@ -66,2103 +60,1613 @@ typedef struct _UDisksLinuxBlockClass   UDisksLinuxBlockClass;
 /**
  * UDisksLinuxBlock:
  *
- * The #UDisksLinuxBlock structure contains only private data and
- * should only be accessed using the provided API.
+ * The #UDisksLinuxBlock structure contains only private data and should
+ * only be accessed using the provided API.
  */
 struct _UDisksLinuxBlock
 {
-  UDisksObjectSkeleton parent_instance;
-
-  UDisksDaemon *daemon;
-  UDisksMountMonitor *mount_monitor;
-
-  GUdevDevice *device;
-
-  /* interface */
-  UDisksBlockDevice *iface_block_device;
-  UDisksFilesystem *iface_filesystem;
-  UDisksSwapspace *iface_swapspace;
-  UDisksEncrypted *iface_encrypted;
-  UDisksLoop *iface_loop;
+  UDisksBlockDeviceSkeleton parent_instance;
 };
 
 struct _UDisksLinuxBlockClass
 {
-  UDisksObjectSkeletonClass parent_class;
-};
-
-enum
-{
-  PROP_0,
-  PROP_DAEMON,
-  PROP_DEVICE
+  UDisksBlockDeviceSkeletonClass parent_class;
 };
 
-G_DEFINE_TYPE (UDisksLinuxBlock, udisks_linux_block, UDISKS_TYPE_OBJECT_SKELETON);
-
-static void on_mount_monitor_mount_added   (UDisksMountMonitor  *monitor,
-                                            UDisksMount         *mount,
-                                            gpointer             user_data);
-static void on_mount_monitor_mount_removed (UDisksMountMonitor  *monitor,
-                                            UDisksMount         *mount,
-                                            gpointer             user_data);
-
-static void
-udisks_linux_block_finalize (GObject *object)
-{
-  UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (object);
-
-  /* note: we don't hold a ref to block->daemon or block->mount_monitor */
-  g_signal_handlers_disconnect_by_func (block->mount_monitor, on_mount_monitor_mount_added, block);
-  g_signal_handlers_disconnect_by_func (block->mount_monitor, on_mount_monitor_mount_removed, block);
-
-  g_object_unref (block->device);
-
-  if (block->iface_block_device != NULL)
-    g_object_unref (block->iface_block_device);
-  if (block->iface_filesystem != NULL)
-    g_object_unref (block->iface_filesystem);
-  if (block->iface_swapspace != NULL)
-    g_object_unref (block->iface_swapspace);
-  if (block->iface_encrypted != NULL)
-    g_object_unref (block->iface_encrypted);
-  if (block->iface_loop != NULL)
-    g_object_unref (block->iface_loop);
-
-  if (G_OBJECT_CLASS (udisks_linux_block_parent_class)->finalize != NULL)
-    G_OBJECT_CLASS (udisks_linux_block_parent_class)->finalize (object);
-}
-
-static void
-udisks_linux_block_get_property (GObject    *object,
-                                 guint       prop_id,
-                                 GValue     *value,
-                                 GParamSpec *pspec)
-{
-  UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (object);
-
-  switch (prop_id)
-    {
-    case PROP_DAEMON:
-      g_value_set_object (value, udisks_linux_block_get_daemon (block));
-      break;
-
-    case PROP_DEVICE:
-      g_value_set_object (value, udisks_linux_block_get_device (block));
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
-
-static void
-udisks_linux_block_set_property (GObject      *object,
-                                 guint         prop_id,
-                                 const GValue *value,
-                                 GParamSpec   *pspec)
-{
-  UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (object);
+static void block_iface_init (UDisksBlockDeviceIface *iface);
 
-  switch (prop_id)
-    {
-    case PROP_DAEMON:
-      g_assert (block->daemon == NULL);
-      /* we don't take a reference to the daemon */
-      block->daemon = g_value_get_object (value);
-      break;
-
-    case PROP_DEVICE:
-      g_assert (block->device == NULL);
-      block->device = g_value_dup_object (value);
-      break;
-
-    default:
-      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
-      break;
-    }
-}
+G_DEFINE_TYPE_WITH_CODE (UDisksLinuxBlock, udisks_linux_block, UDISKS_TYPE_BLOCK_DEVICE_SKELETON,
+                         G_IMPLEMENT_INTERFACE (UDISKS_TYPE_BLOCK_DEVICE, block_iface_init));
 
+/* ---------------------------------------------------------------------------------------------------- */
 
 static void
 udisks_linux_block_init (UDisksLinuxBlock *block)
 {
-}
-
-static void
-udisks_linux_block_constructed (GObject *object)
-{
-  UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (object);
-  GString *str;
-
-  block->mount_monitor = udisks_daemon_get_mount_monitor (block->daemon);
-  g_signal_connect (block->mount_monitor,
-                    "mount-added",
-                    G_CALLBACK (on_mount_monitor_mount_added),
-                    block);
-  g_signal_connect (block->mount_monitor,
-                    "mount-removed",
-                    G_CALLBACK (on_mount_monitor_mount_removed),
-                    block);
-
-  /* initial coldplug */
-  udisks_linux_block_uevent (block, "add", NULL);
-
-  /* compute the object path */
-  str = g_string_new ("/org/freedesktop/UDisks2/block_devices/");
-  udisks_safe_append_to_object_path (str, g_udev_device_get_name (block->device));
-  g_dbus_object_skeleton_set_object_path (G_DBUS_OBJECT_SKELETON (block), str->str);
-  g_string_free (str, TRUE);
-
-  if (G_OBJECT_CLASS (udisks_linux_block_parent_class)->constructed != NULL)
-    G_OBJECT_CLASS (udisks_linux_block_parent_class)->constructed (object);
+  g_dbus_interface_skeleton_set_flags (G_DBUS_INTERFACE_SKELETON (block),
+                                       G_DBUS_INTERFACE_SKELETON_FLAGS_HANDLE_METHOD_INVOCATIONS_IN_THREAD);
 }
 
 static void
 udisks_linux_block_class_init (UDisksLinuxBlockClass *klass)
 {
-  GObjectClass *gobject_class;
-
-  gobject_class = G_OBJECT_CLASS (klass);
-  gobject_class->finalize     = udisks_linux_block_finalize;
-  gobject_class->constructed  = udisks_linux_block_constructed;
-  gobject_class->set_property = udisks_linux_block_set_property;
-  gobject_class->get_property = udisks_linux_block_get_property;
-
-  /**
-   * UDisksLinuxBlock: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));
-
-  /**
-   * UDisksLinuxBlock: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_READABLE |
-                                                        G_PARAM_WRITABLE |
-                                                        G_PARAM_CONSTRUCT_ONLY |
-                                                        G_PARAM_STATIC_STRINGS));
-
 }
 
 /**
  * udisks_linux_block_new:
- * @daemon: A #UDisksDaemon.
- * @device: The #GUdevDevice for the sysfs block device.
- *
- * Create a new block object.
- *
- * Returns: A #UDisksLinuxBlock object. Free with g_object_unref().
- */
-UDisksLinuxBlock *
-udisks_linux_block_new (UDisksDaemon  *daemon,
-                        GUdevDevice   *device)
-{
-  g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
-  return UDISKS_LINUX_BLOCK (g_object_new (UDISKS_TYPE_LINUX_BLOCK,
-                                           "daemon", daemon,
-                                           "device", device,
-                                           NULL));
-}
-
-/**
- * udisks_linux_block_get_daemon:
- * @block: A #UDisksLinuxBlock.
- *
- * Gets the daemon used by @block.
- *
- * Returns: A #UDisksDaemon. Do not free, the object is owned by @block.
- */
-UDisksDaemon *
-udisks_linux_block_get_daemon (UDisksLinuxBlock *block)
-{
-  g_return_val_if_fail (UDISKS_IS_LINUX_BLOCK (block), NULL);
-  return block->daemon;
-}
-
-/**
- * udisks_linux_block_get_device:
- * @block: A #UDisksLinuxBlock.
  *
- * Gets the current #GUdevDevice for @block. Connect to
- * #GObject::notify to track changes to the #UDisksLinuxBlock:device
- * property.
+ * Creates a new #UDisksLinuxBlock instance.
  *
- * Returns: A #GUdevDevice. Free with g_object_unref().
+ * Returns: A new #UDisksLinuxBlock. Free with g_object_unref().
  */
-GUdevDevice *
-udisks_linux_block_get_device (UDisksLinuxBlock *block)
+UDisksBlockDevice *
+udisks_linux_block_new (void)
 {
-  g_return_val_if_fail (UDISKS_IS_LINUX_BLOCK (block), NULL);
-  return g_object_ref (block->device);
+  return UDISKS_BLOCK_DEVICE (g_object_new (UDISKS_TYPE_LINUX_BLOCK,
+                                            NULL));
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-typedef gboolean (*HasInterfaceFunc)    (UDisksLinuxBlock     *block);
-typedef void     (*ConnectInterfaceFunc) (UDisksLinuxBlock     *block);
-typedef void     (*UpdateInterfaceFunc) (UDisksLinuxBlock     *block,
-                                         const gchar    *uevent_action,
-                                         GDBusInterface *interface);
-
-static void
-update_iface (UDisksLinuxBlock           *block,
-              const gchar          *uevent_action,
-              HasInterfaceFunc      has_func,
-              ConnectInterfaceFunc   connect_func,
-              UpdateInterfaceFunc   update_func,
-              GType                 skeleton_type,
-              gpointer              _interface_pointer)
+static gchar *
+get_sysfs_attr (GUdevDevice *device,
+                const gchar *attr)
 {
-  gboolean has;
-  gboolean add;
-  GDBusInterface **interface_pointer = _interface_pointer;
-
-  g_return_if_fail (block != 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 (block);
-  if (*interface_pointer == NULL)
-    {
-      if (has)
-        {
-          *interface_pointer = g_object_new (skeleton_type, NULL);
-          if (connect_func != NULL)
-            connect_func (block);
-          add = TRUE;
-        }
-    }
-  else
-    {
-      if (!has)
-        {
-          g_dbus_object_skeleton_remove_interface (G_DBUS_OBJECT_SKELETON (block), G_DBUS_INTERFACE_SKELETON (*interface_pointer));
-          g_object_unref (*interface_pointer);
-          *interface_pointer = NULL;
-        }
-    }
-
-  if (*interface_pointer != NULL)
-    {
-      update_func (block, uevent_action, G_DBUS_INTERFACE (*interface_pointer));
-      if (add)
-        g_dbus_object_skeleton_add_interface (G_DBUS_OBJECT_SKELETON (block), G_DBUS_INTERFACE_SKELETON (*interface_pointer));
-    }
+  gchar *filename;
+  gchar *value;
+  filename = g_strconcat (g_udev_device_get_sysfs_path (device),
+                          "/",
+                          attr,
+                          NULL);
+  value = NULL;
+  /* don't care about errors */
+  g_file_get_contents (filename,
+                       &value,
+                       NULL,
+                       NULL);
+  g_free (filename);
+  return value;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-static GVariant *calculate_configuration (UDisksLinuxBlock  *block,
-                                          gboolean           include_secrets,
-                                          GError           **error);
-
-static gboolean
-on_get_secret_configuration (UDisksBlockDevice     *block,
-                             GDBusMethodInvocation *invocation,
-                             GVariant              *options,
-                             gpointer               user_data)
+static gchar *
+find_block_device_by_sysfs_path (GDBusObjectManagerServer *object_manager,
+                                 const gchar              *sysfs_path)
 {
-  UDisksLinuxBlock *object = UDISKS_LINUX_BLOCK (user_data);
-  GVariant *configuration;
-  GError *error;
+  gchar *ret;
+  GList *objects;
+  GList *l;
 
-  error = NULL;
-  configuration = calculate_configuration (object, TRUE, &error);
-  if (configuration == NULL)
-    {
-      g_dbus_method_invocation_take_error (invocation, error);
-      goto out;
-    }
+  ret = NULL;
 
-  if (!udisks_daemon_util_check_authorization_sync (object->daemon,
-                                                    NULL,
-                                                    "org.freedesktop.udisks2.read-system-configuration-secrets",
-                                                    options,
-                                                    N_("Authentication is required to read system-level secrets"),
-                                                    invocation))
+  objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
+  for (l = objects; l != NULL; l = l->next)
     {
-      g_variant_unref (configuration);
-      goto out;
-    }
+      GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (l->data);
+      GUdevDevice *device;
 
-  udisks_block_device_complete_get_secret_configuration (object->iface_block_device, invocation,
-                                                         configuration); /* consumes floating ref */
+      if (!UDISKS_IS_LINUX_BLOCK_OBJECT (object))
+        continue;
+
+      device = udisks_linux_block_object_get_device (UDISKS_LINUX_BLOCK_OBJECT (object));
+      if (g_strcmp0 (sysfs_path, g_udev_device_get_sysfs_path (device)) == 0)
+        {
+          ret = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
+          g_object_unref (device);
+          goto out;
+        }
+      g_object_unref (device);
+    }
 
  out:
-  return TRUE; /* returning TRUE means that we handled the method invocation */
+  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
+  g_list_free (objects);
+  return ret;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
 static gchar *
-escape_fstab (const gchar *source)
+find_drive (GDBusObjectManagerServer  *object_manager,
+            GUdevDevice               *block_device,
+            UDisksDrive              **out_drive)
 {
-  GString *s;
-  guint n;
-  s = g_string_new (NULL);
-  for (n = 0; source[n] != '\0'; n++)
-    {
-      switch (source[n])
-        {
-        case ' ':
-        case '\t':
-        case '\n':
-        case '\\':
-          g_string_append_printf (s, "\\%03o", source[n]);
-          break;
+  GUdevDevice *whole_disk_block_device;
+  const gchar *whole_disk_block_device_sysfs_path;
+  gchar *ret;
+  GList *objects;
+  GList *l;
 
-        default:
-          g_string_append_c (s, source[n]);
-          break;
-        }
-    }
-  return g_string_free (s, FALSE);
-}
+  ret = NULL;
 
-/* based on g_strcompress() */
-static gchar *
-unescape_fstab (const gchar *source)
-{
-  const gchar *p = source, *octal;
-  gchar *dest = g_malloc (strlen (source) + 1);
-  gchar *q = dest;
+  if (g_strcmp0 (g_udev_device_get_devtype (block_device), "disk") == 0)
+    whole_disk_block_device = g_object_ref (block_device);
+  else
+    whole_disk_block_device = g_udev_device_get_parent_with_subsystem (block_device, "block", "disk");
+  whole_disk_block_device_sysfs_path = g_udev_device_get_sysfs_path (whole_disk_block_device);
 
-  while (*p)
+  objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
+  for (l = objects; l != NULL; l = l->next)
     {
-      if (*p == '\\')
+      GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (l->data);
+      GList *drive_devices;
+      GList *j;
+
+      if (!UDISKS_IS_LINUX_DRIVE_OBJECT (object))
+        continue;
+
+      drive_devices = udisks_linux_drive_object_get_devices (UDISKS_LINUX_DRIVE_OBJECT (object));
+      for (j = drive_devices; j != NULL; j = j->next)
         {
-          p++;
-          switch (*p)
+          GUdevDevice *drive_device = G_UDEV_DEVICE (j->data);
+          const gchar *drive_sysfs_path;
+
+          drive_sysfs_path = g_udev_device_get_sysfs_path (drive_device);
+          if (g_strcmp0 (whole_disk_block_device_sysfs_path, drive_sysfs_path) == 0)
             {
-            case '\0':
-              g_warning ("unescape_fstab: trailing \\");
+              if (out_drive != NULL)
+                *out_drive = udisks_object_get_drive (UDISKS_OBJECT (object));
+              ret = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
+              g_list_foreach (drive_devices, (GFunc) g_object_unref, NULL);
+              g_list_free (drive_devices);
               goto out;
-            case '0':  case '1':  case '2':  case '3':  case '4':
-            case '5':  case '6':  case '7':
-              *q = 0;
-              octal = p;
-              while ((p < octal + 3) && (*p >= '0') && (*p <= '7'))
-                {
-                  *q = (*q * 8) + (*p - '0');
-                  p++;
-                }
-              q++;
-              p--;
-              break;
-            default:            /* Also handles \" and \\ */
-              *q++ = *p;
-              break;
             }
         }
-      else
-        *q++ = *p;
-      p++;
+      g_list_foreach (drive_devices, (GFunc) g_object_unref, NULL);
+      g_list_free (drive_devices);
     }
-out:
-  *q = 0;
 
-  return dest;
+ out:
+  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
+  g_list_free (objects);
+  g_object_unref (whole_disk_block_device);
+  return ret;
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-/* TODO: maybe move to GLib */
-static gboolean
-_g_file_set_contents_full (const gchar  *filename,
-                           const gchar  *contents,
-                           gssize        contents_len,
-                           gint          mode_for_new_file,
-                           GError      **error)
+static void
+update_hints (UDisksLinuxBlock  *block,
+              GUdevDevice       *device,
+              UDisksDrive       *drive)
 {
-  gboolean ret;
-  struct stat statbuf;
-  gint mode;
-  gchar *tmpl;
-  gint fd;
-  FILE *f;
+  UDisksBlockDevice *iface = UDISKS_BLOCK_DEVICE (block);
+  gboolean hint_system;
+  gboolean hint_ignore;
+  gboolean hint_auto;
+  const gchar *hint_name;
+  const gchar *hint_icon_name;
+  const gchar *device_file;
 
-  ret = FALSE;
-  tmpl = NULL;
+  /* very conservative defaults */
+  hint_system = TRUE;
+  hint_ignore = FALSE;
+  hint_auto = FALSE;
+  hint_name = NULL;
+  hint_icon_name = NULL;
 
-  if (stat (filename, &statbuf) != 0)
+  device_file = g_udev_device_get_device_file (device);
+
+  /* Provide easy access to _only_ the following devices
+   *
+   *  - anything connected via known local buses (e.g. USB or Firewire, MMC or MemoryStick)
+   *  - any device with removable media
+   *
+   * Be careful when extending this list as we don't want to automount
+   * the world when (inadvertently) connecting to a SAN.
+   */
+  if (drive != NULL)
     {
-      if (errno == ENOENT)
-        {
-          mode = mode_for_new_file;
-        }
-      else
+      const gchar *connection_bus;
+      gboolean removable;
+      connection_bus = udisks_drive_get_connection_bus (drive);
+      removable = udisks_drive_get_media_removable (drive);
+      if (removable ||
+          (g_strcmp0 (connection_bus, "usb") == 0 || g_strcmp0 (connection_bus, "firewire") == 0) ||
+          (g_str_has_prefix (device_file, "/dev/mmcblk") || g_str_has_prefix (device_file, "/dev/mspblk")))
         {
-          g_set_error (error,
-                       G_IO_ERROR,
-                       g_io_error_from_errno (errno),
-                       "Error stat(2)'ing %s: %m",
-                       filename);
-          goto out;
+          hint_system = FALSE;
+          hint_auto = TRUE;
         }
     }
-  else
-    {
-      mode = statbuf.st_mode;
-    }
-
-  tmpl = g_strdup_printf ("%s.XXXXXX", filename);
-  fd = g_mkstemp_full (tmpl, O_RDWR, mode);
-  if (fd == -1)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   g_io_error_from_errno (errno),
-                   "Error creating temporary file: %m");
-      goto out;
-    }
-
-  f = fdopen (fd, "w");
-  if (f == NULL)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   g_io_error_from_errno (errno),
-                   "Error calling fdopen: %m");
-      g_unlink (tmpl);
-      goto out;
-    }
-
-  if (contents_len < 0 )
-    contents_len = strlen (contents);
-  if (fwrite (contents, 1, contents_len, f) != contents_len)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   g_io_error_from_errno (errno),
-                   "Error calling fwrite on temp file: %m");
-      fclose (f);
-      g_unlink (tmpl);
-      goto out;
-    }
-
-  if (fsync (fileno (f)) != 0)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   g_io_error_from_errno (errno),
-                   "Error calling fsync on temp file: %m");
-      fclose (f);
-      g_unlink (tmpl);
-      goto out;
-    }
-  fclose (f);
 
-  if (rename (tmpl, filename) != 0)
-    {
-      g_set_error (error,
-                   G_IO_ERROR,
-                   g_io_error_from_errno (errno),
-                   "Error renaming temp file to final file: %m");
-      g_unlink (tmpl);
-      goto out;
-    }
+  /* TODO: set ignore to TRUE for physical paths belonging to a drive with multiple paths */
 
-  ret = TRUE;
+  /* override from udev properties */
+  if (g_udev_device_has_property (device, "UDISKS_SYSTEM"))
+    hint_system = g_udev_device_get_property_as_boolean (device, "UDISKS_SYSTEM");
+  if (g_udev_device_has_property (device, "UDISKS_IGNORE"))
+    hint_ignore = g_udev_device_get_property_as_boolean (device, "UDISKS_IGNORE");
+  if (g_udev_device_has_property (device, "UDISKS_AUTO"))
+    hint_auto = g_udev_device_get_property_as_boolean (device, "UDISKS_AUTO");
+  if (g_udev_device_has_property (device, "UDISKS_NAME"))
+    hint_name = g_udev_device_get_property (device, "UDISKS_NAME");
+  if (g_udev_device_has_property (device, "UDISKS_ICON_NAME"))
+    hint_icon_name = g_udev_device_get_property (device, "UDISKS_ICON_NAME");
 
- out:
-  g_free (tmpl);
-  return ret;
+  /* ... and scene! */
+  udisks_block_device_set_hint_system (iface, hint_system);
+  udisks_block_device_set_hint_ignore (iface, hint_ignore);
+  udisks_block_device_set_hint_auto (iface, hint_auto);
+  udisks_block_device_set_hint_name (iface, hint_name);
+  udisks_block_device_set_hint_icon_name (iface, hint_icon_name);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
-static gboolean
-add_remove_fstab_entry (GVariant  *remove,
-                        GVariant  *add,
-                        GError   **error)
+static GList *
+find_fstab_entries_for_device (UDisksLinuxBlock *block,
+                               UDisksDaemon     *daemon)
 {
-  struct mntent mntent_remove;
-  struct mntent mntent_add;
-  gboolean ret;
-  gchar *contents;
-  gchar **lines;
-  GString *str;
-  gboolean removed;
-  guint n;
+  GList *entries;
+  GList *l;
+  GList *ret;
 
-  contents = NULL;
-  lines = NULL;
-  str = NULL;
-  ret = FALSE;
+  ret = NULL;
 
-  if (remove != NULL)
+  /* if this is too slow, we could add lookup methods to UDisksFstabMonitor... */
+  entries = udisks_fstab_monitor_get_entries (udisks_daemon_get_fstab_monitor (daemon));
+  for (l = entries; l != NULL; l = l->next)
     {
-      if (!g_variant_lookup (remove, "fsname", "^&ay", &mntent_remove.mnt_fsname) ||
-          !g_variant_lookup (remove, "dir", "^&ay", &mntent_remove.mnt_dir) ||
-          !g_variant_lookup (remove, "type", "^&ay", &mntent_remove.mnt_type) ||
-          !g_variant_lookup (remove, "opts", "^&ay", &mntent_remove.mnt_opts) ||
-          !g_variant_lookup (remove, "freq", "i", &mntent_remove.mnt_freq) ||
-          !g_variant_lookup (remove, "passno", "i", &mntent_remove.mnt_passno))
+      UDisksFstabEntry *entry = UDISKS_FSTAB_ENTRY (l->data);
+      const gchar *const *symlinks;
+      const gchar *fsname;
+      gchar *device;
+      guint n;
+
+      fsname = udisks_fstab_entry_get_fsname (entry);
+      device = NULL;
+      if (g_str_has_prefix (fsname, "UUID="))
         {
-          g_set_error (error,
-                       UDISKS_ERROR,
-                       UDISKS_ERROR_FAILED,
-                       "Missing fsname, dir, type, opts, freq or passno parameter in entry to remove");
-          goto out;
+          device = g_strdup_printf ("/dev/disk/by-uuid/%s", fsname + 5);
         }
-    }
-
-  if (add != NULL)
-    {
-      if (!g_variant_lookup (add, "fsname", "^&ay", &mntent_add.mnt_fsname) ||
-          !g_variant_lookup (add, "dir", "^&ay", &mntent_add.mnt_dir) ||
-          !g_variant_lookup (add, "type", "^&ay", &mntent_add.mnt_type) ||
-          !g_variant_lookup (add, "opts", "^&ay", &mntent_add.mnt_opts) ||
-          !g_variant_lookup (add, "freq", "i", &mntent_add.mnt_freq) ||
-          !g_variant_lookup (add, "passno", "i", &mntent_add.mnt_passno))
+      else if (g_str_has_prefix (fsname, "LABEL="))
         {
-          g_set_error (error,
-                       UDISKS_ERROR,
-                       UDISKS_ERROR_FAILED,
-                       "Missing fsname, dir, type, opts, freq or passno parameter in entry to add");
-          goto out;
+          device = g_strdup_printf ("/dev/disk/by-label/%s", fsname + 6);
+        }
+      else if (g_str_has_prefix (fsname, "/dev"))
+        {
+          device = g_strdup (fsname);
+        }
+      else
+        {
+          /* ignore non-device entries */
+          goto continue_loop;
         }
-    }
-
-  if (!g_file_get_contents ("/etc/fstab",
-                            &contents,
-                            NULL,
-                            error))
-    goto out;
-
-  lines = g_strsplit (contents, "\n", 0);
 
-  str = g_string_new (NULL);
-  removed = FALSE;
-  for (n = 0; lines != NULL && lines[n] != NULL; n++)
-    {
-      const gchar *line = lines[n];
-      if (strlen (line) == 0 && lines[n+1] == NULL)
-        break;
-      if (remove != NULL && !removed)
+      if (g_strcmp0 (device, udisks_block_device_get_device (UDISKS_BLOCK_DEVICE (block))) == 0)
         {
-          gchar parsed_fsname[512];
-          gchar parsed_dir[512];
-          gchar parsed_type[512];
-          gchar parsed_opts[512];
-          gint parsed_freq;
-          gint parsed_passno;
-          if (sscanf (line, "%511s %511s %511s %511s %d %d",
-                      parsed_fsname,
-                      parsed_dir,
-                      parsed_type,
-                      parsed_opts,
-                      &parsed_freq,
-                      &parsed_passno) == 6)
+          ret = g_list_prepend (ret, g_object_ref (entry));
+        }
+      else
+        {
+          symlinks = udisks_block_device_get_symlinks (UDISKS_BLOCK_DEVICE (block));
+          if (symlinks != NULL)
             {
-              gchar *unescaped_fsname = unescape_fstab (parsed_fsname);
-              gchar *unescaped_dir = unescape_fstab (parsed_dir);
-              gchar *unescaped_type = unescape_fstab (parsed_type);
-              gchar *unescaped_opts = unescape_fstab (parsed_opts);
-              gboolean matches = FALSE;
-              if (g_strcmp0 (unescaped_fsname,   mntent_remove.mnt_fsname) == 0 &&
-                  g_strcmp0 (unescaped_dir,      mntent_remove.mnt_dir) == 0 &&
-                  g_strcmp0 (unescaped_type,     mntent_remove.mnt_type) == 0 &&
-                  g_strcmp0 (unescaped_opts,     mntent_remove.mnt_opts) == 0 &&
-                  parsed_freq ==      mntent_remove.mnt_freq &&
-                  parsed_passno ==    mntent_remove.mnt_passno)
-                {
-                  matches = TRUE;
-                }
-              g_free (unescaped_fsname);
-              g_free (unescaped_dir);
-              g_free (unescaped_type);
-              g_free (unescaped_opts);
-              if (matches)
+              for (n = 0; symlinks[n] != NULL; n++)
                 {
-                  removed = TRUE;
-                  continue;
+                  if (g_strcmp0 (device, symlinks[n]) == 0)
+                    {
+                      ret = g_list_prepend (ret, g_object_ref (entry));
+                    }
                 }
             }
         }
-      g_string_append (str, line);
-      g_string_append_c (str, '\n');
-    }
 
-  if (remove != NULL && !removed)
-    {
-      g_set_error (error,
-                   UDISKS_ERROR,
-                   UDISKS_ERROR_FAILED,
-                   "Didn't find entry to remove");
-      goto out;
+    continue_loop:
+      g_free (device);
     }
 
-  if (add != NULL)
-    {
-      gchar *escaped_fsname = escape_fstab (mntent_add.mnt_fsname);
-      gchar *escaped_dir = escape_fstab (mntent_add.mnt_dir);
-      gchar *escaped_type = escape_fstab (mntent_add.mnt_type);
-      gchar *escaped_opts = escape_fstab (mntent_add.mnt_opts);
-      g_string_append_printf (str, "%s %s %s %s %d %d\n",
-                              escaped_fsname,
-                              escaped_dir,
-                              escaped_type,
-                              escaped_opts,
-                              mntent_add.mnt_freq,
-                              mntent_add.mnt_passno);
-      g_free (escaped_fsname);
-      g_free (escaped_dir);
-      g_free (escaped_type);
-      g_free (escaped_opts);
-    }
-
-  if (!_g_file_set_contents_full ("/etc/fstab",
-                                  str->str,
-                                  -1,
-                                  0644, /* mode to use if non-existant */
-                                  error) != 0)
-    goto out;
-
-  ret = TRUE;
-
- out:
-  g_strfreev (lines);
-  g_free (contents);
-  if (str != NULL)
-    g_string_free (str, TRUE);
+  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
+  g_list_free (entries);
   return ret;
 }
 
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-has_whitespace (const gchar *s)
-{
-  guint n;
-  g_return_val_if_fail (s != NULL, TRUE);
-  for (n = 0; s[n] != '\0'; n++)
-    if (g_ascii_isspace (s[n]))
-      return TRUE;
-  return FALSE;
-}
-
-static gboolean
-add_remove_crypttab_entry (GVariant  *remove,
-                           GVariant  *add,
-                           GError   **error)
+static GList *
+find_crypttab_entries_for_device (UDisksLinuxBlock *block,
+                                  UDisksDaemon     *daemon)
 {
-  const gchar *remove_name = NULL;
-  const gchar *remove_device = NULL;
-  const gchar *remove_passphrase_path = NULL;
-  const gchar *remove_options = NULL;
-  const gchar *add_name = NULL;
-  const gchar *add_device = NULL;
-  const gchar *add_passphrase_path = NULL;
-  const gchar *add_options = NULL;
-  const gchar *add_passphrase_contents = NULL;
-  gboolean ret;
-  gchar *contents;
-  gchar **lines;
-  GString *str;
-  gboolean removed;
-  guint n;
+  GList *entries;
+  GList *l;
+  GList *ret;
 
-  contents = NULL;
-  lines = NULL;
-  str = NULL;
-  ret = FALSE;
+  ret = NULL;
 
-  if (remove != NULL)
+  /* if this is too slow, we could add lookup methods to UDisksCrypttabMonitor... */
+  entries = udisks_crypttab_monitor_get_entries (udisks_daemon_get_crypttab_monitor (daemon));
+  for (l = entries; l != NULL; l = l->next)
     {
-      if (!g_variant_lookup (remove, "name", "^&ay", &remove_name) ||
-          !g_variant_lookup (remove, "device", "^&ay", &remove_device) ||
-          !g_variant_lookup (remove, "passphrase-path", "^&ay", &remove_passphrase_path) ||
-          !g_variant_lookup (remove, "options", "^&ay", &remove_options))
+      UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
+      const gchar *const *symlinks;
+      const gchar *device_in_entry;
+      gchar *device;
+      guint n;
+
+      device_in_entry = udisks_crypttab_entry_get_device (entry);
+      device = NULL;
+      if (g_str_has_prefix (device_in_entry, "UUID="))
         {
-          g_set_error (error,
-                       UDISKS_ERROR,
-                       UDISKS_ERROR_FAILED,
-                       "Missing name, device, passphrase-path, options or parameter in entry to remove");
-          goto out;
+          device = g_strdup_printf ("/dev/disk/by-uuid/%s", device_in_entry + 5);
         }
-    }
-
-  if (add != NULL)
-    {
-      if (!g_variant_lookup (add, "name", "^&ay", &add_name) ||
-          !g_variant_lookup (add, "device", "^&ay", &add_device) ||
-          !g_variant_lookup (add, "passphrase-path", "^&ay", &add_passphrase_path) ||
-          !g_variant_lookup (add, "options", "^&ay", &add_options) ||
-          !g_variant_lookup (add, "passphrase-contents", "^&ay", &add_passphrase_contents))
+      else if (g_str_has_prefix (device_in_entry, "LABEL="))
         {
-          g_set_error (error,
-                       UDISKS_ERROR,
-                       UDISKS_ERROR_FAILED,
-                       "Missing name, device, passphrase-path, options or passphrase-contents parameter in entry to add");
-          goto out;
+          device = g_strdup_printf ("/dev/disk/by-label/%s", device_in_entry + 6);
         }
-
-      /* reject strings with whitespace in them */
-      if (has_whitespace (add_name) ||
-          has_whitespace (add_device) ||
-          has_whitespace (add_passphrase_path) ||
-          has_whitespace (add_options))
+      else if (g_str_has_prefix (device_in_entry, "/dev"))
         {
-          g_set_error (error,
-                       UDISKS_ERROR,
-                       UDISKS_ERROR_FAILED,
-                       "One of name, device, passphrase-path or options parameter are invalid (whitespace)");
-          goto out;
+          device = g_strdup (device_in_entry);
         }
-    }
-
-  if (!g_file_get_contents ("/etc/crypttab",
-                            &contents,
-                            NULL,
-                            error))
-    goto out;
-
-  lines = g_strsplit (contents, "\n", 0);
-
-  str = g_string_new (NULL);
-  removed = FALSE;
-  for (n = 0; lines != NULL && lines[n] != NULL; n++)
-    {
-      const gchar *line = lines[n];
-      if (strlen (line) == 0 && lines[n+1] == NULL)
-        break;
-      if (remove != NULL && !removed)
+      else
         {
-          gchar parsed_name[512];
-          gchar parsed_device[512];
-          gchar parsed_passphrase_path[512];
-          gchar parsed_options[512];
-          guint num_parsed;
+          /* ignore non-device entries */
+          goto continue_loop;
+        }
 
-          num_parsed = sscanf (line, "%511s %511s %511s %511s",
-                               parsed_name, parsed_device, parsed_passphrase_path, parsed_options);
-          if (num_parsed >= 2)
+      if (g_strcmp0 (device, udisks_block_device_get_device (UDISKS_BLOCK_DEVICE (block))) == 0)
+        {
+          ret = g_list_prepend (ret, g_object_ref (entry));
+        }
+      else
+        {
+          symlinks = udisks_block_device_get_symlinks (UDISKS_BLOCK_DEVICE (block));
+          if (symlinks != NULL)
             {
-              if (num_parsed < 3 || g_strcmp0 (parsed_passphrase_path, "none") == 0)
-                strcpy (parsed_passphrase_path, "");
-              if (num_parsed < 4)
-                strcpy (parsed_options, "");
-              if (g_strcmp0 (parsed_name,            remove_name) == 0 &&
-                  g_strcmp0 (parsed_device,          remove_device) == 0 &&
-                  g_strcmp0 (parsed_passphrase_path, remove_passphrase_path) == 0 &&
-                  g_strcmp0 (parsed_options,         remove_options) == 0)
+              for (n = 0; symlinks[n] != NULL; n++)
                 {
-                  /* Nuke passphrase file */
-                  if (strlen (remove_passphrase_path) > 0 && !g_str_has_prefix (remove_passphrase_path, "/dev"))
+                  if (g_strcmp0 (device, symlinks[n]) == 0)
                     {
-                      /* Is this exploitable? No, 1. the user would have to control
-                       * the /etc/crypttab file for us to delete it; and 2. editing the
-                       * /etc/crypttab file requires a polkit authorization that can't
-                       * be retained (e.g. the user is always asked for the password)..
-                       */
-                      if (unlink (remove_passphrase_path) != 0)
-                        {
-                          g_set_error (error,
-                                       UDISKS_ERROR,
-                                       UDISKS_ERROR_FAILED,
-                                       "Error deleting file `%s' with passphrase",
-                                       remove_passphrase_path);
-                          goto out;
-                        }
+                      ret = g_list_prepend (ret, g_object_ref (entry));
                     }
-                  removed = TRUE;
-                  continue;
                 }
             }
         }
-      g_string_append (str, line);
-      g_string_append_c (str, '\n');
+
+    continue_loop:
+      g_free (device);
     }
 
-  if (remove != NULL && !removed)
+  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
+  g_list_free (entries);
+  return ret;
+}
+
+/* returns a floating GVariant */
+static GVariant *
+calculate_configuration (UDisksLinuxBlock  *block,
+                         UDisksDaemon      *daemon,
+                         gboolean           include_secrets,
+                         GError           **error)
+{
+  GList *entries;
+  GList *l;
+  GVariantBuilder builder;
+  GVariant *ret;
+
+  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+  ret = NULL;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sa{sv})"));
+  /* First the /etc/fstab entries */
+  entries = find_fstab_entries_for_device (block, daemon);
+  for (l = entries; l != NULL; l = l->next)
     {
-      g_set_error (error,
-                   UDISKS_ERROR,
-                   UDISKS_ERROR_FAILED,
-                   "Didn't find entry to remove");
-      goto out;
+      UDisksFstabEntry *entry = UDISKS_FSTAB_ENTRY (l->data);
+      GVariantBuilder dict_builder;
+      g_variant_builder_init (&dict_builder, G_VARIANT_TYPE_VARDICT);
+      g_variant_builder_add (&dict_builder, "{sv}", "fsname",
+                             g_variant_new_bytestring (udisks_fstab_entry_get_fsname (entry)));
+      g_variant_builder_add (&dict_builder, "{sv}", "dir",
+                             g_variant_new_bytestring (udisks_fstab_entry_get_dir (entry)));
+      g_variant_builder_add (&dict_builder, "{sv}", "type",
+                             g_variant_new_bytestring (udisks_fstab_entry_get_fstype (entry)));
+      g_variant_builder_add (&dict_builder, "{sv}", "opts",
+                             g_variant_new_bytestring (udisks_fstab_entry_get_opts (entry)));
+      g_variant_builder_add (&dict_builder, "{sv}", "freq",
+                             g_variant_new_int32 (udisks_fstab_entry_get_freq (entry)));
+      g_variant_builder_add (&dict_builder, "{sv}", "passno",
+                             g_variant_new_int32 (udisks_fstab_entry_get_passno (entry)));
+      g_variant_builder_add (&builder,
+                             "(sa{sv})",
+                             "fstab", &dict_builder);
     }
+  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
+  g_list_free (entries);
 
-  if (add != NULL)
+  /* Then the /etc/crypttab entries */
+  entries = find_crypttab_entries_for_device (block, daemon);
+  for (l = entries; l != NULL; l = l->next)
     {
-      /* First write add_passphrase_content to add_passphrase_path,
-       * if applicable..
-       *
-       * Is this exploitable? No, because editing the /etc/crypttab
-       * file requires a polkit authorization that can't be retained
-       * (e.g. the user is always asked for the password)...
-       *
-       * Just to be on the safe side we only allow writing into the
-       * directory /etc/luks-keys if create a _new_ entry.
-       */
-      if (strlen (add_passphrase_path) > 0)
+      UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
+      GVariantBuilder dict_builder;
+      const gchar *passphrase_path;
+      const gchar *options;
+      gchar *passphrase_contents;
+      gsize passphrase_contents_length;
+
+      passphrase_path = udisks_crypttab_entry_get_passphrase_path (entry);
+      if (passphrase_path == NULL || g_strcmp0 (passphrase_path, "none") == 0)
+        passphrase_path = "";
+      passphrase_contents = NULL;
+      if (!(g_strcmp0 (passphrase_path, "") == 0 || g_str_has_prefix (passphrase_path, "/dev")))
         {
-          gchar *filename;
-          if (g_strcmp0 (add_passphrase_path, remove_passphrase_path) == 0)
-            {
-              filename = g_strdup (add_passphrase_path);
-            }
-          else
+          if (include_secrets)
             {
-              if (!g_str_has_prefix (add_passphrase_path, "/etc/luks-keys/"))
-                {
-                  g_set_error (error,
-                               UDISKS_ERROR,
-                               UDISKS_ERROR_FAILED,
-                               "Crypttab passphrase file can only be created in the /etc/luks-keys directory");
-                  goto out;
-                }
-              /* ensure the directory exists */
-              if (g_mkdir_with_parents ("/etc/luks-keys", 0700) != 0)
+              if (!g_file_get_contents (passphrase_path,
+                                        &passphrase_contents,
+                                        &passphrase_contents_length,
+                                        error))
                 {
-                  g_set_error (error,
-                               UDISKS_ERROR,
-                               UDISKS_ERROR_FAILED,
-                               "Error creating /etc/luks-keys directory: %m");
+                  g_prefix_error (error,
+                                  "Error loading secrets from file `%s' referenced in /etc/crypttab entry: ",
+                                  passphrase_path);
+                  g_variant_builder_clear (&builder);
+                  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
+                  g_list_free (entries);
                   goto out;
                 }
-              /* avoid symlink attacks */
-              filename = g_strdup_printf ("/etc/luks-keys/%s", strrchr (add_passphrase_path, '/') + 1);
             }
+        }
 
-          /* Bail if the requested file already exists */
-          if (g_file_test (filename, G_FILE_TEST_EXISTS))
-            {
-                  g_set_error (error,
-                               UDISKS_ERROR,
-                               UDISKS_ERROR_FAILED,
-                               "Refusing to overwrite existing file %s",
-                               filename);
-                  g_free (filename);
-                  goto out;
-            }
+      options = udisks_crypttab_entry_get_options (entry);
+      if (options == NULL)
+        options = "";
 
-          if (!_g_file_set_contents_full (filename,
-                                          add_passphrase_contents,
-                                          -1,
-                                          0600, /* mode to use if non-existant */
-                                          error))
-            {
-              g_free (filename);
-              goto out;
-            }
-          g_free (filename);
+      g_variant_builder_init (&dict_builder, G_VARIANT_TYPE_VARDICT);
+      g_variant_builder_add (&dict_builder, "{sv}", "name",
+                             g_variant_new_bytestring (udisks_crypttab_entry_get_name (entry)));
+      g_variant_builder_add (&dict_builder, "{sv}", "device",
+                             g_variant_new_bytestring (udisks_crypttab_entry_get_device (entry)));
+      g_variant_builder_add (&dict_builder, "{sv}", "passphrase-path",
+                             g_variant_new_bytestring (passphrase_path));
+      if (passphrase_contents != NULL)
+        {
+          g_variant_builder_add (&dict_builder, "{sv}", "passphrase-contents",
+                                 g_variant_new_bytestring (passphrase_contents));
+        }
+      g_variant_builder_add (&dict_builder, "{sv}", "options",
+                             g_variant_new_bytestring (options));
+      g_variant_builder_add (&builder,
+                             "(sa{sv})",
+                             "crypttab", &dict_builder);
+      if (passphrase_contents != NULL)
+        {
+          memset (passphrase_contents, '\0', passphrase_contents_length);
+          g_free (passphrase_contents);
         }
-      g_string_append_printf (str, "%s %s %s %s\n",
-                              add_name,
-                              add_device,
-                              strlen (add_passphrase_path) > 0 ? add_passphrase_path : "none",
-                              add_options);
     }
+  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
+  g_list_free (entries);
 
-  if (!_g_file_set_contents_full ("/etc/crypttab",
-                                  str->str,
-                                  -1,
-                                  0600, /* mode to use if non-existant */
-                                  error) != 0)
-    goto out;
-
-  ret = TRUE;
+  ret = g_variant_builder_end (&builder);
 
  out:
-  g_strfreev (lines);
-  g_free (contents);
-  if (str != NULL)
-    g_string_free (str, TRUE);
   return ret;
 }
 
-/* ---------------------------------------------------------------------------------------------------- */
-
-static gboolean
-on_add_configuration_item (UDisksBlockDevice     *block,
-                           GDBusMethodInvocation *invocation,
-                           GVariant              *item,
-                           GVariant              *options,
-                           gpointer               user_data)
+static void
+update_configuration (UDisksLinuxBlock  *block,
+                      UDisksDaemon      *daemon)
 {
-  UDisksLinuxBlock *object = UDISKS_LINUX_BLOCK (user_data);
-  const gchar *type;
-  GVariant *details;
+  GVariant *configuration;
   GError *error;
 
-  g_variant_get (item, "(&s@a{sv})", &type, &details);
-
-  if (g_strcmp0 (type, "fstab") == 0)
-    {
-      if (!udisks_daemon_util_check_authorization_sync (object->daemon,
-                                                        NULL,
-                                                        "org.freedesktop.udisks2.modify-system-configuration",
-                                                        options,
-                                                        N_("Authentication is required to add an entry to the /etc/fstab file"),
-                                                        invocation))
-        goto out;
-      error = NULL;
-      if (!add_remove_fstab_entry (NULL, details, &error))
-        {
-          g_dbus_method_invocation_take_error (invocation, error);
-          goto out;
-        }
-      udisks_block_device_complete_add_configuration_item (block, invocation);
-    }
-  else if (g_strcmp0 (type, "crypttab") == 0)
-    {
-      if (!udisks_daemon_util_check_authorization_sync (object->daemon,
-                                                        NULL,
-                                                        "org.freedesktop.udisks2.modify-system-configuration",
-                                                        options,
-                                                        N_("Authentication is required to add an entry to the /etc/crypttab file"),
-                                                        invocation))
-        goto out;
-      error = NULL;
-      if (!add_remove_crypttab_entry (NULL, details, &error))
-        {
-          g_dbus_method_invocation_take_error (invocation, error);
-          goto out;
-        }
-      udisks_block_device_complete_add_configuration_item (block, invocation);
-    }
-  else
+  error = NULL;
+  configuration = calculate_configuration (block, daemon, FALSE, &error);
+  if (configuration == NULL)
     {
-      g_dbus_method_invocation_return_error (invocation,
-                                             UDISKS_ERROR,
-                                             UDISKS_ERROR_FAILED,
-                                             "Only /etc/fstab or /etc/crypttab items can be added");
-      goto out;
+      udisks_warning ("Error loading configuration: %s (%s, %d)",
+                      error->message, g_quark_to_string (error->domain), error->code);
+      g_error_free (error);
+      configuration = g_variant_new ("a(sa{sv})", NULL);
     }
-
- out:
-  g_variant_unref (details);
-  return TRUE; /* returning TRUE means that we handled the method invocation */
+  udisks_block_device_set_configuration (UDISKS_BLOCK_DEVICE (block), configuration);
 }
 
-static gboolean
-on_remove_configuration_item (UDisksBlockDevice     *block,
-                              GDBusMethodInvocation *invocation,
-                              GVariant              *item,
-                              GVariant              *options,
-                              gpointer               user_data)
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * udisks_linux_block_update:
+ * @block: A #UDisksLinuxBlock.
+ * @object: The enclosing #UDisksLinuxBlockObject instance.
+ *
+ * Updates the interface.
+ */
+void
+udisks_linux_block_update (UDisksLinuxBlock        *block,
+                           UDisksLinuxBlockObject *object)
 {
-  UDisksLinuxBlock *object = UDISKS_LINUX_BLOCK (user_data);
-  const gchar *type;
-  GVariant *details;
-  GError *error;
+  UDisksBlockDevice *iface = UDISKS_BLOCK_DEVICE (block);
+  UDisksDaemon *daemon;
+  GDBusObjectManagerServer *object_manager;
+  GUdevDevice *device;
+  GUdevDeviceNumber dev;
+  gchar *drive_object_path;
+  UDisksDrive *drive;
+  gchar *s;
+  gboolean is_partition_table;
+  gboolean is_partition_entry;
+  const gchar *device_file;
+  const gchar *const *symlinks;
+  const gchar *preferred_device_file;
 
-  g_variant_get (item, "(&s@a{sv})", &type, &details);
+  drive = NULL;
 
-  if (g_strcmp0 (type, "fstab") == 0)
+  device = udisks_linux_block_object_get_device (object);
+  if (device == NULL)
+    goto out;
+
+  daemon = udisks_linux_block_object_get_daemon (object);
+  object_manager = udisks_daemon_get_object_manager (daemon);
+
+  dev = g_udev_device_get_device_number (device);
+  device_file = g_udev_device_get_device_file (device);
+  symlinks = g_udev_device_get_device_file_symlinks (device);
+
+  udisks_block_device_set_device (iface, device_file);
+  udisks_block_device_set_symlinks (iface, symlinks);
+  udisks_block_device_set_major (iface, major (dev));
+  udisks_block_device_set_minor (iface, minor (dev));
+  udisks_block_device_set_size (iface, udisks_daemon_util_block_get_size (device));
+
+  /* dm-crypt
+   *
+   * TODO: this might not be the best way to determine if the device-mapper device
+   *       is a dm-crypt device.. but unfortunately device-mapper keeps all this stuff
+   *       in user-space and wants you to use libdevmapper to obtain it...
+   */
+  udisks_block_device_set_crypto_backing_device (iface, "/");
+  if (g_str_has_prefix (g_udev_device_get_name (device), "dm-"))
     {
-      if (!udisks_daemon_util_check_authorization_sync (object->daemon,
-                                                        NULL,
-                                                        "org.freedesktop.udisks2.modify-system-configuration",
-                                                        options,
-                                                        N_("Authentication is required to remove an entry from /etc/fstab file"),
-                                                        invocation))
-        goto out;
-      error = NULL;
-      if (!add_remove_fstab_entry (details, NULL, &error))
+      gchar *dm_uuid;
+      dm_uuid = get_sysfs_attr (device, "dm/uuid");
+      if (dm_uuid != NULL && g_str_has_prefix (dm_uuid, "CRYPT-LUKS1"))
         {
-          g_dbus_method_invocation_take_error (invocation, error);
-          goto out;
+          gchar **slaves;
+          slaves = udisks_daemon_util_resolve_links (g_udev_device_get_sysfs_path (device),
+                                                     "slaves");
+          if (g_strv_length (slaves) == 1)
+            {
+              gchar *slave_object_path;
+              slave_object_path = find_block_device_by_sysfs_path (object_manager, slaves[0]);
+              if (slave_object_path != NULL)
+                {
+                  udisks_block_device_set_crypto_backing_device (iface, slave_object_path);
+                }
+              g_free (slave_object_path);
+            }
+          g_strfreev (slaves);
         }
-      udisks_block_device_complete_add_configuration_item (block, invocation);
+      g_free (dm_uuid);
     }
-  else if (g_strcmp0 (type, "crypttab") == 0)
+
+  /* Sort out preferred device... this is what UI shells should
+   * display. We default to the block device name.
+   *
+   * This is mostly for things like device-mapper where device file is
+   * a name of the form dm-%d and a symlink name conveys more
+   * information.
+   */
+  preferred_device_file = NULL;
+  if (g_str_has_prefix (device_file, "/dev/dm-"))
     {
-      if (!udisks_daemon_util_check_authorization_sync (object->daemon,
-                                                        NULL,
-                                                        "org.freedesktop.udisks2.modify-system-configuration",
-                                                        options,
-                                                        N_("Authentication is required to remove an entry from the /etc/crypttab file"),
-                                                        invocation))
-        goto out;
-      error = NULL;
-      if (!add_remove_crypttab_entry (details, NULL, &error))
-        {
-          g_dbus_method_invocation_take_error (invocation, error);
-          goto out;
+      guint n;
+      const gchar *dm_name;
+      gchar *dm_name_dev_file = NULL;
+      const gchar *dm_name_dev_file_as_symlink = NULL;
+
+      dm_name = g_udev_device_get_property (device, "DM_NAME");
+      if (dm_name != NULL)
+        dm_name_dev_file = g_strdup_printf ("/dev/mapper/%s", dm_name);
+      for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
+        {
+          if (g_str_has_prefix (symlinks[n], "/dev/vg_"))
+            {
+              /* LVM2 */
+              preferred_device_file = symlinks[n];
+              break;
+            }
+          else if (g_strcmp0 (symlinks[n], dm_name_dev_file) == 0)
+            {
+              dm_name_dev_file_as_symlink = symlinks[n];
+            }
         }
-      udisks_block_device_complete_add_configuration_item (block, invocation);
+      /* fall back to /dev/mapper/$DM_NAME, if available as a symlink */
+      if (preferred_device_file == NULL && dm_name_dev_file_as_symlink != NULL)
+        preferred_device_file = dm_name_dev_file_as_symlink;
+      g_free (dm_name_dev_file);
+    }
+  /* fallback to the device name */
+  if (preferred_device_file == NULL)
+    preferred_device_file = g_udev_device_get_device_file (device);
+  udisks_block_device_set_preferred_device (iface, preferred_device_file);
+
+  /* Determine the drive this block device belongs to
+   *
+   * TODO: if this is slow we could have a cache or ensure that we
+   * only do this once or something else
+   */
+  drive_object_path = find_drive (object_manager, device, &drive);
+  if (drive_object_path != NULL)
+    {
+      udisks_block_device_set_drive (iface, drive_object_path);
+      g_free (drive_object_path);
     }
   else
     {
-      g_dbus_method_invocation_return_error (invocation,
-                                             UDISKS_ERROR,
-                                             UDISKS_ERROR_FAILED,
-                                             "Only fstab or crypttab items can be removed");
-      goto out;
+      udisks_block_device_set_drive (iface, "/");
     }
 
- out:
-  g_variant_unref (details);
-  return TRUE; /* returning TRUE means that we handled the method invocation */
-}
+  udisks_block_device_set_id_usage (iface, g_udev_device_get_property (device, "ID_FS_USAGE"));
+  udisks_block_device_set_id_type (iface, g_udev_device_get_property (device, "ID_FS_TYPE"));
+  s = udisks_decode_udev_string (g_udev_device_get_property (device, "ID_FS_VERSION"));
+  udisks_block_device_set_id_version (iface, s);
+  g_free (s);
+  s = udisks_decode_udev_string (g_udev_device_get_property (device, "ID_FS_LABEL_ENC"));
+  udisks_block_device_set_id_label (iface, s);
+  g_free (s);
+  s = udisks_decode_udev_string (g_udev_device_get_property (device, "ID_FS_UUID_ENC"));
+  udisks_block_device_set_id_uuid (iface, s);
+  g_free (s);
 
-static gboolean
-on_update_configuration_item (UDisksBlockDevice     *block,
-                              GDBusMethodInvocation *invocation,
-                              GVariant              *old_item,
-                              GVariant              *new_item,
-                              GVariant              *options,
-                              gpointer               user_data)
-{
-  UDisksLinuxBlock *object = UDISKS_LINUX_BLOCK (user_data);
-  const gchar *old_type;
-  const gchar *new_type;
-  GVariant *old_details;
-  GVariant *new_details;
-  GError *error;
+  /* TODO: port this to blkid properties */
 
-  g_variant_get (old_item, "(&s@a{sv})", &old_type, &old_details);
-  g_variant_get (new_item, "(&s@a{sv})", &new_type, &new_details);
-  if (g_strcmp0 (old_type, new_type) != 0)
+  /* Update the partition table and partition entry properties */
+  is_partition_table = FALSE;
+  is_partition_entry = FALSE;
+  if (g_strcmp0 (g_udev_device_get_devtype (device), "partition") == 0 ||
+      g_udev_device_get_property_as_boolean (device, "UDISKS_PARTITION"))
     {
-      g_dbus_method_invocation_return_error (invocation,
-                                             UDISKS_ERROR,
-                                             UDISKS_ERROR_FAILED,
-                                             "old and new item are not of the same type");
-      goto out;
+      is_partition_entry = TRUE;
+    }
+  else if (g_udev_device_get_property_as_boolean (device, "UDISKS_PARTITION_TABLE"))
+    {
+      is_partition_table = TRUE;
     }
 
-  if (g_strcmp0 (old_type, "fstab") == 0)
+  /* partition table */
+  if (is_partition_table)
     {
-      if (!udisks_daemon_util_check_authorization_sync (object->daemon,
-                                                        NULL,
-                                                        "org.freedesktop.udisks2.modify-system-configuration",
-                                                        options,
-                                                        N_("Authentication is required to modify the /etc/fstab file"),
-                                                        invocation))
-        goto out;
-      error = NULL;
-      if (!add_remove_fstab_entry (old_details, new_details, &error))
-        {
-          g_dbus_method_invocation_take_error (invocation, error);
-          goto out;
-        }
-      udisks_block_device_complete_add_configuration_item (block, invocation);
+      udisks_block_device_set_part_table (iface, TRUE);
+      udisks_block_device_set_part_table_scheme (iface,
+                                                 g_udev_device_get_property (device,
+                                                                             "UDISKS_PARTITION_TABLE_SCHEME"));
     }
-  else if (g_strcmp0 (old_type, "crypttab") == 0)
+  else
     {
-      if (!udisks_daemon_util_check_authorization_sync (object->daemon,
-                                                        NULL,
-                                                        "org.freedesktop.udisks2.modify-system-configuration",
-                                                        options,
-                                                        N_("Authentication is required to modify the /etc/crypttab file"),
-                                                        invocation))
-        goto out;
-      error = NULL;
-      if (!add_remove_crypttab_entry (old_details, new_details, &error))
+      udisks_block_device_set_part_table (iface, FALSE);
+      udisks_block_device_set_part_table_scheme (iface, "");
+    }
+
+  /* partition entry */
+  if (is_partition_entry)
+    {
+      gchar *slave_sysfs_path;
+      udisks_block_device_set_part_entry (iface, TRUE);
+      udisks_block_device_set_part_entry_scheme (iface,
+                                                 g_udev_device_get_property (device,
+                                                                             "UDISKS_PARTITION_SCHEME"));
+      udisks_block_device_set_part_entry_number (iface,
+                                                 g_udev_device_get_property_as_int (device,
+                                                                                    "UDISKS_PARTITION_NUMBER"));
+      udisks_block_device_set_part_entry_type (iface,
+                                               g_udev_device_get_property (device,
+                                                                           "UDISKS_PARTITION_TYPE"));
+      udisks_block_device_set_part_entry_flags (iface,
+                                                g_udev_device_get_property (device,
+                                                                            "UDISKS_PARTITION_FLAGS"));
+      udisks_block_device_set_part_entry_label (iface,
+                                                g_udev_device_get_property (device,
+                                                                            "UDISKS_PARTITION_LABEL"));
+      udisks_block_device_set_part_entry_uuid (iface,
+                                               g_udev_device_get_property (device,
+                                                                           "UDISKS_PARTITION_UUID"));
+      slave_sysfs_path = g_strdup (g_udev_device_get_property (device, "UDISKS_PARTITION_SLAVE"));
+      if (slave_sysfs_path == NULL)
         {
-          g_dbus_method_invocation_take_error (invocation, error);
-          goto out;
+          if (g_strcmp0 (g_udev_device_get_devtype (device), "partition") == 0)
+            {
+              GUdevDevice *parent;
+              parent = g_udev_device_get_parent (device);
+              slave_sysfs_path = g_strdup (g_udev_device_get_sysfs_path (parent));
+              g_object_unref (parent);
+            }
+          else
+            {
+              g_warning ("No UDISKS_PARTITION_SLAVE property and DEVTYPE is not partition for block device %s",
+                         g_udev_device_get_sysfs_path (device));
+            }
+        }
+      if (slave_sysfs_path != NULL)
+        {
+          gchar *slave_object_path;
+          slave_object_path = find_block_device_by_sysfs_path (object_manager, slave_sysfs_path);
+          if (slave_object_path != NULL)
+            udisks_block_device_set_part_entry_table (iface, slave_object_path);
+          else
+            udisks_block_device_set_part_entry_table (iface, "/");
+          g_free (slave_object_path);
+          g_free (slave_sysfs_path);
+        }
+      else
+        {
+          udisks_block_device_set_part_entry_table (iface, "/");
         }
-      udisks_block_device_complete_add_configuration_item (block, invocation);
+      udisks_block_device_set_part_entry_offset (iface,
+                                                 g_udev_device_get_property_as_uint64 (device,
+                                                                                       "UDISKS_PARTITION_OFFSET"));
+      udisks_block_device_set_part_entry_size (iface,
+                                               g_udev_device_get_property_as_uint64 (device,
+                                                                                     "UDISKS_PARTITION_SIZE"));
     }
   else
     {
-      g_dbus_method_invocation_return_error (invocation,
-                                             UDISKS_ERROR,
-                                             UDISKS_ERROR_FAILED,
-                                             "Only fstab or crypttab items can be updated");
-      goto out;
+      udisks_block_device_set_part_entry (iface, FALSE);
+      udisks_block_device_set_part_entry_scheme (iface, "");
+      udisks_block_device_set_part_entry_type (iface, "");
+      udisks_block_device_set_part_entry_flags (iface, "");
+      udisks_block_device_set_part_entry_table (iface, "/");
+      udisks_block_device_set_part_entry_offset (iface, 0);
+      udisks_block_device_set_part_entry_size (iface, 0);
     }
 
+  update_hints (block, device, drive);
+  update_configuration (block, daemon);
+
  out:
-  g_variant_unref (new_details);
-  g_variant_unref (old_details);
-  return TRUE; /* returning TRUE means that we handled the method invocation */
+  if (device != NULL)
+    g_object_unref (device);
+  if (drive != NULL)
+    g_object_unref (drive);
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
-/* org.freedesktop.UDisks.BlockDevice */
 
 static gboolean
-block_device_check (UDisksLinuxBlock *block)
+handle_get_secret_configuration (UDisksBlockDevice     *_block,
+                                 GDBusMethodInvocation *invocation,
+                                 GVariant              *options)
 {
-  return TRUE;
-}
-
-static void
-block_device_connect (UDisksLinuxBlock *block)
-{
-  g_signal_connect (block->iface_block_device,
-                    "handle-get-secret-configuration",
-                    G_CALLBACK (on_get_secret_configuration),
-                    block);
-  g_signal_connect (block->iface_block_device,
-                    "handle-add-configuration-item",
-                    G_CALLBACK (on_add_configuration_item),
-                    block);
-  g_signal_connect (block->iface_block_device,
-                    "handle-remove-configuration-item",
-                    G_CALLBACK (on_remove_configuration_item),
-                    block);
-  g_signal_connect (block->iface_block_device,
-                    "handle-update-configuration-item",
-                    G_CALLBACK (on_update_configuration_item),
-                    block);
-}
-
-static gchar *
-find_drive (GDBusObjectManagerServer  *object_manager,
-            GUdevDevice               *block_device,
-            UDisksDrive              **out_drive)
-{
-  GUdevDevice *whole_disk_block_device;
-  const gchar *whole_disk_block_device_sysfs_path;
-  gchar *ret;
-  GList *objects;
-  GList *l;
-
-  ret = NULL;
+  UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (_block);
+  UDisksLinuxBlockObject *object;
+  UDisksDaemon *daemon;
+  GVariant *configuration;
+  GError *error;
 
-  if (g_strcmp0 (g_udev_device_get_devtype (block_device), "disk") == 0)
-    whole_disk_block_device = g_object_ref (block_device);
-  else
-    whole_disk_block_device = g_udev_device_get_parent_with_subsystem (block_device, "block", "disk");
-  whole_disk_block_device_sysfs_path = g_udev_device_get_sysfs_path (whole_disk_block_device);
+  object = UDISKS_LINUX_BLOCK_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (block)));
+  daemon = udisks_linux_block_object_get_daemon (object);
 
-  objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
-  for (l = objects; l != NULL; l = l->next)
+  error = NULL;
+  configuration = calculate_configuration (block, daemon, TRUE, &error);
+  if (configuration == NULL)
     {
-      GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (l->data);
-      GList *drive_devices;
-      GList *j;
-
-      if (!UDISKS_IS_LINUX_DRIVE_OBJECT (object))
-        continue;
-
-      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);
-          const gchar *drive_sysfs_path;
+      g_dbus_method_invocation_take_error (invocation, error);
+      goto out;
+    }
 
-          drive_sysfs_path = g_udev_device_get_sysfs_path (drive_device);
-          if (g_strcmp0 (whole_disk_block_device_sysfs_path, drive_sysfs_path) == 0)
-            {
-              if (out_drive != NULL)
-                *out_drive = udisks_object_get_drive (UDISKS_OBJECT (object));
-              ret = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
-              g_list_foreach (drive_devices, (GFunc) g_object_unref, NULL);
-              g_list_free (drive_devices);
-              goto out;
-            }
-        }
-      g_list_foreach (drive_devices, (GFunc) g_object_unref, NULL);
-      g_list_free (drive_devices);
+  if (!udisks_daemon_util_check_authorization_sync (daemon,
+                                                    NULL,
+                                                    "org.freedesktop.udisks2.read-system-configuration-secrets",
+                                                    options,
+                                                    N_("Authentication is required to read system-level secrets"),
+                                                    invocation))
+    {
+      g_variant_unref (configuration);
+      goto out;
     }
 
+  udisks_block_device_complete_get_secret_configuration (UDISKS_BLOCK_DEVICE (block),
+                                                         invocation,
+                                                         configuration); /* consumes floating ref */
+
  out:
-  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
-  g_list_free (objects);
-  g_object_unref (whole_disk_block_device);
-  return ret;
+  return TRUE; /* returning TRUE means that we handled the method invocation */
 }
 
+/* ---------------------------------------------------------------------------------------------------- */
+
 static gchar *
-find_block_device_by_sysfs_path (GDBusObjectManagerServer *object_manager,
-                                 const gchar              *sysfs_path)
+escape_fstab (const gchar *source)
 {
-  gchar *ret;
-  GList *objects;
-  GList *l;
-
-  ret = NULL;
-
-  objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager));
-  for (l = objects; l != NULL; l = l->next)
+  GString *s;
+  guint n;
+  s = g_string_new (NULL);
+  for (n = 0; source[n] != '\0'; n++)
     {
-      GDBusObjectSkeleton *object = G_DBUS_OBJECT_SKELETON (l->data);
-      UDisksLinuxBlock *block;
-
-      if (!UDISKS_IS_LINUX_BLOCK (object))
-        continue;
-
-      block = UDISKS_LINUX_BLOCK (object);
-
-      if (g_strcmp0 (sysfs_path, g_udev_device_get_sysfs_path (block->device)) == 0)
+      switch (source[n])
         {
-          ret = g_strdup (g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
-          goto out;
+        case ' ':
+        case '\t':
+        case '\n':
+        case '\\':
+          g_string_append_printf (s, "\\%03o", source[n]);
+          break;
+
+        default:
+          g_string_append_c (s, source[n]);
+          break;
         }
     }
-
- out:
-  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
-  g_list_free (objects);
-  return ret;
+  return g_string_free (s, FALSE);
 }
 
+/* based on g_strcompress() */
 static gchar *
-get_sysfs_attr (GUdevDevice *device,
-                const gchar *attr)
-{
-  gchar *filename;
-  gchar *value;
-  filename = g_strconcat (g_udev_device_get_sysfs_path (device),
-                          "/",
-                          attr,
-                          NULL);
-  value = NULL;
-  /* don't care about errors */
-  g_file_get_contents (filename,
-                       &value,
-                       NULL,
-                       NULL);
-  g_free (filename);
-  return value;
-}
-
-static void
-block_device_update_hints (UDisksLinuxBlock  *block,
-                           const gchar       *uevent_action,
-                           UDisksBlockDevice *iface,
-                           const gchar       *device_file,
-                           UDisksDrive       *drive)
+unescape_fstab (const gchar *source)
 {
-  gboolean hint_system;
-  gboolean hint_ignore;
-  gboolean hint_auto;
-  const gchar *hint_name;
-  const gchar *hint_icon_name;
-
-  /* very conservative defaults */
-  hint_system = TRUE;
-  hint_ignore = FALSE;
-  hint_auto = FALSE;
-  hint_name = NULL;
-  hint_icon_name = NULL;
+  const gchar *p = source, *octal;
+  gchar *dest = g_malloc (strlen (source) + 1);
+  gchar *q = dest;
 
-  /* Provide easy access to _only_ the following devices
-   *
-   *  - anything connected via known local buses (e.g. USB or Firewire, MMC or MemoryStick)
-   *  - any device with removable media
-   *
-   * Be careful when extending this list as we don't want to automount
-   * the world when (inadvertently) connecting to a SAN.
-   */
-  if (drive != NULL)
+  while (*p)
     {
-      const gchar *connection_bus;
-      gboolean removable;
-      connection_bus = udisks_drive_get_connection_bus (drive);
-      removable = udisks_drive_get_media_removable (drive);
-      if (removable ||
-          (g_strcmp0 (connection_bus, "usb") == 0 || g_strcmp0 (connection_bus, "firewire") == 0) ||
-          (g_str_has_prefix (device_file, "/dev/mmcblk") || g_str_has_prefix (device_file, "/dev/mspblk")))
+      if (*p == '\\')
         {
-          hint_system = FALSE;
-          hint_auto = TRUE;
+          p++;
+          switch (*p)
+            {
+            case '\0':
+              g_warning ("unescape_fstab: trailing \\");
+              goto out;
+            case '0':  case '1':  case '2':  case '3':  case '4':
+            case '5':  case '6':  case '7':
+              *q = 0;
+              octal = p;
+              while ((p < octal + 3) && (*p >= '0') && (*p <= '7'))
+                {
+                  *q = (*q * 8) + (*p - '0');
+                  p++;
+                }
+              q++;
+              p--;
+              break;
+            default:            /* Also handles \" and \\ */
+              *q++ = *p;
+              break;
+            }
         }
+      else
+        *q++ = *p;
+      p++;
     }
+out:
+  *q = 0;
 
-  /* TODO: set ignore to TRUE for physical paths belonging to a drive with multiple paths */
-
-  /* override from udev properties */
-  if (g_udev_device_has_property (block->device, "UDISKS_SYSTEM"))
-    hint_system = g_udev_device_get_property_as_boolean (block->device, "UDISKS_SYSTEM");
-  if (g_udev_device_has_property (block->device, "UDISKS_IGNORE"))
-    hint_ignore = g_udev_device_get_property_as_boolean (block->device, "UDISKS_IGNORE");
-  if (g_udev_device_has_property (block->device, "UDISKS_AUTO"))
-    hint_auto = g_udev_device_get_property_as_boolean (block->device, "UDISKS_AUTO");
-  if (g_udev_device_has_property (block->device, "UDISKS_NAME"))
-    hint_name = g_udev_device_get_property (block->device, "UDISKS_NAME");
-  if (g_udev_device_has_property (block->device, "UDISKS_ICON_NAME"))
-    hint_icon_name = g_udev_device_get_property (block->device, "UDISKS_ICON_NAME");
-
-  /* ... and scene! */
-  udisks_block_device_set_hint_system (iface, hint_system);
-  udisks_block_device_set_hint_ignore (iface, hint_ignore);
-  udisks_block_device_set_hint_auto (iface, hint_auto);
-  udisks_block_device_set_hint_name (iface, hint_name);
-  udisks_block_device_set_hint_icon_name (iface, hint_icon_name);
+  return dest;
 }
 
-static GList *
-find_fstab_entries_for_device (UDisksLinuxBlock *block)
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* TODO: maybe move to GLib */
+static gboolean
+_g_file_set_contents_full (const gchar  *filename,
+                           const gchar  *contents,
+                           gssize        contents_len,
+                           gint          mode_for_new_file,
+                           GError      **error)
 {
-  GList *entries;
-  GList *l;
-  GList *ret;
+  gboolean ret;
+  struct stat statbuf;
+  gint mode;
+  gchar *tmpl;
+  gint fd;
+  FILE *f;
 
-  ret = NULL;
+  ret = FALSE;
+  tmpl = NULL;
 
-  /* if this is too slow, we could add lookup methods to UDisksFstabMonitor... */
-  entries = udisks_fstab_monitor_get_entries (udisks_daemon_get_fstab_monitor (block->daemon));
-  for (l = entries; l != NULL; l = l->next)
+  if (stat (filename, &statbuf) != 0)
     {
-      UDisksFstabEntry *entry = UDISKS_FSTAB_ENTRY (l->data);
-      const gchar *const *symlinks;
-      const gchar *fsname;
-      gchar *device;
-      guint n;
-
-      fsname = udisks_fstab_entry_get_fsname (entry);
-      device = NULL;
-      if (g_str_has_prefix (fsname, "UUID="))
-        {
-          device = g_strdup_printf ("/dev/disk/by-uuid/%s", fsname + 5);
-        }
-      else if (g_str_has_prefix (fsname, "LABEL="))
-        {
-          device = g_strdup_printf ("/dev/disk/by-label/%s", fsname + 6);
-        }
-      else if (g_str_has_prefix (fsname, "/dev"))
-        {
-          device = g_strdup (fsname);
-        }
-      else
-        {
-          /* ignore non-device entries */
-          goto continue_loop;
-        }
-
-      if (g_strcmp0 (device, udisks_block_device_get_device (block->iface_block_device)) == 0)
+      if (errno == ENOENT)
         {
-          ret = g_list_prepend (ret, g_object_ref (entry));
+          mode = mode_for_new_file;
         }
       else
         {
-          symlinks = udisks_block_device_get_symlinks (block->iface_block_device);
-          if (symlinks != NULL)
-            {
-              for (n = 0; symlinks[n] != NULL; n++)
-                {
-                  if (g_strcmp0 (device, symlinks[n]) == 0)
-                    {
-                      ret = g_list_prepend (ret, g_object_ref (entry));
-                    }
-                }
-            }
+          g_set_error (error,
+                       G_IO_ERROR,
+                       g_io_error_from_errno (errno),
+                       "Error stat(2)'ing %s: %m",
+                       filename);
+          goto out;
         }
-
-    continue_loop:
-      g_free (device);
+    }
+  else
+    {
+      mode = statbuf.st_mode;
     }
 
-  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
-  g_list_free (entries);
-  return ret;
-}
-
-static GList *
-find_crypttab_entries_for_device (UDisksLinuxBlock *block)
-{
-  GList *entries;
-  GList *l;
-  GList *ret;
+  tmpl = g_strdup_printf ("%s.XXXXXX", filename);
+  fd = g_mkstemp_full (tmpl, O_RDWR, mode);
+  if (fd == -1)
+    {
+      g_set_error (error,
+                   G_IO_ERROR,
+                   g_io_error_from_errno (errno),
+                   "Error creating temporary file: %m");
+      goto out;
+    }
 
-  ret = NULL;
+  f = fdopen (fd, "w");
+  if (f == NULL)
+    {
+      g_set_error (error,
+                   G_IO_ERROR,
+                   g_io_error_from_errno (errno),
+                   "Error calling fdopen: %m");
+      g_unlink (tmpl);
+      goto out;
+    }
 
-  /* if this is too slow, we could add lookup methods to UDisksCrypttabMonitor... */
-  entries = udisks_crypttab_monitor_get_entries (udisks_daemon_get_crypttab_monitor (block->daemon));
-  for (l = entries; l != NULL; l = l->next)
+  if (contents_len < 0 )
+    contents_len = strlen (contents);
+  if (fwrite (contents, 1, contents_len, f) != contents_len)
     {
-      UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
-      const gchar *const *symlinks;
-      const gchar *device_in_entry;
-      gchar *device;
-      guint n;
+      g_set_error (error,
+                   G_IO_ERROR,
+                   g_io_error_from_errno (errno),
+                   "Error calling fwrite on temp file: %m");
+      fclose (f);
+      g_unlink (tmpl);
+      goto out;
+    }
 
-      device_in_entry = udisks_crypttab_entry_get_device (entry);
-      device = NULL;
-      if (g_str_has_prefix (device_in_entry, "UUID="))
-        {
-          device = g_strdup_printf ("/dev/disk/by-uuid/%s", device_in_entry + 5);
-        }
-      else if (g_str_has_prefix (device_in_entry, "LABEL="))
-        {
-          device = g_strdup_printf ("/dev/disk/by-label/%s", device_in_entry + 6);
-        }
-      else if (g_str_has_prefix (device_in_entry, "/dev"))
-        {
-          device = g_strdup (device_in_entry);
-        }
-      else
-        {
-          /* ignore non-device entries */
-          goto continue_loop;
-        }
-
-      if (g_strcmp0 (device, udisks_block_device_get_device (block->iface_block_device)) == 0)
-        {
-          ret = g_list_prepend (ret, g_object_ref (entry));
-        }
-      else
-        {
-          symlinks = udisks_block_device_get_symlinks (block->iface_block_device);
-          if (symlinks != NULL)
-            {
-              for (n = 0; symlinks[n] != NULL; n++)
-                {
-                  if (g_strcmp0 (device, symlinks[n]) == 0)
-                    {
-                      ret = g_list_prepend (ret, g_object_ref (entry));
-                    }
-                }
-            }
-        }
+  if (fsync (fileno (f)) != 0)
+    {
+      g_set_error (error,
+                   G_IO_ERROR,
+                   g_io_error_from_errno (errno),
+                   "Error calling fsync on temp file: %m");
+      fclose (f);
+      g_unlink (tmpl);
+      goto out;
+    }
+  fclose (f);
 
-    continue_loop:
-      g_free (device);
+  if (rename (tmpl, filename) != 0)
+    {
+      g_set_error (error,
+                   G_IO_ERROR,
+                   g_io_error_from_errno (errno),
+                   "Error renaming temp file to final file: %m");
+      g_unlink (tmpl);
+      goto out;
     }
 
-  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
-  g_list_free (entries);
+  ret = TRUE;
+
+ out:
+  g_free (tmpl);
   return ret;
 }
 
-/* returns a floating GVariant */
-static GVariant *
-calculate_configuration (UDisksLinuxBlock  *block,
-                         gboolean           include_secrets,
-                         GError           **error)
-{
-  GList *entries;
-  GList *l;
-  GVariantBuilder builder;
-  GVariant *ret;
+/* ---------------------------------------------------------------------------------------------------- */
 
-  g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+static gboolean
+add_remove_fstab_entry (GVariant  *remove,
+                        GVariant  *add,
+                        GError   **error)
+{
+  struct mntent mntent_remove;
+  struct mntent mntent_add;
+  gboolean ret;
+  gchar *contents;
+  gchar **lines;
+  GString *str;
+  gboolean removed;
+  guint n;
 
-  ret = NULL;
+  contents = NULL;
+  lines = NULL;
+  str = NULL;
+  ret = FALSE;
 
-  g_variant_builder_init (&builder, G_VARIANT_TYPE ("a(sa{sv})"));
-  /* First the /etc/fstab entries */
-  entries = find_fstab_entries_for_device (block);
-  for (l = entries; l != NULL; l = l->next)
+  if (remove != NULL)
     {
-      UDisksFstabEntry *entry = UDISKS_FSTAB_ENTRY (l->data);
-      GVariantBuilder dict_builder;
-      g_variant_builder_init (&dict_builder, G_VARIANT_TYPE_VARDICT);
-      g_variant_builder_add (&dict_builder, "{sv}", "fsname",
-                             g_variant_new_bytestring (udisks_fstab_entry_get_fsname (entry)));
-      g_variant_builder_add (&dict_builder, "{sv}", "dir",
-                             g_variant_new_bytestring (udisks_fstab_entry_get_dir (entry)));
-      g_variant_builder_add (&dict_builder, "{sv}", "type",
-                             g_variant_new_bytestring (udisks_fstab_entry_get_fstype (entry)));
-      g_variant_builder_add (&dict_builder, "{sv}", "opts",
-                             g_variant_new_bytestring (udisks_fstab_entry_get_opts (entry)));
-      g_variant_builder_add (&dict_builder, "{sv}", "freq",
-                             g_variant_new_int32 (udisks_fstab_entry_get_freq (entry)));
-      g_variant_builder_add (&dict_builder, "{sv}", "passno",
-                             g_variant_new_int32 (udisks_fstab_entry_get_passno (entry)));
-      g_variant_builder_add (&builder,
-                             "(sa{sv})",
-                             "fstab", &dict_builder);
+      if (!g_variant_lookup (remove, "fsname", "^&ay", &mntent_remove.mnt_fsname) ||
+          !g_variant_lookup (remove, "dir", "^&ay", &mntent_remove.mnt_dir) ||
+          !g_variant_lookup (remove, "type", "^&ay", &mntent_remove.mnt_type) ||
+          !g_variant_lookup (remove, "opts", "^&ay", &mntent_remove.mnt_opts) ||
+          !g_variant_lookup (remove, "freq", "i", &mntent_remove.mnt_freq) ||
+          !g_variant_lookup (remove, "passno", "i", &mntent_remove.mnt_passno))
+        {
+          g_set_error (error,
+                       UDISKS_ERROR,
+                       UDISKS_ERROR_FAILED,
+                       "Missing fsname, dir, type, opts, freq or passno parameter in entry to remove");
+          goto out;
+        }
     }
-  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
-  g_list_free (entries);
 
-  /* Then the /etc/crypttab entries */
-  entries = find_crypttab_entries_for_device (block);
-  for (l = entries; l != NULL; l = l->next)
+  if (add != NULL)
     {
-      UDisksCrypttabEntry *entry = UDISKS_CRYPTTAB_ENTRY (l->data);
-      GVariantBuilder dict_builder;
-      const gchar *passphrase_path;
-      const gchar *options;
-      gchar *passphrase_contents;
-      gsize passphrase_contents_length;
+      if (!g_variant_lookup (add, "fsname", "^&ay", &mntent_add.mnt_fsname) ||
+          !g_variant_lookup (add, "dir", "^&ay", &mntent_add.mnt_dir) ||
+          !g_variant_lookup (add, "type", "^&ay", &mntent_add.mnt_type) ||
+          !g_variant_lookup (add, "opts", "^&ay", &mntent_add.mnt_opts) ||
+          !g_variant_lookup (add, "freq", "i", &mntent_add.mnt_freq) ||
+          !g_variant_lookup (add, "passno", "i", &mntent_add.mnt_passno))
+        {
+          g_set_error (error,
+                       UDISKS_ERROR,
+                       UDISKS_ERROR_FAILED,
+                       "Missing fsname, dir, type, opts, freq or passno parameter in entry to add");
+          goto out;
+        }
+    }
 
-      passphrase_path = udisks_crypttab_entry_get_passphrase_path (entry);
-      if (passphrase_path == NULL || g_strcmp0 (passphrase_path, "none") == 0)
-        passphrase_path = "";
-      passphrase_contents = NULL;
-      if (!(g_strcmp0 (passphrase_path, "") == 0 || g_str_has_prefix (passphrase_path, "/dev")))
+  if (!g_file_get_contents ("/etc/fstab",
+                            &contents,
+                            NULL,
+                            error))
+    goto out;
+
+  lines = g_strsplit (contents, "\n", 0);
+
+  str = g_string_new (NULL);
+  removed = FALSE;
+  for (n = 0; lines != NULL && lines[n] != NULL; n++)
+    {
+      const gchar *line = lines[n];
+      if (strlen (line) == 0 && lines[n+1] == NULL)
+        break;
+      if (remove != NULL && !removed)
         {
-          if (include_secrets)
+          gchar parsed_fsname[512];
+          gchar parsed_dir[512];
+          gchar parsed_type[512];
+          gchar parsed_opts[512];
+          gint parsed_freq;
+          gint parsed_passno;
+          if (sscanf (line, "%511s %511s %511s %511s %d %d",
+                      parsed_fsname,
+                      parsed_dir,
+                      parsed_type,
+                      parsed_opts,
+                      &parsed_freq,
+                      &parsed_passno) == 6)
             {
-              if (!g_file_get_contents (passphrase_path,
-                                        &passphrase_contents,
-                                        &passphrase_contents_length,
-                                        error))
+              gchar *unescaped_fsname = unescape_fstab (parsed_fsname);
+              gchar *unescaped_dir = unescape_fstab (parsed_dir);
+              gchar *unescaped_type = unescape_fstab (parsed_type);
+              gchar *unescaped_opts = unescape_fstab (parsed_opts);
+              gboolean matches = FALSE;
+              if (g_strcmp0 (unescaped_fsname,   mntent_remove.mnt_fsname) == 0 &&
+                  g_strcmp0 (unescaped_dir,      mntent_remove.mnt_dir) == 0 &&
+                  g_strcmp0 (unescaped_type,     mntent_remove.mnt_type) == 0 &&
+                  g_strcmp0 (unescaped_opts,     mntent_remove.mnt_opts) == 0 &&
+                  parsed_freq ==      mntent_remove.mnt_freq &&
+                  parsed_passno ==    mntent_remove.mnt_passno)
                 {
-                  g_prefix_error (error,
-                                  "Error loading secrets from file `%s' referenced in /etc/crypttab entry: ",
-                                  passphrase_path);
-                  g_variant_builder_clear (&builder);
-                  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
-                  g_list_free (entries);
-                  goto out;
+                  matches = TRUE;
+                }
+              g_free (unescaped_fsname);
+              g_free (unescaped_dir);
+              g_free (unescaped_type);
+              g_free (unescaped_opts);
+              if (matches)
+                {
+                  removed = TRUE;
+                  continue;
                 }
             }
         }
+      g_string_append (str, line);
+      g_string_append_c (str, '\n');
+    }
 
-      options = udisks_crypttab_entry_get_options (entry);
-      if (options == NULL)
-        options = "";
+  if (remove != NULL && !removed)
+    {
+      g_set_error (error,
+                   UDISKS_ERROR,
+                   UDISKS_ERROR_FAILED,
+                   "Didn't find entry to remove");
+      goto out;
+    }
 
-      g_variant_builder_init (&dict_builder, G_VARIANT_TYPE_VARDICT);
-      g_variant_builder_add (&dict_builder, "{sv}", "name",
-                             g_variant_new_bytestring (udisks_crypttab_entry_get_name (entry)));
-      g_variant_builder_add (&dict_builder, "{sv}", "device",
-                             g_variant_new_bytestring (udisks_crypttab_entry_get_device (entry)));
-      g_variant_builder_add (&dict_builder, "{sv}", "passphrase-path",
-                             g_variant_new_bytestring (passphrase_path));
-      if (passphrase_contents != NULL)
-        {
-          g_variant_builder_add (&dict_builder, "{sv}", "passphrase-contents",
-                                 g_variant_new_bytestring (passphrase_contents));
-        }
-      g_variant_builder_add (&dict_builder, "{sv}", "options",
-                             g_variant_new_bytestring (options));
-      g_variant_builder_add (&builder,
-                             "(sa{sv})",
-                             "crypttab", &dict_builder);
-      if (passphrase_contents != NULL)
-        {
-          memset (passphrase_contents, '\0', passphrase_contents_length);
-          g_free (passphrase_contents);
-        }
+  if (add != NULL)
+    {
+      gchar *escaped_fsname = escape_fstab (mntent_add.mnt_fsname);
+      gchar *escaped_dir = escape_fstab (mntent_add.mnt_dir);
+      gchar *escaped_type = escape_fstab (mntent_add.mnt_type);
+      gchar *escaped_opts = escape_fstab (mntent_add.mnt_opts);
+      g_string_append_printf (str, "%s %s %s %s %d %d\n",
+                              escaped_fsname,
+                              escaped_dir,
+                              escaped_type,
+                              escaped_opts,
+                              mntent_add.mnt_freq,
+                              mntent_add.mnt_passno);
+      g_free (escaped_fsname);
+      g_free (escaped_dir);
+      g_free (escaped_type);
+      g_free (escaped_opts);
     }
-  g_list_foreach (entries, (GFunc) g_object_unref, NULL);
-  g_list_free (entries);
 
-  ret = g_variant_builder_end (&builder);
+  if (!_g_file_set_contents_full ("/etc/fstab",
+                                  str->str,
+                                  -1,
+                                  0644, /* mode to use if non-existant */
+                                  error) != 0)
+    goto out;
+
+  ret = TRUE;
 
  out:
+  g_strfreev (lines);
+  g_free (contents);
+  if (str != NULL)
+    g_string_free (str, TRUE);
   return ret;
 }
 
-static void
-block_device_update_configuration (UDisksLinuxBlock  *block,
-                                   const gchar       *uevent_action,
-                                   UDisksBlockDevice *iface,
-                                   const gchar       *device_file,
-                                   UDisksDrive       *drive)
-{
-  GVariant *configuration;
-  GError *error;
+/* ---------------------------------------------------------------------------------------------------- */
 
-  error = NULL;
-  configuration = calculate_configuration (block, FALSE, &error);
-  if (configuration == NULL)
-    {
-      udisks_warning ("Error loading configuration: %s (%s, %d)",
-                      error->message, g_quark_to_string (error->domain), error->code);
-      g_error_free (error);
-      configuration = g_variant_new ("a(sa{sv})", NULL);
-    }
-  udisks_block_device_set_configuration (block->iface_block_device, configuration);
+static gboolean
+has_whitespace (const gchar *s)
+{
+  guint n;
+  g_return_val_if_fail (s != NULL, TRUE);
+  for (n = 0; s[n] != '\0'; n++)
+    if (g_ascii_isspace (s[n]))
+      return TRUE;
+  return FALSE;
 }
 
-static void
-block_device_update (UDisksLinuxBlock *block,
-                     const gchar      *uevent_action,
-                     GDBusInterface   *_iface)
+static gboolean
+add_remove_crypttab_entry (GVariant  *remove,
+                           GVariant  *add,
+                           GError   **error)
 {
-  UDisksBlockDevice *iface = UDISKS_BLOCK_DEVICE (_iface);
-  GUdevDeviceNumber dev;
-  GDBusObjectManagerServer *object_manager;
-  gchar *drive_object_path;
-  UDisksDrive *drive;
-  gchar *s;
-  gboolean is_partition_table;
-  gboolean is_partition_entry;
-  const gchar *device_file;
-  const gchar *const *symlinks;
-  const gchar *preferred_device_file;
-
-  drive = NULL;
-
-  dev = g_udev_device_get_device_number (block->device);
-  device_file = g_udev_device_get_device_file (block->device);
-  symlinks = g_udev_device_get_device_file_symlinks (block->device);
-
-  udisks_block_device_set_device (iface, device_file);
-  udisks_block_device_set_symlinks (iface, symlinks);
-  udisks_block_device_set_major (iface, major (dev));
-  udisks_block_device_set_minor (iface, minor (dev));
-  udisks_block_device_set_size (iface, udisks_daemon_util_block_get_size (block->device));
+  const gchar *remove_name = NULL;
+  const gchar *remove_device = NULL;
+  const gchar *remove_passphrase_path = NULL;
+  const gchar *remove_options = NULL;
+  const gchar *add_name = NULL;
+  const gchar *add_device = NULL;
+  const gchar *add_passphrase_path = NULL;
+  const gchar *add_options = NULL;
+  const gchar *add_passphrase_contents = NULL;
+  gboolean ret;
+  gchar *contents;
+  gchar **lines;
+  GString *str;
+  gboolean removed;
+  guint n;
 
-  /* dm-crypt
-   *
-   * TODO: this might not be the best way to determine if the device-mapper device
-   *       is a dm-crypt device.. but unfortunately device-mapper keeps all this stuff
-   *       in user-space and wants you to use libdevmapper to obtain it...
-   */
-  udisks_block_device_set_crypto_backing_device (iface, "/");
-  if (g_str_has_prefix (g_udev_device_get_name (block->device), "dm-"))
-    {
-      gchar *dm_uuid;
-      dm_uuid = get_sysfs_attr (block->device, "dm/uuid");
-      if (dm_uuid != NULL && g_str_has_prefix (dm_uuid, "CRYPT-LUKS1"))
-        {
-          gchar **slaves;
-          slaves = udisks_daemon_util_resolve_links (g_udev_device_get_sysfs_path (block->device),
-                                                     "slaves");
-          if (g_strv_length (slaves) == 1)
-            {
-              gchar *slave_object_path;
-              slave_object_path = find_block_device_by_sysfs_path (udisks_daemon_get_object_manager (block->daemon),
-                                                                   slaves[0]);
-              if (slave_object_path != NULL)
-                {
-                  udisks_block_device_set_crypto_backing_device (iface, slave_object_path);
-                }
-              g_free (slave_object_path);
-            }
-          g_strfreev (slaves);
-        }
-      g_free (dm_uuid);
-    }
+  contents = NULL;
+  lines = NULL;
+  str = NULL;
+  ret = FALSE;
 
-  /* Sort out preferred device... this is what UI shells should
-   * display. We default to the block device name.
-   *
-   * This is mostly for things like device-mapper where device file is
-   * a name of the form dm-%d and a symlink name conveys more
-   * information.
-   */
-  preferred_device_file = NULL;
-  if (g_str_has_prefix (device_file, "/dev/dm-"))
+  if (remove != NULL)
     {
-      guint n;
-      const gchar *dm_name;
-      gchar *dm_name_dev_file = NULL;
-      const gchar *dm_name_dev_file_as_symlink = NULL;
-
-      dm_name = g_udev_device_get_property (block->device, "DM_NAME");
-      if (dm_name != NULL)
-        dm_name_dev_file = g_strdup_printf ("/dev/mapper/%s", dm_name);
-      for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
+      if (!g_variant_lookup (remove, "name", "^&ay", &remove_name) ||
+          !g_variant_lookup (remove, "device", "^&ay", &remove_device) ||
+          !g_variant_lookup (remove, "passphrase-path", "^&ay", &remove_passphrase_path) ||
+          !g_variant_lookup (remove, "options", "^&ay", &remove_options))
         {
-          if (g_str_has_prefix (symlinks[n], "/dev/vg_"))
-            {
-              /* LVM2 */
-              preferred_device_file = symlinks[n];
-              break;
-            }
-          else if (g_strcmp0 (symlinks[n], dm_name_dev_file) == 0)
-            {
-              dm_name_dev_file_as_symlink = symlinks[n];
-            }
+          g_set_error (error,
+                       UDISKS_ERROR,
+                       UDISKS_ERROR_FAILED,
+                       "Missing name, device, passphrase-path, options or parameter in entry to remove");
+          goto out;
         }
-      /* fall back to /dev/mapper/$DM_NAME, if available as a symlink */
-      if (preferred_device_file == NULL && dm_name_dev_file_as_symlink != NULL)
-        preferred_device_file = dm_name_dev_file_as_symlink;
-      g_free (dm_name_dev_file);
     }
-  /* fallback to the device name */
-  if (preferred_device_file == NULL)
-    preferred_device_file = g_udev_device_get_device_file (block->device);
-  udisks_block_device_set_preferred_device (iface, preferred_device_file);
 
-  /* Determine the drive this block device belongs to
-   *
-   * TODO: if this is slow we could have a cache or ensure that we
-   * only do this once or something else
-   */
-  object_manager = udisks_daemon_get_object_manager (block->daemon);
-  drive_object_path = find_drive (object_manager, block->device, &drive);
-  if (drive_object_path != NULL)
-    {
-      udisks_block_device_set_drive (iface, drive_object_path);
-      g_free (drive_object_path);
-    }
-  else
+  if (add != NULL)
     {
-      udisks_block_device_set_drive (iface, "/");
+      if (!g_variant_lookup (add, "name", "^&ay", &add_name) ||
+          !g_variant_lookup (add, "device", "^&ay", &add_device) ||
+          !g_variant_lookup (add, "passphrase-path", "^&ay", &add_passphrase_path) ||
+          !g_variant_lookup (add, "options", "^&ay", &add_options) ||
+          !g_variant_lookup (add, "passphrase-contents", "^&ay", &add_passphrase_contents))
+        {
+          g_set_error (error,
+                       UDISKS_ERROR,
+                       UDISKS_ERROR_FAILED,
+                       "Missing name, device, passphrase-path, options or passphrase-contents parameter in entry to add");
+          goto out;
+        }
+
+      /* reject strings with whitespace in them */
+      if (has_whitespace (add_name) ||
+          has_whitespace (add_device) ||
+          has_whitespace (add_passphrase_path) ||
+          has_whitespace (add_options))
+        {
+          g_set_error (error,
+                       UDISKS_ERROR,
+                       UDISKS_ERROR_FAILED,
+                       "One of name, device, passphrase-path or options parameter are invalid (whitespace)");
+          goto out;
+        }
     }
 
-  udisks_block_device_set_id_usage (iface, g_udev_device_get_property (block->device, "ID_FS_USAGE"));
-  udisks_block_device_set_id_type (iface, g_udev_device_get_property (block->device, "ID_FS_TYPE"));
-  s = udisks_decode_udev_string (g_udev_device_get_property (block->device, "ID_FS_VERSION"));
-  udisks_block_device_set_id_version (iface, s);
-  g_free (s);
-  s = udisks_decode_udev_string (g_udev_device_get_property (block->device, "ID_FS_LABEL_ENC"));
-  udisks_block_device_set_id_label (iface, s);
-  g_free (s);
-  s = udisks_decode_udev_string (g_udev_device_get_property (block->device, "ID_FS_UUID_ENC"));
-  udisks_block_device_set_id_uuid (iface, s);
-  g_free (s);
+  if (!g_file_get_contents ("/etc/crypttab",
+                            &contents,
+                            NULL,
+                            error))
+    goto out;
 
-  /* TODO: port this to blkid properties */
+  lines = g_strsplit (contents, "\n", 0);
 
-  /* Update the partition table and partition entry properties */
-  is_partition_table = FALSE;
-  is_partition_entry = FALSE;
-  if (g_strcmp0 (g_udev_device_get_devtype (block->device), "partition") == 0 ||
-      g_udev_device_get_property_as_boolean (block->device, "UDISKS_PARTITION"))
-    {
-      is_partition_entry = TRUE;
-    }
-  else if (g_udev_device_get_property_as_boolean (block->device, "UDISKS_PARTITION_TABLE"))
+  str = g_string_new (NULL);
+  removed = FALSE;
+  for (n = 0; lines != NULL && lines[n] != NULL; n++)
     {
-      is_partition_table = TRUE;
-    }
+      const gchar *line = lines[n];
+      if (strlen (line) == 0 && lines[n+1] == NULL)
+        break;
+      if (remove != NULL && !removed)
+        {
+          gchar parsed_name[512];
+          gchar parsed_device[512];
+          gchar parsed_passphrase_path[512];
+          gchar parsed_options[512];
+          guint num_parsed;
 
-  /* partition table */
-  if (is_partition_table)
-    {
-      udisks_block_device_set_part_table (iface, TRUE);
-      udisks_block_device_set_part_table_scheme (iface,
-                                                 g_udev_device_get_property (block->device,
-                                                                             "UDISKS_PARTITION_TABLE_SCHEME"));
+          num_parsed = sscanf (line, "%511s %511s %511s %511s",
+                               parsed_name, parsed_device, parsed_passphrase_path, parsed_options);
+          if (num_parsed >= 2)
+            {
+              if (num_parsed < 3 || g_strcmp0 (parsed_passphrase_path, "none") == 0)
+                strcpy (parsed_passphrase_path, "");
+              if (num_parsed < 4)
+                strcpy (parsed_options, "");
+              if (g_strcmp0 (parsed_name,            remove_name) == 0 &&
+                  g_strcmp0 (parsed_device,          remove_device) == 0 &&
+                  g_strcmp0 (parsed_passphrase_path, remove_passphrase_path) == 0 &&
+                  g_strcmp0 (parsed_options,         remove_options) == 0)
+                {
+                  /* Nuke passphrase file */
+                  if (strlen (remove_passphrase_path) > 0 && !g_str_has_prefix (remove_passphrase_path, "/dev"))
+                    {
+                      /* Is this exploitable? No, 1. the user would have to control
+                       * the /etc/crypttab file for us to delete it; and 2. editing the
+                       * /etc/crypttab file requires a polkit authorization that can't
+                       * be retained (e.g. the user is always asked for the password)..
+                       */
+                      if (unlink (remove_passphrase_path) != 0)
+                        {
+                          g_set_error (error,
+                                       UDISKS_ERROR,
+                                       UDISKS_ERROR_FAILED,
+                                       "Error deleting file `%s' with passphrase",
+                                       remove_passphrase_path);
+                          goto out;
+                        }
+                    }
+                  removed = TRUE;
+                  continue;
+                }
+            }
+        }
+      g_string_append (str, line);
+      g_string_append_c (str, '\n');
     }
-  else
+
+  if (remove != NULL && !removed)
     {
-      udisks_block_device_set_part_table (iface, FALSE);
-      udisks_block_device_set_part_table_scheme (iface, "");
+      g_set_error (error,
+                   UDISKS_ERROR,
+                   UDISKS_ERROR_FAILED,
+                   "Didn't find entry to remove");
+      goto out;
     }
 
-  /* partition entry */
-  if (is_partition_entry)
+  if (add != NULL)
     {
-      gchar *slave_sysfs_path;
-      udisks_block_device_set_part_entry (iface, TRUE);
-      udisks_block_device_set_part_entry_scheme (iface,
-                                                 g_udev_device_get_property (block->device,
-                                                                             "UDISKS_PARTITION_SCHEME"));
-      udisks_block_device_set_part_entry_number (iface,
-                                                 g_udev_device_get_property_as_int (block->device,
-                                                                                    "UDISKS_PARTITION_NUMBER"));
-      udisks_block_device_set_part_entry_type (iface,
-                                               g_udev_device_get_property (block->device,
-                                                                           "UDISKS_PARTITION_TYPE"));
-      udisks_block_device_set_part_entry_flags (iface,
-                                                g_udev_device_get_property (block->device,
-                                                                            "UDISKS_PARTITION_FLAGS"));
-      udisks_block_device_set_part_entry_label (iface,
-                                                g_udev_device_get_property (block->device,
-                                                                            "UDISKS_PARTITION_LABEL"));
-      udisks_block_device_set_part_entry_uuid (iface,
-                                               g_udev_device_get_property (block->device,
-                                                                           "UDISKS_PARTITION_UUID"));
-      slave_sysfs_path = g_strdup (g_udev_device_get_property (block->device, "UDISKS_PARTITION_SLAVE"));
-      if (slave_sysfs_path == NULL)
+      /* First write add_passphrase_content to add_passphrase_path,
+       * if applicable..
+       *
+       * Is this exploitable? No, because editing the /etc/crypttab
+       * file requires a polkit authorization that can't be retained
+       * (e.g. the user is always asked for the password)...
+       *
+       * Just to be on the safe side we only allow writing into the
+       * directory /etc/luks-keys if create a _new_ entry.
+       */
+      if (strlen (add_passphrase_path) > 0)
         {
-          if (g_strcmp0 (g_udev_device_get_devtype (block->device), "partition") == 0)
+          gchar *filename;
+          if (g_strcmp0 (add_passphrase_path, remove_passphrase_path) == 0)
             {
-              GUdevDevice *parent;
-              parent = g_udev_device_get_parent (block->device);
-              slave_sysfs_path = g_strdup (g_udev_device_get_sysfs_path (parent));
-              g_object_unref (parent);
+              filename = g_strdup (add_passphrase_path);
             }
           else
             {
-              g_warning ("No UDISKS_PARTITION_SLAVE property and DEVTYPE is not partition for block device %s",
-                         g_udev_device_get_sysfs_path (block->device));
-            }
-        }
-      if (slave_sysfs_path != NULL)
-        {
-          gchar *slave_object_path;
-          slave_object_path = find_block_device_by_sysfs_path (udisks_daemon_get_object_manager (block->daemon),
-                                                               slave_sysfs_path);
-          if (slave_object_path != NULL)
-            udisks_block_device_set_part_entry_table (iface, slave_object_path);
-          else
-            udisks_block_device_set_part_entry_table (iface, "/");
-          g_free (slave_object_path);
-          g_free (slave_sysfs_path);
-        }
-      else
-        {
-          udisks_block_device_set_part_entry_table (iface, "/");
-        }
-      udisks_block_device_set_part_entry_offset (iface,
-                                                 g_udev_device_get_property_as_uint64 (block->device,
-                                                                                       "UDISKS_PARTITION_OFFSET"));
-      udisks_block_device_set_part_entry_size (iface,
-                                               g_udev_device_get_property_as_uint64 (block->device,
-                                                                                     "UDISKS_PARTITION_SIZE"));
-    }
-  else
-    {
-      udisks_block_device_set_part_entry (iface, FALSE);
-      udisks_block_device_set_part_entry_scheme (iface, "");
-      udisks_block_device_set_part_entry_type (iface, "");
-      udisks_block_device_set_part_entry_flags (iface, "");
-      udisks_block_device_set_part_entry_table (iface, "/");
-      udisks_block_device_set_part_entry_offset (iface, 0);
-      udisks_block_device_set_part_entry_size (iface, 0);
-    }
-
-  block_device_update_hints (block, uevent_action, iface, device_file, drive);
-  block_device_update_configuration (block, uevent_action, iface, device_file, drive);
+              if (!g_str_has_prefix (add_passphrase_path, "/etc/luks-keys/"))
+                {
+                  g_set_error (error,
+                               UDISKS_ERROR,
+                               UDISKS_ERROR_FAILED,
+                               "Crypttab passphrase file can only be created in the /etc/luks-keys directory");
+                  goto out;
+                }
+              /* ensure the directory exists */
+              if (g_mkdir_with_parents ("/etc/luks-keys", 0700) != 0)
+                {
+                  g_set_error (error,
+                               UDISKS_ERROR,
+                               UDISKS_ERROR_FAILED,
+                               "Error creating /etc/luks-keys directory: %m");
+                  goto out;
+                }
+              /* avoid symlink attacks */
+              filename = g_strdup_printf ("/etc/luks-keys/%s", strrchr (add_passphrase_path, '/') + 1);
+            }
 
-  if (drive != NULL)
-    g_object_unref (drive);
-}
+          /* Bail if the requested file already exists */
+          if (g_file_test (filename, G_FILE_TEST_EXISTS))
+            {
+                  g_set_error (error,
+                               UDISKS_ERROR,
+                               UDISKS_ERROR_FAILED,
+                               "Refusing to overwrite existing file %s",
+                               filename);
+                  g_free (filename);
+                  goto out;
+            }
 
-/* ---------------------------------------------------------------------------------------------------- */
-/* org.freedesktop.UDisks.Filesystem */
+          if (!_g_file_set_contents_full (filename,
+                                          add_passphrase_contents,
+                                          -1,
+                                          0600, /* mode to use if non-existant */
+                                          error))
+            {
+              g_free (filename);
+              goto out;
+            }
+          g_free (filename);
+        }
+      g_string_append_printf (str, "%s %s %s %s\n",
+                              add_name,
+                              add_device,
+                              strlen (add_passphrase_path) > 0 ? add_passphrase_path : "none",
+                              add_options);
+    }
 
-static gboolean
-filesystem_check (UDisksLinuxBlock *block)
-{
-  gboolean ret;
-  UDisksMountType mount_type;
+  if (!_g_file_set_contents_full ("/etc/crypttab",
+                                  str->str,
+                                  -1,
+                                  0600, /* mode to use if non-existant */
+                                  error) != 0)
+    goto out;
 
-  ret = FALSE;
-  if (g_strcmp0 (udisks_block_device_get_id_usage (block->iface_block_device), "filesystem") == 0 ||
-      (udisks_mount_monitor_is_dev_in_use (block->mount_monitor,
-                                           g_udev_device_get_device_number (block->device),
-                                           &mount_type) &&
-       mount_type == UDISKS_MOUNT_TYPE_FILESYSTEM))
-    ret = TRUE;
+  ret = TRUE;
 
+ out:
+  g_strfreev (lines);
+  g_free (contents);
+  if (str != NULL)
+    g_string_free (str, TRUE);
   return ret;
 }
 
-static void
-filesystem_update (UDisksLinuxBlock  *block,
-                   const gchar       *uevent_action,
-                   GDBusInterface    *_iface)
-{
-  UDisksFilesystem *iface = UDISKS_FILESYSTEM (_iface);
-  GPtrArray *p;
-  GList *mounts;
-  GList *l;
-
-  p = g_ptr_array_new ();
-  mounts = udisks_mount_monitor_get_mounts_for_dev (block->mount_monitor,
-                                                    g_udev_device_get_device_number (block->device));
-  /* we are guaranteed that the list is sorted so if there are
-   * multiple mounts we'll always get the same order
-   */
-  for (l = mounts; l != NULL; l = l->next)
-    {
-      UDisksMount *mount = UDISKS_MOUNT (l->data);
-      if (udisks_mount_get_mount_type (mount) == UDISKS_MOUNT_TYPE_FILESYSTEM)
-        g_ptr_array_add (p, (gpointer) udisks_mount_get_mount_path (mount));
-    }
-  g_ptr_array_add (p, NULL);
-  udisks_filesystem_set_mount_points (iface, (const gchar *const *) p->pdata);
-  g_ptr_array_free (p, TRUE);
-  g_list_foreach (mounts, (GFunc) g_object_unref, NULL);
-  g_list_free (mounts);
-}
-
 /* ---------------------------------------------------------------------------------------------------- */
-/* org.freedesktop.UDisks.Swapspace */
 
 static gboolean
-swapspace_check (UDisksLinuxBlock *block)
+handle_add_configuration_item (UDisksBlockDevice     *_block,
+                               GDBusMethodInvocation *invocation,
+                               GVariant              *item,
+                               GVariant              *options)
 {
-  gboolean ret;
-  UDisksMountType mount_type;
-
-  ret = FALSE;
-  if ((g_strcmp0 (udisks_block_device_get_id_usage (block->iface_block_device), "other") == 0 &&
-       g_strcmp0 (udisks_block_device_get_id_type (block->iface_block_device), "swap") == 0)
-      || (udisks_mount_monitor_is_dev_in_use (block->mount_monitor,
-                                              g_udev_device_get_device_number (block->device),
-                                              &mount_type)
-          && mount_type == UDISKS_MOUNT_TYPE_SWAP))
-    ret = TRUE;
+  UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (_block);
+  UDisksLinuxBlockObject *object;
+  UDisksDaemon *daemon;
+  const gchar *type;
+  GVariant *details;
+  GError *error;
 
-  return ret;
-}
+  object = UDISKS_LINUX_BLOCK_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (block)));
+  daemon = udisks_linux_block_object_get_daemon (object);
 
-static void
-swapspace_connect (UDisksLinuxBlock *block)
-{
-  /* do nothing */
-}
+  g_variant_get (item, "(&s@a{sv})", &type, &details);
+  if (g_strcmp0 (type, "fstab") == 0)
+    {
+      if (!udisks_daemon_util_check_authorization_sync (daemon,
+                                                        NULL,
+                                                        "org.freedesktop.udisks2.modify-system-configuration",
+                                                        options,
+                                                        N_("Authentication is required to add an entry to the /etc/fstab file"),
+                                                        invocation))
+        goto out;
+      error = NULL;
+      if (!add_remove_fstab_entry (NULL, details, &error))
+        {
+          g_dbus_method_invocation_take_error (invocation, error);
+          goto out;
+        }
+      udisks_block_device_complete_add_configuration_item (UDISKS_BLOCK_DEVICE (block), invocation);
+    }
+  else if (g_strcmp0 (type, "crypttab") == 0)
+    {
+      if (!udisks_daemon_util_check_authorization_sync (daemon,
+                                                        NULL,
+                                                        "org.freedesktop.udisks2.modify-system-configuration",
+                                                        options,
+                                                        N_("Authentication is required to add an entry to the /etc/crypttab file"),
+                                                        invocation))
+        goto out;
+      error = NULL;
+      if (!add_remove_crypttab_entry (NULL, details, &error))
+        {
+          g_dbus_method_invocation_take_error (invocation, error);
+          goto out;
+        }
+      udisks_block_device_complete_add_configuration_item (UDISKS_BLOCK_DEVICE (block), invocation);
+    }
+  else
+    {
+      g_dbus_method_invocation_return_error (invocation,
+                                             UDISKS_ERROR,
+                                             UDISKS_ERROR_FAILED,
+                                             "Only /etc/fstab or /etc/crypttab items can be added");
+      goto out;
+    }
 
-static void
-swapspace_update (UDisksLinuxBlock  *block,
-                  const gchar       *uevent_action,
-                  GDBusInterface    *_iface)
-{
-  UDisksSwapspace *iface = UDISKS_SWAPSPACE (_iface);
-  UDisksMountType mount_type;
-  gboolean active;
-
-  active = FALSE;
-  if (udisks_mount_monitor_is_dev_in_use (block->mount_monitor,
-                                          g_udev_device_get_device_number (block->device),
-                                          &mount_type)
-      && mount_type == UDISKS_MOUNT_TYPE_SWAP)
-    active = TRUE;
-  udisks_swapspace_set_active (iface, active);
+ out:
+  g_variant_unref (details);
+  return TRUE; /* returning TRUE means that we handled the method invocation */
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
 static gboolean
-encrypted_check (UDisksLinuxBlock *block)
+handle_remove_configuration_item (UDisksBlockDevice     *_block,
+                                  GDBusMethodInvocation *invocation,
+                                  GVariant              *item,
+                                  GVariant              *options)
 {
-  gboolean ret;
-
-  ret = FALSE;
-  if (g_strcmp0 (udisks_block_device_get_id_usage (block->iface_block_device), "crypto") == 0 &&
-      g_strcmp0 (udisks_block_device_get_id_type (block->iface_block_device), "crypto_LUKS") == 0)
-    ret = TRUE;
+  UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (_block);
+  UDisksLinuxBlockObject *object;
+  UDisksDaemon *daemon;
+  const gchar *type;
+  GVariant *details;
+  GError *error;
 
-  return ret;
-}
+  object = UDISKS_LINUX_BLOCK_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (block)));
+  daemon = udisks_linux_block_object_get_daemon (object);
 
-static void
-encrypted_connect (UDisksLinuxBlock *block)
-{
-  /* do nothing */
-}
+  g_variant_get (item, "(&s@a{sv})", &type, &details);
+  if (g_strcmp0 (type, "fstab") == 0)
+    {
+      if (!udisks_daemon_util_check_authorization_sync (daemon,
+                                                        NULL,
+                                                        "org.freedesktop.udisks2.modify-system-configuration",
+                                                        options,
+                                                        N_("Authentication is required to remove an entry from /etc/fstab file"),
+                                                        invocation))
+        goto out;
+      error = NULL;
+      if (!add_remove_fstab_entry (details, NULL, &error))
+        {
+          g_dbus_method_invocation_take_error (invocation, error);
+          goto out;
+        }
+      udisks_block_device_complete_add_configuration_item (UDISKS_BLOCK_DEVICE (block), invocation);
+    }
+  else if (g_strcmp0 (type, "crypttab") == 0)
+    {
+      if (!udisks_daemon_util_check_authorization_sync (daemon,
+                                                        NULL,
+                                                        "org.freedesktop.udisks2.modify-system-configuration",
+                                                        options,
+                                                        N_("Authentication is required to remove an entry from the /etc/crypttab file"),
+                                                        invocation))
+        goto out;
+      error = NULL;
+      if (!add_remove_crypttab_entry (details, NULL, &error))
+        {
+          g_dbus_method_invocation_take_error (invocation, error);
+          goto out;
+        }
+      udisks_block_device_complete_add_configuration_item (UDISKS_BLOCK_DEVICE (block), invocation);
+    }
+  else
+    {
+      g_dbus_method_invocation_return_error (invocation,
+                                             UDISKS_ERROR,
+                                             UDISKS_ERROR_FAILED,
+                                             "Only fstab or crypttab items can be removed");
+      goto out;
+    }
 
-static void
-encrypted_update (UDisksLinuxBlock  *block,
-                  const gchar       *uevent_action,
-                  GDBusInterface    *_iface)
-{
-  /* do nothing */
+ out:
+  g_variant_unref (details);
+  return TRUE; /* returning TRUE means that we handled the method invocation */
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
 static gboolean
-loop_check (UDisksLinuxBlock *block)
+handle_update_configuration_item (UDisksBlockDevice     *_block,
+                                  GDBusMethodInvocation *invocation,
+                                  GVariant              *old_item,
+                                  GVariant              *new_item,
+                                  GVariant              *options)
 {
-  gboolean ret;
-
-  ret = FALSE;
-  if (g_str_has_prefix (g_udev_device_get_name (block->device), "loop"))
-    ret = TRUE;
-
-  return ret;
-}
+  UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (_block);
+  UDisksLinuxBlockObject *object;
+  UDisksDaemon *daemon;
+  const gchar *old_type;
+  const gchar *new_type;
+  GVariant *old_details;
+  GVariant *new_details;
+  GError *error;
 
-static void
-loop_connect (UDisksLinuxBlock *block)
-{
-  /* do nothing */
-}
+  object = UDISKS_LINUX_BLOCK_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (block)));
+  daemon = udisks_linux_block_object_get_daemon (object);
 
-static void
-loop_update (UDisksLinuxBlock  *block,
-             const gchar       *uevent_action,
-             GDBusInterface    *_iface)
-{
-  UDisksLoop *iface = UDISKS_LOOP (_iface);
+  g_variant_get (old_item, "(&s@a{sv})", &old_type, &old_details);
+  g_variant_get (new_item, "(&s@a{sv})", &new_type, &new_details);
+  if (g_strcmp0 (old_type, new_type) != 0)
+    {
+      g_dbus_method_invocation_return_error (invocation,
+                                             UDISKS_ERROR,
+                                             UDISKS_ERROR_FAILED,
+                                             "old and new item are not of the same type");
+      goto out;
+    }
 
-  if (g_str_has_prefix (g_udev_device_get_name (block->device), "loop"))
+  if (g_strcmp0 (old_type, "fstab") == 0)
     {
-      gchar *filename;
-      gchar *backing_file;
-      GError *error;
-      filename = g_strconcat (g_udev_device_get_sysfs_path (block->device),
-                              "/loop/backing_file",
-                              NULL);
+      if (!udisks_daemon_util_check_authorization_sync (daemon,
+                                                        NULL,
+                                                        "org.freedesktop.udisks2.modify-system-configuration",
+                                                        options,
+                                                        N_("Authentication is required to modify the /etc/fstab file"),
+                                                        invocation))
+        goto out;
       error = NULL;
-      if (!g_file_get_contents (filename,
-                               &backing_file,
-                               NULL,
-                               &error))
+      if (!add_remove_fstab_entry (old_details, new_details, &error))
         {
-          /* ENOENT is not unexpected */
-          if (!(error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT))
-            {
-              udisks_warning ("Error loading %s: %s (%s, %d)",
-                              filename,
-                              error->message,
-                              g_quark_to_string (error->domain),
-                              error->code);
-            }
-          g_error_free (error);
-          udisks_loop_set_backing_file (iface, "");
+          g_dbus_method_invocation_take_error (invocation, error);
+          goto out;
         }
-      else
+      udisks_block_device_complete_add_configuration_item (UDISKS_BLOCK_DEVICE (block), invocation);
+    }
+  else if (g_strcmp0 (old_type, "crypttab") == 0)
+    {
+      if (!udisks_daemon_util_check_authorization_sync (daemon,
+                                                        NULL,
+                                                        "org.freedesktop.udisks2.modify-system-configuration",
+                                                        options,
+                                                        N_("Authentication is required to modify the /etc/crypttab file"),
+                                                        invocation))
+        goto out;
+      error = NULL;
+      if (!add_remove_crypttab_entry (old_details, new_details, &error))
         {
-          /* TODO: validate UTF-8 */
-          g_strstrip (backing_file);
-          udisks_loop_set_backing_file (iface, backing_file);
-          g_free (backing_file);
+          g_dbus_method_invocation_take_error (invocation, error);
+          goto out;
         }
-      g_free (filename);
+      udisks_block_device_complete_add_configuration_item (UDISKS_BLOCK_DEVICE (block), invocation);
     }
   else
     {
-      udisks_loop_set_backing_file (iface, "");
-    }
-}
-
-/* ---------------------------------------------------------------------------------------------------- */
-
-/**
- * udisks_linux_block_uevent:
- * @block: A #UDisksLinuxBlock.
- * @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 @block.
- */
-void
-udisks_linux_block_uevent (UDisksLinuxBlock *block,
-                           const gchar      *action,
-                           GUdevDevice      *device)
-{
-  g_return_if_fail (UDISKS_IS_LINUX_BLOCK (block));
-  g_return_if_fail (device == NULL || G_UDEV_IS_DEVICE (device));
-
-  if (device != NULL)
-    {
-      g_object_unref (block->device);
-      block->device = g_object_ref (device);
-      g_object_notify (G_OBJECT (block), "device");
+      g_dbus_method_invocation_return_error (invocation,
+                                             UDISKS_ERROR,
+                                             UDISKS_ERROR_FAILED,
+                                             "Only fstab or crypttab items can be updated");
+      goto out;
     }
 
-  update_iface (block, action, block_device_check, block_device_connect, block_device_update,
-                UDISKS_TYPE_BLOCK_DEVICE_SKELETON, &block->iface_block_device);
-  update_iface (block, action, filesystem_check, NULL, filesystem_update,
-                UDISKS_TYPE_LINUX_FILESYSTEM, &block->iface_filesystem);
-  update_iface (block, action, swapspace_check, swapspace_connect, swapspace_update,
-                UDISKS_TYPE_LINUX_SWAPSPACE, &block->iface_swapspace);
-  update_iface (block, action, encrypted_check, encrypted_connect, encrypted_update,
-                UDISKS_TYPE_LINUX_ENCRYPTED, &block->iface_encrypted);
-  update_iface (block, action, loop_check, loop_connect, loop_update,
-                UDISKS_TYPE_LINUX_LOOP, &block->iface_loop);
+ out:
+  g_variant_unref (new_details);
+  g_variant_unref (old_details);
+  return TRUE; /* returning TRUE means that we handled the method invocation */
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-on_mount_monitor_mount_added (UDisksMountMonitor  *monitor,
-                              UDisksMount         *mount,
-                              gpointer             user_data)
-{
-  UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (user_data);
-  if (udisks_mount_get_dev (mount) == g_udev_device_get_device_number (block->device))
-    udisks_linux_block_uevent (block, NULL, NULL);
-}
-
-static void
-on_mount_monitor_mount_removed (UDisksMountMonitor  *monitor,
-                                UDisksMount         *mount,
-                                gpointer             user_data)
+block_iface_init (UDisksBlockDeviceIface *iface)
 {
-  UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (user_data);
-  if (udisks_mount_get_dev (mount) == g_udev_device_get_device_number (block->device))
-    udisks_linux_block_uevent (block, NULL, NULL);
+  iface->handle_get_secret_configuration  = handle_get_secret_configuration;
+  iface->handle_add_configuration_item    = handle_add_configuration_item;
+  iface->handle_remove_configuration_item = handle_remove_configuration_item;
+  iface->handle_update_configuration_item = handle_update_configuration_item;
 }
-
-/* ---------------------------------------------------------------------------------------------------- */
index 9e7fd5b..65ab632 100644 (file)
 #define __UDISKS_LINUX_BLOCK_H__
 
 #include "udisksdaemontypes.h"
-#include <gudev/gudev.h>
 
 G_BEGIN_DECLS
 
-#define UDISKS_TYPE_LINUX_BLOCK         (udisks_linux_block_get_type ())
-#define UDISKS_LINUX_BLOCK(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), UDISKS_TYPE_LINUX_BLOCK, UDisksLinuxBlock))
-#define UDISKS_IS_LINUX_BLOCK(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), UDISKS_TYPE_LINUX_BLOCK))
+#define UDISKS_TYPE_LINUX_BLOCK  (udisks_linux_block_get_type ())
+#define UDISKS_LINUX_BLOCK(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), UDISKS_TYPE_LINUX_BLOCK, UDisksLinuxBlock))
+#define UDISKS_IS_LINUX_BLOCK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UDISKS_TYPE_LINUX_BLOCK))
 
-GType               udisks_linux_block_get_type   (void) G_GNUC_CONST;
-UDisksLinuxBlock   *udisks_linux_block_new        (UDisksDaemon     *daemon,
-                                                   GUdevDevice      *device);
-void                udisks_linux_block_uevent     (UDisksLinuxBlock *block,
-                                                   const gchar      *action,
-                                                   GUdevDevice      *device);
-UDisksDaemon       *udisks_linux_block_get_daemon (UDisksLinuxBlock *block);
-GUdevDevice        *udisks_linux_block_get_device (UDisksLinuxBlock *block);
+GType        udisks_linux_block_get_type (void) G_GNUC_CONST;
+UDisksBlockDevice *udisks_linux_block_new      (void);
+void         udisks_linux_block_update   (UDisksLinuxBlock       *block,
+                                          UDisksLinuxBlockObject *object);
 
 G_END_DECLS
 
diff --git a/src/udiskslinuxblockobject.c b/src/udiskslinuxblockobject.c
new file mode 100644 (file)
index 0000000..e841dcf
--- /dev/null
@@ -0,0 +1,586 @@
+/* -*- 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 <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pwd.h>
+#include <grp.h>
+#include <mntent.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <glib/gstdio.h>
+
+#include "udiskslogging.h"
+#include "udisksdaemon.h"
+#include "udisksdaemonutil.h"
+#include "udiskslinuxblockobject.h"
+#include "udiskslinuxblock.h"
+#include "udisksmount.h"
+#include "udisksmountmonitor.h"
+#include "udiskslinuxdriveobject.h"
+#include "udiskslinuxdrive.h"
+#include "udiskslinuxfilesystem.h"
+#include "udiskslinuxencrypted.h"
+#include "udiskslinuxswapspace.h"
+#include "udiskslinuxloop.h"
+#include "udiskspersistentstore.h"
+#include "udiskslinuxprovider.h"
+#include "udisksfstabmonitor.h"
+#include "udisksfstabentry.h"
+#include "udiskscrypttabmonitor.h"
+#include "udiskscrypttabentry.h"
+
+/**
+ * SECTION:udiskslinuxblockobject
+ * @title: UDisksLinuxBlockObject
+ * @short_description: Object representing a block device on Linux.
+ *
+ * Object corresponding to a block device on Linux.
+ */
+
+typedef struct _UDisksLinuxBlockObjectClass   UDisksLinuxBlockObjectClass;
+
+/**
+ * UDisksLinuxBlockObject:
+ *
+ * The #UDisksLinuxBlockObject structure contains only private data and
+ * should only be accessed using the provided API.
+ */
+struct _UDisksLinuxBlockObject
+{
+  UDisksObjectSkeleton parent_instance;
+
+  UDisksDaemon *daemon;
+  UDisksMountMonitor *mount_monitor;
+
+  GUdevDevice *device;
+
+  /* interface */
+  UDisksBlockDevice *iface_block_device;
+  UDisksFilesystem *iface_filesystem;
+  UDisksSwapspace *iface_swapspace;
+  UDisksEncrypted *iface_encrypted;
+  UDisksLoop *iface_loop;
+};
+
+struct _UDisksLinuxBlockObjectClass
+{
+  UDisksObjectSkeletonClass parent_class;
+};
+
+enum
+{
+  PROP_0,
+  PROP_DAEMON,
+  PROP_DEVICE
+};
+
+G_DEFINE_TYPE (UDisksLinuxBlockObject, udisks_linux_block_object, UDISKS_TYPE_OBJECT_SKELETON);
+
+static void on_mount_monitor_mount_added   (UDisksMountMonitor  *monitor,
+                                            UDisksMount         *mount,
+                                            gpointer             user_data);
+static void on_mount_monitor_mount_removed (UDisksMountMonitor  *monitor,
+                                            UDisksMount         *mount,
+                                            gpointer             user_data);
+
+static void
+udisks_linux_block_object_finalize (GObject *_object)
+{
+  UDisksLinuxBlockObject *object = UDISKS_LINUX_BLOCK_OBJECT (_object);
+
+  /* note: we don't hold a ref to block->daemon or block->mount_monitor */
+  g_signal_handlers_disconnect_by_func (object->mount_monitor, on_mount_monitor_mount_added, object);
+  g_signal_handlers_disconnect_by_func (object->mount_monitor, on_mount_monitor_mount_removed, object);
+
+  g_object_unref (object->device);
+
+  if (object->iface_block_device != NULL)
+    g_object_unref (object->iface_block_device);
+  if (object->iface_filesystem != NULL)
+    g_object_unref (object->iface_filesystem);
+  if (object->iface_swapspace != NULL)
+    g_object_unref (object->iface_swapspace);
+  if (object->iface_encrypted != NULL)
+    g_object_unref (object->iface_encrypted);
+  if (object->iface_loop != NULL)
+    g_object_unref (object->iface_loop);
+
+  if (G_OBJECT_CLASS (udisks_linux_block_object_parent_class)->finalize != NULL)
+    G_OBJECT_CLASS (udisks_linux_block_object_parent_class)->finalize (_object);
+}
+
+static void
+udisks_linux_block_object_get_property (GObject    *_object,
+                                        guint       prop_id,
+                                        GValue     *value,
+                                        GParamSpec *pspec)
+{
+  UDisksLinuxBlockObject *object = UDISKS_LINUX_BLOCK_OBJECT (_object);
+
+  switch (prop_id)
+    {
+    case PROP_DAEMON:
+      g_value_set_object (value, udisks_linux_block_object_get_daemon (object));
+      break;
+
+    case PROP_DEVICE:
+      g_value_set_object (value, udisks_linux_block_object_get_device (object));
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+udisks_linux_block_object_set_property (GObject      *_object,
+                                        guint         prop_id,
+                                        const GValue *value,
+                                        GParamSpec   *pspec)
+{
+  UDisksLinuxBlockObject *object = UDISKS_LINUX_BLOCK_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->device == NULL);
+      object->device = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (_object, prop_id, pspec);
+      break;
+    }
+}
+
+
+static void
+udisks_linux_block_object_init (UDisksLinuxBlockObject *object)
+{
+}
+
+static void
+udisks_linux_block_object_constructed (GObject *_object)
+{
+  UDisksLinuxBlockObject *object = UDISKS_LINUX_BLOCK_OBJECT (_object);
+  GString *str;
+
+  object->mount_monitor = udisks_daemon_get_mount_monitor (object->daemon);
+  g_signal_connect (object->mount_monitor,
+                    "mount-added",
+                    G_CALLBACK (on_mount_monitor_mount_added),
+                    object);
+  g_signal_connect (object->mount_monitor,
+                    "mount-removed",
+                    G_CALLBACK (on_mount_monitor_mount_removed),
+                    object);
+
+  /* initial coldplug */
+  udisks_linux_block_object_uevent (object, "add", NULL);
+
+  /* compute the object path */
+  str = g_string_new ("/org/freedesktop/UDisks2/block_devices/");
+  udisks_safe_append_to_object_path (str, g_udev_device_get_name (object->device));
+  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_block_object_parent_class)->constructed != NULL)
+    G_OBJECT_CLASS (udisks_linux_block_object_parent_class)->constructed (_object);
+}
+
+static void
+udisks_linux_block_object_class_init (UDisksLinuxBlockObjectClass *klass)
+{
+  GObjectClass *gobject_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize     = udisks_linux_block_object_finalize;
+  gobject_class->constructed  = udisks_linux_block_object_constructed;
+  gobject_class->set_property = udisks_linux_block_object_set_property;
+  gobject_class->get_property = udisks_linux_block_object_get_property;
+
+  /**
+   * UDisksLinuxBlockObject: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));
+
+  /**
+   * UDisksLinuxBlockObject: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_READABLE |
+                                                        G_PARAM_WRITABLE |
+                                                        G_PARAM_CONSTRUCT_ONLY |
+                                                        G_PARAM_STATIC_STRINGS));
+
+}
+
+/**
+ * udisks_linux_block_object_new:
+ * @daemon: A #UDisksDaemon.
+ * @device: The #GUdevDevice for the sysfs block device.
+ *
+ * Create a new block object.
+ *
+ * Returns: A #UDisksLinuxBlockObject object. Free with g_object_unref().
+ */
+UDisksLinuxBlockObject *
+udisks_linux_block_object_new (UDisksDaemon  *daemon,
+                               GUdevDevice   *device)
+{
+  g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL);
+  return UDISKS_LINUX_BLOCK_OBJECT (g_object_new (UDISKS_TYPE_LINUX_BLOCK_OBJECT,
+                                                  "daemon", daemon,
+                                                  "device", device,
+                                                  NULL));
+}
+
+/**
+ * udisks_linux_block_object_get_daemon:
+ * @object: A #UDisksLinuxBlockObject.
+ *
+ * Gets the daemon used by @object.
+ *
+ * Returns: A #UDisksDaemon. Do not free, the object is owned by @object.
+ */
+UDisksDaemon *
+udisks_linux_block_object_get_daemon (UDisksLinuxBlockObject *object)
+{
+  g_return_val_if_fail (UDISKS_IS_LINUX_BLOCK_OBJECT (object), NULL);
+  return object->daemon;
+}
+
+/**
+ * udisks_linux_block_object_get_device:
+ * @object: A #UDisksLinuxBlockObject.
+ *
+ * Gets the current #GUdevDevice for @object. Connect to
+ * #GObject::notify to track changes to the #UDisksLinuxBlockObject:device
+ * property.
+ *
+ * Returns: A #GUdevDevice. Free with g_object_unref().
+ */
+GUdevDevice *
+udisks_linux_block_object_get_device (UDisksLinuxBlockObject *object)
+{
+  g_return_val_if_fail (UDISKS_IS_LINUX_BLOCK_OBJECT (object), NULL);
+  return g_object_ref (object->device);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef gboolean (*HasInterfaceFunc)    (UDisksLinuxBlockObject     *object);
+typedef void     (*ConnectInterfaceFunc) (UDisksLinuxBlockObject    *object);
+typedef void     (*UpdateInterfaceFunc) (UDisksLinuxBlockObject     *object,
+                                         const gchar    *uevent_action,
+                                         GDBusInterface *interface);
+
+static void
+update_iface (UDisksLinuxBlockObject   *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));
+    }
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+/* org.freedesktop.UDisks.BlockDevice */
+
+static gboolean
+block_device_check (UDisksLinuxBlockObject *object)
+{
+  return TRUE;
+}
+
+static void
+block_device_connect (UDisksLinuxBlockObject *object)
+{
+}
+
+static void
+block_device_update (UDisksLinuxBlockObject *object,
+                     const gchar            *uevent_action,
+                     GDBusInterface         *_iface)
+{
+  udisks_linux_block_update (UDISKS_LINUX_BLOCK (_iface), object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+/* org.freedesktop.UDisks.Filesystem */
+
+static gboolean
+filesystem_check (UDisksLinuxBlockObject *object)
+{
+  gboolean ret;
+  UDisksMountType mount_type;
+
+  ret = FALSE;
+  if (g_strcmp0 (udisks_block_device_get_id_usage (object->iface_block_device), "filesystem") == 0 ||
+      (udisks_mount_monitor_is_dev_in_use (object->mount_monitor,
+                                           g_udev_device_get_device_number (object->device),
+                                           &mount_type) &&
+       mount_type == UDISKS_MOUNT_TYPE_FILESYSTEM))
+    ret = TRUE;
+
+  return ret;
+}
+
+
+static void
+filesystem_connect (UDisksLinuxBlockObject *object)
+{
+}
+
+static void
+filesystem_update (UDisksLinuxBlockObject  *object,
+                   const gchar             *uevent_action,
+                   GDBusInterface          *_iface)
+{
+  udisks_linux_filesystem_update (UDISKS_LINUX_FILESYSTEM (_iface), object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+/* org.freedesktop.UDisks.Swapspace */
+
+static gboolean
+swapspace_check (UDisksLinuxBlockObject *object)
+{
+  gboolean ret;
+  UDisksMountType mount_type;
+
+  ret = FALSE;
+  if ((g_strcmp0 (udisks_block_device_get_id_usage (object->iface_block_device), "other") == 0 &&
+       g_strcmp0 (udisks_block_device_get_id_type (object->iface_block_device), "swap") == 0)
+      || (udisks_mount_monitor_is_dev_in_use (object->mount_monitor,
+                                              g_udev_device_get_device_number (object->device),
+                                              &mount_type)
+          && mount_type == UDISKS_MOUNT_TYPE_SWAP))
+    ret = TRUE;
+
+  return ret;
+}
+
+static void
+swapspace_connect (UDisksLinuxBlockObject *object)
+{
+}
+
+static void
+swapspace_update (UDisksLinuxBlockObject  *object,
+                  const gchar             *uevent_action,
+                  GDBusInterface          *_iface)
+{
+  udisks_linux_swapspace_update (UDISKS_LINUX_SWAPSPACE (_iface), object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+encrypted_check (UDisksLinuxBlockObject *object)
+{
+  gboolean ret;
+
+  ret = FALSE;
+  if (g_strcmp0 (udisks_block_device_get_id_usage (object->iface_block_device), "crypto") == 0 &&
+      g_strcmp0 (udisks_block_device_get_id_type (object->iface_block_device), "crypto_LUKS") == 0)
+    ret = TRUE;
+
+  return ret;
+}
+
+static void
+encrypted_connect (UDisksLinuxBlockObject *object)
+{
+}
+
+static void
+encrypted_update (UDisksLinuxBlockObject  *object,
+                  const gchar             *uevent_action,
+                  GDBusInterface          *_iface)
+{
+  udisks_linux_encrypted_update (UDISKS_LINUX_ENCRYPTED (_iface), object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+loop_check (UDisksLinuxBlockObject *object)
+{
+  gboolean ret;
+
+  ret = FALSE;
+  if (g_str_has_prefix (g_udev_device_get_name (object->device), "loop"))
+    ret = TRUE;
+
+  return ret;
+}
+
+static void
+loop_connect (UDisksLinuxBlockObject *object)
+{
+}
+
+static void
+loop_update (UDisksLinuxBlockObject  *object,
+             const gchar             *uevent_action,
+             GDBusInterface          *_iface)
+{
+  udisks_linux_loop_update (UDISKS_LINUX_LOOP (_iface), object);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * udisks_linux_block_object_uevent:
+ * @object: A #UDisksLinuxBlockObject.
+ * @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 @object.
+ */
+void
+udisks_linux_block_object_uevent (UDisksLinuxBlockObject *object,
+                                  const gchar            *action,
+                                  GUdevDevice            *device)
+{
+  g_return_if_fail (UDISKS_IS_LINUX_BLOCK_OBJECT (object));
+  g_return_if_fail (device == NULL || G_UDEV_IS_DEVICE (device));
+
+  if (device != NULL)
+    {
+      g_object_unref (object->device);
+      object->device = g_object_ref (device);
+      g_object_notify (G_OBJECT (object), "device");
+    }
+
+  update_iface (object, action, block_device_check, block_device_connect, block_device_update,
+                UDISKS_TYPE_LINUX_BLOCK, &object->iface_block_device);
+  update_iface (object, action, filesystem_check, filesystem_connect, filesystem_update,
+                UDISKS_TYPE_LINUX_FILESYSTEM, &object->iface_filesystem);
+  update_iface (object, action, swapspace_check, swapspace_connect, swapspace_update,
+                UDISKS_TYPE_LINUX_SWAPSPACE, &object->iface_swapspace);
+  update_iface (object, action, encrypted_check, encrypted_connect, encrypted_update,
+                UDISKS_TYPE_LINUX_ENCRYPTED, &object->iface_encrypted);
+  update_iface (object, action, loop_check, loop_connect, loop_update,
+                UDISKS_TYPE_LINUX_LOOP, &object->iface_loop);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+on_mount_monitor_mount_added (UDisksMountMonitor  *monitor,
+                              UDisksMount         *mount,
+                              gpointer             user_data)
+{
+  UDisksLinuxBlockObject *object = UDISKS_LINUX_BLOCK_OBJECT (user_data);
+  if (udisks_mount_get_dev (mount) == g_udev_device_get_device_number (object->device))
+    udisks_linux_block_object_uevent (object, NULL, NULL);
+}
+
+static void
+on_mount_monitor_mount_removed (UDisksMountMonitor  *monitor,
+                                UDisksMount         *mount,
+                                gpointer             user_data)
+{
+  UDisksLinuxBlockObject *object = UDISKS_LINUX_BLOCK_OBJECT (user_data);
+  if (udisks_mount_get_dev (mount) == g_udev_device_get_device_number (object->device))
+    udisks_linux_block_object_uevent (object, NULL, NULL);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
diff --git a/src/udiskslinuxblockobject.h b/src/udiskslinuxblockobject.h
new file mode 100644 (file)
index 0000000..78abaf0
--- /dev/null
@@ -0,0 +1,44 @@
+/* -*- 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_BLOCK_OBJECT_H__
+#define __UDISKS_LINUX_BLOCK_OBJECT_H__
+
+#include "udisksdaemontypes.h"
+#include <gudev/gudev.h>
+
+G_BEGIN_DECLS
+
+#define UDISKS_TYPE_LINUX_BLOCK_OBJECT  (udisks_linux_block_object_get_type ())
+#define UDISKS_LINUX_BLOCK_OBJECT(o)    (G_TYPE_CHECK_INSTANCE_CAST ((o), UDISKS_TYPE_LINUX_BLOCK_OBJECT, UDisksLinuxBlockObject))
+#define UDISKS_IS_LINUX_BLOCK_OBJECT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UDISKS_TYPE_LINUX_BLOCK_OBJECT))
+
+GType                     udisks_linux_block_object_get_type   (void) G_GNUC_CONST;
+UDisksLinuxBlockObject   *udisks_linux_block_object_new        (UDisksDaemon            *daemon,
+                                                                GUdevDevice             *device);
+void                      udisks_linux_block_object_uevent     (UDisksLinuxBlockObject  *object,
+                                                                const gchar             *action,
+                                                                GUdevDevice             *device);
+UDisksDaemon             *udisks_linux_block_object_get_daemon (UDisksLinuxBlockObject  *object);
+GUdevDevice              *udisks_linux_block_object_get_device (UDisksLinuxBlockObject  *object);
+
+G_END_DECLS
+
+#endif /* __UDISKS_LINUX_BLOCK_OBJECT_H__ */
index 9a6db9a..e0002ef 100644 (file)
@@ -35,7 +35,7 @@
 #include "udiskslinuxprovider.h"
 #include "udiskslinuxdriveobject.h"
 #include "udiskslinuxdrive.h"
-#include "udiskslinuxblock.h"
+#include "udiskslinuxblockobject.h"
 #include "udisksdaemon.h"
 #include "udiskscleanup.h"
 #include "udisksdaemonutil.h"
@@ -474,7 +474,7 @@ handle_eject (UDisksDrive           *_drive,
 {
   UDisksLinuxDrive *drive = UDISKS_LINUX_DRIVE (_drive);
   UDisksLinuxDriveObject *object;
-  UDisksLinuxBlock *block_object;
+  UDisksLinuxBlockObject *block_object;
   UDisksBlockDevice *block;
   UDisksDaemon *daemon;
   const gchar *action_id;
index 00104f3..0d55f99 100644 (file)
@@ -37,7 +37,7 @@
 #include "udiskslinuxprovider.h"
 #include "udiskslinuxdriveobject.h"
 #include "udiskslinuxdriveata.h"
-#include "udiskslinuxblock.h"
+#include "udiskslinuxblockobject.h"
 #include "udisksdaemon.h"
 #include "udiskscleanup.h"
 #include "udisksdaemonutil.h"
@@ -297,7 +297,7 @@ handle_smart_update (UDisksDriveAta        *_drive,
 {
   UDisksLinuxDriveAta *drive = UDISKS_LINUX_DRIVE_ATA (_drive);
   UDisksLinuxDriveObject *object;
-  UDisksLinuxBlock *block_object;
+  UDisksLinuxBlockObject *block_object;
   UDisksBlockDevice *block;
   UDisksDaemon *daemon;
   const gchar *action_id;
index 0956419..2874429 100644 (file)
@@ -32,7 +32,7 @@
 #include "udiskslinuxdriveobject.h"
 #include "udiskslinuxdrive.h"
 #include "udiskslinuxdriveata.h"
-#include "udiskslinuxblock.h"
+#include "udiskslinuxblockobject.h"
 
 /**
  * SECTION:udiskslinuxdriveobject
@@ -417,12 +417,12 @@ udisks_linux_drive_object_get_device (UDisksLinuxDriveObject   *object,
  * Returns: A #UDisksLinuxBlockObject or %NULL. The returned object
  * must be freed with g_object_unref().
  */
-UDisksLinuxBlock *
+UDisksLinuxBlockObject *
 udisks_linux_drive_object_get_block (UDisksLinuxDriveObject   *object,
                                      gboolean                  get_hw)
 {
   GDBusObjectManagerServer *object_manager;
-  UDisksLinuxBlock *ret;
+  UDisksLinuxBlockObject *ret;
   GList *objects;
   GList *l;
 
@@ -439,10 +439,10 @@ udisks_linux_drive_object_get_block (UDisksLinuxDriveObject   *object,
       GUdevDevice *device;
       gboolean is_disk;
 
-      if (!UDISKS_IS_LINUX_BLOCK (iter_object))
+      if (!UDISKS_IS_LINUX_BLOCK_OBJECT (iter_object))
         continue;
 
-      device = udisks_linux_block_get_device (UDISKS_LINUX_BLOCK (iter_object));
+      device = udisks_linux_block_object_get_device (UDISKS_LINUX_BLOCK_OBJECT (iter_object));
       is_disk = (g_strcmp0 (g_udev_device_get_devtype (device), "disk") == 0);
       g_object_unref (device);
 
@@ -462,7 +462,6 @@ udisks_linux_drive_object_get_block (UDisksLinuxDriveObject   *object,
   g_list_foreach (objects, (GFunc) g_object_unref, NULL);
   g_list_free (objects);
   return ret;
-
 }
 
 /* ---------------------------------------------------------------------------------------------------- */
index 289bffc..193feb4 100644 (file)
@@ -40,7 +40,7 @@ UDisksDaemon           *udisks_linux_drive_object_get_daemon    (UDisksLinuxDriv
 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,
+UDisksLinuxBlockObject *udisks_linux_drive_object_get_block     (UDisksLinuxDriveObject   *object,
                                                                  gboolean                  get_hw);
 
 gboolean                udisks_linux_drive_object_housekeeping  (UDisksLinuxDriveObject   *object,
index 7dba4d3..336817e 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "udiskslogging.h"
 #include "udiskslinuxencrypted.h"
-#include "udiskslinuxblock.h"
+#include "udiskslinuxblockobject.h"
 #include "udisksdaemon.h"
 #include "udiskspersistentstore.h"
 #include "udisksdaemonutil.h"
@@ -96,6 +96,21 @@ udisks_linux_encrypted_new (void)
   return UDISKS_ENCRYPTED (g_object_new (UDISKS_TYPE_LINUX_ENCRYPTED,
                                          NULL));
 }
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * udisks_linux_encrypted_update:
+ * @encrypted: A #UDisksLinuxEncrypted.
+ * @object: The enclosing #UDisksLinuxBlockObject instance.
+ *
+ * Updates the interface.
+ */
+void
+udisks_linux_encrypted_update (UDisksLinuxEncrypted   *encrypted,
+                               UDisksLinuxBlockObject *object)
+{
+  /* do nothing */
+}
 
 /* ---------------------------------------------------------------------------------------------------- */
 
@@ -211,7 +226,7 @@ handle_unlock (UDisksEncrypted        *encrypted,
 
   object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (encrypted)));
   block = udisks_object_peek_block_device (object);
-  daemon = udisks_linux_block_get_daemon (UDISKS_LINUX_BLOCK (object));
+  daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
   cleanup = udisks_daemon_get_cleanup (daemon);
 
   /* TODO: check if the device is mentioned in /etc/crypttab (see crypttab(5)) - if so use that
@@ -346,7 +361,7 @@ handle_unlock (UDisksEncrypted        *encrypted,
                  udisks_block_device_get_device (block),
                  udisks_block_device_get_device (cleartext_block));
 
-  udev_cleartext_device = udisks_linux_block_get_device (UDISKS_LINUX_BLOCK (cleartext_object));
+  udev_cleartext_device = udisks_linux_block_object_get_device (UDISKS_LINUX_BLOCK_OBJECT (cleartext_object));
 
   /* update the unlocked-luks file */
   if (!udisks_cleanup_add_unlocked_luks (cleanup,
@@ -411,7 +426,7 @@ handle_lock (UDisksEncrypted        *encrypted,
 
   object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (encrypted)));
   block = udisks_object_peek_block_device (object);
-  daemon = udisks_linux_block_get_daemon (UDISKS_LINUX_BLOCK (object));
+  daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
   cleanup = udisks_daemon_get_cleanup (daemon);
 
   /* TODO: check if the device is mentioned in /etc/crypttab (see crypttab(5)) - if so use that
@@ -497,7 +512,7 @@ handle_lock (UDisksEncrypted        *encrypted,
         goto out;
     }
 
-  device = udisks_linux_block_get_device (UDISKS_LINUX_BLOCK (cleartext_object));
+  device = udisks_linux_block_object_get_device (UDISKS_LINUX_BLOCK_OBJECT (cleartext_object));
   escaped_name = g_strescape (g_udev_device_get_sysfs_attr (device, "dm/name"), NULL);
 
   if (cleartext_device_from_file != 0)
index 042d496..a27b42a 100644 (file)
@@ -31,6 +31,8 @@ G_BEGIN_DECLS
 
 GType            udisks_linux_encrypted_get_type (void) G_GNUC_CONST;
 UDisksEncrypted *udisks_linux_encrypted_new      (void);
+void             udisks_linux_encrypted_update   (UDisksLinuxEncrypted   *encrypted,
+                                                  UDisksLinuxBlockObject *object);
 
 G_END_DECLS
 
index 72d0a7a..1d32b60 100644 (file)
 
 #include "udiskslogging.h"
 #include "udiskslinuxfilesystem.h"
-#include "udiskslinuxblock.h"
+#include "udiskslinuxblockobject.h"
 #include "udisksdaemon.h"
 #include "udiskscleanup.h"
 #include "udisksdaemonutil.h"
+#include "udisksmountmonitor.h"
+#include "udisksmount.h"
 
 /**
  * SECTION:udiskslinuxfilesystem
@@ -100,6 +102,48 @@ udisks_linux_filesystem_new (void)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+/**
+ * udisks_linux_filesystem_update:
+ * @filesystem: A #UDisksLinuxFilesystem.
+ * @object: The enclosing #UDisksLinuxBlockObject instance.
+ *
+ * Updates the interface.
+ */
+void
+udisks_linux_filesystem_update (UDisksLinuxFilesystem  *filesystem,
+                                UDisksLinuxBlockObject *object)
+{
+  UDisksMountMonitor *mount_monitor;
+  GUdevDevice *device;
+  GPtrArray *p;
+  GList *mounts;
+  GList *l;
+
+  mount_monitor = udisks_daemon_get_mount_monitor (udisks_linux_block_object_get_daemon (object));
+  device = udisks_linux_block_object_get_device (object);
+
+  p = g_ptr_array_new ();
+  mounts = udisks_mount_monitor_get_mounts_for_dev (mount_monitor, g_udev_device_get_device_number (device));
+  /* we are guaranteed that the list is sorted so if there are
+   * multiple mounts we'll always get the same order
+   */
+  for (l = mounts; l != NULL; l = l->next)
+    {
+      UDisksMount *mount = UDISKS_MOUNT (l->data);
+      if (udisks_mount_get_mount_type (mount) == UDISKS_MOUNT_TYPE_FILESYSTEM)
+        g_ptr_array_add (p, (gpointer) udisks_mount_get_mount_path (mount));
+    }
+  g_ptr_array_add (p, NULL);
+  udisks_filesystem_set_mount_points (UDISKS_FILESYSTEM (filesystem),
+                                      (const gchar *const *) p->pdata);
+  g_ptr_array_free (p, TRUE);
+  g_list_foreach (mounts, (GFunc) g_object_unref, NULL);
+  g_list_free (mounts);
+  g_object_unref (device);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 typedef struct
 {
   const gchar *fstype;
@@ -784,7 +828,7 @@ handle_mount (UDisksFilesystem       *filesystem,
 
   object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (filesystem)));
   block = udisks_object_peek_block_device (object);
-  daemon = udisks_linux_block_get_daemon (UDISKS_LINUX_BLOCK (object));
+  daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
   cleanup = udisks_daemon_get_cleanup (daemon);
 
   /* check if mount point is managed by e.g. /etc/fstab or similar */
@@ -1104,7 +1148,7 @@ handle_unmount (UDisksFilesystem       *filesystem,
 
   object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (filesystem)));
   block = udisks_object_peek_block_device (object);
-  daemon = udisks_linux_block_get_daemon (UDISKS_LINUX_BLOCK (object));
+  daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
   cleanup = udisks_daemon_get_cleanup (daemon);
   system_managed = FALSE;
 
@@ -1394,7 +1438,7 @@ handle_set_label (UDisksFilesystem       *filesystem,
   escaped_label = NULL;
 
   object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (filesystem)));
-  daemon = udisks_linux_block_get_daemon (UDISKS_LINUX_BLOCK (object));
+  daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
   block = udisks_object_peek_block_device (object);
 
   probed_fs_usage = udisks_block_device_get_id_usage (block);
index 73afea4..cee47c6 100644 (file)
@@ -31,6 +31,8 @@ G_BEGIN_DECLS
 
 GType             udisks_linux_filesystem_get_type (void) G_GNUC_CONST;
 UDisksFilesystem *udisks_linux_filesystem_new      (void);
+void              udisks_linux_filesystem_update   (UDisksLinuxFilesystem  *filesystem,
+                                                    UDisksLinuxBlockObject *object);
 
 G_END_DECLS
 
index 61d42f6..1790cbb 100644 (file)
@@ -31,7 +31,7 @@
 
 #include "udiskslogging.h"
 #include "udiskslinuxloop.h"
-#include "udiskslinuxblock.h"
+#include "udiskslinuxblockobject.h"
 #include "udisksdaemon.h"
 #include "udiskscleanup.h"
 #include "udisksdaemonutil.h"
@@ -98,6 +98,61 @@ udisks_linux_loop_new (void)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+/**
+ * udisks_linux_loop_update:
+ * @loop: A #UDisksLinuxLoop.
+ * @object: The enclosing #UDisksLinuxBlockObject instance.
+ *
+ * Updates the interface.
+ */
+void
+udisks_linux_loop_update (UDisksLinuxLoop        *loop,
+                          UDisksLinuxBlockObject *object)
+{
+  GUdevDevice *device;
+  device = udisks_linux_block_object_get_device (object);
+  if (g_str_has_prefix (g_udev_device_get_name (device), "loop"))
+    {
+      gchar *filename;
+      gchar *backing_file;
+      GError *error;
+      filename = g_strconcat (g_udev_device_get_sysfs_path (device), "/loop/backing_file", NULL);
+      error = NULL;
+      if (!g_file_get_contents (filename,
+                                &backing_file,
+                                NULL,
+                                &error))
+        {
+          /* ENOENT is not unexpected */
+          if (!(error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT))
+            {
+              udisks_warning ("Error loading %s: %s (%s, %d)",
+                              filename,
+                              error->message,
+                              g_quark_to_string (error->domain),
+                              error->code);
+            }
+          g_error_free (error);
+          udisks_loop_set_backing_file (UDISKS_LOOP (loop), "");
+        }
+      else
+        {
+          /* TODO: validate UTF-8 */
+          g_strstrip (backing_file);
+          udisks_loop_set_backing_file (UDISKS_LOOP (loop), backing_file);
+          g_free (backing_file);
+        }
+      g_free (filename);
+    }
+  else
+    {
+      udisks_loop_set_backing_file (UDISKS_LOOP (loop), "");
+    }
+  g_object_unref (device);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 /* runs in thread dedicated to handling @invocation */
 static gboolean
 handle_delete (UDisksLoop             *loop,
@@ -121,7 +176,7 @@ handle_delete (UDisksLoop             *loop,
 
   object = g_object_ref (UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (loop))));
   block = udisks_object_peek_block_device (object);
-  daemon = udisks_linux_block_get_daemon (UDISKS_LINUX_BLOCK (object));
+  daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
   cleanup = udisks_daemon_get_cleanup (daemon);
 
   error = NULL;
index f8dfcba..21eacd5 100644 (file)
@@ -31,6 +31,8 @@ G_BEGIN_DECLS
 
 GType       udisks_linux_loop_get_type (void) G_GNUC_CONST;
 UDisksLoop *udisks_linux_loop_new      (void);
+void        udisks_linux_loop_update   (UDisksLinuxLoop        *loop,
+                                        UDisksLinuxBlockObject *object);
 
 G_END_DECLS
 
index 9a0fbca..76893e3 100644 (file)
@@ -27,7 +27,7 @@
 #include "udisksdaemon.h"
 #include "udisksprovider.h"
 #include "udiskslinuxprovider.h"
-#include "udiskslinuxblock.h"
+#include "udiskslinuxblockobject.h"
 #include "udiskslinuxdriveobject.h"
 #include "udiskslinuxmanager.h"
 #include "udiskscleanup.h"
@@ -57,7 +57,7 @@ struct _UDisksLinuxProvider
 
   UDisksObjectSkeleton *manager_object;
 
-  /* maps from sysfs path to UDisksLinuxBlock objects */
+  /* maps from sysfs path to UDisksLinuxBlockObject objects */
   GHashTable *sysfs_to_block;
 
   /* maps from VPD (serial, wwn) and sysfs_path to UDisksLinuxDriveObject instances */
@@ -395,7 +395,7 @@ handle_block_uevent_for_block (UDisksLinuxProvider *provider,
                                GUdevDevice         *device)
 {
   const gchar *sysfs_path;
-  UDisksLinuxBlock *block;
+  UDisksLinuxBlockObject *object;
   UDisksDaemon *daemon;
 
   daemon = udisks_provider_get_daemon (UDISKS_PROVIDER (provider));
@@ -403,27 +403,27 @@ handle_block_uevent_for_block (UDisksLinuxProvider *provider,
 
   if (g_strcmp0 (action, "remove") == 0)
     {
-      block = g_hash_table_lookup (provider->sysfs_to_block, sysfs_path);
-      if (block != NULL)
+      object = g_hash_table_lookup (provider->sysfs_to_block, sysfs_path);
+      if (object != NULL)
         {
           g_dbus_object_manager_server_unexport (udisks_daemon_get_object_manager (daemon),
-                                                 g_dbus_object_get_object_path (G_DBUS_OBJECT (block)));
+                                                 g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
           g_warn_if_fail (g_hash_table_remove (provider->sysfs_to_block, sysfs_path));
         }
     }
   else
     {
-      block = g_hash_table_lookup (provider->sysfs_to_block, sysfs_path);
-      if (block != NULL)
+      object = g_hash_table_lookup (provider->sysfs_to_block, sysfs_path);
+      if (object != NULL)
         {
-          udisks_linux_block_uevent (block, action, device);
+          udisks_linux_block_object_uevent (object, action, device);
         }
       else
         {
-          block = udisks_linux_block_new (daemon, device);
+          object = udisks_linux_block_object_new (daemon, device);
           g_dbus_object_manager_server_export_uniquely (udisks_daemon_get_object_manager (daemon),
-                                                        G_DBUS_OBJECT_SKELETON (block));
-          g_hash_table_insert (provider->sysfs_to_block, g_strdup (sysfs_path), block);
+                                                        G_DBUS_OBJECT_SKELETON (object));
+          g_hash_table_insert (provider->sysfs_to_block, g_strdup (sysfs_path), object);
         }
     }
 }
@@ -434,9 +434,9 @@ handle_block_uevent (UDisksLinuxProvider *provider,
                      const gchar         *action,
                      GUdevDevice         *device)
 {
-  /* We use the sysfs block device for both UDisksLinuxDriveObject and BlockDevice
-   * objects. Ensure that drive are added before and removed after
-   * BlockDevice
+  /* We use the sysfs block device for both UDisksLinuxDriveObject and
+   * UDisksLinuxBlockObject objects. Ensure that drive objects are
+   * added before and removed after block objects.
    */
   if (g_strcmp0 (action, "remove") == 0)
     {
@@ -571,24 +571,24 @@ on_housekeeping_timeout (gpointer user_data)
 /* ---------------------------------------------------------------------------------------------------- */
 
 static void
-update_all_block_devices (UDisksLinuxProvider *provider)
+update_all_block_objects (UDisksLinuxProvider *provider)
 {
-  GList *block_devices;
+  GList *objects;
   GList *l;
 
   G_LOCK (provider_lock);
-  block_devices = g_hash_table_get_values (provider->sysfs_to_block);
-  g_list_foreach (block_devices, (GFunc) g_object_ref, NULL);
+  objects = g_hash_table_get_values (provider->sysfs_to_block);
+  g_list_foreach (objects, (GFunc) g_object_ref, NULL);
   G_UNLOCK (provider_lock);
 
-  for (l = block_devices; l != NULL; l = l->next)
+  for (l = objects; l != NULL; l = l->next)
     {
-      UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (l->data);
-      udisks_linux_block_uevent (block, "change", NULL);
+      UDisksLinuxBlockObject *object = UDISKS_LINUX_BLOCK_OBJECT (l->data);
+      udisks_linux_block_object_uevent (object, "change", NULL);
     }
 
-  g_list_foreach (block_devices, (GFunc) g_object_unref, NULL);
-  g_list_free (block_devices);
+  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
+  g_list_free (objects);
 }
 
 static void
@@ -597,7 +597,7 @@ fstab_monitor_on_entry_added (UDisksFstabMonitor *monitor,
                               gpointer            user_data)
 {
   UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (user_data);
-  update_all_block_devices (provider);
+  update_all_block_objects (provider);
 }
 
 static void
@@ -606,7 +606,7 @@ fstab_monitor_on_entry_removed (UDisksFstabMonitor *monitor,
                                 gpointer            user_data)
 {
   UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (user_data);
-  update_all_block_devices (provider);
+  update_all_block_objects (provider);
 }
 
 static void
@@ -615,7 +615,7 @@ crypttab_monitor_on_entry_added (UDisksCrypttabMonitor *monitor,
                                  gpointer               user_data)
 {
   UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (user_data);
-  update_all_block_devices (provider);
+  update_all_block_objects (provider);
 }
 
 static void
@@ -624,5 +624,5 @@ crypttab_monitor_on_entry_removed (UDisksCrypttabMonitor *monitor,
                                    gpointer               user_data)
 {
   UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (user_data);
-  update_all_block_devices (provider);
+  update_all_block_objects (provider);
 }
index 32ae054..9499bb2 100644 (file)
 
 #include "udiskslogging.h"
 #include "udiskslinuxswapspace.h"
-#include "udiskslinuxblock.h"
+#include "udiskslinuxblockobject.h"
 #include "udisksdaemon.h"
 #include "udiskscleanup.h"
 #include "udisksdaemonutil.h"
+#include "udisksmountmonitor.h"
 
 /**
  * SECTION:udiskslinuxswapspace
@@ -98,6 +99,36 @@ udisks_linux_swapspace_new (void)
 
 /* ---------------------------------------------------------------------------------------------------- */
 
+/**
+ * udisks_linux_swapspace_update:
+ * @swapspace: A #UDisksLinuxSwapspace.
+ * @object: The enclosing #UDisksLinuxBlockObject instance.
+ *
+ * Updates the interface.
+ */
+void
+udisks_linux_swapspace_update (UDisksLinuxSwapspace   *swapspace,
+                               UDisksLinuxBlockObject *object)
+{
+  UDisksMountMonitor *mount_monitor;
+  GUdevDevice *device;
+  UDisksMountType mount_type;
+  gboolean active;
+
+  mount_monitor = udisks_daemon_get_mount_monitor (udisks_linux_block_object_get_daemon (object));
+  device = udisks_linux_block_object_get_device (object);
+
+  active = FALSE;
+  if (udisks_mount_monitor_is_dev_in_use (mount_monitor, g_udev_device_get_device_number (device), &mount_type) &&
+      mount_type == UDISKS_MOUNT_TYPE_SWAP)
+    active = TRUE;
+  udisks_swapspace_set_active (UDISKS_SWAPSPACE (swapspace), active);
+
+  g_object_unref (device);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
 
 static void
 swapspace_start_on_job_completed (UDisksJob   *job,
@@ -129,7 +160,7 @@ handle_start (UDisksSwapspace        *swapspace,
   UDisksBaseJob *job;
 
   object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (swapspace)));
-  daemon = udisks_linux_block_get_daemon (UDISKS_LINUX_BLOCK (object));
+  daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
   block = udisks_object_peek_block_device (object);
 
   if (!udisks_daemon_util_check_authorization_sync (daemon,
@@ -186,7 +217,7 @@ handle_stop (UDisksSwapspace        *swapspace,
   UDisksBaseJob *job;
 
   object = UDISKS_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (swapspace)));
-  daemon = udisks_linux_block_get_daemon (UDISKS_LINUX_BLOCK (object));
+  daemon = udisks_linux_block_object_get_daemon (UDISKS_LINUX_BLOCK_OBJECT (object));
   block = udisks_object_peek_block_device (object);
 
   /* Now, check that the user is actually authorized to stop the swap space.
index bfe13ad..45c9942 100644 (file)
@@ -31,6 +31,8 @@ G_BEGIN_DECLS
 
 GType            udisks_linux_swapspace_get_type (void) G_GNUC_CONST;
 UDisksSwapspace *udisks_linux_swapspace_new      (void);
+void             udisks_linux_swapspace_update   (UDisksLinuxSwapspace   *swapspace,
+                                                  UDisksLinuxBlockObject *object);
 
 G_END_DECLS