84
84
static gboolean devkit_disks_device_local_partitions_are_busy (DevkitDisksDevice *device);
85
85
static gboolean devkit_disks_device_local_logical_partitions_are_busy (DevkitDisksDevice *device);
86
static gboolean devkit_disks_device_has_logical_partitions (DevkitDisksDevice *device);
88
89
static gboolean luks_get_uid_from_dm_name (const char *dm_name, uid_t *out_uid);
226
227
PROP_DRIVE_ATA_SMART_BLOB,
228
229
PROP_LINUX_MD_COMPONENT_LEVEL,
230
PROP_LINUX_MD_COMPONENT_POSITION,
229
231
PROP_LINUX_MD_COMPONENT_NUM_RAID_DEVICES,
230
232
PROP_LINUX_MD_COMPONENT_UUID,
231
233
PROP_LINUX_MD_COMPONENT_HOME_HOST,
564
566
case PROP_LINUX_MD_COMPONENT_LEVEL:
565
567
g_value_set_string (value, device->priv->linux_md_component_level);
569
case PROP_LINUX_MD_COMPONENT_POSITION:
570
g_value_set_int (value, device->priv->linux_md_component_position);
567
572
case PROP_LINUX_MD_COMPONENT_NUM_RAID_DEVICES:
568
573
g_value_set_int (value, device->priv->linux_md_component_num_raid_devices);
1014
1019
g_param_spec_string ("linux-md-component-level", NULL, NULL, NULL, G_PARAM_READABLE));
1015
1020
g_object_class_install_property (
1022
PROP_LINUX_MD_COMPONENT_POSITION,
1023
g_param_spec_int ("linux-md-component-position", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE));
1024
g_object_class_install_property (
1017
1026
PROP_LINUX_MD_COMPONENT_NUM_RAID_DEVICES,
1018
1027
g_param_spec_int ("linux-md-component-num-raid-devices", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE));
1019
1028
g_object_class_install_property (
1125
1134
device = DEVKIT_DISKS_DEVICE (object);
1126
1135
g_return_if_fail (device->priv != NULL);
1128
g_debug ("finalizing %s", device->priv->native_path);
1137
/* g_debug ("finalizing %s", device->priv->native_path); */
1130
1139
g_object_unref (device->priv->d);
1131
1140
g_object_unref (device->priv->daemon);
1284
1293
device->priv->object_path = compute_object_path (device->priv->native_path);
1286
1296
if (dbus_g_connection_lookup_g_object (device->priv->system_bus_connection,
1287
1297
device->priv->object_path) != NULL) {
1288
/* TODO: see devkit_disks_device_removed() for where we want to unregister the object but
1289
* we're missing the API. So do it manually here if we are forced to do so...
1292
g_print ("**** HACK: Wanting to register object at path `%s' but there is already an "
1293
"object there. Using a hack to move it out of the way.\n",
1298
g_error ("**** HACK: Wanting to register object at path `%s' but there is already an "
1299
"object there. This is an internal error in the daemon. Aborting.\n",
1294
1300
device->priv->object_path);
1296
dbus_connection_unregister_object_path (dbus_g_connection_get_connection (device->priv->system_bus_connection),
1297
device->priv->object_path);
1300
1303
dbus_g_connection_register_g_object (device->priv->system_bus_connection,
1624
1627
update_info_id (DevkitDisksDevice *device)
1626
1629
gchar *decoded_string;
1630
const gchar *partition_scheme;
1631
gint partition_type;
1633
partition_scheme = g_udev_device_get_property (device->priv->d, "DKD_PARTITION_SCHEME");
1634
partition_type = g_udev_device_get_property_as_int (device->priv->d, "DKD_PARTITION_TYPE");
1635
if (g_strcmp0 (partition_scheme, "mbr") == 0 &&
1636
(partition_type == 0x05 || partition_type == 0x0f || partition_type == 0x85)) {
1637
devkit_disks_device_set_id_usage (device, "");
1638
devkit_disks_device_set_id_type (device, "");
1639
devkit_disks_device_set_id_version (device, "");
1640
devkit_disks_device_set_id_label (device, "");
1641
devkit_disks_device_set_id_uuid (device, "");
1628
1645
devkit_disks_device_set_id_usage (device, g_udev_device_get_property (device->priv->d, "ID_FS_USAGE"));
1629
1646
devkit_disks_device_set_id_type (device, g_udev_device_get_property (device->priv->d, "ID_FS_TYPE"));
2278
2302
g_strstrip (state_contents);
2279
2303
state_tokens = g_strsplit (state_contents, ",", 0);
2305
slot_contents = sysfs_get_string (md_dev_path, "slot");
2306
g_strstrip (slot_contents);
2307
slot_number = strtol (slot_contents, &endp, 0);
2308
if (endp != NULL && *endp == '\0') {
2309
md_comp_position = slot_number;
2312
g_free (slot_contents);
2281
2313
g_free (state_contents);
2282
2314
g_free (md_dev_path);
2283
2315
g_free (dev_name);
2310
2342
md_comp_version = device->priv->id_version;
2312
2344
devkit_disks_device_set_linux_md_component_level (device, md_comp_level);
2345
devkit_disks_device_set_linux_md_component_position (device, md_comp_position);
2313
2346
devkit_disks_device_set_linux_md_component_num_raid_devices (device, md_comp_num_raid_devices);
2314
2347
devkit_disks_device_set_linux_md_component_uuid (device, md_comp_uuid);
2315
2348
devkit_disks_device_set_linux_md_component_home_host (device, md_comp_home_host);
2321
2354
devkit_disks_device_set_device_is_linux_md_component (device, FALSE);
2322
2355
devkit_disks_device_set_linux_md_component_level (device, NULL);
2356
devkit_disks_device_set_linux_md_component_position (device, -1);
2323
2357
devkit_disks_device_set_linux_md_component_num_raid_devices (device, 0);
2324
2358
devkit_disks_device_set_linux_md_component_uuid (device, NULL);
2325
2359
devkit_disks_device_set_linux_md_component_home_host (device, NULL);
2832
2866
/* ---------------------------------------------------------------------------------------------------- */
2870
DevkitDisksDevice *device;
2871
} UpdateInfoInIdleData;
2874
update_info_in_idle_device_unreffed (gpointer user_data,
2875
GObject *where_the_object_was)
2877
UpdateInfoInIdleData *data = user_data;
2878
g_source_remove (data->idle_id);
2882
update_info_in_idle_data_free (UpdateInfoInIdleData *data)
2884
g_object_weak_unref (G_OBJECT (data->device),
2885
update_info_in_idle_device_unreffed,
2891
update_info_in_idle_cb (gpointer user_data)
2893
UpdateInfoInIdleData *data = user_data;
2895
/* this indirectly calls update_info and also removes the device
2896
* if it wants to be removed (e.g. if update_info() returns FALSE)
2898
devkit_disks_daemon_local_synthesize_changed (data->device->priv->daemon, data->device);
2900
return FALSE; /* remove source */
2904
* update_info_in_idle:
2905
* @device: A #DevkitDisksDevice.
2907
* Like update_info() but does the update in idle. Takes a weak ref to
2908
* @device and cancels the update if @device is unreffed.
2911
update_info_in_idle (DevkitDisksDevice *device)
2913
UpdateInfoInIdleData *data;
2915
data = g_new0 (UpdateInfoInIdleData, 1);
2916
data->device = device;
2917
data->idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
2918
update_info_in_idle_cb,
2920
(GDestroyNotify) update_info_in_idle_data_free);
2922
g_object_weak_ref (G_OBJECT (device),
2923
update_info_in_idle_device_unreffed,
2836
2929
* @device: the device
2987
/* ignore dm devices that are not active */
2988
if (g_str_has_prefix (g_udev_device_get_name (device->priv->d), "dm-") &&
2989
g_udev_device_get_property (device->priv->d, "DKD_DM_STATE") == NULL)
2894
2992
major = g_udev_device_get_property_as_int (device->priv->d, "MAJOR");
2895
2993
minor = g_udev_device_get_property_as_int (device->priv->d, "MINOR");
2896
2994
device->priv->dev = makedev (major, minor);
3172
3270
* We have to do this because the kernel doesn't generate any 'change' event
3173
3271
* when slaves/ or holders/ change. This is unfortunate because we *need* such
3174
3272
* a change event to update properties devices (for example: luks_holder).
3274
* We do the update in idle because the update may depend on the device
3275
* currently being processed being added.
3177
3278
cur_slaves_objpath = dup_list_from_ptrarray (device->priv->slaves_objpath);
3192
3293
//g_debug ("### %s added slave %s", device->priv->object_path, objpath2);
3193
3294
device2 = devkit_disks_daemon_local_find_by_object_path (device->priv->daemon, objpath2);
3194
3295
if (device2 != NULL) {
3195
update_info (device2);
3296
update_info_in_idle (device2);
3197
3298
g_print ("**** NOTE: %s added non-existant slave %s\n", device->priv->object_path, objpath2);
3204
3305
//g_debug ("### %s removed slave %s", device->priv->object_path, objpath2);
3205
3306
device2 = devkit_disks_daemon_local_find_by_object_path (device->priv->daemon, objpath2);
3206
3307
if (device2 != NULL) {
3207
update_info (device2);
3308
update_info_in_idle (device2);
3209
3310
//g_debug ("### %s removed non-existant slave %s", device->priv->object_path, objpath2);
3222
3323
//g_debug ("### %s added holder %s", device->priv->object_path, objpath2);
3223
3324
device2 = devkit_disks_daemon_local_find_by_object_path (device->priv->daemon, objpath2);
3224
3325
if (device2 != NULL) {
3225
update_info (device2);
3326
update_info_in_idle (device2);
3227
3328
g_print ("**** NOTE: %s added non-existant holder %s\n", device->priv->object_path, objpath2);
3234
3335
//g_debug ("### %s removed holder %s", device->priv->object_path, objpath2);
3235
3336
device2 = devkit_disks_daemon_local_find_by_object_path (device->priv->daemon, objpath2);
3236
3337
if (device2 != NULL) {
3237
update_info (device2);
3338
update_info_in_idle (device2);
3239
3340
//g_debug ("### %s removed non-existant holder %s", device->priv->object_path, objpath2);
3502
devkit_disks_device_has_logical_partitions (DevkitDisksDevice *device)
3510
devices = devkit_disks_daemon_local_get_all_devices (device->priv->daemon);
3511
for (l = devices; l != NULL; l = l->next) {
3512
DevkitDisksDevice *d = DEVKIT_DISKS_DEVICE (l->data);
3514
if (d->priv->device_is_partition &&
3515
d->priv->partition_slave != NULL &&
3516
g_strcmp0 (d->priv->partition_slave, device->priv->object_path) == 0 &&
3517
g_strcmp0 (d->priv->partition_scheme, "mbr") == 0 &&
3518
d->priv->partition_number >= 5) {
3524
g_list_free (devices);
3401
3530
devkit_disks_device_removed (DevkitDisksDevice *device)
3405
3534
device->priv->removed = TRUE;
3407
/* TODO: this is in a yet to be released version of dbus-glib, use it when available
3409
3536
dbus_g_connection_unregister_g_object (device->priv->system_bus_connection,
3410
3537
G_OBJECT (device));
3538
g_assert (dbus_g_connection_lookup_g_object (device->priv->system_bus_connection,
3539
device->priv->object_path) == NULL);
3413
3541
/* device is now removed; update all slaves and holders */
3414
3542
for (n = 0; n < device->priv->slaves_objpath->len; n++) {
3728
job_child_watch_cb (GPid pid, int status, gpointer user_data)
3858
job_complete (Job *job)
3732
Job *job = user_data;
3734
if (g_io_channel_read_to_end (job->error_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL) {
3735
g_string_append_len (job->error_string, buf, buf_size);
3738
if (g_io_channel_read_to_end (job->out_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL) {
3739
g_string_append_len (job->stdout_string, buf, buf_size);
3743
g_print ("helper(pid %5d): completed with exit code %d\n", job->pid, WEXITSTATUS (status));
3745
3860
if (job->device != NULL && job->job_id != NULL) {
3746
3861
job->device->priv->job_in_progress = FALSE;
3747
3862
g_free (job->device->priv->job_id);
3764
3879
if (job->device != NULL && job->job_id != NULL) {
3765
3880
emit_job_changed (job->device);
3767
3883
job_free (job);
3887
job_udevadm_settle_child_cb (GPid pid,
3891
Job *job = user_data;
3896
job_child_watch_cb (GPid pid, int status, gpointer user_data)
3900
Job *job = user_data;
3902
if (g_io_channel_read_to_end (job->error_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL) {
3903
g_string_append_len (job->error_string, buf, buf_size);
3906
if (g_io_channel_read_to_end (job->out_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL) {
3907
g_string_append_len (job->stdout_string, buf, buf_size);
3911
g_print ("helper(pid %5d): completed with exit code %d\n", job->pid, WEXITSTATUS (status));
3913
job->status = status;
3915
/* if requested, run 'udevadm settle' on success */
3916
if (!job->was_cancelled && WIFEXITED (status) && WEXITSTATUS (status) == 0 && job->udev_settle) {
3918
gchar *argv[] = {"udevadm", "settle", "--quiet", NULL};
3922
if (!g_spawn_async (NULL,
3925
G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
3930
g_warning ("Error running 'udevadm settle --quiet': %s", error->message);
3931
g_error_free (error);
3935
g_child_watch_add (udevadm_pid,
3936
job_udevadm_settle_child_cb,
3940
/* return immediately on error */
3771
3946
job_cancel (DevkitDisksDevice *device)
3773
3948
g_return_if_fail (device->priv->job != NULL);
3936
4112
job->stdin_cursor = job->stdin_str;
3937
4113
job->stdout_string = g_string_sized_new (1024);
3938
4114
job->job_id = g_strdup (job_id);
4115
job->udev_settle = udev_settle;
3940
4117
if (device != NULL && job_id != NULL) {
3941
4118
g_free (job->device->priv->job_id);
4445
4622
throw_error (context,
4446
4623
DEVKIT_DISKS_ERROR_CANCELLED,
4447
4624
"Job was cancelled");
4625
} else if (WEXITSTATUS (status) == 32) {
4626
throw_error (context,
4627
DEVKIT_DISKS_ERROR_FILESYSTEM_DRIVER_MISSING ,
4628
"Error mounting: %s",
4449
4631
throw_error (context,
4450
4632
DEVKIT_DISKS_ERROR_FAILED,
4663
4845
filesystem_mount_completed_cb,
4664
4847
filesystem_mount_data_new (mount_point, remove_dir_on_unmount),
4665
4848
(GDestroyNotify) filesystem_mount_data_free)) {
4666
4849
if (remove_dir_on_unmount) {
5701
/* don't allow deleting an extended partition if we have any logical partitions */
5702
partition_scheme = g_udev_device_get_property (device->priv->d, "DKD_PARTITION_SCHEME");
5703
partition_type = g_udev_device_get_property_as_int (device->priv->d, "DKD_PARTITION_TYPE");
5704
if (g_strcmp0 (partition_scheme, "mbr") == 0 &&
5705
(partition_type == 0x05 || partition_type == 0x0f || partition_type == 0x85)) {
5706
if (devkit_disks_device_has_logical_partitions (enclosing_device)) {
5707
throw_error (context,
5708
DEVKIT_DISKS_ERROR_FAILED,
5709
"Cannot delete extended partition while logical partitions exist");
5511
5714
offset_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", device->priv->partition_offset);
5512
5715
size_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", device->priv->partition_size);
5513
5716
part_number_as_string = g_strdup_printf ("%d", device->priv->partition_number);
5605
5809
throw_error (context,
5606
5810
DEVKIT_DISKS_ERROR_CANCELLED,
5607
5811
"Job was cancelled");
5812
} else if (WEXITSTATUS (status) == 3) {
5813
throw_error (context,
5814
DEVKIT_DISKS_ERROR_FILESYSTEM_TOOLS_MISSING ,
5815
"Error creating file system: Cannot run mkfs: %s",
5609
5818
throw_error (context,
5610
5819
DEVKIT_DISKS_ERROR_FAILED,
6338
6549
partition_create_completed_cb,
6339
6551
partition_create_data_new (context, device, offset, size, fstype, fsoptions),
6340
6552
(GDestroyNotify) partition_create_data_unref)) {
6553
6765
partition_modify_completed_cb,
6554
6767
partition_modify_data_new (context, device, enclosing_device, type, label, flags),
6555
6768
(GDestroyNotify) partition_modify_data_unref)) {
6764
if (g_strcmp0 (device->priv->partition_table_scheme, scheme) == 0) {
6765
throw_error (context,
6766
DEVKIT_DISKS_ERROR_FAILED,
6767
"device already has a partition table of given scheme");
6772
6978
argv[n++] = PACKAGE_LIBEXEC_DIR "/devkit-disks-helper-create-partition-table";
6773
6979
argv[n++] = device->priv->device_file;
6915
7123
device->priv->device_is_luks_cleartext &&
6916
7124
strcmp (device->priv->luks_cleartext_slave, data->device->priv->object_path) == 0) {
7126
g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
7127
g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
7128
g_source_remove (data->device_added_timeout_id);
6918
7130
/* update and emit a Changed() signal on the holder since the luks-holder
6919
7131
* property indicates the cleartext device
6927
7139
dbus_g_method_return (data->context, object_path);
6930
g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
6931
g_source_remove (data->device_added_timeout_id);
6932
7142
unlock_encryption_data_unref (data);
6939
7149
UnlockEncryptionData *data = user_data;
7151
g_signal_handler_disconnect (data->device->priv->daemon, data->device_added_signal_handler_id);
7152
g_signal_handler_disconnect (data->device->priv->daemon, data->device_changed_signal_handler_id);
6941
7154
throw_error (data->context,
6942
7155
DEVKIT_DISKS_ERROR_FAILED,
6943
7156
"Error unlocking device: timeout (10s) waiting for cleartext device to show up");
6946
7159
data->hook_func (data->context, NULL, data->hook_user_data);
6949
if (data->device_added_signal_handler_id > 0)
6950
g_signal_handler_disconnect (data->device->priv->daemon, data->device_added_signal_handler_id);
6952
7162
unlock_encryption_data_unref (data);
6957
luks_unlock_start_waiting_for_cleartext_device (gpointer user_data)
7167
luks_unlock_start_waiting_for_cleartext_device (UnlockEncryptionData *data)
6959
UnlockEncryptionData *data = user_data;
6960
7169
DevkitDisksDevice *cleartext_device;
6962
7171
cleartext_device = find_cleartext_device (data->device);
6980
7189
"device-added",
6981
7190
(GCallback) luks_unlock_device_added_cb,
7192
data->device_changed_signal_handler_id = g_signal_connect_after (data->device->priv->daemon,
7194
(GCallback) luks_unlock_device_added_cb,
6984
7197
/* set up timeout for error reporting if waiting failed */
6985
data->device_added_timeout_id = g_timeout_add (10 * 1000,
7198
data->device_added_timeout_id = g_timeout_add (15 * 1000,
6986
7199
luks_unlock_device_not_seen_cb,
6989
7202
/* Note that the signal and timeout handlers share the ref to data - one will cancel the other */
6997
7208
luks_unlock_completed_cb (DBusGMethodInvocation *context,
6998
DevkitDisksDevice *device,
6999
gboolean job_was_cancelled,
7209
DevkitDisksDevice *device,
7210
gboolean job_was_cancelled,
7005
7216
UnlockEncryptionData *data = user_data;
7007
7218
if (WEXITSTATUS (status) == 0 && !job_was_cancelled) {
7009
/* yay, so it turns out /sbin/cryptsetup returns way too early; what happens is this
7011
* - invoke /sbin/cryptsetup
7012
* - temporary dm node with name temporary-cryptsetup-* appears. We ignore these,
7014
* - temporary dm node removed
7015
* - /sbin/cryptsetup returns with success (brings us here)
7016
* - proper dm node appears
7017
* - with the name we requested, e.g. devkit-disks-luks-uuid-%s-uid%d
7018
* - proper dm node disappears
7019
* - proper dm node reappears
7021
* Obiviously /sbin/cryptsetup shouldn't return before the dm node we are
7022
* looking for is really there.
7024
* TODO: file a bug against /sbin/cryptsetup, probably fix it too. This probably
7025
* involves fixing device-mapper as well
7027
* CURRENT WORKAROUND: Basically, we just sleep two seconds before waiting for the
7028
* cleartext device to appear. That way we can ignore the initial
7032
g_timeout_add (2 * 1000,
7033
luks_unlock_start_waiting_for_cleartext_device,
7034
unlock_encryption_data_ref (data));
7220
luks_unlock_start_waiting_for_cleartext_device (unlock_encryption_data_ref (data));
7037
7223
if (job_was_cancelled) {
7099
7285
argv[n++] = "cryptsetup";
7100
7288
argv[n++] = "luksOpen";
7101
7289
argv[n++] = device->priv->device_file;
7102
7290
argv[n++] = luks_name;
7103
7291
argv[n++] = NULL;
7293
/* yay, so it turns out /sbin/cryptsetup returns way too early; what happens is this
7295
* - invoke /sbin/cryptsetup
7296
* - temporary dm node with name temporary-cryptsetup-* appears. We ignore these,
7298
* - temporary dm node removed
7299
* - /sbin/cryptsetup returns with success (brings us here)
7300
* - proper dm node appears
7301
* - with the name we requested, e.g. devkit-disks-luks-uuid-%s-uid%d
7302
* - proper dm node disappears
7303
* - proper dm node reappears
7305
* Obiviously /sbin/cryptsetup shouldn't return before the dm node we are
7306
* looking for is really there or ready to use. But that's not how things
7309
* This bug has been reported here:
7311
* https://bugzilla.redhat.com/show_bug.cgi?id=530721
7313
* WORKAROUND: wait for the udev queue to settle before returning. Long
7314
* term fix is device-mapper/udev integration.
7105
7316
if (!job_new (context,
7110
7321
secret_as_stdin,
7111
7322
luks_unlock_completed_cb,
7323
TRUE, /* see note above */
7112
7324
unlock_encryption_data_new (context, device, hook_func, hook_user_data),
7113
7325
(GDestroyNotify) unlock_encryption_data_unref)) {
7482
7695
throw_error (context,
7483
7696
DEVKIT_DISKS_ERROR_CANCELLED,
7484
7697
"Job was cancelled");
7698
} else if (WEXITSTATUS (status) == 3) {
7699
throw_error (context,
7700
DEVKIT_DISKS_ERROR_FILESYSTEM_TOOLS_MISSING ,
7701
"Error changing fs label: tool not available: %s",
7486
7704
throw_error (context,
7487
7705
DEVKIT_DISKS_ERROR_FAILED,
9297
9524
argv[n++] = NULL;
9299
for (m = 0; argv[m] != NULL; m++)
9300
g_debug ("arg[%d] = `%s'", m, argv[m]);
9526
//for (m = 0; argv[m] != NULL; m++)
9527
// g_debug ("arg[%d] = `%s'", m, argv[m]);
9302
9529
if (!job_new (context,
9303
9530
"LinuxMdCreate",
9434
9662
force_unmount_completed_cb,
9435
9664
force_unmount_data_new (mount_path, callback, user_data),
9436
9665
(GDestroyNotify) force_unmount_data_unref)) {
9437
9666
g_warning ("Couldn't spawn unmount for force unmounting %s", mount_path);