diff options
author | David Zeuthen <davidz@redhat.com> | 2009-10-23 22:12:22 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2009-10-23 22:12:22 -0400 |
commit | a95d351dcae957e36b1cd3c7c6c1a784de65dcf8 (patch) | |
tree | 4180bfce6a87bd137374bc40d07daba2da41e99a | |
parent | d265ec7132e50dab067fafcf0a10d8bf3d2e235c (diff) |
Various device-mapper and cryptsetup fixes
-rw-r--r-- | data/95-devkit-disks.rules | 6 | ||||
-rw-r--r-- | src/devkit-disks-device.c | 183 |
2 files changed, 125 insertions, 64 deletions
diff --git a/data/95-devkit-disks.rules b/data/95-devkit-disks.rules index e383e6c..f49eba9 100644 --- a/data/95-devkit-disks.rules +++ b/data/95-devkit-disks.rules @@ -3,12 +3,16 @@ # we only care about block devices ACTION!="add|change", GOTO="devkit_disks_end" SUBSYSTEM!="block", GOTO="devkit_disks_end" KERNEL=="loop*|ram*", GOTO="devkit_disks_end" +# we only care about change events on device-mapper +# devices - never touch the device on add events +KERNEL=="dm-*", ACTION!="change", GOTO="devkit_disks_end" + ############################################################################################################## # Probe for partition tables; this really should be part of udev # # skip rules for inappropriate block devices @@ -30,13 +34,13 @@ LABEL="probe_parttable_end" ############################################################################################################## # pick up device-mapper data; this REALLY should be done by rules installed # by the device-mapper package # KERNEL!="dm-*", GOTO="device_mapper_end" -ACTION!="add|change", GOTO="device_mapper_end" +ACTION!="change", GOTO="device_mapper_end" IMPORT{program}="devkit-disks-dm-export %M %m" ENV{DKD_DM_NAME}!="?*", GOTO="device_mapper_end" ENV{DKD_DM_STATE}=="SUSPENDED", GOTO="device_mapper_end" ENV{DKD_DM_TARGET_TYPES}=="|*error*", GOTO="device_mapper_end" diff --git a/src/devkit-disks-device.c b/src/devkit-disks-device.c index 5af03ce..8df2708 100644 --- a/src/devkit-disks-device.c +++ b/src/devkit-disks-device.c @@ -1122,13 +1122,13 @@ devkit_disks_device_finalize (GObject *object) g_return_if_fail (object != NULL); g_return_if_fail (DEVKIT_DISKS_IS_DEVICE (object)); device = DEVKIT_DISKS_DEVICE (object); g_return_if_fail (device->priv != NULL); - g_debug ("finalizing %s", device->priv->native_path); + /* g_debug ("finalizing %s", device->priv->native_path); */ g_object_unref (device->priv->d); g_object_unref (device->priv->daemon); g_free (device->priv->object_path); g_free (device->priv->native_path); @@ -2888,12 +2888,17 @@ update_info (DevkitDisksDevice *device) if (!g_udev_device_has_property (device->priv->d, "MAJOR") || !g_udev_device_has_property (device->priv->d, "MINOR")) { g_warning ("No major/minor for %s", device->priv->native_path); goto out; } + /* ignore dm devices that are not active */ + if (g_str_has_prefix (g_udev_device_get_name (device->priv->d), "dm-") && + g_udev_device_get_property (device->priv->d, "DKD_DM_STATE") == NULL) + goto out; + major = g_udev_device_get_property_as_int (device->priv->d, "MAJOR"); minor = g_udev_device_get_property_as_int (device->priv->d, "MINOR"); device->priv->dev = makedev (major, minor); devkit_disks_device_set_device_file (device, g_udev_device_get_device_file (device->priv->d)); if (device->priv->device_file == NULL) { @@ -3671,12 +3676,14 @@ struct Job { DBusGMethodInvocation *context; JobCompletedFunc job_completed_func; GPid pid; gpointer user_data; GDestroyNotify user_data_destroy_func; gboolean was_cancelled; + guint msec_sleep; + int status; int stderr_fd; GIOChannel *error_channel; guint error_channel_source_id; GString *error_string; @@ -3721,29 +3728,16 @@ job_free (Job *job) g_string_free (job->stdout_string, TRUE); g_free (job->stdin_str); g_free (job->job_id); g_free (job); } -static void -job_child_watch_cb (GPid pid, int status, gpointer user_data) +static gboolean +job_completed_in_idle (gpointer data) { - char *buf; - gsize buf_size; - Job *job = user_data; - - if (g_io_channel_read_to_end (job->error_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL) { - g_string_append_len (job->error_string, buf, buf_size); - g_free (buf); - } - if (g_io_channel_read_to_end (job->out_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL) { - g_string_append_len (job->stdout_string, buf, buf_size); - g_free (buf); - } - - g_print ("helper(pid %5d): completed with exit code %d\n", job->pid, WEXITSTATUS (status)); + Job *job = data; if (job->device != NULL && job->job_id != NULL) { job->device->priv->job_in_progress = FALSE; g_free (job->device->priv->job_id); job->device->priv->job_id = NULL; job->device->priv->job_initiated_by_uid = 0; @@ -3753,21 +3747,48 @@ job_child_watch_cb (GPid pid, int status, gpointer user_data) job->device->priv->job = NULL; } job->job_completed_func (job->context, job->device, job->was_cancelled, - status, + job->status, job->error_string->str, job->stdout_string->str, job->user_data); if (job->device != NULL && job->job_id != NULL) { emit_job_changed (job->device); } + job_free (job); + return FALSE; +} + +static void +job_child_watch_cb (GPid pid, int status, gpointer user_data) +{ + char *buf; + gsize buf_size; + Job *job = user_data; + + if (g_io_channel_read_to_end (job->error_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL) { + g_string_append_len (job->error_string, buf, buf_size); + g_free (buf); + } + if (g_io_channel_read_to_end (job->out_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL) { + g_string_append_len (job->stdout_string, buf, buf_size); + g_free (buf); + } + + g_print ("helper(pid %5d): completed with exit code %d\n", job->pid, WEXITSTATUS (status)); + + job->status = status; + + g_timeout_add (job->msec_sleep, + job_completed_in_idle, + job); } static void job_cancel (DevkitDisksDevice *device) { g_return_if_fail (device->priv->job != NULL); @@ -3901,12 +3922,13 @@ job_new (DBusGMethodInvocation *context, const char *job_id, gboolean is_cancellable, DevkitDisksDevice *device, char **argv, const char *stdin_str, JobCompletedFunc job_completed_func, + guint msec_sleep, gpointer user_data, GDestroyNotify user_data_destroy_func) { Job *job; gboolean ret; GError *error; @@ -3933,12 +3955,13 @@ job_new (DBusGMethodInvocation *context, job->stdout_fd = -1; job->stdin_fd = -1; job->stdin_str = g_strdup (stdin_str); job->stdin_cursor = job->stdin_str; job->stdout_string = g_string_sized_new (1024); job->job_id = g_strdup (job_id); + job->msec_sleep = msec_sleep; if (device != NULL && job_id != NULL) { g_free (job->device->priv->job_id); job->device->priv->job_id = g_strdup (job_id); } @@ -4658,12 +4681,13 @@ run_job: "FilesystemMount", FALSE, device, argv, NULL, filesystem_mount_completed_cb, + 0, filesystem_mount_data_new (mount_point, remove_dir_on_unmount), (GDestroyNotify) filesystem_mount_data_free)) { if (remove_dir_on_unmount) { devkit_disks_mount_file_remove (device->priv->device_file, mount_point); if (g_rmdir (mount_point) != 0) { g_warning ("Error removing dir in early mount error path: %m"); @@ -4843,12 +4867,13 @@ run_job: "FilesystemUnmount", FALSE, device, argv, NULL, filesystem_unmount_completed_cb, + 0, g_strdup (mount_path), g_free)) { goto out; } out: @@ -5033,12 +5058,13 @@ devkit_disks_device_filesystem_list_open_files_authorized_cb (DevkitDisksDaemon NULL, /* don't run this as a job */ FALSE, device, argv, NULL, filesystem_list_open_files_completed_cb, + 0, NULL, NULL)) { goto out; } out: @@ -5153,12 +5179,13 @@ devkit_disks_device_drive_eject_authorized_cb (DevkitDisksDaemon *daemon, "DriveEject", FALSE, device, argv, NULL, drive_eject_completed_cb, + 0, NULL, NULL)) { goto out; } out: @@ -5278,12 +5305,13 @@ devkit_disks_device_drive_detach_authorized_cb (DevkitDisksDaemon *daemon, "DriveDetach", FALSE, device, argv, NULL, drive_detach_completed_cb, + 0, NULL, NULL)) { goto out; } out: @@ -5393,12 +5421,13 @@ devkit_disks_device_filesystem_check_authorized_cb (DevkitDisksDaemon *daemo "FilesystemCheck", FALSE, device, argv, NULL, filesystem_check_completed_cb, + 0, NULL, NULL)) { goto out; } out: @@ -5535,12 +5564,13 @@ devkit_disks_device_partition_delete_authorized_cb (DevkitDisksDaemon *daemo "PartitionDelete", TRUE, device, argv, NULL, partition_delete_completed_cb, + 0, g_object_ref (enclosing_device), g_object_unref)) { goto out; } out: @@ -5853,12 +5883,13 @@ devkit_disks_device_filesystem_create_internal (DevkitDisksDevice *device, "LuksFormat", TRUE, device, argv, passphrase_stdin, filesystem_create_create_luks_device_completed_cb, + 0, mkfse_data, (GDestroyNotify) mkfse_data_unref)) { goto out; } goto out; @@ -5885,12 +5916,13 @@ devkit_disks_device_filesystem_create_internal (DevkitDisksDevice *device, "FilesystemCreate", TRUE, device, argv, options_for_stdin, filesystem_create_completed_cb, + 0, mkfs_data, (GDestroyNotify) mkfs_data_unref)) { goto out; } out: @@ -6333,12 +6365,13 @@ devkit_disks_device_partition_create_authorized_cb (DevkitDisksDaemon *daemo "PartitionCreate", TRUE, device, argv, NULL, partition_create_completed_cb, + 0, partition_create_data_new (context, device, offset, size, fstype, fsoptions), (GDestroyNotify) partition_create_data_unref)) { goto out; } out: @@ -6548,12 +6581,13 @@ devkit_disks_device_partition_modify_authorized_cb (DevkitDisksDaemon *daemo "PartitionModify", TRUE, device, argv, NULL, partition_modify_completed_cb, + 0, partition_modify_data_new (context, device, enclosing_device, type, label, flags), (GDestroyNotify) partition_modify_data_unref)) { goto out; } out: @@ -6788,12 +6822,13 @@ devkit_disks_device_partition_table_create_authorized_cb (DevkitDisksDaemon "PartitionTableCreate", TRUE, device, argv, NULL, partition_table_create_completed_cb, + 0, partition_table_create_data_new (context, device, scheme), (GDestroyNotify) partition_table_create_data_unref)) { goto out; } out: @@ -6852,12 +6887,13 @@ out: } typedef struct { int refcount; gulong device_added_signal_handler_id; + gulong device_changed_signal_handler_id; guint device_added_timeout_id; DBusGMethodInvocation *context; DevkitDisksDevice *device; UnlockEncryptionHookFunc hook_func; @@ -6899,67 +6935,68 @@ unlock_encryption_data_unref (UnlockEncryptionData *data) } } static void luks_unlock_device_added_cb (DevkitDisksDaemon *daemon, - const char *object_path, - gpointer user_data) + const char *object_path, + gpointer user_data) { UnlockEncryptionData *data = user_data; DevkitDisksDevice *device; /* check the device is a cleartext partition for us */ device = devkit_disks_daemon_local_find_by_object_path (daemon, object_path); if (device != NULL && device->priv->device_is_luks_cleartext && strcmp (device->priv->luks_cleartext_slave, data->device->priv->object_path) == 0) { + g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id); + g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id); + g_source_remove (data->device_added_timeout_id); + /* update and emit a Changed() signal on the holder since the luks-holder * property indicates the cleartext device */ update_info (data->device); drain_pending_changes (data->device, FALSE); if (data->hook_func != NULL) { data->hook_func (data->context, device, data->hook_user_data); } else { dbus_g_method_return (data->context, object_path); } - g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id); - g_source_remove (data->device_added_timeout_id); unlock_encryption_data_unref (data); } } static gboolean luks_unlock_device_not_seen_cb (gpointer user_data) { UnlockEncryptionData *data = user_data; + g_signal_handler_disconnect (data->device->priv->daemon, data->device_added_signal_handler_id); + g_signal_handler_disconnect (data->device->priv->daemon, data->device_changed_signal_handler_id); + throw_error (data->context, DEVKIT_DISKS_ERROR_FAILED, "Error unlocking device: timeout (10s) waiting for cleartext device to show up"); if (data->hook_func != NULL) { data->hook_func (data->context, NULL, data->hook_user_data); } - if (data->device_added_signal_handler_id > 0) - g_signal_handler_disconnect (data->device->priv->daemon, data->device_added_signal_handler_id); - unlock_encryption_data_unref (data); return FALSE; } -static gboolean -luks_unlock_start_waiting_for_cleartext_device (gpointer user_data) +static void +luks_unlock_start_waiting_for_cleartext_device (UnlockEncryptionData *data) { - UnlockEncryptionData *data = user_data; DevkitDisksDevice *cleartext_device; cleartext_device = find_cleartext_device (data->device); if (cleartext_device != NULL) { /* update and emit a Changed() signal on the holder since the luks-holder * property indicates the cleartext device @@ -6977,64 +7014,41 @@ luks_unlock_start_waiting_for_cleartext_device (gpointer user_data) } else { /* sit around wait for the cleartext device to appear */ data->device_added_signal_handler_id = g_signal_connect_after (data->device->priv->daemon, "device-added", (GCallback) luks_unlock_device_added_cb, data); + data->device_changed_signal_handler_id = g_signal_connect_after (data->device->priv->daemon, + "device-changed", + (GCallback) luks_unlock_device_added_cb, + data); /* set up timeout for error reporting if waiting failed */ - data->device_added_timeout_id = g_timeout_add (10 * 1000, + data->device_added_timeout_id = g_timeout_add (15 * 1000, luks_unlock_device_not_seen_cb, data); /* Note that the signal and timeout handlers share the ref to data - one will cancel the other */ } - - return FALSE; } static void luks_unlock_completed_cb (DBusGMethodInvocation *context, - DevkitDisksDevice *device, - gboolean job_was_cancelled, - int status, - const char *stderr, - const char *stdout, - gpointer user_data) + DevkitDisksDevice *device, + gboolean job_was_cancelled, + int status, + const char *stderr, + const char *stdout, + gpointer user_data) { UnlockEncryptionData *data = user_data; if (WEXITSTATUS (status) == 0 && !job_was_cancelled) { - /* yay, so it turns out /sbin/cryptsetup returns way too early; what happens is this - * - * - invoke /sbin/cryptsetup - * - temporary dm node with name temporary-cryptsetup-* appears. We ignore these, - * see above - * - temporary dm node removed - * - /sbin/cryptsetup returns with success (brings us here) - * - proper dm node appears - * - with the name we requested, e.g. devkit-disks-luks-uuid-%s-uid%d - * - proper dm node disappears - * - proper dm node reappears - * - * Obiviously /sbin/cryptsetup shouldn't return before the dm node we are - * looking for is really there. - * - * TODO: file a bug against /sbin/cryptsetup, probably fix it too. This probably - * involves fixing device-mapper as well - * - * CURRENT WORKAROUND: Basically, we just sleep two seconds before waiting for the - * cleartext device to appear. That way we can ignore the initial - * nodes. - */ - - g_timeout_add (2 * 1000, - luks_unlock_start_waiting_for_cleartext_device, - unlock_encryption_data_ref (data)); + luks_unlock_start_waiting_for_cleartext_device (unlock_encryption_data_ref (data)); } else { if (job_was_cancelled) { throw_error (context, DEVKIT_DISKS_ERROR_CANCELLED, "Job was cancelled"); @@ -7099,19 +7113,48 @@ devkit_disks_device_luks_unlock_internal (DevkitDisksDevice *device, argv[n++] = "cryptsetup"; argv[n++] = "luksOpen"; argv[n++] = device->priv->device_file; argv[n++] = luks_name; argv[n++] = NULL; + /* yay, so it turns out /sbin/cryptsetup returns way too early; what happens is this + * + * - invoke /sbin/cryptsetup + * - temporary dm node with name temporary-cryptsetup-* appears. We ignore these, + * see above + * - temporary dm node removed + * - /sbin/cryptsetup returns with success (brings us here) + * - proper dm node appears + * - with the name we requested, e.g. devkit-disks-luks-uuid-%s-uid%d + * - proper dm node disappears + * - proper dm node reappears + * + * Obiviously /sbin/cryptsetup shouldn't return before the dm node we are + * looking for is really there or ready to use. But that's not how things + * work. + * + * TODO: file a bug against /sbin/cryptsetup, probably fix it too. This probably + * involves fixing device-mapper as well + * + * CURRENT WORKAROUND: Basically, we just sleep 15 seconds before considering the + * job to be completed. That way we can ignore the initial + * nodes. + * + * davidz 10/23 2009: Bumped from 2 secs to 15 secs because + * cryptsetup-luks-1.1.0-0.1.fc12.x86_64 seems to require that.. + * on this system it apparently takes 9-10 seconds for things + * to settle. Annoying. + */ if (!job_new (context, "LuksUnlock", FALSE, device, argv, secret_as_stdin, luks_unlock_completed_cb, + 15 * 1000, /* see note above */ unlock_encryption_data_new (context, device, hook_func, hook_user_data), (GDestroyNotify) unlock_encryption_data_unref)) { goto out; } out: @@ -7391,12 +7434,13 @@ devkit_disks_device_luks_lock_authorized_cb (DevkitDisksDaemon *daemon, "LuksLock", FALSE, device, argv, NULL, luks_lock_completed_cb, + 0, lock_encryption_data_new (context, device, cleartext_device), (GDestroyNotify) lock_encryption_data_unref)) { goto out; } out: @@ -7527,12 +7571,13 @@ devkit_disks_device_luks_change_passphrase_authorized_cb (DevkitDisksDaemon "LuksChangePassphrase", FALSE, device, argv, secrets_as_stdin, luks_change_passphrase_completed_cb, + 0, NULL, NULL)) { goto out; } out: @@ -7665,12 +7710,13 @@ devkit_disks_device_filesystem_set_label_authorized_cb (DevkitDisksDaemon *d "FilesystemSetLabel", FALSE, device, argv, NULL, filesystem_set_label_completed_cb, + 0, g_strdup (new_label), g_free)) { goto out; } out: @@ -7888,12 +7934,13 @@ devkit_disks_device_drive_ata_smart_refresh_data_authorized_cb (DevkitDisksDaemo NULL, /* don't run this as a job */ FALSE, device, argv, NULL, drive_ata_smart_refresh_data_completed_cb, + 0, NULL, NULL)) { goto out; } out: @@ -8008,12 +8055,13 @@ devkit_disks_device_drive_ata_smart_initiate_selftest_authorized_cb (DevkitDisks job_name, TRUE, device, argv, NULL, drive_ata_smart_initiate_selftest_completed_cb, + 0, NULL, NULL)) { goto out; } out: @@ -8108,12 +8156,13 @@ devkit_disks_device_linux_md_stop_authorized_cb (DevkitDisksDaemon *daemon, "LinuxMdStop", TRUE, device, argv, NULL, linux_md_stop_completed_cb, + 0, NULL, NULL)) { goto out; } out: @@ -8229,12 +8278,13 @@ devkit_disks_device_linux_md_check_authorized_cb (DevkitDisksDaemon *daemon, job_name, TRUE, device, argv, NULL, linux_md_check_completed_cb, + 0, NULL, NULL)) { goto out; } out: @@ -8369,12 +8419,13 @@ devkit_disks_device_linux_md_add_component_authorized_cb (DevkitDisksDaemon "LinuxMdAddComponent", TRUE, device, argv, NULL, linux_md_add_component_completed_cb, + 0, g_object_ref (slave), g_object_unref)) { goto out; } out: @@ -8615,12 +8666,13 @@ devkit_disks_device_linux_md_remove_component_authorized_cb (DevkitDisksDaemon "LinuxMdRemoveComponent", TRUE, device, argv, NULL, linux_md_remove_component_completed_cb, + 0, remove_component_data_new (context, slave, options), (GDestroyNotify) remove_component_data_unref)) { goto out; } out: @@ -8942,12 +8994,13 @@ devkit_disks_daemon_linux_md_start_authorized_cb (DevkitDisksDaemon *daemon, "LinuxMdStart", TRUE, NULL, argv, NULL, linux_md_start_completed_cb, + 0, linux_md_start_data_new (context, daemon, uuid), (GDestroyNotify) linux_md_start_data_unref)) { goto out; } out: @@ -9303,12 +9356,13 @@ devkit_disks_daemon_linux_md_create_authorized_cb (DevkitDisksDaemon *daemon "LinuxMdCreate", TRUE, NULL, argv, NULL, linux_md_create_completed_cb, + 0, linux_md_create_data_new (context, daemon, components_as_strv[0]), (GDestroyNotify) linux_md_create_data_unref)) { goto out; } out: @@ -9429,12 +9483,13 @@ force_unmount (DevkitDisksDevice *device, "ForceUnmount", FALSE, device, argv, NULL, force_unmount_completed_cb, + 0, force_unmount_data_new (mount_path, callback, user_data), (GDestroyNotify) force_unmount_data_unref)) { g_warning ("Couldn't spawn unmount for force unmounting %s", mount_path); if (callback != NULL) callback (device, FALSE, user_data); } @@ -9529,12 +9584,13 @@ force_luks_teardown_cleartext_done (DevkitDisksDevice *device, "ForceLuksTeardown", FALSE, data->device, argv, NULL, force_luks_teardown_completed_cb, + 0, data, (GDestroyNotify) force_luks_teardown_data_unref)) { g_warning ("Couldn't spawn cryptsetup for force teardown for device %s", data->dm_name); if (data->fr_callback != NULL) data->fr_callback (data->device, FALSE, data->fr_user_data); @@ -9802,12 +9858,13 @@ devkit_disks_device_drive_poll_media_authorized_cb (DevkitDisksDaemon *daemo "DrivePollMedia", FALSE, device, argv, NULL, drive_poll_media_completed_cb, + 0, NULL, NULL)) { goto out; } out: |