summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2011-07-23 13:13:45 -0400
committerDavid Zeuthen <davidz@redhat.com>2011-07-23 13:13:45 -0400
commit9df40b766a92a3a39c78476278d6b0e0f741e88b (patch)
tree576bca4e5aaaf47acaab620f176ddadf8088f670
parentcc375e9e3890c68669771f8aefa674be1757c66f (diff)
Track loop devices set up in /run/udisks2/loop
Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r--doc/udisks2-sections.txt5
-rw-r--r--src/udiskscleanup.c429
-rw-r--r--src/udiskscleanup.h20
-rw-r--r--src/udisksdaemonutil.c43
-rw-r--r--src/udiskslinuxencrypted.c6
-rw-r--r--src/udiskslinuxfilesystem.c3
-rw-r--r--src/udiskslinuxloop.c43
-rw-r--r--src/udiskslinuxmanager.c74
8 files changed, 593 insertions, 30 deletions
diff --git a/doc/udisks2-sections.txt b/doc/udisks2-sections.txt
index 4a1db23..8d0171c 100644
--- a/doc/udisks2-sections.txt
+++ b/doc/udisks2-sections.txt
@@ -276,6 +276,11 @@ udisks_cleanup_find_unlocked_luks
udisks_cleanup_ignore_unlocked_luks
udisks_cleanup_remove_unlocked_luks
udisks_cleanup_unignore_unlocked_luks
+<SUBSECTION>
+udisks_cleanup_add_loop
+udisks_cleanup_ignore_loop
+udisks_cleanup_remove_loop
+udisks_cleanup_unignore_loop
<SUBSECTION Standard>
UDISKS_TYPE_CLEANUP
UDISKS_CLEANUP
diff --git a/src/udiskscleanup.c b/src/udiskscleanup.c
index 8d94df8..7fa5801 100644
--- a/src/udiskscleanup.c
+++ b/src/udiskscleanup.c
@@ -64,7 +64,7 @@
* (of type <link linkend="G-VARIANT-TYPE-UINT64:CAPS">'t'</link>) that is the #dev_t
* for the mounted device and
* <literal>mounted-by-uid</literal>
- * (of type <link linkend="G-VARIANT-TYPE-UINT64:CAPS">'u'</link>) that is the #uid_t
+ * (of type <link linkend="G-VARIANT-TYPE-UINT32:CAPS">'u'</link>) that is the #uid_t
* of the user who mounted the device.
* </entry>
* </row>
@@ -78,13 +78,29 @@
* (of type <link linkend="G-VARIANT-TYPE-UINT64:CAPS">'t'</link>) that is the #dev_t
* for the crypto-text device,
* <literal>dm-uuid</literal>
- * (of type <link linkend="G-VARIANT-TYPE-UINT64:CAPS">'ay'</link>) that is the device mapper UUID
+ * (of type <link linkend="G-VARIANT-TYPE-ARRAY:CAPS">'ay'</link>) that is the device mapper UUID
* for the clear-text device and
* <literal>unlocked-by-uid</literal>
- * (of type <link linkend="G-VARIANT-TYPE-UINT64:CAPS">'u'</link>) that is the #uid_t
+ * (of type <link linkend="G-VARIANT-TYPE-UINT32:CAPS">'u'</link>) that is the #uid_t
* of the user who unlocked the device.
* </entry>
* </row>
+ * <row>
+ * <entry><filename>/run/udisks2/loop</filename></entry>
+ * <entry>
+ * A serialized 'a{sa{sv}}' #GVariant mapping from the
+ * loop device name (e.g. <filename>/dev/loop0</filename>) into a set of details.
+ * Known details include
+ * <literal>backing-file</literal>
+ * (of type <link linkend="G-VARIANT-TYPE-ARRAY:CAPS">'ay'</link>) for the name of the backing file and
+ * <literal>backing-file-device</literal>
+ * (of type <link linkend="G-VARIANT-TYPE-UINT64:CAPS">'t'</link>) for the #dev_t
+ * for of the device holding the backing file and
+ * <literal>setup-by-uid</literal>
+ * (of type <link linkend="G-VARIANT-TYPE-UINT32:CAPS">'u'</link>) that is the #uid_t
+ * of the user who set up the loop device.
+ * </entry>
+ * </row>
* </tbody>
* </tgroup>
* </table>
@@ -119,6 +135,7 @@ struct _UDisksCleanup
GHashTable *currently_unmounting;
GHashTable *currently_locking;
+ GHashTable *currently_deleting;
GThread *thread;
GMainContext *context;
@@ -147,6 +164,10 @@ static void udisks_cleanup_check_unlocked_luks (UDisksCleanup *cleanup,
gboolean check_only,
GArray *devs_to_clean);
+static void udisks_cleanup_check_loop (UDisksCleanup *cleanup,
+ gboolean check_only,
+ GArray *devs_to_clean);
+
G_DEFINE_TYPE (UDisksCleanup, udisks_cleanup, G_TYPE_OBJECT);
@@ -156,6 +177,7 @@ udisks_cleanup_init (UDisksCleanup *cleanup)
cleanup->lock = g_mutex_new ();
cleanup->currently_unmounting = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
cleanup->currently_locking = g_hash_table_new_full (g_int64_hash, g_int64_equal, g_free, NULL);
+ cleanup->currently_deleting = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
}
static void
@@ -165,6 +187,7 @@ udisks_cleanup_finalize (GObject *object)
g_hash_table_unref (cleanup->currently_unmounting);
g_hash_table_unref (cleanup->currently_locking);
+ g_hash_table_unref (cleanup->currently_deleting);
g_mutex_free (cleanup->lock);
G_OBJECT_CLASS (udisks_cleanup_parent_class)->finalize (object);
@@ -386,6 +409,9 @@ udisks_cleanup_check_in_thread (UDisksCleanup *cleanup)
udisks_cleanup_check_unlocked_luks (cleanup,
TRUE, /* check_only */
devs_to_clean);
+ udisks_cleanup_check_loop (cleanup,
+ TRUE, /* check_only */
+ devs_to_clean);
/* Then go through all mounted filesystems and pass the
* devices that we intend to clean...
@@ -398,6 +424,9 @@ udisks_cleanup_check_in_thread (UDisksCleanup *cleanup)
udisks_cleanup_check_unlocked_luks (cleanup,
FALSE, /* check_only */
NULL);
+ udisks_cleanup_check_loop (cleanup,
+ FALSE, /* check_only */
+ NULL);
g_array_unref (devs_to_clean);
@@ -1728,3 +1757,397 @@ udisks_cleanup_unignore_unlocked_luks (UDisksCleanup *cleanup,
}
/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+udisks_cleanup_check_loop (UDisksCleanup *cleanup,
+ gboolean check_only,
+ GArray *devs_to_clean)
+{
+ /* TODO */
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
+ * udisks_cleanup_add_loop:
+ * @cleanup: A #UDisksCleanup.
+ * @device_file: The loop device file.
+ * @backing_file: The backing file.
+ * @backing_file_device: The #dev_t of the backing file.
+ * @uid: The user id of the process requesting the loop device.
+ * @error: Return location for error or %NULL.
+ *
+ * Adds a new entry to the <filename>/run/udisks2/loop</filename>
+ * file.
+ *
+ * Returns: %TRUE if the entry was added, %FALSE if @error is set.
+ */
+gboolean
+udisks_cleanup_add_loop (UDisksCleanup *cleanup,
+ const gchar *device_file,
+ const gchar *backing_file,
+ dev_t backing_file_device,
+ uid_t uid,
+ GError **error)
+{
+ gboolean ret;
+ GVariant *value;
+ GVariant *new_value;
+ GVariant *details_value;
+ GVariantBuilder builder;
+ GVariantBuilder details_builder;
+ GError *local_error;
+
+ g_return_val_if_fail (UDISKS_IS_CLEANUP (cleanup), FALSE);
+ g_return_val_if_fail (device_file != NULL, FALSE);
+ g_return_val_if_fail (backing_file != NULL, FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ g_mutex_lock (cleanup->lock);
+
+ ret = FALSE;
+
+ /* load existing entries */
+ local_error = NULL;
+ value = udisks_persistent_store_get (cleanup->persistent_store,
+ UDISKS_PERSISTENT_FLAGS_TEMPORARY_STORE,
+ "loop",
+ G_VARIANT_TYPE ("a{sa{sv}}"),
+ &local_error);
+ if (local_error != NULL)
+ {
+ g_set_error (error,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error getting loop: %s (%s, %d)",
+ local_error->message,
+ g_quark_to_string (local_error->domain),
+ local_error->code);
+ g_error_free (local_error);
+ goto out;
+ }
+
+ /* start by including existing entries */
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sa{sv}}"));
+ if (value != NULL)
+ {
+ GVariantIter iter;
+ GVariant *child;
+ g_variant_iter_init (&iter, value);
+ while ((child = g_variant_iter_next_value (&iter)) != NULL)
+ {
+ g_variant_builder_add_value (&builder, child);
+ g_variant_unref (child);
+ }
+ g_variant_unref (value);
+ }
+
+ /* build the details */
+ g_variant_builder_init (&details_builder, G_VARIANT_TYPE ("a{sv}"));
+ g_variant_builder_add (&details_builder,
+ "{sv}",
+ "backing-file",
+ g_variant_new_bytestring (backing_file));
+ g_variant_builder_add (&details_builder,
+ "{sv}",
+ "backing-file-device",
+ g_variant_new_uint64 (backing_file_device));
+ g_variant_builder_add (&details_builder,
+ "{sv}",
+ "setup-by-uid",
+ g_variant_new_uint32 (uid));
+ details_value = g_variant_builder_end (&details_builder);
+
+ /* finally add the new entry */
+ g_variant_builder_add (&builder,
+ "{s@a{sv}}",
+ device_file,
+ details_value); /* consumes details_value */
+ new_value = g_variant_builder_end (&builder);
+
+ /* save new entries */
+ local_error = NULL;
+ if (!udisks_persistent_store_set (cleanup->persistent_store,
+ UDISKS_PERSISTENT_FLAGS_TEMPORARY_STORE,
+ "loop",
+ G_VARIANT_TYPE ("a{sa{sv}}"),
+ new_value, /* consumes new_value */
+ &local_error))
+ {
+ g_set_error (error,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error setting loop: %s (%s, %d)",
+ local_error->message,
+ g_quark_to_string (local_error->domain),
+ local_error->code);
+ g_error_free (local_error);
+ goto out;
+ }
+
+ ret = TRUE;
+
+ out:
+ g_mutex_unlock (cleanup->lock);
+ return ret;
+}
+
+/**
+ * udisks_cleanup_remove_loop:
+ * @cleanup: A #UDisksCleanup.
+ * @device_file: The loop device file.
+ * @error: Return location for error or %NULL.
+ *
+ * Removes an entry previously added with udisks_cleanup_add_loop().
+ *
+ * Returns: %TRUE if the entry was removed, %FALSE if @error is set.
+ */
+gboolean
+udisks_cleanup_remove_loop (UDisksCleanup *cleanup,
+ const gchar *device_file,
+ GError **error)
+{
+ gboolean ret;
+ GVariant *value;
+ GVariant *new_value;
+ GVariantBuilder builder;
+ GError *local_error;
+ gboolean removed;
+
+ g_return_val_if_fail (UDISKS_IS_CLEANUP (cleanup), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ g_mutex_lock (cleanup->lock);
+
+ ret = FALSE;
+ removed = FALSE;
+
+ /* load existing entries */
+ local_error = NULL;
+ value = udisks_persistent_store_get (cleanup->persistent_store,
+ UDISKS_PERSISTENT_FLAGS_TEMPORARY_STORE,
+ "loop",
+ G_VARIANT_TYPE ("a{sa{sv}}"),
+ &local_error);
+ if (local_error != NULL)
+ {
+ g_set_error (error,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error getting loop: %s (%s, %d)",
+ local_error->message,
+ g_quark_to_string (local_error->domain),
+ local_error->code);
+ g_error_free (local_error);
+ goto out;
+ }
+
+ /* start by including existing entries except for the one we want to remove */
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sa{sv}}"));
+ if (value != NULL)
+ {
+ GVariantIter iter;
+ GVariant *child;
+
+ g_variant_iter_init (&iter, value);
+ while ((child = g_variant_iter_next_value (&iter)) != NULL)
+ {
+ const gchar *iter_device_file;
+ g_variant_get (child, "{&s@a{sv}}", &iter_device_file, NULL);
+ if (g_strcmp0 (iter_device_file, device_file) == 0)
+ {
+ removed = TRUE;
+ }
+ else
+ {
+ g_variant_builder_add_value (&builder, child);
+ }
+ g_variant_unref (child);
+ }
+ g_variant_unref (value);
+ }
+ new_value = g_variant_builder_end (&builder);
+ if (removed)
+ {
+ /* save new entries */
+ local_error = NULL;
+ if (!udisks_persistent_store_set (cleanup->persistent_store,
+ UDISKS_PERSISTENT_FLAGS_TEMPORARY_STORE,
+ "loop",
+ G_VARIANT_TYPE ("a{sa{sv}}"),
+ new_value, /* consumes new_value */
+ &local_error))
+ {
+ g_set_error (error,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error setting loop: %s (%s, %d)",
+ local_error->message,
+ g_quark_to_string (local_error->domain),
+ local_error->code);
+ g_error_free (local_error);
+ goto out;
+ }
+ ret = TRUE;
+ }
+ else
+ {
+ g_variant_unref (new_value);
+ }
+
+ out:
+ g_mutex_unlock (cleanup->lock);
+ return ret;
+}
+
+/**
+ * udisks_cleanup_has_loop:
+ * @cleanup: A #UDisksCleanup
+ * @device_file: A loop device file.
+ * @out_uid: Return location for the user id who setup the loop device or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Checks if @device_file is set up via udisks.
+ *
+ * Returns: %TRUE if set up via udisks, otherwise %FALSE or if @error is set.
+ */
+gboolean
+udisks_cleanup_has_loop (UDisksCleanup *cleanup,
+ const gchar *device_file,
+ uid_t *out_uid,
+ GError **error)
+{
+ gboolean ret;
+ GVariant *value;
+ GError *local_error;
+
+ g_return_val_if_fail (UDISKS_IS_CLEANUP (cleanup), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ g_mutex_lock (cleanup->lock);
+
+ ret = 0;
+ value = NULL;
+
+ /* load existing entries */
+ local_error = NULL;
+ value = udisks_persistent_store_get (cleanup->persistent_store,
+ UDISKS_PERSISTENT_FLAGS_TEMPORARY_STORE,
+ "loop",
+ G_VARIANT_TYPE ("a{sa{sv}}"),
+ &local_error);
+ if (local_error != NULL)
+ {
+ g_set_error (error,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error getting loop: %s (%s, %d)",
+ local_error->message,
+ g_quark_to_string (local_error->domain),
+ local_error->code);
+ g_error_free (local_error);
+ goto out;
+ }
+
+ /* look through list */
+ if (value != NULL)
+ {
+ GVariantIter iter;
+ GVariant *child;
+ g_variant_iter_init (&iter, value);
+ while ((child = g_variant_iter_next_value (&iter)) != NULL)
+ {
+ const gchar *iter_device_file;
+ GVariant *details;
+
+ g_variant_get (child,
+ "{&s@a{sv}}",
+ &iter_device_file,
+ &details);
+
+ if (g_strcmp0 (iter_device_file, device_file) == 0)
+ {
+ ret = TRUE;
+ if (out_uid != NULL)
+ {
+ GVariant *value;
+ value = lookup_asv (details, "setup-by-uid");
+ *out_uid = 0;
+ if (value != NULL)
+ {
+ *out_uid = g_variant_get_uint32 (value);
+ g_variant_unref (value);
+ }
+ }
+ g_variant_unref (details);
+ g_variant_unref (child);
+ goto out;
+ }
+ g_variant_unref (details);
+ g_variant_unref (child);
+ }
+ }
+
+ out:
+ if (value != NULL)
+ g_variant_unref (value);
+ g_mutex_unlock (cleanup->lock);
+ return ret;
+}
+
+/**
+ * udisks_cleanup_ignore_loop:
+ * @cleanup: A #UDisksCleanup.
+ * @device_file: A loop device file.
+ *
+ * Set @device_file as currently being ignored. This ensures that the
+ * entry for @device_file won't get cleaned up by the cleanup routines
+ * until udisks_cleanup_unignore_loop() is called.
+ *
+ * Returns: %TRUE if @device_file was successfully ignored, %FALSE if
+ * it was already ignored.
+ */
+gboolean
+udisks_cleanup_ignore_loop (UDisksCleanup *cleanup,
+ const gchar *device_file)
+{
+ gboolean ret;
+
+ g_return_val_if_fail (UDISKS_IS_CLEANUP (cleanup), FALSE);
+ g_return_val_if_fail (device_file != NULL, FALSE);
+
+ g_mutex_lock (cleanup->lock);
+
+ ret = FALSE;
+
+ if (g_hash_table_lookup (cleanup->currently_deleting, device_file) != NULL)
+ goto out;
+
+ g_hash_table_insert (cleanup->currently_deleting, g_strdup (device_file), (gpointer) device_file);
+
+ ret = TRUE;
+
+ out:
+ g_mutex_unlock (cleanup->lock);
+ return ret;
+}
+
+/**
+ * udisks_cleanup_unignore_loop:
+ * @cleanup: A #UDisksCleanup.
+ * @device_file: A loop device file.
+ *
+ * Stops ignoring a loop device file previously ignored using
+ * udisks_cleanup_ignore_loop().
+ */
+void
+udisks_cleanup_unignore_loop (UDisksCleanup *cleanup,
+ const gchar *device_file)
+{
+ g_return_if_fail (UDISKS_IS_CLEANUP (cleanup));
+ g_return_if_fail (device_file != NULL);
+
+ g_mutex_lock (cleanup->lock);
+ g_warn_if_fail (g_hash_table_remove (cleanup->currently_deleting, device_file));
+ g_mutex_unlock (cleanup->lock);
+}
diff --git a/src/udiskscleanup.h b/src/udiskscleanup.h
index 5b0976e..0fe710a 100644
--- a/src/udiskscleanup.h
+++ b/src/udiskscleanup.h
@@ -76,6 +76,26 @@ gboolean udisks_cleanup_ignore_unlocked_luks (UDisksCleanup *cleanup
void udisks_cleanup_unignore_unlocked_luks (UDisksCleanup *cleanup,
dev_t cleartext_device);
+/* loop */
+
+gboolean udisks_cleanup_add_loop (UDisksCleanup *cleanup,
+ const gchar *device_file,
+ const gchar *backing_file,
+ dev_t backing_file_device,
+ uid_t uid,
+ GError **error);
+gboolean udisks_cleanup_remove_loop (UDisksCleanup *cleanup,
+ const gchar *device_file,
+ GError **error);
+gboolean udisks_cleanup_has_loop (UDisksCleanup *cleanup,
+ const gchar *device_file,
+ uid_t *out_uid,
+ GError **error);
+gboolean udisks_cleanup_ignore_loop (UDisksCleanup *cleanup,
+ const gchar *device);
+void udisks_cleanup_unignore_loop (UDisksCleanup *cleanup,
+ const gchar *device);
+
G_END_DECLS
#endif /* __UDISKS_CLEANUP_H__ */
diff --git a/src/udisksdaemonutil.c b/src/udisksdaemonutil.c
index 1f1b4a0..d685325 100644
--- a/src/udisksdaemonutil.c
+++ b/src/udisksdaemonutil.c
@@ -305,34 +305,47 @@ udisks_daemon_util_setup_by_user (UDisksDaemon *daemon,
UDisksBlockDevice *block;
UDisksCleanup *cleanup;
uid_t setup_by_user;
+ UDisksObject *crypto_object;
ret = FALSE;
cleanup = udisks_daemon_get_cleanup (daemon);
block = udisks_object_peek_block_device (object);
- if (block != NULL)
+ if (block == NULL)
+ goto out;
+
+ /* loop devices */
+ if (udisks_cleanup_has_loop (cleanup, udisks_block_device_get_device (block), &setup_by_user, NULL))
{
- UDisksObject *crypto_object;
- crypto_object = udisks_daemon_find_object (daemon, udisks_block_device_get_crypto_backing_device (block));
- if (crypto_object != NULL)
+ if (setup_by_user == user)
{
- UDisksBlockDevice *crypto_block;
- crypto_block = udisks_object_peek_block_device (crypto_object);
+ ret = TRUE;
+ goto out;
+ }
+ }
- if (udisks_cleanup_find_unlocked_luks (cleanup,
- makedev (udisks_block_device_get_major (crypto_block),
- udisks_block_device_get_minor (crypto_block)),
- &setup_by_user, NULL))
+ /* LUKS devices */
+ crypto_object = udisks_daemon_find_object (daemon, udisks_block_device_get_crypto_backing_device (block));
+ if (crypto_object != NULL)
+ {
+ UDisksBlockDevice *crypto_block;
+ crypto_block = udisks_object_peek_block_device (crypto_object);
+ if (udisks_cleanup_find_unlocked_luks (cleanup,
+ makedev (udisks_block_device_get_major (crypto_block),
+ udisks_block_device_get_minor (crypto_block)),
+ &setup_by_user, NULL))
+ {
+ if (setup_by_user == user)
{
- if (setup_by_user == user)
- {
- ret = TRUE;
- }
+ ret = TRUE;
+ g_object_unref (crypto_object);
+ goto out;
}
- g_object_unref (crypto_object);
}
+ g_object_unref (crypto_object);
}
+ out:
return ret;
}
diff --git a/src/udiskslinuxencrypted.c b/src/udiskslinuxencrypted.c
index a10d5fa..41c4edd 100644
--- a/src/udiskslinuxencrypted.c
+++ b/src/udiskslinuxencrypted.c
@@ -204,7 +204,8 @@ handle_unlock (UDisksEncrypted *encrypted,
/* Now, check that the user is actually authorized to unlock the device.
*/
action_id = "org.freedesktop.udisks2.encrypted-unlock";
- if (udisks_block_device_get_hint_system (block))
+ if (udisks_block_device_get_hint_system (block) &&
+ !(udisks_daemon_util_setup_by_user (daemon, object, caller_uid)))
action_id = "org.freedesktop.udisks2.encrypted-unlock-system";
if (!udisks_daemon_util_check_authorization_sync (daemon,
object,
@@ -397,9 +398,6 @@ handle_lock (UDisksEncrypted *encrypted,
goto out;
}
- udisks_debug ("cleartext_device_from_file=%d:%d caller_uid=%d unlocked_by_uid=%d",
- major (cleartext_device_from_file), minor (cleartext_device_from_file), caller_uid, unlocked_by_uid);
-
/* Check that the user is authorized to lock the device - if he
* already unlocked it, he is implicitly authorized...
*/
diff --git a/src/udiskslinuxfilesystem.c b/src/udiskslinuxfilesystem.c
index 121cbc8..553bd6a 100644
--- a/src/udiskslinuxfilesystem.c
+++ b/src/udiskslinuxfilesystem.c
@@ -776,7 +776,8 @@ handle_mount (UDisksFilesystem *filesystem,
* may be racing with other threads...
*/
action_id = "org.freedesktop.udisks2.filesystem-mount";
- if (udisks_block_device_get_hint_system (block) && !(udisks_daemon_util_setup_by_user (daemon, object, caller_uid)))
+ if (udisks_block_device_get_hint_system (block) &&
+ !(udisks_daemon_util_setup_by_user (daemon, object, caller_uid)))
action_id = "org.freedesktop.udisks2.filesystem-mount-system";
if (!udisks_daemon_util_check_authorization_sync (daemon,
object,
diff --git a/src/udiskslinuxloop.c b/src/udiskslinuxloop.c
index b54d4a0..d32281b 100644
--- a/src/udiskslinuxloop.c
+++ b/src/udiskslinuxloop.c
@@ -107,8 +107,10 @@ handle_delete (UDisksLoop *loop,
UDisksObject *object;
UDisksBlockDevice *block;
UDisksDaemon *daemon;
+ UDisksCleanup *cleanup;
gchar *error_message;
gchar *escaped_device;
+ GError *error;
object = NULL;
daemon = NULL;
@@ -118,6 +120,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));
+ cleanup = udisks_daemon_get_cleanup (daemon);
if (!udisks_daemon_util_check_authorization_sync (daemon,
object,
@@ -129,6 +132,16 @@ handle_delete (UDisksLoop *loop,
escaped_device = g_strescape (udisks_block_device_get_device (block), NULL);
+ if (!udisks_cleanup_ignore_loop (cleanup, udisks_block_device_get_device (block)))
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_ALREADY_UNMOUNTING,
+ "Cannot delete %s as it's currently being deleted",
+ udisks_block_device_get_device (block));
+ goto out;
+ }
+
if (!udisks_daemon_launch_spawned_job_sync (daemon,
NULL, /* GCancellable */
&error_message,
@@ -136,6 +149,7 @@ handle_delete (UDisksLoop *loop,
"losetup -d \"%s\"",
escaped_device))
{
+ udisks_cleanup_unignore_loop (cleanup, udisks_block_device_get_device (block));
g_dbus_method_invocation_return_error (invocation,
UDISKS_ERROR,
UDISKS_ERROR_FAILED,
@@ -145,6 +159,35 @@ handle_delete (UDisksLoop *loop,
goto out;
}
+ error = NULL;
+ if (!udisks_cleanup_remove_loop (cleanup, udisks_block_device_get_device (block), &error))
+ {
+ if (error == NULL)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error removing entry for `%s' from loop file: Entry not found",
+ udisks_block_device_get_device (block));
+
+ }
+ else
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR,
+ UDISKS_ERROR_FAILED,
+ "Error removing entry for `%s' from loop file: %s (%s, %d)",
+ udisks_block_device_get_device (block),
+ error->message,
+ g_quark_to_string (error->domain),
+ error->code);
+ g_error_free (error);
+ }
+ udisks_cleanup_unignore_loop (cleanup, udisks_block_device_get_device (block));
+ goto out;
+ }
+ udisks_cleanup_unignore_loop (cleanup, udisks_block_device_get_device (block));
+
udisks_notice ("Deleted loop device %s (was backed by %s)",
udisks_block_device_get_device (block),
udisks_loop_get_backing_file (loop));
diff --git a/src/udiskslinuxmanager.c b/src/udiskslinuxmanager.c
index 28ca63d..344e483 100644
--- a/src/udiskslinuxmanager.c
+++ b/src/udiskslinuxmanager.c
@@ -40,6 +40,7 @@
#include "udiskslinuxmanager.h"
#include "udisksdaemon.h"
#include "udisksdaemonutil.h"
+#include "udiskscleanup.h"
/**
* SECTION:udiskslinuxmanager
@@ -202,22 +203,35 @@ udisks_linux_manager_get_daemon (UDisksLinuxManager *manager)
/* ---------------------------------------------------------------------------------------------------- */
+typedef struct
+{
+ const gchar *loop_device;
+ const gchar *path;
+} WaitForLoopData;
+
static gboolean
wait_for_loop_object (UDisksDaemon *daemon,
UDisksObject *object,
gpointer user_data)
{
- const gchar *loop_device = user_data;
+ WaitForLoopData *data = user_data;
UDisksBlockDevice *block;
+ UDisksLoop *loop;
gboolean ret;
ret = FALSE;
block = udisks_object_peek_block_device (object);
- if (block == NULL)
+ loop = udisks_object_peek_loop (object);
+ if (block == NULL || loop == NULL)
goto out;
- if (g_strcmp0 (udisks_block_device_get_device (block), loop_device) == 0)
- ret = TRUE;
+ if (g_strcmp0 (udisks_block_device_get_device (block), data->loop_device) != 0)
+ goto out;
+
+ if (g_strcmp0 (udisks_loop_get_backing_file (loop), data->path) != 0)
+ goto out;
+
+ ret = TRUE;
out:
return ret;
@@ -251,6 +265,10 @@ handle_loop_setup (UDisksManager *object,
gboolean option_read_only;
guint64 option_offset;
guint64 option_size;
+ uid_t caller_uid;
+ struct stat fd_statbuf;
+ struct stat path_statbuf;
+ WaitForLoopData wait_data;
fd = -1;
loop_fd = -1;
@@ -260,6 +278,15 @@ handle_loop_setup (UDisksManager *object,
option_offset = 0;
option_size = 0;
+ /* we need the uid of the caller for the loop file */
+ error = NULL;
+ if (!udisks_daemon_util_get_caller_uid_sync (manager->daemon, invocation, NULL /* GCancellable */, &caller_uid, &error))
+ {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ goto out;
+ }
+
/* Check if the user is authorized to manage loop devices */
if (!udisks_daemon_util_check_authorization_sync (manager->daemon,
NULL,
@@ -305,9 +332,31 @@ handle_loop_setup (UDisksManager *object,
g_variant_lookup (options, "offset", "t", &option_offset);
g_variant_lookup (options, "size", "t", &option_size);
- /* TODO: maybe validate that st_ino and st_dev from fstat(fd) are
- * the same as for stat(path)
+ /* Validate that st_ino and st_dev from fstat(fd) are the same as
+ * for stat(path)
*/
+ if (fstat (fd, &fd_statbuf) != 0)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR, UDISKS_ERROR_FAILED,
+ "Error statting fd: %m");
+ goto out;
+ }
+ if (stat (path, &path_statbuf) != 0)
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR, UDISKS_ERROR_FAILED,
+ "Error statting path: %m");
+ goto out;
+ }
+ if ((fd_statbuf.st_ino != path_statbuf.st_ino) ||
+ (fd_statbuf.st_dev != path_statbuf.st_dev))
+ {
+ g_dbus_method_invocation_return_error (invocation,
+ UDISKS_ERROR, UDISKS_ERROR_FAILED,
+ "stat(2) info for path and fd does not agree");
+ goto out;
+ }
/* TODO: we will soon have API to create loop devices on
* demand... once that is in place we can nuke this silly
@@ -351,9 +400,11 @@ handle_loop_setup (UDisksManager *object,
/* Determine the resulting object */
error = NULL;
+ wait_data.loop_device = loop_device;
+ wait_data.path = path;
loop_object = udisks_daemon_wait_for_object_sync (manager->daemon,
wait_for_loop_object,
- loop_device,
+ &wait_data,
NULL,
10, /* timeout_seconds */
&error);
@@ -366,6 +417,15 @@ handle_loop_setup (UDisksManager *object,
goto out;
}
+ /* update the loop file */
+ if (!udisks_cleanup_add_loop (udisks_daemon_get_cleanup (manager->daemon),
+ loop_device,
+ path,
+ fd_statbuf.st_dev,
+ caller_uid,
+ &error))
+ goto out;
+
udisks_notice ("Set up loop device %s (backed by %s)",
loop_device,
path);