diff options
author | David Zeuthen <davidz@redhat.com> | 2011-07-23 13:13:45 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2011-07-23 13:13:45 -0400 |
commit | 9df40b766a92a3a39c78476278d6b0e0f741e88b (patch) | |
tree | 576bca4e5aaaf47acaab620f176ddadf8088f670 | |
parent | cc375e9e3890c68669771f8aefa674be1757c66f (diff) |
Track loop devices set up in /run/udisks2/loop
Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r-- | doc/udisks2-sections.txt | 5 | ||||
-rw-r--r-- | src/udiskscleanup.c | 429 | ||||
-rw-r--r-- | src/udiskscleanup.h | 20 | ||||
-rw-r--r-- | src/udisksdaemonutil.c | 43 | ||||
-rw-r--r-- | src/udiskslinuxencrypted.c | 6 | ||||
-rw-r--r-- | src/udiskslinuxfilesystem.c | 3 | ||||
-rw-r--r-- | src/udiskslinuxloop.c | 43 | ||||
-rw-r--r-- | src/udiskslinuxmanager.c | 74 |
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); |