From bebb0c9adcd57045dee71408ae756cf6532568e8 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Tue, 16 Aug 2011 12:36:42 -0400 Subject: [PATCH] Factor block devices into separate types Signed-off-by: David Zeuthen --- doc/udisks2-docs.xml | 50 +- doc/udisks2-sections.txt | 73 +- doc/udisks2.types | 3 +- src/Makefile.am | 1 + src/udisksdaemontypes.h | 3 + src/udiskslinuxblock.c | 3068 ++++++++++++++++++------------------------ src/udiskslinuxblock.h | 19 +- src/udiskslinuxblockobject.c | 586 ++++++++ src/udiskslinuxblockobject.h | 44 + src/udiskslinuxdrive.c | 4 +- src/udiskslinuxdriveata.c | 4 +- src/udiskslinuxdriveobject.c | 11 +- src/udiskslinuxdriveobject.h | 2 +- src/udiskslinuxencrypted.c | 25 +- src/udiskslinuxencrypted.h | 2 + src/udiskslinuxfilesystem.c | 52 +- src/udiskslinuxfilesystem.h | 2 + src/udiskslinuxloop.c | 59 +- src/udiskslinuxloop.h | 2 + src/udiskslinuxprovider.c | 56 +- src/udiskslinuxswapspace.c | 37 +- src/udiskslinuxswapspace.h | 2 + 22 files changed, 2209 insertions(+), 1896 deletions(-) create mode 100644 src/udiskslinuxblockobject.c create mode 100644 src/udiskslinuxblockobject.h diff --git a/doc/udisks2-docs.xml b/doc/udisks2-docs.xml index a6a7426..bfbaba5 100644 --- a/doc/udisks2-docs.xml +++ b/doc/udisks2-docs.xml @@ -171,18 +171,24 @@ Daemon Implementation Details - - - - - - - - - - - - + + Core + + + + + + + + + State and Configuration + + + + + + + Jobs @@ -190,22 +196,26 @@ - - Linux-specific objects and providers - + + Drives on Linux - - - Linux implementation of interfaces - - + + + Block devices on Linux + + + + Other Linux-specific interfaces + + + diff --git a/doc/udisks2-sections.txt b/doc/udisks2-sections.txt index 4d5e48c..b26c12c 100644 --- a/doc/udisks2-sections.txt +++ b/doc/udisks2-sections.txt @@ -144,22 +144,6 @@ udisks_simple_job_get_type
-udiskslinuxblock -UDisksLinuxBlock -UDisksLinuxBlock -udisks_linux_block_new -udisks_linux_block_uevent -udisks_linux_block_get_daemon -udisks_linux_block_get_device - -UDISKS_TYPE_LINUX_BLOCK -UDISKS_LINUX_BLOCK -UDISKS_IS_LINUX_BLOCK - -udisks_linux_block_get_type -
- -
udiskslinuxdriveobject UDisksLinuxDriveObject UDisksLinuxDriveObject @@ -336,9 +320,39 @@ udisks_daemon_util_setup_by_user
+udiskslinuxblockobject +UDisksLinuxBlockObject +UDisksLinuxBlockObject +udisks_linux_block_object_new +udisks_linux_block_object_uevent +udisks_linux_block_object_get_daemon +udisks_linux_block_object_get_device + +UDISKS_TYPE_LINUX_BLOCK_OBJECT +UDISKS_LINUX_BLOCK_OBJECT +UDISKS_IS_LINUX_BLOCK_OBJECT + +udisks_linux_block_object_get_type +
+ +
+udiskslinuxblock +UDisksLinuxBlock +udisks_linux_block_new +udisks_linux_block_update + +UDISKS_LINUX_BLOCK +UDISKS_IS_LINUX_BLOCK +UDISKS_TYPE_LINUX_BLOCK + +udisks_linux_block_get_type +
+ +
udiskslinuxfilesystem UDisksLinuxFilesystem udisks_linux_filesystem_new +udisks_linux_filesystem_update UDISKS_LINUX_FILESYSTEM UDISKS_IS_LINUX_FILESYSTEM @@ -351,6 +365,7 @@ udisks_linux_filesystem_get_type udiskslinuxencrypted UDisksLinuxEncrypted udisks_linux_encrypted_new +udisks_linux_encrypted_update UDISKS_LINUX_ENCRYPTED UDISKS_IS_LINUX_ENCRYPTED @@ -363,6 +378,7 @@ udisks_linux_encrypted_get_type udiskslinuxswapspace UDisksLinuxSwapspace udisks_linux_swapspace_new +udisks_linux_swapspace_update UDISKS_LINUX_SWAPSPACE UDISKS_IS_LINUX_SWAPSPACE @@ -372,6 +388,19 @@ udisks_linux_swapspace_get_type
+udiskslinuxloop +UDisksLinuxLoop +udisks_linux_loop_new +udisks_linux_loop_update + +UDISKS_LINUX_LOOP +UDISKS_IS_LINUX_LOOP +UDISKS_TYPE_LINUX_LOOP + +udisks_linux_loop_get_type +
+ +
UDisksObject UDisksObject UDisksObject @@ -968,18 +997,6 @@ udisks_linux_manager_get_type
-udiskslinuxloop -UDisksLinuxLoop -udisks_linux_loop_new - -UDISKS_LINUX_LOOP -UDISKS_IS_LINUX_LOOP -UDISKS_TYPE_LINUX_LOOP - -udisks_linux_loop_get_type -
- -
UDisksLoop UDisksLoop UDisksLoopIface diff --git a/doc/udisks2.types b/doc/udisks2.types index c8de422..994a6a1 100644 --- a/doc/udisks2.types +++ b/doc/udisks2.types @@ -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 diff --git a/src/Makefile.am b/src/Makefile.am index f628971..01faace 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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 \ diff --git a/src/udisksdaemontypes.h b/src/udisksdaemontypes.h index 853fbc8..86238a9 100644 --- a/src/udisksdaemontypes.h +++ b/src/udisksdaemontypes.h @@ -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; diff --git a/src/udiskslinuxblock.c b/src/udiskslinuxblock.c index b6b13a7..41a950e 100644 --- a/src/udiskslinuxblock.c +++ b/src/udiskslinuxblock.c @@ -24,29 +24,22 @@ #include #include #include -#include -#include #include #include -#include - #include #include +#include +#include + #include #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" @@ -56,9 +49,10 @@ /** * 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; } - -/* ---------------------------------------------------------------------------------------------------- */ diff --git a/src/udiskslinuxblock.h b/src/udiskslinuxblock.h index 9e7fd5b..65ab632 100644 --- a/src/udiskslinuxblock.h +++ b/src/udiskslinuxblock.h @@ -22,22 +22,17 @@ #define __UDISKS_LINUX_BLOCK_H__ #include "udisksdaemontypes.h" -#include 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 index 0000000..e841dcf --- /dev/null +++ b/src/udiskslinuxblockobject.c @@ -0,0 +1,586 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2007-2010 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include "config.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 index 0000000..78abaf0 --- /dev/null +++ b/src/udiskslinuxblockobject.h @@ -0,0 +1,44 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2007-2010 David Zeuthen + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef __UDISKS_LINUX_BLOCK_OBJECT_H__ +#define __UDISKS_LINUX_BLOCK_OBJECT_H__ + +#include "udisksdaemontypes.h" +#include + +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__ */ diff --git a/src/udiskslinuxdrive.c b/src/udiskslinuxdrive.c index 9a6db9a..e0002ef 100644 --- a/src/udiskslinuxdrive.c +++ b/src/udiskslinuxdrive.c @@ -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; diff --git a/src/udiskslinuxdriveata.c b/src/udiskslinuxdriveata.c index 00104f3..0d55f99 100644 --- a/src/udiskslinuxdriveata.c +++ b/src/udiskslinuxdriveata.c @@ -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; diff --git a/src/udiskslinuxdriveobject.c b/src/udiskslinuxdriveobject.c index 0956419..2874429 100644 --- a/src/udiskslinuxdriveobject.c +++ b/src/udiskslinuxdriveobject.c @@ -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; - } /* ---------------------------------------------------------------------------------------------------- */ diff --git a/src/udiskslinuxdriveobject.h b/src/udiskslinuxdriveobject.h index 289bffc..193feb4 100644 --- a/src/udiskslinuxdriveobject.h +++ b/src/udiskslinuxdriveobject.h @@ -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, diff --git a/src/udiskslinuxencrypted.c b/src/udiskslinuxencrypted.c index 7dba4d3..336817e 100644 --- a/src/udiskslinuxencrypted.c +++ b/src/udiskslinuxencrypted.c @@ -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) diff --git a/src/udiskslinuxencrypted.h b/src/udiskslinuxencrypted.h index 042d496..a27b42a 100644 --- a/src/udiskslinuxencrypted.h +++ b/src/udiskslinuxencrypted.h @@ -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 diff --git a/src/udiskslinuxfilesystem.c b/src/udiskslinuxfilesystem.c index 72d0a7a..1d32b60 100644 --- a/src/udiskslinuxfilesystem.c +++ b/src/udiskslinuxfilesystem.c @@ -33,10 +33,12 @@ #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); diff --git a/src/udiskslinuxfilesystem.h b/src/udiskslinuxfilesystem.h index 73afea4..cee47c6 100644 --- a/src/udiskslinuxfilesystem.h +++ b/src/udiskslinuxfilesystem.h @@ -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 diff --git a/src/udiskslinuxloop.c b/src/udiskslinuxloop.c index 61d42f6..1790cbb 100644 --- a/src/udiskslinuxloop.c +++ b/src/udiskslinuxloop.c @@ -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; diff --git a/src/udiskslinuxloop.h b/src/udiskslinuxloop.h index f8dfcba..21eacd5 100644 --- a/src/udiskslinuxloop.h +++ b/src/udiskslinuxloop.h @@ -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 diff --git a/src/udiskslinuxprovider.c b/src/udiskslinuxprovider.c index 9a0fbca..76893e3 100644 --- a/src/udiskslinuxprovider.c +++ b/src/udiskslinuxprovider.c @@ -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); } diff --git a/src/udiskslinuxswapspace.c b/src/udiskslinuxswapspace.c index 32ae054..9499bb2 100644 --- a/src/udiskslinuxswapspace.c +++ b/src/udiskslinuxswapspace.c @@ -31,10 +31,11 @@ #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. diff --git a/src/udiskslinuxswapspace.h b/src/udiskslinuxswapspace.h index bfe13ad..45c9942 100644 --- a/src/udiskslinuxswapspace.h +++ b/src/udiskslinuxswapspace.h @@ -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 -- 2.7.4