1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
3
* Copyright (C) 2008 David Zeuthen <david@fubar.dk>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31
#include <sys/types.h>
35
#include <sys/resource.h>
41
#include <sys/ioctl.h>
42
#include <linux/cdrom.h>
43
#include <linux/loop.h>
46
#include <glib/gstdio.h>
47
#include <glib/gi18n-lib.h>
48
#include <glib-object.h>
49
#include <gio/gunixmounts.h>
50
#include <dbus/dbus-glib.h>
51
#include <dbus/dbus-glib-lowlevel.h>
52
#include <gudev/gudev.h>
57
#include "device-private.h"
60
#include "mount-monitor.h"
61
#include "mount-file.h"
62
#include "inhibitor.h"
69
/*--------------------------------------------------------------------------------------------------------------*/
70
#include "device-glue.h"
72
static void device_class_init (DeviceClass *klass);
73
static void device_init (Device *seat);
74
static void device_finalize (GObject *object);
76
static void polling_inhibitor_disconnected_cb (Inhibitor *inhibitor,
79
static void spindown_inhibitor_disconnected_cb (Inhibitor *inhibitor,
82
static gboolean update_info (Device *device);
83
static void update_info_in_idle (Device *device);
85
static void drain_pending_changes (Device *device,
86
gboolean force_update);
88
static gboolean device_local_is_busy (Device *device,
89
gboolean check_partitions,
90
gboolean check_mounted,
93
static gboolean device_local_partitions_are_busy (Device *device);
94
static gboolean device_local_logical_partitions_are_busy (Device *device);
95
static gboolean device_has_logical_partitions (Device *device);
97
static gboolean luks_get_uid_from_dm_name (const char *dm_name,
100
/* Returns the cleartext device. If device==NULL, unlocking failed and an error has
101
* been reported back to the caller
103
typedef void (*UnlockEncryptionHookFunc) (DBusGMethodInvocation *context,
107
static gboolean device_luks_unlock_internal (Device *device,
110
UnlockEncryptionHookFunc hook_func,
111
gpointer hook_user_data,
112
DBusGMethodInvocation *context);
114
/* if filesystem_create_succeeded==FALSE, mkfs failed and an error has been reported back to the caller */
115
typedef void (*FilesystemCreateHookFunc) (DBusGMethodInvocation *context,
117
gboolean filesystem_create_succeeded,
120
static gboolean device_filesystem_create_internal (Device *device,
123
FilesystemCreateHookFunc hook_func,
124
gpointer hook_user_data,
125
DBusGMethodInvocation *context);
127
typedef void (*ForceRemovalCompleteFunc) (Device *device,
131
static void force_removal (Device *device,
132
ForceRemovalCompleteFunc callback,
135
static void force_unmount (Device *device,
136
ForceRemovalCompleteFunc callback,
139
static void force_luks_teardown (Device *device,
140
Device *cleartext_device,
141
ForceRemovalCompleteFunc callback,
145
ptr_array_has_string (GPtrArray *p, const gchar *str)
151
for (n = 0; n < p->len; n++)
153
if (g_strcmp0 (p->pdata[n], str) == 0)
164
/* TODO: this is kinda a hack */
166
get_dmmp_device_node (Device *device)
168
static gchar buf[1024];
170
g_assert (device->priv->device_is_linux_dmmp);
171
g_snprintf (buf, sizeof (buf), "/dev/mapper/%s", device->priv->linux_dmmp_name);
180
PROP_DEVICE_AUTOMOUNT_HINT,
181
PROP_DEVICE_DETECTION_TIME,
182
PROP_DEVICE_MEDIA_DETECTION_TIME,
186
PROP_DEVICE_FILE_PRESENTATION,
187
PROP_DEVICE_FILE_BY_ID,
188
PROP_DEVICE_FILE_BY_PATH,
189
PROP_DEVICE_IS_SYSTEM_INTERNAL,
190
PROP_DEVICE_IS_PARTITION,
191
PROP_DEVICE_IS_PARTITION_TABLE,
192
PROP_DEVICE_IS_REMOVABLE,
193
PROP_DEVICE_IS_MEDIA_AVAILABLE,
194
PROP_DEVICE_IS_MEDIA_CHANGE_DETECTED,
195
PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_POLLING,
196
PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITABLE,
197
PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITED,
198
PROP_DEVICE_IS_READ_ONLY,
199
PROP_DEVICE_IS_DRIVE,
200
PROP_DEVICE_IS_OPTICAL_DISC,
202
PROP_DEVICE_IS_LUKS_CLEARTEXT,
203
PROP_DEVICE_IS_LINUX_MD_COMPONENT,
204
PROP_DEVICE_IS_LINUX_MD,
205
PROP_DEVICE_IS_LINUX_LVM2_LV,
206
PROP_DEVICE_IS_LINUX_LVM2_PV,
207
PROP_DEVICE_IS_LINUX_DMMP,
208
PROP_DEVICE_IS_LINUX_DMMP_COMPONENT,
209
PROP_DEVICE_IS_LINUX_LOOP,
211
PROP_DEVICE_BLOCK_SIZE,
212
PROP_DEVICE_IS_MOUNTED,
213
PROP_DEVICE_MOUNT_PATHS,
214
PROP_DEVICE_MOUNTED_BY_UID,
215
PROP_DEVICE_PRESENTATION_HIDE,
216
PROP_DEVICE_PRESENTATION_NOPOLICY,
217
PROP_DEVICE_PRESENTATION_NAME,
218
PROP_DEVICE_PRESENTATION_ICON_NAME,
220
PROP_JOB_IN_PROGRESS,
222
PROP_JOB_INITIATED_BY_UID,
223
PROP_JOB_IS_CANCELLABLE,
232
PROP_PARTITION_SLAVE,
233
PROP_PARTITION_SCHEME,
235
PROP_PARTITION_LABEL,
237
PROP_PARTITION_FLAGS,
238
PROP_PARTITION_NUMBER,
239
PROP_PARTITION_OFFSET,
241
PROP_PARTITION_ALIGNMENT_OFFSET,
243
PROP_PARTITION_TABLE_SCHEME,
244
PROP_PARTITION_TABLE_COUNT,
248
PROP_LUKS_CLEARTEXT_SLAVE,
249
PROP_LUKS_CLEARTEXT_UNLOCKED_BY_UID,
256
PROP_DRIVE_CONNECTION_INTERFACE,
257
PROP_DRIVE_CONNECTION_SPEED,
258
PROP_DRIVE_MEDIA_COMPATIBILITY,
260
PROP_DRIVE_IS_MEDIA_EJECTABLE,
261
PROP_DRIVE_CAN_DETACH,
262
PROP_DRIVE_CAN_SPINDOWN,
263
PROP_DRIVE_IS_ROTATIONAL,
264
PROP_DRIVE_ROTATION_RATE,
265
PROP_DRIVE_WRITE_CACHE,
268
PROP_DRIVE_SIMILAR_DEVICES,
270
PROP_OPTICAL_DISC_IS_BLANK,
271
PROP_OPTICAL_DISC_IS_APPENDABLE,
272
PROP_OPTICAL_DISC_IS_CLOSED,
273
PROP_OPTICAL_DISC_NUM_TRACKS,
274
PROP_OPTICAL_DISC_NUM_AUDIO_TRACKS,
275
PROP_OPTICAL_DISC_NUM_SESSIONS,
277
PROP_DRIVE_ATA_SMART_IS_AVAILABLE,
278
PROP_DRIVE_ATA_SMART_TIME_COLLECTED,
279
PROP_DRIVE_ATA_SMART_STATUS,
280
PROP_DRIVE_ATA_SMART_BLOB,
282
PROP_LINUX_MD_COMPONENT_LEVEL,
283
PROP_LINUX_MD_COMPONENT_POSITION,
284
PROP_LINUX_MD_COMPONENT_NUM_RAID_DEVICES,
285
PROP_LINUX_MD_COMPONENT_UUID,
286
PROP_LINUX_MD_COMPONENT_HOME_HOST,
287
PROP_LINUX_MD_COMPONENT_NAME,
288
PROP_LINUX_MD_COMPONENT_VERSION,
289
PROP_LINUX_MD_COMPONENT_HOLDER,
290
PROP_LINUX_MD_COMPONENT_STATE,
294
PROP_LINUX_MD_NUM_RAID_DEVICES,
296
PROP_LINUX_MD_HOME_HOST,
298
PROP_LINUX_MD_VERSION,
299
PROP_LINUX_MD_SLAVES,
300
PROP_LINUX_MD_IS_DEGRADED,
301
PROP_LINUX_MD_SYNC_ACTION,
302
PROP_LINUX_MD_SYNC_PERCENTAGE,
303
PROP_LINUX_MD_SYNC_SPEED,
305
PROP_LINUX_LVM2_LV_NAME,
306
PROP_LINUX_LVM2_LV_UUID,
307
PROP_LINUX_LVM2_LV_GROUP_NAME,
308
PROP_LINUX_LVM2_LV_GROUP_UUID,
310
PROP_LINUX_LVM2_PV_UUID,
311
PROP_LINUX_LVM2_PV_NUM_METADATA_AREAS,
312
PROP_LINUX_LVM2_PV_GROUP_NAME,
313
PROP_LINUX_LVM2_PV_GROUP_UUID,
314
PROP_LINUX_LVM2_PV_GROUP_SIZE,
315
PROP_LINUX_LVM2_PV_GROUP_UNALLOCATED_SIZE,
316
PROP_LINUX_LVM2_PV_GROUP_SEQUENCE_NUMBER,
317
PROP_LINUX_LVM2_PV_GROUP_EXTENT_SIZE,
318
PROP_LINUX_LVM2_PV_GROUP_PHYSICAL_VOLUMES,
319
PROP_LINUX_LVM2_PV_GROUP_LOGICAL_VOLUMES,
321
PROP_LINUX_DMMP_COMPONENT_HOLDER,
323
PROP_LINUX_DMMP_NAME,
324
PROP_LINUX_DMMP_SLAVES,
325
PROP_LINUX_DMMP_PARAMETERS,
327
PROP_LINUX_LOOP_FILENAME,
337
static guint signals[LAST_SIGNAL] = { 0 };
339
G_DEFINE_TYPE (Device, device, G_TYPE_OBJECT)
341
#define DEVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_DEVICE, DevicePrivate))
344
device_constructor (GType type,
345
guint n_construct_properties,
346
GObjectConstructParam *construct_properties)
350
device = DEVICE (G_OBJECT_CLASS (device_parent_class)->constructor (type,
351
n_construct_properties,
352
construct_properties));
353
return G_OBJECT (device);
357
get_property (GObject *object,
362
Device *device = DEVICE (object);
366
case PROP_NATIVE_PATH:
367
g_value_set_string (value, device->priv->native_path);
370
case PROP_DEVICE_DETECTION_TIME:
371
g_value_set_uint64 (value, device->priv->device_detection_time);
373
case PROP_DEVICE_MEDIA_DETECTION_TIME:
374
g_value_set_uint64 (value, device->priv->device_media_detection_time);
376
case PROP_DEVICE_MAJOR:
377
g_value_set_int64 (value, major (device->priv->dev));
379
case PROP_DEVICE_MINOR:
380
g_value_set_int64 (value, minor (device->priv->dev));
382
case PROP_DEVICE_FILE:
383
g_value_set_string (value, device->priv->device_file);
385
case PROP_DEVICE_AUTOMOUNT_HINT:
386
g_value_set_string (value, device->priv->device_automount_hint);
388
case PROP_DEVICE_FILE_PRESENTATION:
389
if (device->priv->device_file_presentation != NULL)
390
g_value_set_string (value, device->priv->device_file_presentation);
392
g_value_set_string (value, device->priv->device_file);
394
case PROP_DEVICE_FILE_BY_ID:
395
g_value_set_boxed (value, device->priv->device_file_by_id);
397
case PROP_DEVICE_FILE_BY_PATH:
398
g_value_set_boxed (value, device->priv->device_file_by_path);
400
case PROP_DEVICE_IS_SYSTEM_INTERNAL:
401
g_value_set_boolean (value, device->priv->device_is_system_internal);
403
case PROP_DEVICE_IS_PARTITION:
404
g_value_set_boolean (value, device->priv->device_is_partition);
406
case PROP_DEVICE_IS_PARTITION_TABLE:
407
g_value_set_boolean (value, device->priv->device_is_partition_table);
409
case PROP_DEVICE_IS_REMOVABLE:
410
g_value_set_boolean (value, device->priv->device_is_removable);
412
case PROP_DEVICE_IS_MEDIA_AVAILABLE:
413
g_value_set_boolean (value, device->priv->device_is_media_available);
415
case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTED:
416
g_value_set_boolean (value, device->priv->device_is_media_change_detected);
418
case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_POLLING:
419
g_value_set_boolean (value, device->priv->device_is_media_change_detection_polling);
421
case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITABLE:
422
g_value_set_boolean (value, device->priv->device_is_media_change_detection_inhibitable);
424
case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITED:
425
g_value_set_boolean (value, device->priv->device_is_media_change_detection_inhibited);
427
case PROP_DEVICE_IS_READ_ONLY:
428
g_value_set_boolean (value, device->priv->device_is_read_only);
430
case PROP_DEVICE_IS_DRIVE:
431
g_value_set_boolean (value, device->priv->device_is_drive);
433
case PROP_DEVICE_IS_OPTICAL_DISC:
434
g_value_set_boolean (value, device->priv->device_is_optical_disc);
436
case PROP_DEVICE_IS_LUKS:
437
g_value_set_boolean (value, device->priv->device_is_luks);
439
case PROP_DEVICE_IS_LUKS_CLEARTEXT:
440
g_value_set_boolean (value, device->priv->device_is_luks_cleartext);
442
case PROP_DEVICE_IS_LINUX_MD_COMPONENT:
443
g_value_set_boolean (value, device->priv->device_is_linux_md_component);
445
case PROP_DEVICE_IS_LINUX_MD:
446
g_value_set_boolean (value, device->priv->device_is_linux_md);
448
case PROP_DEVICE_IS_LINUX_LVM2_LV:
449
g_value_set_boolean (value, device->priv->device_is_linux_lvm2_lv);
451
case PROP_DEVICE_IS_LINUX_LVM2_PV:
452
g_value_set_boolean (value, device->priv->device_is_linux_lvm2_pv);
454
case PROP_DEVICE_IS_LINUX_DMMP:
455
g_value_set_boolean (value, device->priv->device_is_linux_dmmp);
457
case PROP_DEVICE_IS_LINUX_DMMP_COMPONENT:
458
g_value_set_boolean (value, device->priv->device_is_linux_dmmp_component);
460
case PROP_DEVICE_IS_LINUX_LOOP:
461
g_value_set_boolean (value, device->priv->device_is_linux_loop);
463
case PROP_DEVICE_SIZE:
464
g_value_set_uint64 (value, device->priv->device_size);
466
case PROP_DEVICE_BLOCK_SIZE:
467
g_value_set_uint64 (value, device->priv->device_block_size);
469
case PROP_DEVICE_IS_MOUNTED:
470
g_value_set_boolean (value, device->priv->device_is_mounted);
472
case PROP_DEVICE_MOUNT_PATHS:
473
g_value_set_boxed (value, device->priv->device_mount_paths);
475
case PROP_DEVICE_MOUNTED_BY_UID:
476
g_value_set_uint (value, device->priv->device_mounted_by_uid);
478
case PROP_DEVICE_PRESENTATION_HIDE:
479
g_value_set_boolean (value, device->priv->device_presentation_hide);
481
case PROP_DEVICE_PRESENTATION_NOPOLICY:
482
g_value_set_boolean (value, device->priv->device_presentation_nopolicy);
484
case PROP_DEVICE_PRESENTATION_NAME:
485
g_value_set_string (value, device->priv->device_presentation_name);
487
case PROP_DEVICE_PRESENTATION_ICON_NAME:
488
g_value_set_string (value, device->priv->device_presentation_icon_name);
491
case PROP_JOB_IN_PROGRESS:
492
g_value_set_boolean (value, device->priv->job_in_progress);
495
g_value_set_string (value, device->priv->job_id);
497
case PROP_JOB_INITIATED_BY_UID:
498
g_value_set_uint (value, device->priv->job_initiated_by_uid);
500
case PROP_JOB_IS_CANCELLABLE:
501
g_value_set_boolean (value, device->priv->job_is_cancellable);
503
case PROP_JOB_PERCENTAGE:
504
g_value_set_double (value, device->priv->job_percentage);
508
g_value_set_string (value, device->priv->id_usage);
511
g_value_set_string (value, device->priv->id_type);
513
case PROP_ID_VERSION:
514
g_value_set_string (value, device->priv->id_version);
517
g_value_set_string (value, device->priv->id_uuid);
520
g_value_set_string (value, device->priv->id_label);
523
case PROP_PARTITION_SLAVE:
524
if (device->priv->partition_slave != NULL)
525
g_value_set_boxed (value, device->priv->partition_slave);
527
g_value_set_boxed (value, "/");
529
case PROP_PARTITION_SCHEME:
530
g_value_set_string (value, device->priv->partition_scheme);
532
case PROP_PARTITION_TYPE:
533
g_value_set_string (value, device->priv->partition_type);
535
case PROP_PARTITION_LABEL:
536
g_value_set_string (value, device->priv->partition_label);
538
case PROP_PARTITION_UUID:
539
g_value_set_string (value, device->priv->partition_uuid);
541
case PROP_PARTITION_FLAGS:
542
g_value_set_boxed (value, device->priv->partition_flags);
544
case PROP_PARTITION_NUMBER:
545
g_value_set_int (value, device->priv->partition_number);
547
case PROP_PARTITION_OFFSET:
548
g_value_set_uint64 (value, device->priv->partition_offset);
550
case PROP_PARTITION_SIZE:
551
g_value_set_uint64 (value, device->priv->partition_size);
553
case PROP_PARTITION_ALIGNMENT_OFFSET:
554
g_value_set_uint64 (value, device->priv->partition_alignment_offset);
557
case PROP_PARTITION_TABLE_SCHEME:
558
g_value_set_string (value, device->priv->partition_table_scheme);
560
case PROP_PARTITION_TABLE_COUNT:
561
g_value_set_int (value, device->priv->partition_table_count);
564
case PROP_LUKS_HOLDER:
565
if (device->priv->luks_holder != NULL)
566
g_value_set_boxed (value, device->priv->luks_holder);
568
g_value_set_boxed (value, "/");
571
case PROP_LUKS_CLEARTEXT_SLAVE:
572
if (device->priv->luks_cleartext_slave != NULL)
573
g_value_set_boxed (value, device->priv->luks_cleartext_slave);
575
g_value_set_boxed (value, "/");
577
case PROP_LUKS_CLEARTEXT_UNLOCKED_BY_UID:
578
g_value_set_uint (value, device->priv->luks_cleartext_unlocked_by_uid);
581
case PROP_DRIVE_VENDOR:
582
g_value_set_string (value, device->priv->drive_vendor);
584
case PROP_DRIVE_MODEL:
585
g_value_set_string (value, device->priv->drive_model);
587
case PROP_DRIVE_REVISION:
588
g_value_set_string (value, device->priv->drive_revision);
590
case PROP_DRIVE_SERIAL:
591
g_value_set_string (value, device->priv->drive_serial);
594
g_value_set_string (value, device->priv->drive_wwn);
596
case PROP_DRIVE_CONNECTION_INTERFACE:
597
g_value_set_string (value, device->priv->drive_connection_interface);
599
case PROP_DRIVE_CONNECTION_SPEED:
600
g_value_set_uint64 (value, device->priv->drive_connection_speed);
602
case PROP_DRIVE_MEDIA_COMPATIBILITY:
603
g_value_set_boxed (value, device->priv->drive_media_compatibility);
605
case PROP_DRIVE_MEDIA:
606
g_value_set_string (value, device->priv->drive_media);
608
case PROP_DRIVE_IS_MEDIA_EJECTABLE:
609
g_value_set_boolean (value, device->priv->drive_is_media_ejectable);
611
case PROP_DRIVE_CAN_DETACH:
612
g_value_set_boolean (value, device->priv->drive_can_detach);
614
case PROP_DRIVE_CAN_SPINDOWN:
615
g_value_set_boolean (value, device->priv->drive_can_spindown);
617
case PROP_DRIVE_IS_ROTATIONAL:
618
g_value_set_boolean (value, device->priv->drive_is_rotational);
620
case PROP_DRIVE_WRITE_CACHE:
621
g_value_set_string (value, device->priv->drive_write_cache);
623
case PROP_DRIVE_ROTATION_RATE:
624
g_value_set_uint (value, device->priv->drive_rotation_rate);
626
case PROP_DRIVE_ADAPTER:
627
if (device->priv->drive_adapter != NULL)
628
g_value_set_boxed (value, device->priv->drive_adapter);
630
g_value_set_boxed (value, "/");
632
case PROP_DRIVE_PORTS:
633
g_value_set_boxed (value, device->priv->drive_ports);
635
case PROP_DRIVE_SIMILAR_DEVICES:
636
g_value_set_boxed (value, device->priv->drive_similar_devices);
639
case PROP_OPTICAL_DISC_IS_BLANK:
640
g_value_set_boolean (value, device->priv->optical_disc_is_blank);
642
case PROP_OPTICAL_DISC_IS_APPENDABLE:
643
g_value_set_boolean (value, device->priv->optical_disc_is_appendable);
645
case PROP_OPTICAL_DISC_IS_CLOSED:
646
g_value_set_boolean (value, device->priv->optical_disc_is_closed);
648
case PROP_OPTICAL_DISC_NUM_TRACKS:
649
g_value_set_uint (value, device->priv->optical_disc_num_tracks);
651
case PROP_OPTICAL_DISC_NUM_AUDIO_TRACKS:
652
g_value_set_uint (value, device->priv->optical_disc_num_audio_tracks);
654
case PROP_OPTICAL_DISC_NUM_SESSIONS:
655
g_value_set_uint (value, device->priv->optical_disc_num_sessions);
658
case PROP_DRIVE_ATA_SMART_IS_AVAILABLE:
659
g_value_set_boolean (value, device->priv->drive_ata_smart_is_available);
661
case PROP_DRIVE_ATA_SMART_TIME_COLLECTED:
662
g_value_set_uint64 (value, device->priv->drive_ata_smart_time_collected);
664
case PROP_DRIVE_ATA_SMART_STATUS:
667
if (device->priv->drive_ata_smart_status == (SkSmartOverall) - 1)
670
status = sk_smart_overall_to_string (device->priv->drive_ata_smart_status);
671
g_value_set_string (value, status);
674
case PROP_DRIVE_ATA_SMART_BLOB:
677
a = g_array_new (FALSE, FALSE, 1);
678
if (device->priv->drive_ata_smart_blob != NULL)
680
g_array_append_vals (a, device->priv->drive_ata_smart_blob, device->priv->drive_ata_smart_blob_size);
682
g_value_set_boxed (value, a);
687
case PROP_LINUX_MD_COMPONENT_LEVEL:
688
g_value_set_string (value, device->priv->linux_md_component_level);
690
case PROP_LINUX_MD_COMPONENT_POSITION:
691
g_value_set_int (value, device->priv->linux_md_component_position);
693
case PROP_LINUX_MD_COMPONENT_NUM_RAID_DEVICES:
694
g_value_set_int (value, device->priv->linux_md_component_num_raid_devices);
696
case PROP_LINUX_MD_COMPONENT_UUID:
697
g_value_set_string (value, device->priv->linux_md_component_uuid);
699
case PROP_LINUX_MD_COMPONENT_HOME_HOST:
700
g_value_set_string (value, device->priv->linux_md_component_home_host);
702
case PROP_LINUX_MD_COMPONENT_NAME:
703
g_value_set_string (value, device->priv->linux_md_component_name);
705
case PROP_LINUX_MD_COMPONENT_VERSION:
706
g_value_set_string (value, device->priv->linux_md_component_version);
708
case PROP_LINUX_MD_COMPONENT_HOLDER:
709
if (device->priv->linux_md_component_holder != NULL)
710
g_value_set_boxed (value, device->priv->linux_md_component_holder);
712
g_value_set_boxed (value, "/");
714
case PROP_LINUX_MD_COMPONENT_STATE:
715
g_value_set_boxed (value, device->priv->linux_md_component_state);
718
case PROP_LINUX_MD_STATE:
719
g_value_set_string (value, device->priv->linux_md_state);
721
case PROP_LINUX_MD_LEVEL:
722
g_value_set_string (value, device->priv->linux_md_level);
724
case PROP_LINUX_MD_NUM_RAID_DEVICES:
725
g_value_set_int (value, device->priv->linux_md_num_raid_devices);
727
case PROP_LINUX_MD_UUID:
728
g_value_set_string (value, device->priv->linux_md_uuid);
730
case PROP_LINUX_MD_HOME_HOST:
731
g_value_set_string (value, device->priv->linux_md_home_host);
733
case PROP_LINUX_MD_NAME:
734
g_value_set_string (value, device->priv->linux_md_name);
736
case PROP_LINUX_MD_VERSION:
737
g_value_set_string (value, device->priv->linux_md_version);
739
case PROP_LINUX_MD_SLAVES:
740
g_value_set_boxed (value, device->priv->linux_md_slaves);
742
case PROP_LINUX_MD_IS_DEGRADED:
743
g_value_set_boolean (value, device->priv->linux_md_is_degraded);
745
case PROP_LINUX_MD_SYNC_ACTION:
746
g_value_set_string (value, device->priv->linux_md_sync_action);
748
case PROP_LINUX_MD_SYNC_PERCENTAGE:
749
g_value_set_double (value, device->priv->linux_md_sync_percentage);
751
case PROP_LINUX_MD_SYNC_SPEED:
752
g_value_set_uint64 (value, device->priv->linux_md_sync_speed);
755
case PROP_LINUX_LVM2_LV_NAME:
756
g_value_set_string (value, device->priv->linux_lvm2_lv_name);
758
case PROP_LINUX_LVM2_LV_UUID:
759
g_value_set_string (value, device->priv->linux_lvm2_lv_uuid);
761
case PROP_LINUX_LVM2_LV_GROUP_NAME:
762
g_value_set_string (value, device->priv->linux_lvm2_lv_group_name);
764
case PROP_LINUX_LVM2_LV_GROUP_UUID:
765
g_value_set_string (value, device->priv->linux_lvm2_lv_group_uuid);
768
case PROP_LINUX_LVM2_PV_UUID:
769
g_value_set_string (value, device->priv->linux_lvm2_pv_uuid);
771
case PROP_LINUX_LVM2_PV_NUM_METADATA_AREAS:
772
g_value_set_uint (value, device->priv->linux_lvm2_pv_num_metadata_areas);
774
case PROP_LINUX_LVM2_PV_GROUP_NAME:
775
g_value_set_string (value, device->priv->linux_lvm2_pv_group_name);
777
case PROP_LINUX_LVM2_PV_GROUP_UUID:
778
g_value_set_string (value, device->priv->linux_lvm2_pv_group_uuid);
780
case PROP_LINUX_LVM2_PV_GROUP_SIZE:
781
g_value_set_uint64 (value, device->priv->linux_lvm2_pv_group_size);
783
case PROP_LINUX_LVM2_PV_GROUP_UNALLOCATED_SIZE:
784
g_value_set_uint64 (value, device->priv->linux_lvm2_pv_group_unallocated_size);
786
case PROP_LINUX_LVM2_PV_GROUP_SEQUENCE_NUMBER:
787
g_value_set_uint64 (value, device->priv->linux_lvm2_pv_group_sequence_number);
789
case PROP_LINUX_LVM2_PV_GROUP_EXTENT_SIZE:
790
g_value_set_uint64 (value, device->priv->linux_lvm2_pv_group_extent_size);
792
case PROP_LINUX_LVM2_PV_GROUP_PHYSICAL_VOLUMES:
793
g_value_set_boxed (value, device->priv->linux_lvm2_pv_group_physical_volumes);
795
case PROP_LINUX_LVM2_PV_GROUP_LOGICAL_VOLUMES:
796
g_value_set_boxed (value, device->priv->linux_lvm2_pv_group_logical_volumes);
799
case PROP_LINUX_DMMP_COMPONENT_HOLDER:
800
if (device->priv->linux_dmmp_component_holder != NULL)
801
g_value_set_boxed (value, device->priv->linux_dmmp_component_holder);
803
g_value_set_boxed (value, "/");
806
case PROP_LINUX_DMMP_NAME:
807
g_value_set_string (value, device->priv->linux_dmmp_name);
810
case PROP_LINUX_DMMP_PARAMETERS:
811
g_value_set_string (value, device->priv->linux_dmmp_parameters);
814
case PROP_LINUX_DMMP_SLAVES:
815
g_value_set_boxed (value, device->priv->linux_dmmp_slaves);
818
case PROP_LINUX_LOOP_FILENAME:
819
g_value_set_string (value, device->priv->linux_loop_filename);
823
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
829
device_class_init (DeviceClass *klass)
831
GObjectClass *object_class = G_OBJECT_CLASS (klass);
833
object_class->constructor = device_constructor;
834
object_class->finalize = device_finalize;
835
object_class->get_property = get_property;
837
g_type_class_add_private (klass, sizeof(DevicePrivate));
839
signals[CHANGED_SIGNAL] = g_signal_new ("changed",
840
G_OBJECT_CLASS_TYPE (klass),
841
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
845
g_cclosure_marshal_VOID__VOID,
849
signals[JOB_CHANGED_SIGNAL] = g_signal_new ("job-changed",
850
G_OBJECT_CLASS_TYPE (klass),
851
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
855
marshal_VOID__BOOLEAN_STRING_UINT_BOOLEAN_DOUBLE,
864
dbus_g_object_type_install_info (TYPE_DEVICE, &dbus_glib_device_object_info);
866
g_object_class_install_property (object_class, PROP_NATIVE_PATH, g_param_spec_string ("native-path",
872
g_object_class_install_property (object_class,
873
PROP_DEVICE_AUTOMOUNT_HINT,
874
g_param_spec_string ("device-automount-hint",
880
g_object_class_install_property (object_class,
881
PROP_DEVICE_DETECTION_TIME,
882
g_param_spec_uint64 ("device-detection-time",
889
g_object_class_install_property (object_class,
890
PROP_DEVICE_MEDIA_DETECTION_TIME,
891
g_param_spec_uint64 ("device-media-detection-time",
898
g_object_class_install_property (object_class, PROP_DEVICE_MAJOR, g_param_spec_int64 ("device-major",
905
g_object_class_install_property (object_class, PROP_DEVICE_MINOR, g_param_spec_int64 ("device-minor",
912
g_object_class_install_property (object_class,
914
g_param_spec_string ("device-file",
919
g_object_class_install_property (object_class,
920
PROP_DEVICE_FILE_PRESENTATION,
921
g_param_spec_string ("device-file-presentation",
926
g_object_class_install_property (object_class,
927
PROP_DEVICE_FILE_BY_ID,
928
g_param_spec_boxed ("device-file-by-id",
931
dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
933
g_object_class_install_property (object_class,
934
PROP_DEVICE_FILE_BY_PATH,
935
g_param_spec_boxed ("device-file-by-path",
938
dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
940
g_object_class_install_property (object_class,
941
PROP_DEVICE_IS_SYSTEM_INTERNAL,
942
g_param_spec_boolean ("device-is-system-internal",
947
g_object_class_install_property (object_class, PROP_DEVICE_IS_PARTITION, g_param_spec_boolean ("device-is-partition",
952
g_object_class_install_property (object_class,
953
PROP_DEVICE_IS_PARTITION_TABLE,
954
g_param_spec_boolean ("device-is-partition-table",
959
g_object_class_install_property (object_class, PROP_DEVICE_IS_REMOVABLE, g_param_spec_boolean ("device-is-removable",
964
g_object_class_install_property (object_class,
965
PROP_DEVICE_IS_MEDIA_AVAILABLE,
966
g_param_spec_boolean ("device-is-media-available",
971
g_object_class_install_property (object_class,
972
PROP_DEVICE_IS_MEDIA_CHANGE_DETECTED,
973
g_param_spec_boolean ("device-is-media-change-detected",
978
g_object_class_install_property (object_class,
979
PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_POLLING,
980
g_param_spec_boolean ("device-is-media-change-detection-polling",
985
g_object_class_install_property (object_class,
986
PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITABLE,
987
g_param_spec_boolean ("device-is-media-change-detection-inhibitable",
992
g_object_class_install_property (object_class,
993
PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITED,
994
g_param_spec_boolean ("device-is-media-change-detection-inhibited",
999
g_object_class_install_property (object_class, PROP_DEVICE_IS_READ_ONLY, g_param_spec_boolean ("device-is-read-only",
1004
g_object_class_install_property (object_class, PROP_DEVICE_IS_DRIVE, g_param_spec_boolean ("device-is-drive",
1009
g_object_class_install_property (object_class,
1010
PROP_DEVICE_IS_OPTICAL_DISC,
1011
g_param_spec_boolean ("device-is-optical-disc", NULL, NULL, FALSE, G_PARAM_READABLE));
1012
g_object_class_install_property (object_class, PROP_DEVICE_IS_LUKS, g_param_spec_boolean ("device-is-luks",
1017
g_object_class_install_property (object_class,
1018
PROP_DEVICE_IS_LUKS_CLEARTEXT,
1019
g_param_spec_boolean ("device-is-luks-cleartext",
1024
g_object_class_install_property (object_class,
1025
PROP_DEVICE_IS_LINUX_MD_COMPONENT,
1026
g_param_spec_boolean ("device-is-linux-md-component",
1031
g_object_class_install_property (object_class, PROP_DEVICE_IS_LINUX_MD, g_param_spec_boolean ("device-is-linux-md",
1036
g_object_class_install_property (object_class,
1037
PROP_DEVICE_IS_LINUX_LVM2_LV,
1038
g_param_spec_boolean ("device-is-linux-lvm2-lv",
1043
g_object_class_install_property (object_class,
1044
PROP_DEVICE_IS_LINUX_LVM2_PV,
1045
g_param_spec_boolean ("device-is-linux-lvm2-pv",
1050
g_object_class_install_property (object_class,
1051
PROP_DEVICE_IS_LINUX_DMMP,
1052
g_param_spec_boolean ("device-is-linux-dmmp",
1057
g_object_class_install_property (object_class,
1058
PROP_DEVICE_IS_LINUX_DMMP_COMPONENT,
1059
g_param_spec_boolean ("device-is-linux-dmmp-component",
1064
g_object_class_install_property (object_class,
1065
PROP_DEVICE_IS_LINUX_LOOP,
1066
g_param_spec_boolean ("device-is-linux-loop",
1072
g_object_class_install_property (object_class, PROP_DEVICE_SIZE, g_param_spec_uint64 ("device-size",
1079
g_object_class_install_property (object_class, PROP_DEVICE_BLOCK_SIZE, g_param_spec_uint64 ("device-block-size",
1086
g_object_class_install_property (object_class, PROP_DEVICE_IS_MOUNTED, g_param_spec_boolean ("device-is-mounted",
1091
g_object_class_install_property (object_class,
1092
PROP_DEVICE_MOUNT_PATHS,
1093
g_param_spec_boxed ("device-mount-paths",
1096
dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
1098
g_object_class_install_property (object_class,
1099
PROP_DEVICE_MOUNTED_BY_UID,
1100
g_param_spec_uint ("device-mounted-by-uid",
1107
g_object_class_install_property (object_class,
1108
PROP_DEVICE_PRESENTATION_HIDE,
1109
g_param_spec_boolean ("device-presentation-hide",
1114
g_object_class_install_property (object_class,
1115
PROP_DEVICE_PRESENTATION_NOPOLICY,
1116
g_param_spec_boolean ("device-presentation-nopolicy",
1121
g_object_class_install_property (object_class,
1122
PROP_DEVICE_PRESENTATION_NAME,
1123
g_param_spec_string ("device-presentation-name", NULL, NULL, NULL, G_PARAM_READABLE));
1124
g_object_class_install_property (object_class,
1125
PROP_DEVICE_PRESENTATION_ICON_NAME,
1126
g_param_spec_string ("device-presentation-icon-name",
1132
g_object_class_install_property (object_class, PROP_JOB_IN_PROGRESS, g_param_spec_boolean ("job-in-progress",
1137
g_object_class_install_property (object_class, PROP_JOB_ID, g_param_spec_string ("job-id",
1142
g_object_class_install_property (object_class, PROP_JOB_INITIATED_BY_UID, g_param_spec_uint ("job-initiated-by-uid",
1149
g_object_class_install_property (object_class, PROP_JOB_IS_CANCELLABLE, g_param_spec_boolean ("job-is-cancellable",
1154
g_object_class_install_property (object_class, PROP_JOB_PERCENTAGE, g_param_spec_double ("job-percentage",
1162
g_object_class_install_property (object_class, PROP_ID_USAGE, g_param_spec_string ("id-usage",
1167
g_object_class_install_property (object_class, PROP_ID_TYPE, g_param_spec_string ("id-type",
1172
g_object_class_install_property (object_class, PROP_ID_VERSION, g_param_spec_string ("id-version",
1177
g_object_class_install_property (object_class, PROP_ID_UUID, g_param_spec_string ("id-uuid",
1182
g_object_class_install_property (object_class, PROP_ID_LABEL, g_param_spec_string ("id-label",
1188
g_object_class_install_property (object_class, PROP_PARTITION_SLAVE, g_param_spec_boxed ("partition-slave",
1191
DBUS_TYPE_G_OBJECT_PATH,
1193
g_object_class_install_property (object_class, PROP_PARTITION_SCHEME, g_param_spec_string ("partition-scheme",
1198
g_object_class_install_property (object_class, PROP_PARTITION_TYPE, g_param_spec_string ("partition-type",
1203
g_object_class_install_property (object_class, PROP_PARTITION_LABEL, g_param_spec_string ("partition-label",
1208
g_object_class_install_property (object_class, PROP_PARTITION_UUID, g_param_spec_string ("partition-uuid",
1213
g_object_class_install_property (object_class,
1214
PROP_PARTITION_FLAGS,
1215
g_param_spec_boxed ("partition-flags",
1218
dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
1220
g_object_class_install_property (object_class, PROP_PARTITION_NUMBER, g_param_spec_int ("partition-number",
1227
g_object_class_install_property (object_class, PROP_PARTITION_OFFSET, g_param_spec_uint64 ("partition-offset",
1234
g_object_class_install_property (object_class, PROP_PARTITION_SIZE, g_param_spec_uint64 ("partition-size",
1241
g_object_class_install_property (object_class,
1242
PROP_PARTITION_ALIGNMENT_OFFSET,
1243
g_param_spec_uint64 ("partition-alignment-offset",
1251
g_object_class_install_property (object_class,
1252
PROP_PARTITION_TABLE_SCHEME,
1253
g_param_spec_string ("partition-table-scheme", NULL, NULL, NULL, G_PARAM_READABLE));
1254
g_object_class_install_property (object_class, PROP_PARTITION_TABLE_COUNT, g_param_spec_int ("partition-table-count",
1262
g_object_class_install_property (object_class, PROP_LUKS_HOLDER, g_param_spec_boxed ("luks-holder",
1265
DBUS_TYPE_G_OBJECT_PATH,
1268
g_object_class_install_property (object_class,
1269
PROP_LUKS_CLEARTEXT_SLAVE,
1270
g_param_spec_boxed ("luks-cleartext-slave",
1273
DBUS_TYPE_G_OBJECT_PATH,
1275
g_object_class_install_property (object_class,
1276
PROP_LUKS_CLEARTEXT_UNLOCKED_BY_UID,
1277
g_param_spec_uint ("luks-cleartext-unlocked-by-uid",
1285
g_object_class_install_property (object_class, PROP_DRIVE_VENDOR, g_param_spec_string ("drive-vendor",
1290
g_object_class_install_property (object_class, PROP_DRIVE_MODEL, g_param_spec_string ("drive-model",
1295
g_object_class_install_property (object_class, PROP_DRIVE_REVISION, g_param_spec_string ("drive-revision",
1300
g_object_class_install_property (object_class, PROP_DRIVE_SERIAL, g_param_spec_string ("drive-serial",
1305
g_object_class_install_property (object_class, PROP_DRIVE_WWN, g_param_spec_string ("drive-wwn",
1310
g_object_class_install_property (object_class,
1311
PROP_DRIVE_CONNECTION_INTERFACE,
1312
g_param_spec_string ("drive-connection-interface",
1317
g_object_class_install_property (object_class,
1318
PROP_DRIVE_CONNECTION_SPEED,
1319
g_param_spec_uint64 ("drive-connection-speed",
1326
g_object_class_install_property (object_class,
1327
PROP_DRIVE_MEDIA_COMPATIBILITY,
1328
g_param_spec_boxed ("drive-media-compatibility",
1331
dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
1333
g_object_class_install_property (object_class, PROP_DRIVE_MEDIA, g_param_spec_string ("drive-media",
1338
g_object_class_install_property (object_class,
1339
PROP_DRIVE_IS_MEDIA_EJECTABLE,
1340
g_param_spec_boolean ("drive-is-media-ejectable",
1345
g_object_class_install_property (object_class, PROP_DRIVE_CAN_DETACH, g_param_spec_boolean ("drive-can-detach",
1350
g_object_class_install_property (object_class, PROP_DRIVE_CAN_SPINDOWN, g_param_spec_boolean ("drive-can-spindown",
1355
g_object_class_install_property (object_class, PROP_DRIVE_IS_ROTATIONAL, g_param_spec_boolean ("drive-is-rotational",
1360
g_object_class_install_property (object_class, PROP_DRIVE_ROTATION_RATE, g_param_spec_uint ("drive-rotation-rate",
1367
g_object_class_install_property (object_class, PROP_DRIVE_WRITE_CACHE, g_param_spec_string ("drive-write-cache",
1372
g_object_class_install_property (object_class, PROP_DRIVE_ADAPTER, g_param_spec_boxed ("drive-adapter",
1375
DBUS_TYPE_G_OBJECT_PATH,
1377
g_object_class_install_property (object_class,
1379
g_param_spec_boxed ("drive-ports",
1382
dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
1384
g_object_class_install_property (object_class,
1385
PROP_DRIVE_SIMILAR_DEVICES,
1386
g_param_spec_boxed ("drive-similar-devices",
1389
dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
1392
g_object_class_install_property (object_class,
1393
PROP_OPTICAL_DISC_IS_BLANK,
1394
g_param_spec_boolean ("optical-disc-is-blank", NULL, NULL, FALSE, G_PARAM_READABLE));
1395
g_object_class_install_property (object_class,
1396
PROP_OPTICAL_DISC_IS_APPENDABLE,
1397
g_param_spec_boolean ("optical-disc-is-appendable",
1402
g_object_class_install_property (object_class,
1403
PROP_OPTICAL_DISC_IS_CLOSED,
1404
g_param_spec_boolean ("optical-disc-is-closed", NULL, NULL, FALSE, G_PARAM_READABLE));
1405
g_object_class_install_property (object_class,
1406
PROP_OPTICAL_DISC_NUM_TRACKS,
1407
g_param_spec_uint ("optical-disc-num-tracks",
1414
g_object_class_install_property (object_class,
1415
PROP_OPTICAL_DISC_NUM_AUDIO_TRACKS,
1416
g_param_spec_uint ("optical-disc-num-audio-tracks",
1423
g_object_class_install_property (object_class,
1424
PROP_OPTICAL_DISC_NUM_SESSIONS,
1425
g_param_spec_uint ("optical-disc-num-sessions",
1433
g_object_class_install_property (object_class,
1434
PROP_DRIVE_ATA_SMART_IS_AVAILABLE,
1435
g_param_spec_boolean ("drive-ata-smart-is-available",
1440
g_object_class_install_property (object_class,
1441
PROP_DRIVE_ATA_SMART_TIME_COLLECTED,
1442
g_param_spec_uint64 ("drive-ata-smart-time-collected",
1449
g_object_class_install_property (object_class,
1450
PROP_DRIVE_ATA_SMART_STATUS,
1451
g_param_spec_string ("drive-ata-smart-status", NULL, NULL, NULL, G_PARAM_READABLE));
1452
g_object_class_install_property (object_class,
1453
PROP_DRIVE_ATA_SMART_BLOB,
1454
g_param_spec_boxed ("drive-ata-smart-blob",
1457
dbus_g_type_get_collection ("GArray", G_TYPE_UCHAR),
1460
g_object_class_install_property (object_class,
1461
PROP_LINUX_MD_COMPONENT_LEVEL,
1462
g_param_spec_string ("linux-md-component-level", NULL, NULL, NULL, G_PARAM_READABLE));
1463
g_object_class_install_property (object_class,
1464
PROP_LINUX_MD_COMPONENT_POSITION,
1465
g_param_spec_int ("linux-md-component-position",
1472
g_object_class_install_property (object_class,
1473
PROP_LINUX_MD_COMPONENT_NUM_RAID_DEVICES,
1474
g_param_spec_int ("linux-md-component-num-raid-devices",
1481
g_object_class_install_property (object_class,
1482
PROP_LINUX_MD_COMPONENT_UUID,
1483
g_param_spec_string ("linux-md-component-uuid", NULL, NULL, NULL, G_PARAM_READABLE));
1484
g_object_class_install_property (object_class,
1485
PROP_LINUX_MD_COMPONENT_HOME_HOST,
1486
g_param_spec_string ("linux-md-component-home-host",
1491
g_object_class_install_property (object_class,
1492
PROP_LINUX_MD_COMPONENT_NAME,
1493
g_param_spec_string ("linux-md-component-name", NULL, NULL, NULL, G_PARAM_READABLE));
1494
g_object_class_install_property (object_class,
1495
PROP_LINUX_MD_COMPONENT_VERSION,
1496
g_param_spec_string ("linux-md-component-version",
1501
g_object_class_install_property (object_class,
1502
PROP_LINUX_MD_COMPONENT_HOLDER,
1503
g_param_spec_boxed ("linux-md-component-holder",
1506
DBUS_TYPE_G_OBJECT_PATH,
1508
g_object_class_install_property (object_class,
1509
PROP_LINUX_MD_COMPONENT_STATE,
1510
g_param_spec_boxed ("linux-md-component-state",
1513
dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
1516
g_object_class_install_property (object_class, PROP_LINUX_MD_STATE, g_param_spec_string ("linux-md-state",
1521
g_object_class_install_property (object_class, PROP_LINUX_MD_LEVEL, g_param_spec_string ("linux-md-level",
1526
g_object_class_install_property (object_class,
1527
PROP_LINUX_MD_NUM_RAID_DEVICES,
1528
g_param_spec_int ("linux-md-num-raid-devices",
1535
g_object_class_install_property (object_class, PROP_LINUX_MD_UUID, g_param_spec_string ("linux-md-uuid",
1540
g_object_class_install_property (object_class, PROP_LINUX_MD_HOME_HOST, g_param_spec_string ("linux-md-home-host",
1545
g_object_class_install_property (object_class, PROP_LINUX_MD_NAME, g_param_spec_string ("linux-md-name",
1550
g_object_class_install_property (object_class, PROP_LINUX_MD_VERSION, g_param_spec_string ("linux-md-version",
1555
g_object_class_install_property (object_class,
1556
PROP_LINUX_MD_SLAVES,
1557
g_param_spec_boxed ("linux-md-slaves",
1560
dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
1562
g_object_class_install_property (object_class,
1563
PROP_LINUX_MD_IS_DEGRADED,
1564
g_param_spec_boolean ("linux-md-is-degraded", NULL, NULL, FALSE, G_PARAM_READABLE));
1565
g_object_class_install_property (object_class,
1566
PROP_LINUX_MD_SYNC_ACTION,
1567
g_param_spec_string ("linux-md-sync-action", NULL, NULL, NULL, G_PARAM_READABLE));
1568
g_object_class_install_property (object_class,
1569
PROP_LINUX_MD_SYNC_PERCENTAGE,
1570
g_param_spec_double ("linux-md-sync-percentage",
1577
g_object_class_install_property (object_class, PROP_LINUX_MD_SYNC_SPEED, g_param_spec_uint64 ("linux-md-sync-speed",
1585
g_object_class_install_property (object_class,
1586
PROP_LINUX_LVM2_LV_NAME,
1587
g_param_spec_string ("linux-lvm2-lv-name",
1592
g_object_class_install_property (object_class,
1593
PROP_LINUX_LVM2_LV_UUID,
1594
g_param_spec_string ("linux-lvm2-lv-uuid",
1599
g_object_class_install_property (object_class,
1600
PROP_LINUX_LVM2_LV_GROUP_NAME,
1601
g_param_spec_string ("linux-lvm2-lv-group-name",
1606
g_object_class_install_property (object_class,
1607
PROP_LINUX_LVM2_LV_GROUP_UUID,
1608
g_param_spec_string ("linux-lvm2-lv-group-uuid",
1614
g_object_class_install_property (object_class,
1615
PROP_LINUX_LVM2_PV_UUID,
1616
g_param_spec_string ("linux-lvm2-pv-uuid",
1621
g_object_class_install_property (object_class,
1622
PROP_LINUX_LVM2_PV_NUM_METADATA_AREAS,
1623
g_param_spec_uint ("linux-lvm2-pv-num-metadata-areas",
1630
g_object_class_install_property (object_class,
1631
PROP_LINUX_LVM2_PV_GROUP_NAME,
1632
g_param_spec_string ("linux-lvm2-pv-group-name",
1637
g_object_class_install_property (object_class,
1638
PROP_LINUX_LVM2_PV_GROUP_UUID,
1639
g_param_spec_string ("linux-lvm2-pv-group-uuid",
1644
g_object_class_install_property (object_class,
1645
PROP_LINUX_LVM2_PV_GROUP_SIZE,
1646
g_param_spec_uint64 ("linux-lvm2-pv-group-size",
1653
g_object_class_install_property (object_class,
1654
PROP_LINUX_LVM2_PV_GROUP_UNALLOCATED_SIZE,
1655
g_param_spec_uint64 ("linux-lvm2-pv-group-unallocated-size",
1662
g_object_class_install_property (object_class,
1663
PROP_LINUX_LVM2_PV_GROUP_SEQUENCE_NUMBER,
1664
g_param_spec_uint64 ("linux-lvm2-pv-group-sequence-number",
1671
g_object_class_install_property (object_class,
1672
PROP_LINUX_LVM2_PV_GROUP_EXTENT_SIZE,
1673
g_param_spec_uint64 ("linux-lvm2-pv-group-extent-size",
1680
g_object_class_install_property (object_class,
1681
PROP_LINUX_LVM2_PV_GROUP_PHYSICAL_VOLUMES,
1682
g_param_spec_boxed ("linux-lvm2-pv-group-physical-volumes",
1685
dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
1687
g_object_class_install_property (object_class,
1688
PROP_LINUX_LVM2_PV_GROUP_LOGICAL_VOLUMES,
1689
g_param_spec_boxed ("linux-lvm2-pv-group-logical-volumes",
1692
dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
1694
g_object_class_install_property (object_class,
1695
PROP_LINUX_DMMP_COMPONENT_HOLDER,
1696
g_param_spec_boxed ("linux-dmmp-component-holder",
1699
DBUS_TYPE_G_OBJECT_PATH,
1702
g_object_class_install_property (object_class,
1703
PROP_LINUX_DMMP_NAME,
1704
g_param_spec_string ("linux-dmmp-name",
1709
g_object_class_install_property (object_class,
1710
PROP_LINUX_DMMP_PARAMETERS,
1711
g_param_spec_string ("linux-dmmp-parameters",
1716
g_object_class_install_property (object_class,
1717
PROP_LINUX_DMMP_SLAVES,
1718
g_param_spec_boxed ("linux-dmmp-slaves",
1721
dbus_g_type_get_collection ("GPtrArray",
1722
DBUS_TYPE_G_OBJECT_PATH),
1725
g_object_class_install_property (object_class,
1726
PROP_LINUX_LOOP_FILENAME,
1727
g_param_spec_string ("linux-loop-filename",
1735
device_init (Device *device)
1737
device->priv = DEVICE_GET_PRIVATE (device);
1739
device->priv->device_file_by_id = g_ptr_array_new ();
1740
device->priv->device_file_by_path = g_ptr_array_new ();
1741
device->priv->device_mount_paths = g_ptr_array_new ();
1742
device->priv->partition_flags = g_ptr_array_new ();
1743
device->priv->drive_media_compatibility = g_ptr_array_new ();
1744
device->priv->drive_ports = g_ptr_array_new ();
1745
device->priv->drive_similar_devices = g_ptr_array_new ();
1746
device->priv->linux_md_component_state = g_ptr_array_new ();
1747
device->priv->linux_md_slaves = g_ptr_array_new ();
1748
device->priv->linux_lvm2_pv_group_physical_volumes = g_ptr_array_new ();
1749
device->priv->linux_lvm2_pv_group_logical_volumes = g_ptr_array_new ();
1750
device->priv->linux_dmmp_slaves = g_ptr_array_new ();
1752
device->priv->slaves_objpath = g_ptr_array_new ();
1753
device->priv->holders_objpath = g_ptr_array_new ();
1755
device->priv->drive_ata_smart_status = -1;
1759
device_finalize (GObject *object)
1764
g_return_if_fail (object != NULL);
1765
g_return_if_fail (IS_DEVICE (object));
1767
device = DEVICE (object);
1768
g_return_if_fail (device->priv != NULL);
1770
/* g_debug ("finalizing %s", device->priv->native_path); */
1772
g_object_unref (device->priv->d);
1773
g_object_unref (device->priv->daemon);
1774
g_free (device->priv->object_path);
1776
g_free (device->priv->native_path);
1778
for (l = device->priv->polling_inhibitors; l != NULL; l = l->next)
1780
Inhibitor *inhibitor = INHIBITOR (l->data);
1781
g_signal_handlers_disconnect_by_func (inhibitor, polling_inhibitor_disconnected_cb, device);
1782
g_object_unref (inhibitor);
1784
g_list_free (device->priv->polling_inhibitors);
1786
for (l = device->priv->spindown_inhibitors; l != NULL; l = l->next)
1788
Inhibitor *inhibitor = INHIBITOR (l->data);
1789
g_signal_handlers_disconnect_by_func (inhibitor, spindown_inhibitor_disconnected_cb, device);
1790
g_object_unref (inhibitor);
1792
g_list_free (device->priv->spindown_inhibitors);
1794
if (device->priv->linux_md_poll_timeout_id > 0)
1795
g_source_remove (device->priv->linux_md_poll_timeout_id);
1797
if (device->priv->emit_changed_idle_id > 0)
1798
g_source_remove (device->priv->emit_changed_idle_id);
1800
/* free properties */
1801
g_free (device->priv->device_file);
1802
g_free (device->priv->device_file_presentation);
1803
g_ptr_array_foreach (device->priv->device_file_by_id, (GFunc) g_free, NULL);
1804
g_ptr_array_foreach (device->priv->device_file_by_path, (GFunc) g_free, NULL);
1805
g_ptr_array_free (device->priv->device_file_by_id, TRUE);
1806
g_ptr_array_free (device->priv->device_file_by_path, TRUE);
1807
g_ptr_array_free (device->priv->device_mount_paths, TRUE);
1808
g_free (device->priv->device_presentation_name);
1809
g_free (device->priv->device_presentation_icon_name);
1811
g_free (device->priv->id_usage);
1812
g_free (device->priv->id_type);
1813
g_free (device->priv->id_version);
1814
g_free (device->priv->id_uuid);
1815
g_free (device->priv->id_label);
1817
g_free (device->priv->partition_slave);
1818
g_free (device->priv->partition_scheme);
1819
g_free (device->priv->partition_type);
1820
g_free (device->priv->partition_label);
1821
g_free (device->priv->partition_uuid);
1822
g_ptr_array_foreach (device->priv->partition_flags, (GFunc) g_free, NULL);
1823
g_ptr_array_free (device->priv->partition_flags, TRUE);
1825
g_free (device->priv->partition_table_scheme);
1827
g_free (device->priv->luks_holder);
1829
g_free (device->priv->luks_cleartext_slave);
1831
g_free (device->priv->drive_vendor);
1832
g_free (device->priv->drive_model);
1833
g_free (device->priv->drive_revision);
1834
g_free (device->priv->drive_serial);
1835
g_free (device->priv->drive_wwn);
1836
g_free (device->priv->drive_connection_interface);
1837
g_ptr_array_foreach (device->priv->drive_media_compatibility, (GFunc) g_free, NULL);
1838
g_ptr_array_free (device->priv->drive_media_compatibility, TRUE);
1839
g_free (device->priv->drive_media);
1840
g_free (device->priv->drive_write_cache);
1841
g_free (device->priv->drive_adapter);
1842
g_ptr_array_foreach (device->priv->drive_ports, (GFunc) g_free, NULL);
1843
g_ptr_array_free (device->priv->drive_ports, TRUE);
1844
g_ptr_array_foreach (device->priv->drive_similar_devices, (GFunc) g_free, NULL);
1845
g_ptr_array_free (device->priv->drive_similar_devices, TRUE);
1847
g_free (device->priv->linux_md_component_level);
1848
g_free (device->priv->linux_md_component_uuid);
1849
g_free (device->priv->linux_md_component_home_host);
1850
g_free (device->priv->linux_md_component_name);
1851
g_free (device->priv->linux_md_component_version);
1852
g_free (device->priv->linux_md_component_holder);
1853
g_ptr_array_foreach (device->priv->linux_md_component_state, (GFunc) g_free, NULL);
1854
g_ptr_array_free (device->priv->linux_md_component_state, TRUE);
1856
g_free (device->priv->linux_md_state);
1857
g_free (device->priv->linux_md_level);
1858
g_free (device->priv->linux_md_uuid);
1859
g_free (device->priv->linux_md_home_host);
1860
g_free (device->priv->linux_md_name);
1861
g_free (device->priv->linux_md_version);
1862
g_ptr_array_foreach (device->priv->linux_md_slaves, (GFunc) g_free, NULL);
1863
g_ptr_array_free (device->priv->linux_md_slaves, TRUE);
1865
g_free (device->priv->linux_dmmp_component_holder);
1867
g_free (device->priv->linux_dmmp_name);
1868
g_ptr_array_foreach (device->priv->linux_dmmp_slaves, (GFunc) g_free, NULL);
1869
g_ptr_array_free (device->priv->linux_dmmp_slaves, TRUE);
1870
g_free (device->priv->linux_dmmp_parameters);
1872
g_free (device->priv->linux_loop_filename);
1874
g_free (device->priv->linux_lvm2_lv_name);
1875
g_free (device->priv->linux_lvm2_lv_uuid);
1876
g_free (device->priv->linux_lvm2_lv_group_name);
1877
g_free (device->priv->linux_lvm2_lv_group_uuid);
1879
g_free (device->priv->linux_lvm2_pv_uuid);
1880
g_free (device->priv->linux_lvm2_pv_group_name);
1881
g_free (device->priv->linux_lvm2_pv_group_uuid);
1882
g_ptr_array_foreach (device->priv->linux_lvm2_pv_group_physical_volumes, (GFunc) g_free, NULL);
1883
g_ptr_array_free (device->priv->linux_lvm2_pv_group_physical_volumes, TRUE);
1884
g_ptr_array_foreach (device->priv->linux_lvm2_pv_group_logical_volumes, (GFunc) g_free, NULL);
1885
g_ptr_array_free (device->priv->linux_lvm2_pv_group_logical_volumes, TRUE);
1887
g_free (device->priv->drive_ata_smart_blob);
1889
g_free (device->priv->dm_name);
1890
g_ptr_array_foreach (device->priv->slaves_objpath, (GFunc) g_free, NULL);
1891
g_ptr_array_free (device->priv->slaves_objpath, TRUE);
1892
g_ptr_array_foreach (device->priv->holders_objpath, (GFunc) g_free, NULL);
1893
g_ptr_array_free (device->priv->holders_objpath, TRUE);
1895
G_OBJECT_CLASS (device_parent_class)->finalize (object);
1899
* compute_object_path:
1900
* @native_path: Either an absolute sysfs path or the basename
1902
* Maps @native_path to the D-Bus object path for the device.
1904
* Returns: A valid D-Bus object path. Free with g_free().
1907
compute_object_path (const char *native_path)
1909
const gchar *basename;
1913
g_return_val_if_fail (native_path != NULL, NULL);
1915
basename = strrchr (native_path, '/');
1916
if (basename != NULL)
1922
basename = native_path;
1925
s = g_string_new ("/org/freedesktop/UDisks/devices/");
1926
for (n = 0; basename[n] != '\0'; n++)
1928
gint c = basename[n];
1932
* Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_"
1934
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
1936
g_string_append_c (s, c);
1940
/* Escape bytes not in [A-Z][a-z][0-9] as _<hex-with-two-digits> */
1941
g_string_append_printf (s, "_%02x", c);
1945
return g_string_free (s, FALSE);
1949
register_disks_device (Device *device)
1951
GError *error = NULL;
1953
device->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
1954
if (device->priv->system_bus_connection == NULL)
1958
g_critical ("error getting system bus: %s", error->message);
1959
g_error_free (error);
1963
device->priv->object_path = compute_object_path (device->priv->native_path);
1966
if (dbus_g_connection_lookup_g_object (device->priv->system_bus_connection, device->priv->object_path) != NULL)
1968
g_error ("**** HACK: Wanting to register object at path `%s' but there is already an "
1969
"object there. This is an internal error in the daemon. Aborting.\n", device->priv->object_path);
1972
dbus_g_connection_register_g_object (device->priv->system_bus_connection,
1973
device->priv->object_path,
1983
sysfs_get_double (const char *dir,
1984
const char *attribute)
1991
filename = g_build_filename (dir, attribute, NULL);
1992
if (g_file_get_contents (filename, &contents, NULL, NULL))
1994
result = atof (contents);
2003
sysfs_get_string (const char *dir,
2004
const char *attribute)
2010
filename = g_build_filename (dir, attribute, NULL);
2011
if (!g_file_get_contents (filename, &result, NULL, NULL))
2013
result = g_strdup ("");
2021
sysfs_get_int (const char *dir,
2022
const char *attribute)
2029
filename = g_build_filename (dir, attribute, NULL);
2030
if (g_file_get_contents (filename, &contents, NULL, NULL))
2032
result = strtol (contents, NULL, 0);
2041
sysfs_get_uint64 (const char *dir,
2042
const char *attribute)
2049
filename = g_build_filename (dir, attribute, NULL);
2050
if (g_file_get_contents (filename, &contents, NULL, NULL))
2052
result = strtoll (contents, NULL, 0);
2061
sysfs_file_exists (const char *dir,
2062
const char *attribute)
2068
filename = g_build_filename (dir, attribute, NULL);
2069
if (g_file_test (filename, G_FILE_TEST_EXISTS))
2079
device_generate_kernel_change_event (Device *device)
2084
filename = g_build_filename (device->priv->native_path, "uevent", NULL);
2085
f = fopen (filename, "w");
2088
g_warning ("error opening %s for writing: %m", filename);
2092
if (fputs ("change", f) == EOF)
2094
g_warning ("error writing 'change' to %s: %m", filename);
2102
_dupv8 (const char *s)
2104
const char *end_valid;
2106
if (!g_utf8_validate (s, -1, &end_valid))
2108
g_print ("**** NOTE: The string '%s' is not valid UTF-8. Invalid characters begins at '%s'\n", s, end_valid);
2109
return g_strndup (s, end_valid - s);
2113
return g_strdup (s);
2118
sysfs_resolve_link (const char *sysfs_path,
2122
char link_path[PATH_MAX];
2123
char resolved_path[PATH_MAX];
2129
full_path = g_build_filename (sysfs_path, name, NULL);
2131
//g_debug ("name='%s'", name);
2132
//g_debug ("full_path='%s'", full_path);
2133
num = readlink (full_path, link_path, sizeof(link_path) - 1);
2136
char *absolute_path;
2138
link_path[num] = '\0';
2140
//g_debug ("link_path='%s'", link_path);
2141
absolute_path = g_build_filename (sysfs_path, link_path, NULL);
2142
//g_debug ("absolute_path='%s'", absolute_path);
2143
if (realpath (absolute_path, resolved_path) != NULL)
2145
//g_debug ("resolved_path='%s'", resolved_path);
2148
g_free (absolute_path);
2153
return g_strdup (resolved_path);
2158
/* unescapes things like \x20 to " " and ensures the returned string is valid UTF-8.
2160
* see volume_id_encode_string() in extras/volume_id/lib/volume_id.c in the
2161
* udev tree for the encoder
2164
decode_udev_encoded_string (const gchar *str)
2168
const gchar *end_valid;
2171
s = g_string_new (NULL);
2172
for (n = 0; str[n] != '\0'; n++)
2178
if (str[n + 1] != 'x' || str[n + 2] == '\0' || str[n + 3] == '\0')
2180
g_print ("**** NOTE: malformed encoded string '%s'\n", str);
2184
val = (g_ascii_xdigit_value (str[n + 2]) << 4) | g_ascii_xdigit_value (str[n + 3]);
2186
g_string_append_c (s, val);
2192
g_string_append_c (s, str[n]);
2196
if (!g_utf8_validate (s->str, -1, &end_valid))
2198
g_print ("**** NOTE: The string '%s' is not valid UTF-8. Invalid characters begins at '%s'\n", s->str, end_valid);
2199
ret = g_strndup (s->str, end_valid - s->str);
2200
g_string_free (s, TRUE);
2204
ret = g_string_free (s, FALSE);
2211
poll_syncing_md_device (gpointer user_data)
2213
Device *device = DEVICE (user_data);
2215
g_print ("**** POLL SYNCING MD %s\n", device->priv->native_path);
2217
device->priv->linux_md_poll_timeout_id = 0;
2218
daemon_local_synthesize_changed (device->priv->daemon, device);
2223
dup_list_from_ptrarray (GPtrArray *p)
2230
for (n = 0; n < p->len; n++)
2231
ret = g_list_prepend (ret, g_strdup (((gchar **) p->pdata)[n]));
2237
ptr_str_array_compare (const gchar **a,
2240
return g_strcmp0 (*a, *b);
2244
diff_sorted_lists (GList *list1,
2246
GCompareFunc compare,
2252
*added = *removed = NULL;
2254
while (list1 != NULL && list2 != NULL)
2256
order = (*compare) (list1->data, list2->data);
2259
*removed = g_list_prepend (*removed, list1->data);
2260
list1 = list1->next;
2264
*added = g_list_prepend (*added, list2->data);
2265
list2 = list2->next;
2269
list1 = list1->next;
2270
list2 = list2->next;
2274
while (list1 != NULL)
2276
*removed = g_list_prepend (*removed, list1->data);
2277
list1 = list1->next;
2279
while (list2 != NULL)
2281
*added = g_list_prepend (*added, list2->data);
2282
list2 = list2->next;
2286
/* ---------------------------------------------------------------------------------------------------- */
2288
/* update id_* properties */
2290
update_info_presentation (Device *device)
2294
const gchar *automount_hint;
2297
if (g_udev_device_has_property (device->priv->d, "UDISKS_PRESENTATION_HIDE"))
2298
hide = g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_PRESENTATION_HIDE");
2299
device_set_device_presentation_hide (device, hide);
2302
if (g_udev_device_has_property (device->priv->d, "UDISKS_PRESENTATION_NOPOLICY"))
2303
nopolicy = g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_PRESENTATION_NOPOLICY");
2304
device_set_device_presentation_nopolicy (device, nopolicy);
2306
device_set_device_presentation_name (device, g_udev_device_get_property (device->priv->d, "UDISKS_PRESENTATION_NAME"));
2308
device_set_device_presentation_icon_name (device, g_udev_device_get_property (device->priv->d,
2309
"UDISKS_PRESENTATION_ICON_NAME"));
2311
automount_hint = "";
2312
if (g_udev_device_has_property (device->priv->d, "UDISKS_AUTOMOUNT_HINT"))
2313
automount_hint = g_udev_device_get_property (device->priv->d, "UDISKS_AUTOMOUNT_HINT");
2315
device_set_device_automount_hint (device, automount_hint);
2320
/* ---------------------------------------------------------------------------------------------------- */
2322
/* update id_* properties */
2324
update_info_id (Device *device)
2326
gchar *decoded_string;
2327
const gchar *partition_scheme;
2328
gint partition_type;
2330
partition_scheme = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_SCHEME");
2331
partition_type = g_udev_device_get_property_as_int (device->priv->d, "UDISKS_PARTITION_TYPE");
2332
if (g_strcmp0 (partition_scheme, "mbr") == 0 && (partition_type == 0x05 || partition_type == 0x0f || partition_type
2335
device_set_id_usage (device, "");
2336
device_set_id_type (device, "");
2337
device_set_id_version (device, "");
2338
device_set_id_label (device, "");
2339
device_set_id_uuid (device, "");
2343
device_set_id_usage (device, g_udev_device_get_property (device->priv->d, "ID_FS_USAGE"));
2344
device_set_id_type (device, g_udev_device_get_property (device->priv->d, "ID_FS_TYPE"));
2345
device_set_id_version (device, g_udev_device_get_property (device->priv->d, "ID_FS_VERSION"));
2346
if (g_udev_device_has_property (device->priv->d, "ID_FS_LABEL_ENC"))
2348
decoded_string = decode_udev_encoded_string (g_udev_device_get_property (device->priv->d, "ID_FS_LABEL_ENC"));
2349
device_set_id_label (device, decoded_string);
2350
g_free (decoded_string);
2354
device_set_id_label (device, g_udev_device_get_property (device->priv->d, "ID_FS_LABEL"));
2356
device_set_id_uuid (device, g_udev_device_get_property (device->priv->d, "ID_FS_UUID"));
2362
/* ---------------------------------------------------------------------------------------------------- */
2364
/* update partition_table_* properties */
2366
update_info_partition_table (Device *device)
2368
gboolean is_partition_table;
2370
is_partition_table = FALSE;
2372
/* Check if udisks-part-id identified the device as a partition table.. this includes
2373
* identifying partition tables set up by kpartx for multipath etc.
2375
if (g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_PARTITION_TABLE"))
2377
device_set_partition_table_scheme (device,
2378
g_udev_device_get_property (device->priv->d,
2379
"UDISKS_PARTITION_TABLE_SCHEME"));
2380
device_set_partition_table_count (device,
2381
g_udev_device_get_property_as_int (device->priv->d,
2382
"UDISKS_PARTITION_TABLE_COUNT"));
2383
is_partition_table = TRUE;
2386
/* Note that udisks-part-id might not detect all partition table
2387
* formats.. so in the negative case, also double check with
2388
* information in sysfs.
2390
* The kernel guarantees that all childs are created before the
2391
* uevent for the parent is created. So if we have childs, we must
2392
* be a partition table.
2394
* To detect a child we check for the existance of a subdir that has
2395
* the parents name as a prefix (e.g. for parent sda then sda1,
2396
* sda2, sda3 ditto md0, md0p1 etc. etc. will work).
2398
if (!is_partition_table)
2403
s = g_path_get_basename (device->priv->native_path);
2404
if ((dir = g_dir_open (device->priv->native_path, 0, NULL)) != NULL)
2406
guint partition_count;
2409
partition_count = 0;
2410
while ((name = g_dir_read_name (dir)) != NULL)
2412
if (g_str_has_prefix (name, s))
2419
if (partition_count > 0)
2421
device_set_partition_table_scheme (device, "");
2422
device_set_partition_table_count (device, partition_count);
2423
is_partition_table = TRUE;
2429
device_set_device_is_partition_table (device, is_partition_table);
2430
if (!is_partition_table)
2432
/* otherwise, clear all the data */
2433
device_set_partition_table_scheme (device, NULL);
2434
device_set_partition_table_count (device, 0);
2440
/* ---------------------------------------------------------------------------------------------------- */
2442
/* update partition_* properties */
2444
update_info_partition (Device *device)
2446
gboolean is_partition;
2448
is_partition = FALSE;
2450
/* Check if udisks-part-id identified the device as a partition.. this includes
2451
* identifying partitions set up by kpartx for multipath
2453
if (g_udev_device_has_property (device->priv->d, "UDISKS_PARTITION"))
2456
const gchar *scheme;
2460
const gchar* const *flags;
2462
guint64 alignment_offset;
2463
const gchar *slave_sysfs_path;
2466
scheme = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_SCHEME");
2467
size = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_PARTITION_SIZE");
2468
type = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_TYPE");
2469
label = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_LABEL");
2470
uuid = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_UUID");
2471
flags = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_PARTITION_FLAGS");
2472
offset = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_PARTITION_OFFSET");
2473
alignment_offset = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_PARTITION_ALIGNMENT_OFFSET");
2474
number = g_udev_device_get_property_as_int (device->priv->d, "UDISKS_PARTITION_NUMBER");
2475
slave_sysfs_path = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_SLAVE");
2477
if (slave_sysfs_path != NULL && scheme != NULL && number > 0)
2481
device_set_partition_scheme (device, scheme);
2482
device_set_partition_size (device, size);
2483
device_set_partition_type (device, type);
2484
device_set_partition_label (device, label);
2485
device_set_partition_uuid (device, uuid);
2486
device_set_partition_flags (device, (gchar **) flags);
2487
device_set_partition_offset (device, offset);
2488
device_set_partition_alignment_offset (device, alignment_offset);
2489
device_set_partition_number (device, number);
2491
s = compute_object_path (slave_sysfs_path);
2492
device_set_partition_slave (device, s);
2495
is_partition = TRUE;
2499
/* Also handle the case where we are partitioned by the kernel and don't have
2500
* any UDISKS_PARTITION_* properties.
2502
* This works without any udev UDISKS_PARTITION_* properties and is
2503
* there for maximum compatibility since udisks-part-id only knows a
2504
* limited set of partition table formats.
2506
if (!is_partition && sysfs_file_exists (device->priv->native_path, "start"))
2510
guint64 alignment_offset;
2514
device_set_device_is_partition (device, TRUE);
2515
size = sysfs_get_uint64 (device->priv->native_path, "size");
2516
alignment_offset = sysfs_get_uint64 (device->priv->native_path, "alignment_offset");
2518
device_set_partition_size (device, size * 512); /* device->priv->device_block_size; */
2519
device_set_partition_alignment_offset (device, alignment_offset);
2521
offset = sysfs_get_uint64 (device->priv->native_path, "start") * device->priv->device_block_size;
2522
device_set_partition_offset (device, offset);
2524
s = device->priv->native_path;
2525
for (n = strlen (s) - 1; n >= 0 && g_ascii_isdigit (s[n]); n--)
2527
device_set_partition_number (device, strtol (s + n + 1, NULL, 0));
2529
s = g_strdup (device->priv->native_path);
2530
for (n = strlen (s) - 1; n >= 0 && s[n] != '/'; n--)
2533
device_set_partition_slave (device, compute_object_path (s));
2536
is_partition = TRUE;
2539
device_set_device_is_partition (device, is_partition);
2542
/* otherwise, clear all the data */
2543
device_set_partition_scheme (device, NULL);
2544
device_set_partition_size (device, device->priv->device_size);
2545
device_set_partition_type (device, NULL);
2546
device_set_partition_label (device, NULL);
2547
device_set_partition_uuid (device, NULL);
2548
device_set_partition_flags (device, NULL);
2552
device_set_device_is_drive (device, FALSE);
2558
/* ---------------------------------------------------------------------------------------------------- */
2560
/* this function sets
2562
* - drive_vendor (unless set already)
2563
* - drive_model (unless set already)
2564
* - connection_interface (if we can figure that out)
2565
* - connection_speed (if we can figure that out)
2567
* All this should really come from udev properties but right now it isn't.
2570
update_drive_properties_from_sysfs (Device *device)
2580
const char *connection_interface;
2581
guint64 connection_speed;
2583
connection_interface = NULL;
2584
connection_speed = 0;
2586
/* walk up the device tree to figure out the subsystem */
2587
s = g_strdup (device->priv->native_path);
2590
p = sysfs_resolve_link (s, "subsystem");
2593
subsystem = g_path_get_basename (p);
2596
if (strcmp (subsystem, "scsi") == 0)
2598
connection_interface = "scsi";
2599
connection_speed = 0;
2601
/* continue walking up the chain; we just use scsi as a fallback */
2603
/* grab the names from SCSI since the names from udev currently
2604
* - replaces whitespace with _
2605
* - is missing for e.g. Firewire
2607
vendor = sysfs_get_string (s, "vendor");
2610
g_strstrip (vendor);
2611
/* Don't overwrite what we set earlier from ID_VENDOR */
2612
if (device->priv->drive_vendor == NULL)
2614
q = _dupv8 (vendor);
2615
device_set_drive_vendor (device, q);
2621
model = sysfs_get_string (s, "model");
2625
/* Don't overwrite what we set earlier from ID_MODEL */
2626
if (device->priv->drive_model == NULL)
2629
device_set_drive_model (device, q);
2635
/* TODO: need to improve this code; we probably need the kernel to export more
2636
* information before we can properly get the type and speed.
2639
if (device->priv->drive_vendor != NULL && strcmp (device->priv->drive_vendor, "ATA") == 0)
2641
connection_interface = "ata";
2646
else if (strcmp (subsystem, "usb") == 0)
2650
/* both the interface and the device will be 'usb'. However only
2651
* the device will have the 'speed' property.
2653
usb_speed = sysfs_get_double (s, "speed");
2656
connection_interface = "usb";
2657
connection_speed = usb_speed * (1000 * 1000);
2662
else if (strcmp (subsystem, "firewire") == 0 || strcmp (subsystem, "ieee1394") == 0)
2665
/* TODO: krh has promised a speed file in sysfs; theoretically, the speed can
2666
* be anything from 100, 200, 400, 800 and 3200. Till then we just hardcode
2667
* a resonable default of 400 Mbit/s.
2670
connection_interface = "firewire";
2671
connection_speed = 400 * (1000 * 1000);
2675
else if (strcmp (subsystem, "mmc") == 0)
2678
/* TODO: what about non-SD, e.g. MMC? Is that another bus? */
2679
connection_interface = "sdio";
2681
/* Set vendor name. According to this MMC document
2683
* http://www.mmca.org/membership/IAA_Agreement_10_12_06.pdf
2685
* - manfid: the manufacturer id
2686
* - oemid: the customer of the manufacturer
2688
* Apparently these numbers are kept secret. It would be nice
2689
* to map these into names for setting the manufacturer of the drive,
2690
* e.g. Panasonic, Sandisk etc.
2693
model = sysfs_get_string (s, "name");
2697
/* Don't overwrite what we set earlier from ID_MODEL */
2698
if (device->priv->drive_model == NULL)
2701
device_set_drive_model (device, q);
2707
serial = sysfs_get_string (s, "serial");
2710
g_strstrip (serial);
2711
/* Don't overwrite what we set earlier from ID_SERIAL */
2712
if (device->priv->drive_serial == NULL)
2714
/* this is formatted as a hexnumber; drop the leading 0x */
2715
q = _dupv8 (serial + 2);
2716
device_set_drive_serial (device, q);
2722
/* TODO: use hwrev and fwrev files? */
2723
revision = sysfs_get_string (s, "date");
2724
if (revision != NULL)
2726
g_strstrip (revision);
2727
/* Don't overwrite what we set earlier from ID_REVISION */
2728
if (device->priv->drive_revision == NULL)
2730
q = _dupv8 (revision);
2731
device_set_drive_revision (device, q);
2737
/* TODO: interface speed; the kernel driver knows; would be nice
2738
* if it could export it */
2741
else if (strcmp (subsystem, "platform") == 0)
2743
const gchar *sysfs_name;
2745
sysfs_name = g_strrstr (s, "/");
2746
if (g_str_has_prefix (sysfs_name + 1, "floppy."))
2748
device_set_drive_vendor (device, "Floppy Drive");
2749
connection_interface = "platform";
2756
/* advance up the chain */
2757
p = g_strrstr (s, "/");
2762
/* but stop at the root */
2763
if (strcmp (s, "/sys/devices") == 0)
2769
if (connection_interface != NULL)
2771
device_set_drive_connection_interface (device, connection_interface);
2772
device_set_drive_connection_speed (device, connection_speed);
2780
const gchar *udev_property;
2781
const gchar *media_name;
2782
} drive_media_mapping[] =
2784
{ "ID_DRIVE_FLASH", "flash" },
2785
{ "ID_DRIVE_FLASH_CF", "flash_cf" },
2786
{ "ID_DRIVE_FLASH_MS", "flash_ms" },
2787
{ "ID_DRIVE_FLASH_SM", "flash_sm" },
2788
{ "ID_DRIVE_FLASH_SD", "flash_sd" },
2789
{ "ID_DRIVE_FLASH_SDHC", "flash_sdhc" },
2790
{ "ID_DRIVE_FLASH_MMC", "flash_mmc" },
2791
{ "ID_DRIVE_FLOPPY", "floppy" },
2792
{ "ID_DRIVE_FLOPPY_ZIP", "floppy_zip" },
2793
{ "ID_DRIVE_FLOPPY_JAZ", "floppy_jaz" },
2794
{ "ID_CDROM", "optical_cd" },
2795
{ "ID_CDROM_CD_R", "optical_cd_r" },
2796
{ "ID_CDROM_CD_RW", "optical_cd_rw" },
2797
{ "ID_CDROM_DVD", "optical_dvd" },
2798
{ "ID_CDROM_DVD_R", "optical_dvd_r" },
2799
{ "ID_CDROM_DVD_RW", "optical_dvd_rw" },
2800
{ "ID_CDROM_DVD_RAM", "optical_dvd_ram" },
2801
{ "ID_CDROM_DVD_PLUS_R", "optical_dvd_plus_r" },
2802
{ "ID_CDROM_DVD_PLUS_RW", "optical_dvd_plus_rw" },
2803
{ "ID_CDROM_DVD_PLUS_R_DL", "optical_dvd_plus_r_dl" },
2804
{ "ID_CDROM_DVD_PLUS_RW_DL", "optical_dvd_plus_rw_dl" },
2805
{ "ID_CDROM_BD", "optical_bd" },
2806
{ "ID_CDROM_BD_R", "optical_bd_r" },
2807
{ "ID_CDROM_BD_RE", "optical_bd_re" },
2808
{ "ID_CDROM_HDDVD", "optical_hddvd" },
2809
{ "ID_CDROM_HDDVD_R", "optical_hddvd_r" },
2810
{ "ID_CDROM_HDDVD_RW", "optical_hddvd_rw" },
2811
{ "ID_CDROM_MO", "optical_mo" },
2812
{ "ID_CDROM_MRW", "optical_mrw" },
2813
{ "ID_CDROM_MRW_W", "optical_mrw_w" },
2818
const gchar *udev_property;
2819
const gchar *media_name;
2822
{ "ID_DRIVE_MEDIA_FLASH", "flash" },
2823
{ "ID_DRIVE_MEDIA_FLASH_CF", "flash_cf" },
2824
{ "ID_DRIVE_MEDIA_FLASH_MS", "flash_ms" },
2825
{ "ID_DRIVE_MEDIA_FLASH_SM", "flash_sm" },
2826
{ "ID_DRIVE_MEDIA_FLASH_SD", "flash_sd" },
2827
{ "ID_DRIVE_MEDIA_FLASH_SDHC", "flash_sdhc" },
2828
{ "ID_DRIVE_MEDIA_FLASH_MMC", "flash_mmc" },
2829
{ "ID_DRIVE_MEDIA_FLOPPY", "floppy" },
2830
{ "ID_DRIVE_MEDIA_FLOPPY_ZIP", "floppy_zip" },
2831
{ "ID_DRIVE_MEDIA_FLOPPY_JAZ", "floppy_jaz" },
2832
{ "ID_CDROM_MEDIA_CD", "optical_cd" },
2833
{ "ID_CDROM_MEDIA_CD_R", "optical_cd_r" },
2834
{ "ID_CDROM_MEDIA_CD_RW", "optical_cd_rw" },
2835
{ "ID_CDROM_MEDIA_DVD", "optical_dvd" },
2836
{ "ID_CDROM_MEDIA_DVD_R", "optical_dvd_r" },
2837
{ "ID_CDROM_MEDIA_DVD_RW", "optical_dvd_rw" },
2838
{ "ID_CDROM_MEDIA_DVD_RAM", "optical_dvd_ram" },
2839
{ "ID_CDROM_MEDIA_DVD_PLUS_R", "optical_dvd_plus_r" },
2840
{ "ID_CDROM_MEDIA_DVD_PLUS_RW", "optical_dvd_plus_rw" },
2841
{ "ID_CDROM_MEDIA_DVD_PLUS_R_DL", "optical_dvd_plus_r_dl" },
2842
{ "ID_CDROM_MEDIA_DVD_PLUS_RW_DL", "optical_dvd_plus_rw_dl" },
2843
{ "ID_CDROM_MEDIA_BD", "optical_bd" },
2844
{ "ID_CDROM_MEDIA_BD_R", "optical_bd_r" },
2845
{ "ID_CDROM_MEDIA_BD_RE", "optical_bd_re" },
2846
{ "ID_CDROM_MEDIA_HDDVD", "optical_hddvd" },
2847
{ "ID_CDROM_MEDIA_HDDVD_R", "optical_hddvd_r" },
2848
{ "ID_CDROM_MEDIA_HDDVD_RW", "optical_hddvd_rw" },
2849
{ "ID_CDROM_MEDIA_MO", "optical_mo" },
2850
{ "ID_CDROM_MEDIA_MRW", "optical_mrw" },
2851
{ "ID_CDROM_MEDIA_MRW_W", "optical_mrw_w" },
2854
/* update drive_* properties */
2856
update_info_drive (Device *device)
2858
GPtrArray *media_compat_array;
2859
const gchar *media_in_drive;
2860
gboolean drive_is_ejectable;
2861
gboolean drive_can_detach;
2862
gchar *decoded_string;
2865
if (g_udev_device_has_property (device->priv->d, "ID_VENDOR_ENC"))
2867
decoded_string = decode_udev_encoded_string (g_udev_device_get_property (device->priv->d, "ID_VENDOR_ENC"));
2868
g_strstrip (decoded_string);
2869
device_set_drive_vendor (device, decoded_string);
2870
g_free (decoded_string);
2872
else if (g_udev_device_has_property (device->priv->d, "ID_VENDOR"))
2874
device_set_drive_vendor (device, g_udev_device_get_property (device->priv->d, "ID_VENDOR"));
2877
if (g_udev_device_has_property (device->priv->d, "ID_MODEL_ENC"))
2879
decoded_string = decode_udev_encoded_string (g_udev_device_get_property (device->priv->d, "ID_MODEL_ENC"));
2880
g_strstrip (decoded_string);
2881
device_set_drive_model (device, decoded_string);
2882
g_free (decoded_string);
2884
else if (g_udev_device_has_property (device->priv->d, "ID_MODEL"))
2886
device_set_drive_model (device, g_udev_device_get_property (device->priv->d, "ID_MODEL"));
2889
if (g_udev_device_has_property (device->priv->d, "ID_REVISION"))
2890
device_set_drive_revision (device, g_udev_device_get_property (device->priv->d, "ID_REVISION"));
2891
if (g_udev_device_has_property (device->priv->d, "ID_SCSI_SERIAL"))
2893
/* scsi_id sometimes use the WWN as the serial - annoying - see
2894
* http://git.kernel.org/?p=linux/hotplug/udev.git;a=commit;h=4e9fdfccbdd16f0cfdb5c8fa8484a8ba0f2e69d3
2897
device_set_drive_serial (device, g_udev_device_get_property (device->priv->d, "ID_SCSI_SERIAL"));
2899
else if (g_udev_device_has_property (device->priv->d, "ID_SERIAL_SHORT"))
2901
device_set_drive_serial (device, g_udev_device_get_property (device->priv->d, "ID_SERIAL_SHORT"));
2904
if (g_udev_device_has_property (device->priv->d, "ID_WWN_WITH_EXTENSION"))
2905
device_set_drive_wwn (device, g_udev_device_get_property (device->priv->d, "ID_WWN_WITH_EXTENSION") + 2);
2906
else if (g_udev_device_has_property (device->priv->d, "ID_WWN"))
2907
device_set_drive_wwn (device, g_udev_device_get_property (device->priv->d, "ID_WWN") + 2);
2909
/* pick up some things (vendor, model, connection_interface, connection_speed)
2910
* not (yet) exported by udev helpers
2912
update_drive_properties_from_sysfs (device);
2914
if (g_udev_device_has_property (device->priv->d, "ID_DRIVE_EJECTABLE"))
2916
drive_is_ejectable = g_udev_device_get_property_as_boolean (device->priv->d, "ID_DRIVE_EJECTABLE");
2920
drive_is_ejectable = FALSE;
2921
drive_is_ejectable |= g_udev_device_has_property (device->priv->d, "ID_CDROM");
2922
drive_is_ejectable |= g_udev_device_has_property (device->priv->d, "ID_DRIVE_FLOPPY_ZIP");
2923
drive_is_ejectable |= g_udev_device_has_property (device->priv->d, "ID_DRIVE_FLOPPY_JAZ");
2925
device_set_drive_is_media_ejectable (device, drive_is_ejectable);
2927
media_compat_array = g_ptr_array_new ();
2928
for (n = 0; drive_media_mapping[n].udev_property != NULL; n++)
2930
if (!g_udev_device_has_property (device->priv->d, drive_media_mapping[n].udev_property))
2933
g_ptr_array_add (media_compat_array, (gpointer) drive_media_mapping[n].media_name);
2935
/* special handling for SDIO since we don't yet have a sdio_id helper in udev to set properties */
2936
if (g_strcmp0 (device->priv->drive_connection_interface, "sdio") == 0)
2940
type = sysfs_get_string (device->priv->native_path, "../../type");
2942
if (g_strcmp0 (type, "MMC") == 0)
2944
g_ptr_array_add (media_compat_array, "flash_mmc");
2946
else if (g_strcmp0 (type, "SD") == 0)
2948
g_ptr_array_add (media_compat_array, "flash_sd");
2950
else if (g_strcmp0 (type, "SDHC") == 0)
2952
g_ptr_array_add (media_compat_array, "flash_sdhc");
2956
g_ptr_array_sort (media_compat_array, (GCompareFunc) ptr_str_array_compare);
2957
g_ptr_array_add (media_compat_array, NULL);
2958
device_set_drive_media_compatibility (device, (GStrv) media_compat_array->pdata);
2960
media_in_drive = NULL;
2962
if (device->priv->device_is_media_available)
2964
for (n = 0; media_mapping[n].udev_property != NULL; n++)
2966
if (!g_udev_device_has_property (device->priv->d, media_mapping[n].udev_property))
2969
media_in_drive = drive_media_mapping[n].media_name;
2972
/* If the media isn't set (from e.g. udev rules), just pick the first one in media_compat - note
2973
* that this may be NULL (if we don't know what media is compatible with the drive) which is OK.
2975
if (media_in_drive == NULL)
2976
media_in_drive = ((const gchar **) media_compat_array->pdata)[0];
2978
device_set_drive_media (device, media_in_drive);
2980
g_ptr_array_free (media_compat_array, TRUE);
2982
/* right now, we only offer to detach USB devices */
2983
drive_can_detach = FALSE;
2984
if (g_strcmp0 (device->priv->drive_connection_interface, "usb") == 0)
2986
drive_can_detach = TRUE;
2988
if (g_udev_device_has_property (device->priv->d, "ID_DRIVE_DETACHABLE"))
2990
drive_can_detach = g_udev_device_get_property_as_boolean (device->priv->d, "ID_DRIVE_DETACHABLE");
2992
device_set_drive_can_detach (device, drive_can_detach);
2994
/* rotational is in sysfs */
2995
device_set_drive_is_rotational (device, g_udev_device_get_sysfs_attr_as_boolean (device->priv->d, "queue/rotational"));
2997
if (g_udev_device_has_property (device->priv->d, "ID_ATA_ROTATION_RATE_RPM"))
2999
device_set_drive_rotation_rate (device, g_udev_device_get_property_as_int (device->priv->d,
3000
"ID_ATA_ROTATION_RATE_RPM"));
3003
if (g_udev_device_get_property_as_boolean (device->priv->d, "ID_ATA_WRITE_CACHE"))
3005
if (g_udev_device_get_property_as_boolean (device->priv->d, "ID_ATA_WRITE_CACHE_ENABLED"))
3007
device_set_drive_write_cache (device, "enabled");
3011
device_set_drive_write_cache (device, "disabled");
3018
/* ---------------------------------------------------------------------------------------------------- */
3020
/* update drive_can_spindown property */
3022
update_info_drive_can_spindown (Device *device)
3024
gboolean drive_can_spindown;
3026
/* Right now we only know how to spin down ATA devices (including those USB devices
3027
* that can do ATA SMART)
3029
* This would probably also work for SCSI devices (since the helper is doing SCSI
3030
* STOP (which translated in libata to ATA's STANDBY IMMEDIATE) - but that needs
3033
drive_can_spindown = FALSE;
3034
if (g_strcmp0 (device->priv->drive_connection_interface, "ata") == 0 || device->priv->drive_ata_smart_is_available)
3036
drive_can_spindown = TRUE;
3038
if (g_udev_device_has_property (device->priv->d, "ID_DRIVE_CAN_SPINDOWN"))
3040
drive_can_spindown = g_udev_device_get_property_as_boolean (device->priv->d, "ID_DRIVE_CAN_SPINDOWN");
3042
device_set_drive_can_spindown (device, drive_can_spindown);
3047
/* ---------------------------------------------------------------------------------------------------- */
3049
/* update device_is_optical_disc and optical_disc_* properties */
3051
update_info_optical_disc (Device *device)
3053
const gchar *cdrom_disc_state;
3054
gint cdrom_track_count;
3055
gint cdrom_track_count_audio;
3056
gint cdrom_session_count;
3058
/* device_is_optical_disc and optical_disc_* */
3059
if (g_udev_device_has_property (device->priv->d, "ID_CDROM_MEDIA"))
3061
device_set_device_is_optical_disc (device, TRUE);
3063
cdrom_track_count = 0;
3064
cdrom_track_count_audio = 0;
3065
cdrom_session_count = 0;
3067
if (g_udev_device_has_property (device->priv->d, "ID_CDROM_MEDIA_TRACK_COUNT"))
3068
cdrom_track_count = g_udev_device_get_property_as_int (device->priv->d, "ID_CDROM_MEDIA_TRACK_COUNT");
3069
if (g_udev_device_has_property (device->priv->d, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO"))
3070
cdrom_track_count_audio = g_udev_device_get_property_as_int (device->priv->d,
3071
"ID_CDROM_MEDIA_TRACK_COUNT_AUDIO");
3072
if (g_udev_device_has_property (device->priv->d, "ID_CDROM_MEDIA_SESSION_COUNT"))
3073
cdrom_session_count = g_udev_device_get_property_as_int (device->priv->d, "ID_CDROM_MEDIA_SESSION_COUNT");
3074
device_set_optical_disc_num_tracks (device, cdrom_track_count);
3075
device_set_optical_disc_num_audio_tracks (device, cdrom_track_count_audio);
3076
device_set_optical_disc_num_sessions (device, cdrom_session_count);
3077
cdrom_disc_state = g_udev_device_get_property (device->priv->d, "ID_CDROM_MEDIA_STATE");
3078
device_set_optical_disc_is_blank (device, g_strcmp0 (cdrom_disc_state, "blank") == 0);
3079
device_set_optical_disc_is_appendable (device, g_strcmp0 (cdrom_disc_state, "appendable") == 0);
3080
device_set_optical_disc_is_closed (device, g_strcmp0 (cdrom_disc_state, "complete") == 0);
3084
device_set_device_is_optical_disc (device, FALSE);
3086
device_set_optical_disc_num_tracks (device, 0);
3087
device_set_optical_disc_num_audio_tracks (device, 0);
3088
device_set_optical_disc_num_sessions (device, 0);
3089
device_set_optical_disc_is_blank (device, FALSE);
3090
device_set_optical_disc_is_appendable (device, FALSE);
3091
device_set_optical_disc_is_closed (device, FALSE);
3097
/* ---------------------------------------------------------------------------------------------------- */
3099
/* update device_is_luks and luks_holder properties */
3101
update_info_luks (Device *device)
3103
if (g_strcmp0 (device->priv->id_type, "crypto_LUKS") == 0 && device->priv->holders_objpath->len == 1)
3105
device_set_device_is_luks (device, TRUE);
3106
device_set_luks_holder (device, device->priv->holders_objpath->pdata[0]);
3110
device_set_device_is_luks (device, FALSE);
3111
device_set_luks_holder (device, NULL);
3117
/* ---------------------------------------------------------------------------------------------------- */
3119
/* update device_is_luks_cleartext and luks_cleartext_* properties */
3121
update_info_luks_cleartext (Device *device)
3123
uid_t unlocked_by_uid;
3124
const gchar *dkd_dm_name;
3125
const gchar *dkd_dm_target_types;
3130
dkd_dm_name = g_udev_device_get_property (device->priv->d, "DM_NAME");
3131
dkd_dm_target_types = g_udev_device_get_property (device->priv->d, "UDISKS_DM_TARGETS_TYPE");
3132
if (dkd_dm_name != NULL && g_strcmp0 (dkd_dm_target_types, "crypt") == 0 && device->priv->slaves_objpath->len == 1)
3135
/* TODO: might be racing with setting is_drive earlier */
3136
device_set_device_is_drive (device, FALSE);
3138
if (g_str_has_prefix (dkd_dm_name, "temporary-cryptsetup-"))
3140
/* ignore temporary devices created by /sbin/cryptsetup */
3144
device_set_device_is_luks_cleartext (device, TRUE);
3146
device_set_luks_cleartext_slave (device, ((gchar **) device->priv->slaves_objpath->pdata)[0]);
3148
if (luks_get_uid_from_dm_name (dkd_dm_name, &unlocked_by_uid))
3150
device_set_luks_cleartext_unlocked_by_uid (device, unlocked_by_uid);
3153
/* TODO: export this at some point */
3154
device_set_dm_name (device, dkd_dm_name);
3158
device_set_device_is_luks_cleartext (device, FALSE);
3159
device_set_luks_cleartext_slave (device, NULL);
3168
/* ---------------------------------------------------------------------------------------------------- */
3172
extract_lvm_uuid (const gchar *s)
3176
if (s == NULL || strlen (s) < 32)
3179
str = g_string_new_len (s, 6); g_string_append_c (str, '-'); s += 6;
3180
g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
3181
g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
3182
g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
3183
g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
3184
g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
3185
g_string_append_len (str, s, 6);
3187
return g_string_free (str, FALSE);
3190
/* update device_is_linux_lvm2_lv and linux_lvm2_lv_* properties */
3192
update_info_linux_lvm2_lv (Device *device)
3194
const gchar *lv_name;
3195
const gchar *vg_name;
3205
lv_name = g_udev_device_get_property (device->priv->d, "DM_LV_NAME");
3206
vg_name = g_udev_device_get_property (device->priv->d, "DM_VG_NAME");
3208
if (lv_name == NULL || vg_name == NULL)
3211
uuid = g_udev_device_get_sysfs_attr (device->priv->d, "dm/uuid");
3212
if (uuid == NULL || !g_str_has_prefix (uuid, "LVM-"))
3215
vg_uuid = extract_lvm_uuid (uuid + 4);
3216
if (vg_uuid == NULL)
3219
lv_uuid = extract_lvm_uuid (uuid + 4 + 32);
3220
if (lv_uuid == NULL)
3224
device_set_linux_lvm2_lv_name (device, lv_name);
3225
device_set_linux_lvm2_lv_uuid (device, lv_uuid);
3226
device_set_linux_lvm2_lv_group_name (device, vg_name);
3227
device_set_linux_lvm2_lv_group_uuid (device, vg_uuid);
3229
device_set_device_is_drive (device, FALSE);
3230
device_set_device_is_partition (device, FALSE);
3233
device_set_device_is_linux_lvm2_lv (device, is_lv);
3240
/* ---------------------------------------------------------------------------------------------------- */
3243
/* update device_is_linux_dmmp and linux_dmmp_* properties */
3245
update_info_linux_dmmp (Device *device)
3247
const gchar *dm_name;
3248
const gchar* const *target_types;
3249
const gchar* const *target_parameters;
3250
gchar *decoded_params;
3259
decoded_params = NULL;
3261
dm_name = g_udev_device_get_property (device->priv->d, "DM_NAME");
3262
if (dm_name == NULL)
3265
target_types = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_TYPE");
3266
if (target_types == NULL || g_strcmp0 (target_types[0], "multipath") != 0)
3269
if (device->priv->slaves_objpath->len == 0)
3272
target_parameters = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_PARAMS");
3273
if (target_parameters == NULL || g_strv_length ((gchar **) target_parameters) != 1)
3275
decoded_params = decode_udev_encoded_string (target_parameters[0]);
3277
device_set_linux_dmmp_name (device, dm_name);
3279
device_set_linux_dmmp_parameters (device, decoded_params);
3281
p = g_ptr_array_new ();
3283
for (n = 0; n < device->priv->slaves_objpath->len; n++)
3285
const gchar *component_objpath = device->priv->slaves_objpath->pdata[n];
3286
if (component == NULL)
3288
component = daemon_local_find_by_object_path (device->priv->daemon, component_objpath);
3290
g_ptr_array_add (p, (gpointer) component_objpath);
3292
g_ptr_array_add (p, NULL);
3293
device_set_linux_dmmp_slaves (device, (GStrv) p->pdata);
3295
if (component == NULL)
3298
/* Copy only drive properties used for identification to the multipath device. Yes,
3299
* this means, we'll get serial/wwn clashes but this is already so for each path.
3301
* Also, clients *should* be smart about things and special-handle linux_dmmp and
3302
* linux_dmmp_component devices.
3304
device_set_drive_vendor (device, component->priv->drive_vendor);
3305
device_set_drive_model (device, component->priv->drive_model);
3306
device_set_drive_revision (device, component->priv->drive_revision);
3307
device_set_drive_serial (device, component->priv->drive_serial);
3308
device_set_drive_wwn (device, component->priv->drive_wwn);
3310
/* connection interface */
3311
device_set_drive_connection_interface (device, "virtual_multipath");
3312
device_set_drive_connection_speed (device, 0);
3314
s = g_strdup_printf ("/dev/mapper/%s", dm_name);
3315
device_set_device_file_presentation (device, s);
3321
g_free (decoded_params);
3323
g_ptr_array_free (p, TRUE);
3324
device_set_device_is_linux_dmmp (device, is_dmmp);
3329
/* ---------------------------------------------------------------------------------------------------- */
3332
/* updates device_is_partition and partition_* properties for dm-0 "partitions" on a multi-path device */
3334
update_info_partition_on_linux_dmmp (Device *device)
3336
const gchar *dm_name;
3337
const gchar* const *targets_type;
3338
const gchar* const *targets_params;
3340
gint linear_slave_major;
3341
gint linear_slave_minor;
3342
guint64 offset_sectors;
3343
Device *linear_slave;
3348
dm_name = g_udev_device_get_property (device->priv->d, "DM_NAME");
3349
if (dm_name == NULL)
3352
targets_type = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_TYPE");
3353
/* If we ever need this for other types than "linear", remember to update
3354
udisks-dm-export.c as well. */
3355
if (targets_type == NULL || !(g_strcmp0 (targets_type[0], "linear") == 0 ||
3356
g_strcmp0 (targets_type[0], "multipath") == 0))
3359
targets_params = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_PARAMS");
3360
if (targets_params == NULL)
3362
params = decode_udev_encoded_string (targets_params[0]);
3365
"%d:%d %" G_GUINT64_FORMAT,
3366
&linear_slave_major,
3367
&linear_slave_minor,
3368
&offset_sectors) != 3)
3371
linear_slave = daemon_local_find_by_dev (device->priv->daemon,
3372
makedev (linear_slave_major, linear_slave_minor));
3373
if (linear_slave == NULL)
3375
if (!linear_slave->priv->device_is_linux_dmmp)
3378
/* The Partition* properties has been set as part of
3379
* update_info_partition() by reading UDISKS_PARTITION_*
3380
* properties.. so here we bascially just update the presentation
3381
* device file name and and whether the device is a drive.
3384
s = g_strdup_printf ("/dev/mapper/%s", dm_name);
3385
device_set_device_file_presentation (device, s);
3388
device_set_device_is_drive (device, FALSE);
3396
/* ---------------------------------------------------------------------------------------------------- */
3399
/* update device_is_linux_dmmp_component and linux_dmmp_component_* properties */
3401
update_info_linux_dmmp_component (Device *device)
3403
gboolean is_dmmp_component;
3405
is_dmmp_component = FALSE;
3407
if (device->priv->holders_objpath->len == 1)
3411
holder = daemon_local_find_by_object_path (device->priv->daemon, device->priv->holders_objpath->pdata[0]);
3412
if (holder != NULL && holder->priv->device_is_linux_dmmp)
3414
is_dmmp_component = TRUE;
3415
device_set_linux_dmmp_component_holder (device, holder->priv->object_path);
3419
device_set_device_is_linux_dmmp_component (device, is_dmmp_component);
3424
/* ---------------------------------------------------------------------------------------------------- */
3427
/* update device_is_linux_lvm2_pv and linux_lvm2_pv_* properties */
3429
update_info_linux_lvm2_pv (Device *device)
3431
const gchar *pv_uuid;
3433
const gchar *vg_name;
3434
const gchar *vg_uuid;
3437
guint64 vg_unallocated_size;
3438
guint64 vg_extent_size;
3440
const gchar* const *vg_pvs;
3441
const gchar* const *vg_lvs;
3443
pv_uuid = g_udev_device_get_property (device->priv->d, "UDISKS_LVM2_PV_UUID");
3444
pv_num_mda = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_NUM_MDA");
3445
vg_name = g_udev_device_get_property (device->priv->d, "UDISKS_LVM2_PV_VG_NAME");
3446
vg_uuid = g_udev_device_get_property (device->priv->d, "UDISKS_LVM2_PV_VG_UUID");
3447
vg_size = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_VG_SIZE");
3448
vg_unallocated_size = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_VG_FREE_SIZE");
3449
vg_extent_size = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_VG_EXTENT_SIZE");
3450
vg_seqnum = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_VG_SEQNUM");
3451
vg_pvs = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_LVM2_PV_VG_PV_LIST");
3452
vg_lvs = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_LVM2_PV_VG_LV_LIST");
3456
if (pv_uuid == NULL)
3460
device_set_linux_lvm2_pv_uuid (device, pv_uuid);
3461
device_set_linux_lvm2_pv_num_metadata_areas (device, pv_num_mda);
3462
device_set_linux_lvm2_pv_group_name (device, vg_name);
3463
device_set_linux_lvm2_pv_group_uuid (device, vg_uuid);
3464
device_set_linux_lvm2_pv_group_size (device, vg_size);
3465
device_set_linux_lvm2_pv_group_unallocated_size (device, vg_unallocated_size);
3466
device_set_linux_lvm2_pv_group_extent_size (device, vg_extent_size);
3467
device_set_linux_lvm2_pv_group_sequence_number (device, vg_seqnum);
3468
device_set_linux_lvm2_pv_group_physical_volumes (device, (GStrv) vg_pvs);
3469
device_set_linux_lvm2_pv_group_logical_volumes (device, (GStrv) vg_lvs);
3472
device_set_device_is_linux_lvm2_pv (device, is_pv);
3477
/* ---------------------------------------------------------------------------------------------------- */
3479
/* update device_is_linux_md_component and linux_md_component_* properties */
3481
update_info_linux_md_component (Device *device)
3483
if (g_strcmp0 (device->priv->id_type, "linux_raid_member") == 0)
3485
const gchar *md_comp_level;
3486
gint md_comp_num_raid_devices;
3487
const gchar *md_comp_uuid;
3488
const gchar *md_comp_home_host;
3489
const gchar *md_comp_name;
3490
const gchar *md_comp_version;
3493
int md_comp_position;
3495
md_comp_position = -1;
3497
device_set_device_is_linux_md_component (device, TRUE);
3499
/* linux_md_component_holder and linux_md_component_state */
3500
if (device->priv->holders_objpath->len == 1)
3503
gchar **state_tokens;
3505
device_set_linux_md_component_holder (device, device->priv->holders_objpath->pdata[0]);
3506
state_tokens = NULL;
3507
holder = daemon_local_find_by_object_path (device->priv->daemon, device->priv->holders_objpath->pdata[0]);
3508
if (holder != NULL && holder->priv->device_is_linux_md)
3512
gchar *state_contents;
3513
gchar *slot_contents;
3517
dev_name = g_path_get_basename (device->priv->native_path);
3518
md_dev_path = g_strdup_printf ("%s/md/dev-%s", holder->priv->native_path, dev_name);
3519
state_contents = sysfs_get_string (md_dev_path, "state");
3520
g_strstrip (state_contents);
3521
state_tokens = g_strsplit (state_contents, ",", 0);
3523
slot_contents = sysfs_get_string (md_dev_path, "slot");
3524
g_strstrip (slot_contents);
3525
slot_number = strtol (slot_contents, &endp, 0);
3526
if (endp != NULL && *endp == '\0')
3528
md_comp_position = slot_number;
3531
g_free (slot_contents);
3532
g_free (state_contents);
3533
g_free (md_dev_path);
3537
device_set_linux_md_component_state (device, state_tokens);
3538
g_strfreev (state_tokens);
3543
/* no holder, nullify properties */
3544
device_set_linux_md_component_holder (device, NULL);
3545
device_set_linux_md_component_state (device, NULL);
3548
md_comp_level = g_udev_device_get_property (device->priv->d, "MD_LEVEL");
3549
md_comp_num_raid_devices = g_udev_device_get_property_as_int (device->priv->d, "MD_DEVICES");
3550
md_comp_uuid = g_udev_device_get_property (device->priv->d, "MD_UUID");
3551
md_name = g_strdup (g_udev_device_get_property (device->priv->d, "MD_NAME"));
3553
if (md_name != NULL)
3554
s = strstr (md_name, ":");
3558
md_comp_home_host = md_name;
3559
md_comp_name = s + 1;
3563
md_comp_home_host = "";
3564
md_comp_name = md_name;
3566
md_comp_version = device->priv->id_version;
3568
device_set_linux_md_component_level (device, md_comp_level);
3569
device_set_linux_md_component_position (device, md_comp_position);
3570
device_set_linux_md_component_num_raid_devices (device, md_comp_num_raid_devices);
3571
device_set_linux_md_component_uuid (device, md_comp_uuid);
3572
device_set_linux_md_component_home_host (device, md_comp_home_host);
3573
device_set_linux_md_component_name (device, md_comp_name);
3574
device_set_linux_md_component_version (device, md_comp_version);
3580
device_set_device_is_linux_md_component (device, FALSE);
3581
device_set_linux_md_component_level (device, NULL);
3582
device_set_linux_md_component_position (device, -1);
3583
device_set_linux_md_component_num_raid_devices (device, 0);
3584
device_set_linux_md_component_uuid (device, NULL);
3585
device_set_linux_md_component_home_host (device, NULL);
3586
device_set_linux_md_component_name (device, NULL);
3587
device_set_linux_md_component_version (device, NULL);
3588
device_set_linux_md_component_holder (device, NULL);
3589
device_set_linux_md_component_state (device, NULL);
3595
/* ---------------------------------------------------------------------------------------------------- */
3597
/* update device_is_linux_md and linux_md_* properties */
3599
update_info_linux_md (Device *device)
3608
if (sysfs_file_exists (device->priv->native_path, "md"))
3611
gint num_raid_devices;
3615
GPtrArray *md_slaves;
3616
const gchar *md_name;
3617
const gchar *md_home_host;
3619
device_set_device_is_linux_md (device, TRUE);
3621
/* figure out if the array is active */
3622
array_state = sysfs_get_string (device->priv->native_path, "md/array_state");
3623
if (array_state == NULL)
3625
g_print ("**** NOTE: Linux MD array %s has no array_state file'; removing\n", device->priv->native_path);
3628
g_strstrip (array_state);
3630
/* ignore clear arrays since these have no devices, no size, no level */
3631
if (strcmp (array_state, "clear") == 0)
3633
g_print ("**** NOTE: Linux MD array %s is 'clear'; removing\n", device->priv->native_path);
3634
g_free (array_state);
3638
device_set_linux_md_state (device, array_state);
3639
g_free (array_state);
3641
/* find a slave from the array */
3643
for (n = 0; n < device->priv->slaves_objpath->len; n++)
3645
const gchar *slave_objpath;
3647
slave_objpath = device->priv->slaves_objpath->pdata[n];
3648
slave = daemon_local_find_by_object_path (device->priv->daemon, slave_objpath);
3653
uuid = g_strdup (g_udev_device_get_property (device->priv->d, "MD_UUID"));
3654
num_raid_devices = sysfs_get_int (device->priv->native_path, "md/raid_disks");
3655
raid_level = g_strstrip (sysfs_get_string (device->priv->native_path, "md/level"));
3659
/* if the UUID isn't set by the udev rules (array may be inactive) get it from a slave */
3660
if (uuid == NULL || strlen (uuid) == 0)
3663
uuid = g_strdup (slave->priv->linux_md_component_uuid);
3666
/* ditto for raid level */
3667
if (raid_level == NULL || strlen (raid_level) == 0)
3669
g_free (raid_level);
3670
raid_level = g_strdup (slave->priv->linux_md_component_level);
3673
/* and num_raid_devices too */
3674
if (device->priv->linux_md_num_raid_devices == 0)
3676
num_raid_devices = slave->priv->linux_md_component_num_raid_devices;
3680
device_set_linux_md_uuid (device, uuid);
3681
device_set_linux_md_num_raid_devices (device, num_raid_devices);
3682
device_set_linux_md_level (device, raid_level);
3683
g_free (raid_level);
3686
/* infer the array name and homehost */
3687
p = g_strdup (g_udev_device_get_property (device->priv->d, "MD_NAME"));
3690
s = strstr (p, ":");
3702
device_set_linux_md_home_host (device, md_home_host);
3703
device_set_linux_md_name (device, md_name);
3706
s = g_strstrip (sysfs_get_string (device->priv->native_path, "md/metadata_version"));
3707
device_set_linux_md_version (device, s);
3710
/* Go through all block slaves and build up the linux_md_slaves property
3712
* Also update the slaves since the slave state may have changed.
3714
md_slaves = g_ptr_array_new ();
3715
for (n = 0; n < device->priv->slaves_objpath->len; n++)
3717
Device *slave_device;
3718
const gchar *slave_objpath;
3720
slave_objpath = device->priv->slaves_objpath->pdata[n];
3721
g_ptr_array_add (md_slaves, (gpointer) slave_objpath);
3722
slave_device = daemon_local_find_by_object_path (device->priv->daemon, slave_objpath);
3723
if (slave_device != NULL)
3725
update_info (slave_device);
3728
g_ptr_array_sort (md_slaves, (GCompareFunc) ptr_str_array_compare);
3729
g_ptr_array_add (md_slaves, NULL);
3730
device_set_linux_md_slaves (device, (GStrv) md_slaves->pdata);
3731
g_ptr_array_free (md_slaves, TRUE);
3733
/* TODO: may race */
3734
device_set_drive_vendor (device, "Linux");
3735
if (device->priv->linux_md_level != NULL)
3736
s = g_strdup_printf ("Software RAID %s", device->priv->linux_md_level);
3738
s = g_strdup_printf ("Software RAID");
3739
device_set_drive_model (device, s);
3741
device_set_drive_revision (device, device->priv->linux_md_version);
3742
device_set_drive_connection_interface (device, "virtual");
3743
device_set_drive_serial (device, device->priv->linux_md_uuid);
3745
/* RAID-0 can never resync or run degraded */
3746
if (g_strcmp0 (device->priv->linux_md_level, "raid0") == 0 || g_strcmp0 (device->priv->linux_md_level, "linear")
3749
device_set_linux_md_sync_action (device, "idle");
3750
device_set_linux_md_is_degraded (device, FALSE);
3754
gchar *degraded_file;
3755
gint num_degraded_devices;
3757
degraded_file = sysfs_get_string (device->priv->native_path, "md/degraded");
3758
if (degraded_file == NULL)
3760
num_degraded_devices = 0;
3764
num_degraded_devices = strtol (degraded_file, NULL, 0);
3766
g_free (degraded_file);
3768
device_set_linux_md_is_degraded (device, (num_degraded_devices > 0));
3770
s = g_strstrip (sysfs_get_string (device->priv->native_path, "md/sync_action"));
3771
device_set_linux_md_sync_action (device, s);
3774
if (device->priv->linux_md_sync_action == NULL || strlen (device->priv->linux_md_sync_action) == 0)
3776
device_set_linux_md_sync_action (device, "idle");
3779
/* if not idle; update percentage and speed */
3780
if (g_strcmp0 (device->priv->linux_md_sync_action, "idle") != 0)
3786
s = g_strstrip (sysfs_get_string (device->priv->native_path, "md/sync_completed"));
3787
if (sscanf (s, "%" G_GUINT64_FORMAT " / %" G_GUINT64_FORMAT "", &done, &remaining) == 2)
3789
device_set_linux_md_sync_percentage (device, 100.0 * ((double) done) / ((double) remaining));
3793
g_warning ("cannot parse md/sync_completed for %s: '%s'", device->priv->native_path, s);
3797
device_set_linux_md_sync_speed (device, 1000L * sysfs_get_uint64 (device->priv->native_path,
3800
/* Since the kernel doesn't emit uevents while the job is pending, set up
3801
* a timeout for every two seconds to synthesize the change event so we can
3802
* refresh the completed/speed properties.
3804
if (device->priv->linux_md_poll_timeout_id == 0)
3806
device->priv->linux_md_poll_timeout_id = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
3808
poll_syncing_md_device,
3809
g_object_ref (device),
3815
device_set_linux_md_sync_percentage (device, 0.0);
3816
device_set_linux_md_sync_speed (device, 0);
3823
device_set_device_is_linux_md (device, FALSE);
3824
device_set_linux_md_state (device, NULL);
3825
device_set_linux_md_level (device, NULL);
3826
device_set_linux_md_num_raid_devices (device, 0);
3827
device_set_linux_md_uuid (device, NULL);
3828
device_set_linux_md_home_host (device, NULL);
3829
device_set_linux_md_name (device, NULL);
3830
device_set_linux_md_version (device, NULL);
3831
device_set_linux_md_slaves (device, NULL);
3832
device_set_linux_md_is_degraded (device, FALSE);
3833
device_set_linux_md_sync_action (device, NULL);
3834
device_set_linux_md_sync_percentage (device, 0.0);
3835
device_set_linux_md_sync_speed (device, 0);
3844
/* ---------------------------------------------------------------------------------------------------- */
3846
/* update drive_ata_smart_* properties */
3848
update_info_drive_ata_smart (Device *device)
3850
gboolean ata_smart_is_available;
3852
ata_smart_is_available = FALSE;
3853
if (device->priv->device_is_drive && g_udev_device_has_property (device->priv->d, "UDISKS_ATA_SMART_IS_AVAILABLE"))
3854
ata_smart_is_available = g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_ATA_SMART_IS_AVAILABLE");
3856
device_set_drive_ata_smart_is_available (device, ata_smart_is_available);
3858
/* NOTE: we don't collect ATA SMART data here, we only set whether the device is ATA SMART capable;
3859
* collecting data is done in separate routines, see the
3860
* device_drive_ata_smart_refresh_data() function for details.
3866
/* ---------------------------------------------------------------------------------------------------- */
3868
/* device_is_system_internal */
3870
update_info_is_system_internal (Device *device)
3872
gboolean is_system_internal;
3874
if (g_udev_device_has_property (device->priv->d, "UDISKS_SYSTEM_INTERNAL"))
3876
is_system_internal = g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_SYSTEM_INTERNAL");
3880
/* start out by assuming the device is system internal, then adjust depending on what kind of
3881
* device we are dealing with
3883
is_system_internal = TRUE;
3885
/* A Linux MD device is system internal if, and only if
3887
* - a single component is system internal
3888
* - there are no components
3890
if (device->priv->device_is_linux_md)
3892
is_system_internal = FALSE;
3894
if (device->priv->slaves_objpath->len == 0)
3896
is_system_internal = TRUE;
3902
for (n = 0; n < device->priv->slaves_objpath->len; n++)
3904
const gchar *slave_objpath;
3907
slave_objpath = device->priv->slaves_objpath->pdata[n];
3908
slave = daemon_local_find_by_object_path (device->priv->daemon, slave_objpath);
3912
if (slave->priv->device_is_system_internal)
3914
is_system_internal = TRUE;
3923
/* a partition is system internal only if the drive it belongs to is system internal */
3924
if (device->priv->device_is_partition)
3926
Device *enclosing_device;
3928
enclosing_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->partition_slave);
3929
if (enclosing_device != NULL)
3931
is_system_internal = enclosing_device->priv->device_is_system_internal;
3935
is_system_internal = TRUE;
3941
/* a LUKS cleartext device is system internal only if the underlying crypto-text
3942
* device is system internal
3944
if (device->priv->device_is_luks_cleartext)
3946
Device *enclosing_device;
3947
enclosing_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->luks_cleartext_slave);
3948
if (enclosing_device != NULL)
3950
is_system_internal = enclosing_device->priv->device_is_system_internal;
3954
is_system_internal = TRUE;
3960
/* devices with removable media are never system internal */
3961
if (device->priv->device_is_removable)
3963
is_system_internal = FALSE;
3967
/* devices on certain buses are never system internal */
3968
if (device->priv->device_is_drive && device->priv->drive_connection_interface != NULL)
3971
if (strcmp (device->priv->drive_connection_interface, "ata_serial_esata") == 0
3972
|| strcmp (device->priv->drive_connection_interface, "sdio") == 0
3973
|| strcmp (device->priv->drive_connection_interface, "usb") == 0
3974
|| strcmp (device->priv->drive_connection_interface, "firewire") == 0)
3976
is_system_internal = FALSE;
3980
is_system_internal = TRUE;
3986
device_set_device_is_system_internal (device, is_system_internal);
3991
/* ---------------------------------------------------------------------------------------------------- */
3993
/* device_is_mounted, device_mount, device_mounted_by_uid */
3995
update_info_mount_state (Device *device)
3997
MountMonitor *monitor;
3999
gboolean was_mounted;
4003
/* defer setting the mount point until FilesystemMount returns and
4004
* the mounts file is written
4006
if (device->priv->job_in_progress && g_strcmp0 (device->priv->job_id, "FilesystemMount") == 0)
4009
monitor = daemon_local_get_mount_monitor (device->priv->daemon);
4011
mounts = mount_monitor_get_mounts_for_dev (monitor, device->priv->dev);
4013
was_mounted = device->priv->device_is_mounted;
4019
gchar **mount_paths;
4021
mount_paths = g_new0 (gchar *, g_list_length (mounts) + 1);
4022
for (l = mounts, n = 0; l != NULL; l = l->next, n++)
4024
mount_paths[n] = g_strdup (mount_get_mount_path (MOUNT (l->data)));
4027
device_set_device_is_mounted (device, TRUE);
4028
device_set_device_mount_paths (device, mount_paths);
4031
uid_t mounted_by_uid;
4033
if (!mount_file_has_device (device->priv->device_file, &mounted_by_uid, NULL))
4035
device_set_device_mounted_by_uid (device, mounted_by_uid);
4038
g_strfreev (mount_paths);
4043
gboolean remove_dir_on_unmount;
4044
gchar *old_mount_path;
4046
old_mount_path = NULL;
4047
if (device->priv->device_mount_paths->len > 0)
4048
old_mount_path = g_strdup (((gchar **) device->priv->device_mount_paths->pdata)[0]);
4050
device_set_device_is_mounted (device, FALSE);
4051
device_set_device_mount_paths (device, NULL);
4052
device_set_device_mounted_by_uid (device, 0);
4054
/* clean up stale mount directory */
4055
remove_dir_on_unmount = FALSE;
4056
if (was_mounted && mount_file_has_device (device->priv->device_file, NULL, &remove_dir_on_unmount))
4058
mount_file_remove (device->priv->device_file, old_mount_path);
4059
if (remove_dir_on_unmount)
4061
if (g_rmdir (old_mount_path) != 0)
4063
g_warning ("Error removing dir '%s' on unmount: %m", old_mount_path);
4068
g_free (old_mount_path);
4073
g_list_foreach (mounts, (GFunc) g_object_unref, NULL);
4074
g_list_free (mounts);
4079
/* ---------------------------------------------------------------------------------------------------- */
4081
/* device_is_media_change_detected, device_is_media_change_detection_* properties */
4083
update_info_media_detection (Device *device)
4087
gboolean inhibitable;
4092
inhibitable = FALSE;
4095
if (device->priv->device_is_removable)
4097
guint64 evt_media_change;
4098
GUdevDevice *parent;
4100
evt_media_change = sysfs_get_uint64 (device->priv->native_path, "../../evt_media_change");
4101
if (evt_media_change & 1)
4103
/* SATA AN capabable drive */
4110
parent = g_udev_device_get_parent_with_subsystem (device->priv->d, "platform", NULL);
4113
/* never poll PC floppy drives, they are noisy (fdo #22149) */
4114
if (g_str_has_prefix (g_udev_device_get_name (parent), "floppy."))
4116
g_object_unref (parent);
4119
g_object_unref (parent);
4122
/* assume the device needs polling */
4126
/* custom udev rules might want to disable polling for known-broken
4127
* devices (fdo #26508) */
4128
if (g_udev_device_has_property (device->priv->d, "UDISKS_DISABLE_POLLING") &&
4129
g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_DISABLE_POLLING"))
4132
if (device->priv->polling_inhibitors != NULL || daemon_local_has_polling_inhibitors (device->priv->daemon))
4146
device_set_device_is_media_change_detected (device, detected);
4147
device_set_device_is_media_change_detection_polling (device, polling);
4148
device_set_device_is_media_change_detection_inhibitable (device, inhibitable);
4149
device_set_device_is_media_change_detection_inhibited (device, inhibited);
4154
/* ---------------------------------------------------------------------------------------------------- */
4156
/* drive_adapter property */
4158
update_info_drive_adapter (Device *device)
4161
const gchar *adapter_object_path;
4163
adapter_object_path = NULL;
4165
adapter = daemon_local_find_enclosing_adapter (device->priv->daemon, device->priv->native_path);
4166
if (adapter != NULL)
4168
adapter_object_path = adapter_local_get_object_path (adapter);
4171
device_set_drive_adapter (device, adapter_object_path);
4176
/* drive_ports property */
4178
update_info_drive_ports (Device *device)
4184
ports = daemon_local_find_enclosing_ports (device->priv->daemon, device->priv->native_path);
4186
p = g_ptr_array_new ();
4187
for (l = ports; l != NULL; l = l->next)
4189
Port *port = PORT (l->data);
4191
g_ptr_array_add (p, (gpointer) port_local_get_object_path (port));
4193
g_ptr_array_add (p, NULL);
4194
device_set_drive_ports (device, (GStrv) p->pdata);
4195
g_ptr_array_unref (p);
4197
g_list_free (ports);
4202
/* drive_similar_devices property */
4204
update_info_drive_similar_devices (Device *device)
4210
p = g_ptr_array_new ();
4212
if (!device->priv->device_is_drive)
4215
/* We need non-empty SERIAL and WWN for this to work */
4216
if ((device->priv->drive_serial == NULL || strlen (device->priv->drive_serial) == 0) ||
4217
(device->priv->drive_wwn == NULL || strlen (device->priv->drive_wwn) == 0))
4220
/* TODO: this might be slow - if so, use a hash on the Daemon class */
4221
devices = daemon_local_get_all_devices (device->priv->daemon);
4222
for (l = devices; l != NULL; l = l->next)
4224
Device *d = DEVICE (l->data);
4226
if (!d->priv->device_is_drive)
4233
g_debug ("looking at %s:\n"
4238
d->priv->device_file,
4239
d->priv->drive_serial,
4240
device->priv->drive_serial,
4242
device->priv->drive_wwn);
4245
/* current policy is that *both* SERIAL and WWN must match */
4246
if (g_strcmp0 (d->priv->drive_serial, device->priv->drive_serial) == 0 &&
4247
g_strcmp0 (d->priv->drive_wwn, device->priv->drive_wwn) == 0)
4249
g_ptr_array_add (p, d->priv->object_path);
4251
/* ensure that the device we added also exists in its own drive_similar_devices property */
4252
if (!ptr_array_has_string (d->priv->drive_similar_devices, device->priv->object_path))
4254
//g_debug ("\n************************************************************\nforcing update in idle");
4255
update_info_in_idle (d);
4259
//g_debug ("\n************************************************************\nNOT forcing update in idle");
4265
g_ptr_array_add (p, NULL);
4266
device_set_drive_similar_devices (device, (GStrv) p->pdata);
4267
g_ptr_array_free (p, TRUE);
4271
/* ---------------------------------------------------------------------------------------------------- */
4273
/* update device_is_linux_loop and linux_loop_* properties */
4275
update_info_linux_loop (Device *device)
4279
struct loop_info64 loop_info_buf;
4288
if (!g_str_has_prefix (device->priv->native_path, "/sys/devices/virtual/block/loop"))
4294
fd = open (device->priv->device_file, O_RDONLY);
4298
if (ioctl (fd, LOOP_GET_STATUS64, &loop_info_buf) != 0)
4301
/* TODO: is lo_file_name really NUL-terminated? */
4302
device_set_linux_loop_filename (device, (const gchar *) loop_info_buf.lo_file_name);
4307
device_set_drive_vendor (device, "Linux");
4308
s2 = g_path_get_basename ((gchar *) loop_info_buf.lo_file_name);
4309
s = g_strdup_printf ("Loop: %s", s2);
4311
device_set_drive_model (device, s);
4317
device_set_device_is_linux_loop (device, is_loop);
4321
/* ---------------------------------------------------------------------------------------------------- */
4327
} UpdateInfoInIdleData;
4330
update_info_in_idle_device_unreffed (gpointer user_data,
4331
GObject *where_the_object_was)
4333
UpdateInfoInIdleData *data = user_data;
4334
g_source_remove (data->idle_id);
4338
update_info_in_idle_data_free (UpdateInfoInIdleData *data)
4340
g_object_weak_unref (G_OBJECT (data->device), update_info_in_idle_device_unreffed, data);
4345
update_info_in_idle_cb (gpointer user_data)
4347
UpdateInfoInIdleData *data = user_data;
4349
/* this indirectly calls update_info and also removes the device
4350
* if it wants to be removed (e.g. if update_info() returns FALSE)
4352
daemon_local_synthesize_changed (data->device->priv->daemon, data->device);
4354
return FALSE; /* remove source */
4358
* update_info_in_idle:
4359
* @device: A #Device.
4361
* Like update_info() but does the update in idle. Takes a weak ref to
4362
* @device and cancels the update if @device is unreffed.
4365
update_info_in_idle (Device *device)
4367
UpdateInfoInIdleData *data;
4369
data = g_new0 (UpdateInfoInIdleData, 1);
4370
data->device = device;
4371
data->idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
4372
update_info_in_idle_cb,
4374
(GDestroyNotify) update_info_in_idle_data_free);
4376
g_object_weak_ref (G_OBJECT (device), update_info_in_idle_device_unreffed, data);
4381
* @device: the device
4383
* Update information about the device.
4385
* If one or more properties changed, the changes are scheduled to be emitted. Use
4386
* drain_pending_changes() to force emitting the pending changes (which is useful
4387
* before returning the result of an operation).
4389
* Returns: #TRUE to keep (or add) the device; #FALSE to ignore (or remove) the device
4392
update_info (Device *device)
4401
GList *old_slaves_objpath;
4402
GList *old_holders_objpath;
4403
GList *cur_slaves_objpath;
4404
GList *cur_holders_objpath;
4405
GList *added_objpath;
4406
GList *removed_objpath;
4407
GPtrArray *symlinks_by_id;
4408
GPtrArray *symlinks_by_path;
4413
gboolean media_available;
4417
PROFILE ("update_info(device=%s) start", device->priv->native_path);
4419
g_print ("**** UPDATING %s\n", device->priv->native_path);
4421
/* need the slaves/holders to synthesize 'change' events if a device goes away (since the kernel
4422
* doesn't do generate these)
4424
old_slaves_objpath = dup_list_from_ptrarray (device->priv->slaves_objpath);
4425
old_holders_objpath = dup_list_from_ptrarray (device->priv->holders_objpath);
4427
/* drive identification */
4428
if (sysfs_file_exists (device->priv->native_path, "range"))
4430
device_set_device_is_drive (device, TRUE);
4434
device_set_device_is_drive (device, FALSE);
4437
if (!g_udev_device_has_property (device->priv->d, "MAJOR") || !g_udev_device_has_property (device->priv->d, "MINOR"))
4439
g_warning ("No major/minor for %s", device->priv->native_path);
4443
/* ignore dm devices that are suspended */
4444
if (g_str_has_prefix (g_udev_device_get_name (device->priv->d), "dm-"))
4446
if (g_strcmp0 (g_udev_device_get_property (device->priv->d, "DM_SUSPENDED"), "1") == 0)
4450
major = g_udev_device_get_property_as_int (device->priv->d, "MAJOR");
4451
minor = g_udev_device_get_property_as_int (device->priv->d, "MINOR");
4452
device->priv->dev = makedev (major, minor);
4454
device_set_device_file (device, g_udev_device_get_device_file (device->priv->d));
4455
if (device->priv->device_file == NULL)
4457
g_warning ("No device file for %s", device->priv->native_path);
4461
const char * const * symlinks;
4462
symlinks = g_udev_device_get_device_file_symlinks (device->priv->d);
4463
symlinks_by_id = g_ptr_array_new ();
4464
symlinks_by_path = g_ptr_array_new ();
4465
for (n = 0; symlinks[n] != NULL; n++)
4467
if (g_str_has_prefix (symlinks[n], "/dev/disk/by-id/") || g_str_has_prefix (symlinks[n], "/dev/disk/by-uuid/"))
4469
g_ptr_array_add (symlinks_by_id, (gpointer) symlinks[n]);
4471
else if (g_str_has_prefix (symlinks[n], "/dev/disk/by-path/"))
4473
g_ptr_array_add (symlinks_by_path, (gpointer) symlinks[n]);
4476
g_ptr_array_sort (symlinks_by_id, (GCompareFunc) ptr_str_array_compare);
4477
g_ptr_array_sort (symlinks_by_path, (GCompareFunc) ptr_str_array_compare);
4478
g_ptr_array_add (symlinks_by_id, NULL);
4479
g_ptr_array_add (symlinks_by_path, NULL);
4480
device_set_device_file_by_id (device, (GStrv) symlinks_by_id->pdata);
4481
device_set_device_file_by_path (device, (GStrv) symlinks_by_path->pdata);
4482
g_ptr_array_free (symlinks_by_id, TRUE);
4483
g_ptr_array_free (symlinks_by_path, TRUE);
4485
device_set_device_is_removable (device, (sysfs_get_int (device->priv->native_path, "removable") != 0));
4487
/* device_is_media_available and device_media_detection_time property */
4488
if (device->priv->device_is_removable)
4490
media_available = FALSE;
4492
if (!g_udev_device_get_property_as_boolean (device->priv->d, "ID_CDROM") &&
4493
!g_udev_device_get_property_as_boolean (device->priv->d, "ID_DRIVE_FLOPPY"))
4496
fd = open (device->priv->device_file, O_RDONLY);
4499
media_available = TRUE;
4505
if (g_udev_device_get_property_as_boolean (device->priv->d, "ID_CDROM_MEDIA"))
4507
media_available = TRUE;
4511
media_available = FALSE;
4517
media_available = TRUE;
4519
device_set_device_is_media_available (device, media_available);
4520
if (media_available)
4522
if (device->priv->device_media_detection_time == 0)
4523
device_set_device_media_detection_time (device, (guint64) time (NULL));
4527
device_set_device_media_detection_time (device, 0);
4530
/* device_size, device_block_size and device_is_read_only properties */
4531
if (device->priv->device_is_media_available)
4535
device_set_device_size (device, sysfs_get_uint64 (device->priv->native_path, "size") * ((guint64) 512));
4536
device_set_device_is_read_only (device, (sysfs_get_int (device->priv->native_path, "ro") != 0));
4537
/* This is not available on all devices so fall back to 512 if unavailable.
4539
* Another way to get this information is the BLKSSZGET ioctl but we don't want
4540
* to open the device. Ideally vol_id would export it.
4542
block_size = sysfs_get_uint64 (device->priv->native_path, "queue/hw_sector_size");
4543
if (block_size == 0)
4545
device_set_device_block_size (device, block_size);
4550
device_set_device_size (device, 0);
4551
device_set_device_block_size (device, 0);
4552
device_set_device_is_read_only (device, FALSE);
4555
/* Maintain (non-exported) properties holders and slaves for the holders resp. slaves
4556
* directories in sysfs. The entries in these arrays are object paths - we ignore
4557
* an entry unless it corresponds to an device in our local database.
4559
path = g_build_filename (device->priv->native_path, "slaves", NULL);
4560
slaves = g_ptr_array_new ();
4561
if ((dir = g_dir_open (path, 0, NULL)) != NULL)
4563
while ((name = g_dir_read_name (dir)) != NULL)
4567
s = compute_object_path (name);
4569
device2 = daemon_local_find_by_object_path (device->priv->daemon, s);
4570
if (device2 != NULL)
4572
//g_debug ("%s has slave %s", device->priv->object_path, s);
4573
g_ptr_array_add (slaves, s);
4577
//g_debug ("%s has non-existant slave %s", device->priv->object_path, s);
4584
g_ptr_array_sort (slaves, (GCompareFunc) ptr_str_array_compare);
4585
g_ptr_array_add (slaves, NULL);
4586
device_set_slaves_objpath (device, (GStrv) slaves->pdata);
4587
g_ptr_array_foreach (slaves, (GFunc) g_free, NULL);
4588
g_ptr_array_free (slaves, TRUE);
4590
path = g_build_filename (device->priv->native_path, "holders", NULL);
4591
holders = g_ptr_array_new ();
4592
if ((dir = g_dir_open (path, 0, NULL)) != NULL)
4594
while ((name = g_dir_read_name (dir)) != NULL)
4598
s = compute_object_path (name);
4599
device2 = daemon_local_find_by_object_path (device->priv->daemon, s);
4600
if (device2 != NULL)
4602
//g_debug ("%s has holder %s", device->priv->object_path, s);
4603
g_ptr_array_add (holders, s);
4607
//g_debug ("%s has non-existant holder %s", device->priv->object_path, s);
4614
g_ptr_array_sort (holders, (GCompareFunc) ptr_str_array_compare);
4615
g_ptr_array_add (holders, NULL);
4616
device_set_holders_objpath (device, (GStrv) holders->pdata);
4617
g_ptr_array_foreach (holders, (GFunc) g_free, NULL);
4618
g_ptr_array_free (holders, TRUE);
4620
/* ------------------------------------- */
4621
/* Now set all properties from udev data */
4622
/* ------------------------------------- */
4624
/* at this point we have
4627
* - device_file_by_id
4628
* - device_file_by_path
4630
* - device_block_size
4631
* - device_is_removable
4632
* - device_is_read_only
4634
* - device_is_media_available
4635
* - device_is_partition
4636
* - device_is_partition_table
4640
* - partition_number
4645
/* device_is_linux_loop and linux_loop_* properties */
4646
if (!update_info_linux_loop (device))
4649
/* partition_* properties */
4650
if (!update_info_partition (device))
4653
/* partition_table_* properties */
4654
if (!update_info_partition_table (device))
4657
/* device_presentation_hide, device_presentation_name and device_presentation_icon_name properties */
4658
if (!update_info_presentation (device))
4661
/* id_* properties */
4662
if (!update_info_id (device))
4665
/* drive_* properties */
4666
if (!update_info_drive (device))
4669
/* device_is_optical_disc and optical_disc_* properties */
4670
if (!update_info_optical_disc (device))
4673
/* device_is_luks and luks_holder */
4674
if (!update_info_luks (device))
4677
/* device_is_luks_cleartext and luks_cleartext_* properties */
4678
if (!update_info_luks_cleartext (device))
4682
/* device_is_linux_lvm2_lv and linux_lvm2_lv_* properties */
4683
if (!update_info_linux_lvm2_lv (device))
4686
/* device_is_linux_lvm2_pv and linux_lvm2_pv_* properties */
4687
if (!update_info_linux_lvm2_pv (device))
4692
/* device_is_linux_dmmp and linux_dmmp_* properties */
4693
if (!update_info_linux_dmmp (device))
4696
/* device_is_partition and partition_* properties for dm-0 "partitions" on a multi-path device */
4697
if (!update_info_partition_on_linux_dmmp (device))
4700
/* device_is_linux_dmmp_component and linux_dmmp_component_* properties */
4701
if (!update_info_linux_dmmp_component (device))
4705
/* device_is_linux_md_component and linux_md_component_* properties */
4706
if (!update_info_linux_md_component (device))
4709
/* device_is_linux_md and linux_md_* properties */
4710
if (!update_info_linux_md (device))
4713
/* drive_ata_smart_* properties */
4714
if (!update_info_drive_ata_smart (device))
4717
/* drive_can_spindown property */
4718
if (!update_info_drive_can_spindown (device))
4721
/* device_is_system_internal property */
4722
if (!update_info_is_system_internal (device))
4725
/* device_is_mounted, device_mount, device_mounted_by_uid */
4726
if (!update_info_mount_state (device))
4729
/* device_is_media_change_detected, device_is_media_change_detection_* properties */
4730
if (!update_info_media_detection (device))
4733
/* drive_adapter proprety */
4734
if (!update_info_drive_adapter (device))
4737
/* drive_ports property */
4738
if (!update_info_drive_ports (device))
4741
/* drive_similar_devices property */
4742
if (!update_info_drive_similar_devices (device))
4749
/* Now check if holders/ or slaves/ has changed since last update. We compute
4750
* the delta and do update_info() on each holder/slave that has been
4753
* Note that this won't trigger an endless loop since we look at the diffs.
4755
* We have to do this because the kernel doesn't generate any 'change' event
4756
* when slaves/ or holders/ change. This is unfortunate because we *need* such
4757
* a change event to update properties devices (for example: luks_holder).
4759
* We do the update in idle because the update may depend on the device
4760
* currently being processed being added.
4763
cur_slaves_objpath = dup_list_from_ptrarray (device->priv->slaves_objpath);
4764
cur_holders_objpath = dup_list_from_ptrarray (device->priv->holders_objpath);
4766
old_slaves_objpath = g_list_sort (old_slaves_objpath, (GCompareFunc) g_strcmp0);
4767
old_holders_objpath = g_list_sort (old_holders_objpath, (GCompareFunc) g_strcmp0);
4768
cur_slaves_objpath = g_list_sort (cur_slaves_objpath, (GCompareFunc) g_strcmp0);
4769
cur_holders_objpath = g_list_sort (cur_holders_objpath, (GCompareFunc) g_strcmp0);
4771
diff_sorted_lists (old_slaves_objpath, cur_slaves_objpath, (GCompareFunc) g_strcmp0, &added_objpath, &removed_objpath);
4772
for (l = added_objpath; l != NULL; l = l->next)
4774
const gchar *objpath2 = l->data;
4777
//g_debug ("### %s added slave %s", device->priv->object_path, objpath2);
4778
device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
4779
if (device2 != NULL)
4781
update_info_in_idle (device2);
4785
g_print ("**** NOTE: %s added non-existant slave %s\n", device->priv->object_path, objpath2);
4788
for (l = removed_objpath; l != NULL; l = l->next)
4790
const gchar *objpath2 = l->data;
4793
//g_debug ("### %s removed slave %s", device->priv->object_path, objpath2);
4794
device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
4795
if (device2 != NULL)
4797
update_info_in_idle (device2);
4801
//g_debug ("### %s removed non-existant slave %s", device->priv->object_path, objpath2);
4804
g_list_free (added_objpath);
4805
g_list_free (removed_objpath);
4807
diff_sorted_lists (old_holders_objpath,
4808
cur_holders_objpath,
4809
(GCompareFunc) g_strcmp0,
4812
for (l = added_objpath; l != NULL; l = l->next)
4814
const gchar *objpath2 = l->data;
4817
//g_debug ("### %s added holder %s", device->priv->object_path, objpath2);
4818
device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
4819
if (device2 != NULL)
4821
update_info_in_idle (device2);
4825
g_print ("**** NOTE: %s added non-existant holder %s\n", device->priv->object_path, objpath2);
4828
for (l = removed_objpath; l != NULL; l = l->next)
4830
const gchar *objpath2 = l->data;
4833
//g_debug ("### %s removed holder %s", device->priv->object_path, objpath2);
4834
device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
4835
if (device2 != NULL)
4837
update_info_in_idle (device2);
4841
//g_debug ("### %s removed non-existant holder %s", device->priv->object_path, objpath2);
4844
g_list_free (added_objpath);
4845
g_list_free (removed_objpath);
4847
g_list_foreach (old_slaves_objpath, (GFunc) g_free, NULL);
4848
g_list_free (old_slaves_objpath);
4849
g_list_foreach (old_holders_objpath, (GFunc) g_free, NULL);
4850
g_list_free (old_holders_objpath);
4851
g_list_foreach (cur_slaves_objpath, (GFunc) g_free, NULL);
4852
g_list_free (cur_slaves_objpath);
4853
g_list_foreach (cur_holders_objpath, (GFunc) g_free, NULL);
4854
g_list_free (cur_holders_objpath);
4856
PROFILE ("update_info(device=%s) end", device->priv->native_path);
4861
* device_local_is_busy:
4862
* @device: A #Device.
4863
* @check_partitions: Whether to check if partitions is busy if @device is a partition table
4864
* @check_mounted: Whether to check if device has mounted file systems
4865
* @error: Either %NULL or a #GError to set to #ERROR_BUSY and an appropriate
4866
* message, e.g. "Device is busy" or "A partition on the device is busy" if the device is busy.
4868
* Checks if @device is busy.
4870
* Returns: %TRUE if the device or, if @check_partitions is %TRUE, a partition on the device is busy.
4873
device_local_is_busy (Device *device,
4874
gboolean check_partitions,
4875
gboolean check_mounted,
4882
/* busy if a job is pending */
4883
if (device->priv->job != NULL)
4885
g_set_error (error, ERROR, ERROR_BUSY, "A job is pending on %s", device->priv->device_file);
4889
/* or if we're mounted */
4890
if (check_mounted && device->priv->device_is_mounted)
4892
g_set_error (error, ERROR, ERROR_BUSY, "%s is mounted", device->priv->device_file);
4896
/* or if another block device is using/holding us (e.g. if holders/ is non-empty in sysfs) */
4897
if (device->priv->holders_objpath->len > 0)
4899
if (device->priv->device_is_linux_dmmp)
4908
"One or more block devices are holding %s",
4909
device->priv->device_file);
4914
/* If we are an extended partition, we are also busy if one or more logical partitions are busy
4915
* even if @check_partitions is FALSE... This is because an extended partition only really is
4918
if (g_strcmp0 (device->priv->partition_scheme, "mbr") == 0 && device->priv->partition_type != NULL)
4920
gint partition_type;
4921
partition_type = strtol (device->priv->partition_type, NULL, 0);
4922
if (partition_type == 0x05 || partition_type == 0x0f || partition_type == 0x85)
4924
Device *drive_device;
4925
drive_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->partition_slave);
4926
if (device_local_logical_partitions_are_busy (drive_device))
4928
g_set_error (error, ERROR, ERROR_BUSY, "%s is an MS-DOS extended partition and one or more "
4929
"logical partitions are busy", device->priv->device_file);
4935
/* if we are a partition table, we are busy if one of our partitions are busy */
4936
if (check_partitions && device->priv->device_is_partition_table)
4938
if (device_local_partitions_are_busy (device))
4940
g_set_error (error, ERROR, ERROR_BUSY, "One or more partitions are busy on %s", device->priv->device_file);
4951
/* note: this only checks whether the actual partitions are busy;
4952
* caller will need to check the main device itself too
4955
device_local_partitions_are_busy (Device *device)
4963
devices = daemon_local_get_all_devices (device->priv->daemon);
4964
for (l = devices; l != NULL; l = l->next)
4966
Device *d = DEVICE (l->data);
4968
if (d->priv->device_is_partition && d->priv->partition_slave != NULL && g_strcmp0 (d->priv->partition_slave,
4969
device->priv->object_path)
4973
if (device_local_is_busy (d, FALSE, TRUE, NULL))
4981
g_list_free (devices);
4987
device_local_logical_partitions_are_busy (Device *device)
4995
devices = daemon_local_get_all_devices (device->priv->daemon);
4996
for (l = devices; l != NULL; l = l->next)
4998
Device *d = DEVICE (l->data);
5000
if (d->priv->device_is_partition && d->priv->partition_slave != NULL && g_strcmp0 (d->priv->partition_slave,
5001
device->priv->object_path)
5002
== 0 && g_strcmp0 (d->priv->partition_scheme, "mbr") == 0 && d->priv->partition_number >= 5)
5005
if (device_local_is_busy (d, FALSE, TRUE, NULL))
5013
g_list_free (devices);
5019
device_has_logical_partitions (Device *device)
5027
devices = daemon_local_get_all_devices (device->priv->daemon);
5028
for (l = devices; l != NULL; l = l->next)
5030
Device *d = DEVICE (l->data);
5032
if (d->priv->device_is_partition && d->priv->partition_slave != NULL && g_strcmp0 (d->priv->partition_slave,
5033
device->priv->object_path)
5034
== 0 && g_strcmp0 (d->priv->partition_scheme, "mbr") == 0 && d->priv->partition_number >= 5)
5041
g_list_free (devices);
5047
device_removed (Device *device)
5051
device->priv->removed = TRUE;
5053
dbus_g_connection_unregister_g_object (device->priv->system_bus_connection, G_OBJECT (device));
5054
g_assert (dbus_g_connection_lookup_g_object (device->priv->system_bus_connection, device->priv->object_path) == NULL);
5056
/* device is now removed; update all slaves and holders */
5057
for (n = 0; n < device->priv->slaves_objpath->len; n++)
5059
const gchar *objpath2 = ((gchar **) device->priv->slaves_objpath->pdata)[n];
5062
device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
5063
if (device2 != NULL)
5065
update_info (device2);
5068
for (n = 0; n < device->priv->holders_objpath->len; n++)
5070
const gchar *objpath2 = ((gchar **) device->priv->holders_objpath->pdata)[n];
5073
device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
5074
if (device2 != NULL)
5076
update_info (device2);
5080
/* If the device is busy, we possibly need to clean up if the
5081
* device itself is busy. This includes
5083
* - force unmounting the device and/or all it's partitions
5085
* - tearing down a luks mapping if it's a cleartext device
5086
* backed by a crypted device
5088
* but see force_removal() for details.
5090
* This is the normally the path where the enclosing device is
5091
* removed. Compare with device_changed() for the
5094
force_removal (device, NULL, NULL);
5098
device_initial_ata_smart_refresh (gpointer data)
5100
Device *device = (Device *) data;
5101
static gchar *ata_smart_refresh_data_options[] = { NULL };
5103
/* if we are inhibited, try again */
5104
if (daemon_local_is_inhibited (device->priv->daemon))
5106
g_print("**** INITIAL ATA SMART POLL for %s: Daemon inhibited, trying again\n", device->priv->device_file);
5110
/* if the SMART status was manually updated, or the device got removed in the
5111
* meantime, don't bother */
5112
if (device->priv->drive_ata_smart_status == (SkSmartOverall) - 1 &&
5113
!device->priv->removed)
5115
g_print("**** INITIAL ATA SMART POLL for %s\n", device->priv->device_file);
5116
device_drive_ata_smart_refresh_data (device, ata_smart_refresh_data_options, NULL);
5119
g_object_unref (device);
5124
device_new (Daemon *daemon,
5128
const char *native_path;
5131
native_path = g_udev_device_get_sysfs_path (d);
5133
/* ignore ram devices */
5134
if (g_str_has_prefix (native_path, "/sys/devices/virtual/block/ram"))
5137
PROFILE ("device_new(native_path=%s): start", native_path);
5139
device = DEVICE (g_object_new (TYPE_DEVICE, NULL));
5140
device->priv->d = g_object_ref (d);
5141
device->priv->daemon = g_object_ref (daemon);
5142
device->priv->native_path = g_strdup (native_path);
5144
/* TODO: we might want to get this from udev or the kernel... to get the time when the device
5145
* was initially detected... as opposed to this value which is when the device was detected
5146
* by our daemon... but this will do for now...
5148
device->priv->device_detection_time = (guint64) time (NULL);
5150
PROFILE ("device_new(native_path=%s): update_info", native_path);
5151
if (!update_info (device))
5153
g_object_unref (device);
5158
PROFILE ("device_new(native_path=%s): register_disks_device", native_path);
5159
if (!register_disks_device (DEVICE (device)))
5161
g_object_unref (device);
5166
/* if just added, update the smart data if applicable */
5167
if (device->priv->drive_ata_smart_is_available)
5169
g_print("**** QUEUEING initial ata smart refresh for %s\n", device->priv->device_file);
5170
g_timeout_add_seconds (30, device_initial_ata_smart_refresh, g_object_ref (device));
5173
PROFILE ("device_new(native_path=%s): end", native_path);
5179
drain_pending_changes (Device *device,
5180
gboolean force_update)
5182
gboolean emit_changed;
5184
emit_changed = FALSE;
5186
/* the update-in-idle is set up if, and only if, there are pending changes - so
5187
* we should emit a 'change' event only if it is set up
5189
if (device->priv->emit_changed_idle_id != 0)
5191
g_source_remove (device->priv->emit_changed_idle_id);
5192
device->priv->emit_changed_idle_id = 0;
5193
emit_changed = TRUE;
5196
if ((!device->priv->removed) && (emit_changed || force_update))
5198
if (device->priv->object_path != NULL)
5200
g_print ("**** EMITTING CHANGED for %s\n", device->priv->native_path);
5201
g_signal_emit_by_name (device, "changed");
5202
g_signal_emit_by_name (device->priv->daemon, "device-changed", device->priv->object_path);
5208
emit_job_changed (Device *device)
5210
drain_pending_changes (device, FALSE);
5212
if (!device->priv->removed)
5214
g_print ("**** EMITTING JOB-CHANGED for %s\n", device->priv->native_path);
5215
g_signal_emit_by_name (device->priv->daemon,
5216
"device-job-changed",
5217
device->priv->object_path,
5218
device->priv->job_in_progress,
5219
device->priv->job_id,
5220
device->priv->job_initiated_by_uid,
5221
device->priv->job_is_cancellable,
5222
device->priv->job_percentage,
5224
g_signal_emit (device,
5225
signals[JOB_CHANGED_SIGNAL],
5227
device->priv->job_in_progress,
5228
device->priv->job_id,
5229
device->priv->job_initiated_by_uid,
5230
device->priv->job_is_cancellable,
5231
device->priv->job_percentage);
5235
/* called by the daemon on the 'change' uevent */
5237
device_changed (Device *device,
5239
gboolean synthesized)
5241
gboolean keep_device;
5243
g_object_unref (device->priv->d);
5244
device->priv->d = g_object_ref (d);
5246
keep_device = update_info (device);
5248
/* this 'change' event might prompt us to remove the device */
5252
/* no, it's good .. keep it.. and always force a 'change' signal if the event isn't synthesized */
5253
drain_pending_changes (device, !synthesized);
5255
/* Check if media was removed. If so, we possibly need to clean up
5256
* if the device itself is busy. This includes
5258
* - force unmounting the device
5260
* - tearing down a luks mapping if it's a cleartext device
5261
* backed by a crypted device
5263
* but see force_removal() for details.
5265
* This is the normally the path where the media is removed but the enclosing
5266
* device is still present. Compare with device_removed() for
5269
if (!device->priv->device_is_media_available)
5274
force_removal (device, NULL, NULL);
5276
/* check all partitions */
5277
devices = daemon_local_get_all_devices (device->priv->daemon);
5278
for (l = devices; l != NULL; l = l->next)
5280
Device *d = DEVICE (l->data);
5282
if (d->priv->device_is_partition && d->priv->partition_slave != NULL && strcmp (d->priv->partition_slave,
5283
device->priv->object_path)
5287
force_removal (d, NULL, NULL);
5291
g_list_free (devices);
5297
/*--------------------------------------------------------------------------------------------------------------*/
5300
device_local_get_object_path (Device *device)
5302
return device->priv->object_path;
5306
device_local_get_native_path (Device *device)
5308
return device->priv->native_path;
5312
device_local_get_dev (Device *device)
5314
return device->priv->dev;
5318
device_local_get_device_file (Device *device)
5320
return device->priv->device_file;
5323
/*--------------------------------------------------------------------------------------------------------------*/
5326
throw_error (DBusGMethodInvocation *context,
5335
va_start (args, format);
5336
message = g_strdup_vprintf (format, args);
5339
if (context == NULL)
5341
g_warning ("%s", message);
5345
error = g_error_new (ERROR, error_code, "%s", message);
5346
dbus_g_method_return_error (context, error);
5347
g_error_free (error);
5352
/*--------------------------------------------------------------------------------------------------------------*/
5355
(*JobCompletedFunc) (DBusGMethodInvocation *context,
5357
gboolean was_cancelled,
5361
gpointer user_data);
5368
DBusGMethodInvocation *context;
5369
JobCompletedFunc job_completed_func;
5372
GDestroyNotify user_data_destroy_func;
5373
gboolean was_cancelled;
5374
gboolean udev_settle;
5378
GIOChannel *error_channel;
5379
guint error_channel_source_id;
5380
GString *error_string;
5383
GIOChannel *out_channel;
5384
guint out_channel_source_id;
5385
GString *stdout_string;
5386
int stdout_string_cursor;
5391
GIOChannel *in_channel;
5392
guint in_channel_source_id;
5398
if (job->user_data_destroy_func != NULL)
5399
job->user_data_destroy_func (job->user_data);
5400
if (job->device != NULL)
5401
g_object_unref (job->device);
5402
if (job->stderr_fd >= 0)
5403
close (job->stderr_fd);
5404
if (job->stdout_fd >= 0)
5405
close (job->stdout_fd);
5406
if (job->stdin_fd >= 0)
5408
close (job->stdin_fd);
5409
g_source_remove (job->in_channel_source_id);
5410
g_io_channel_unref (job->in_channel);
5412
g_source_remove (job->error_channel_source_id);
5413
g_source_remove (job->out_channel_source_id);
5414
g_io_channel_unref (job->error_channel);
5415
g_io_channel_unref (job->out_channel);
5416
g_string_free (job->error_string, TRUE);
5417
/* scrub stdin (may contain secrets) */
5418
if (job->stdin_str != NULL)
5420
memset (job->stdin_str, '\0', strlen (job->stdin_str));
5422
g_string_free (job->stdout_string, TRUE);
5423
g_free (job->stdin_str);
5424
g_free (job->job_id);
5429
job_complete (Job *job)
5431
if (job->device != NULL && job->job_id != NULL)
5433
job->device->priv->job_in_progress = FALSE;
5434
g_free (job->device->priv->job_id);
5435
job->device->priv->job_id = NULL;
5436
job->device->priv->job_initiated_by_uid = 0;
5437
job->device->priv->job_is_cancellable = FALSE;
5438
job->device->priv->job_percentage = -1.0;
5440
job->device->priv->job = NULL;
5443
job->job_completed_func (job->context,
5447
job->error_string->str,
5448
job->stdout_string->str,
5451
if (job->device != NULL && job->job_id != NULL)
5453
emit_job_changed (job->device);
5460
job_udevadm_settle_child_cb (GPid pid,
5464
Job *job = user_data;
5469
job_child_watch_cb (GPid pid,
5475
Job *job = user_data;
5477
if (g_io_channel_read_to_end (job->error_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
5479
g_string_append_len (job->error_string, buf, buf_size);
5482
if (g_io_channel_read_to_end (job->out_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
5484
g_string_append_len (job->stdout_string, buf, buf_size);
5488
PROFILE ("job finish (id=%s, pid=%i, device=%s)", job->job_id, job->pid, job->device ? job->device->priv->device_file : "none");
5489
g_print ("helper(pid %5d): completed with exit code %d\n", job->pid, WEXITSTATUS (status));
5491
job->status = status;
5493
/* if requested, run 'udevadm settle' on success */
5494
if (!job->was_cancelled && WIFEXITED (status) && WEXITSTATUS (status) == 0 && job->udev_settle)
5498
{ "udevadm", "settle", "--quiet", NULL };
5502
if (!g_spawn_async (NULL,
5505
G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
5511
g_warning ("Error running 'udevadm settle --quiet': %s", error->message);
5512
g_error_free (error);
5518
g_child_watch_add (udevadm_pid, job_udevadm_settle_child_cb, job);
5523
/* return immediately on error */
5529
job_cancel (Device *device)
5531
g_return_if_fail (device->priv->job != NULL);
5533
device->priv->job->was_cancelled = TRUE;
5535
/* TODO: maybe wait and user a bigger hammer? (SIGKILL) */
5536
kill (device->priv->job->pid, SIGTERM);
5540
job_read_error (GIOChannel *channel,
5541
GIOCondition condition,
5546
Job *job = user_data;
5548
g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
5549
g_string_append_len (job->error_string, buf, bytes_read);
5554
job_write_in (GIOChannel *channel,
5555
GIOCondition condition,
5558
Job *job = user_data;
5559
gsize bytes_written;
5561
if (job->stdin_cursor == NULL || job->stdin_cursor[0] == '\0')
5563
/* nothing left to write; remove ourselves */
5567
g_io_channel_write_chars (channel, job->stdin_cursor, strlen (job->stdin_cursor), &bytes_written, NULL);
5568
g_io_channel_flush (channel, NULL);
5569
job->stdin_cursor += bytes_written;
5574
job_read_out (GIOChannel *channel,
5575
GIOCondition condition,
5582
Job *job = user_data;
5584
g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
5585
g_string_append_len (job->stdout_string, buf, bytes_read);
5591
s = strstr (job->stdout_string->str + job->stdout_string_cursor, "\n");
5595
line_len = s - (job->stdout_string->str + job->stdout_string_cursor);
5596
line = g_strndup (job->stdout_string->str + job->stdout_string_cursor, line_len);
5597
job->stdout_string_cursor += line_len + 1;
5599
//g_print ("helper(pid %5d): '%s'\n", job->pid, line);
5601
if (strlen (line) < 256)
5603
double cur_percentage;
5606
if (sscanf (line, "udisks-helper-progress: %lg", &cur_percentage) == 1)
5608
if (job->device != NULL && job->job_id != NULL)
5610
job->device->priv->job_percentage = cur_percentage;
5611
emit_job_changed (job->device);
5624
job_local_start (Device *device,
5627
if (device->priv->job != NULL || device->priv->job_in_progress)
5629
g_warning ("There is already a job running");
5633
g_free (device->priv->job_id);
5634
device->priv->job_id = g_strdup (job_id);
5635
device->priv->job_initiated_by_uid = 0;
5636
device->priv->job_in_progress = TRUE;
5637
device->priv->job_is_cancellable = FALSE;
5638
device->priv->job_percentage = -1.0;
5640
emit_job_changed (device);
5646
job_local_end (Device *device)
5648
if (!device->priv->job_in_progress || device->priv->job != NULL)
5650
g_warning ("There is no job running");
5654
device->priv->job_in_progress = FALSE;
5655
g_free (device->priv->job_id);
5656
device->priv->job_id = NULL;
5657
device->priv->job_initiated_by_uid = 0;
5658
device->priv->job_is_cancellable = FALSE;
5659
device->priv->job_percentage = -1.0;
5660
emit_job_changed (device);
5666
job_new (DBusGMethodInvocation *context,
5668
gboolean is_cancellable,
5671
const char *stdin_str,
5672
JobCompletedFunc job_completed_func,
5673
gboolean udev_settle, /* if TRUE, runs udevsettle before returning if the command succeeded */
5675
GDestroyNotify user_data_destroy_func)
5684
PROFILE ("job_new(id=%s, device=%s): start", job_id ? job_id : argv[0], device ? device->priv->device_file : "none");
5688
if (device->priv->job != NULL || device->priv->job_in_progress)
5690
throw_error (context, ERROR_BUSY, "There is already a job running");
5695
job = g_new0 (Job, 1);
5696
job->context = context;
5697
job->device = device != NULL ? DEVICE (g_object_ref (device)) : NULL;
5698
job->job_completed_func = job_completed_func;
5699
job->user_data = user_data;
5700
job->user_data_destroy_func = user_data_destroy_func;
5701
job->stderr_fd = -1;
5702
job->stdout_fd = -1;
5704
job->stdin_str = g_strdup (stdin_str);
5705
job->stdin_cursor = job->stdin_str;
5706
job->stdout_string = g_string_sized_new (1024);
5707
job->job_id = g_strdup (job_id);
5708
job->udev_settle = udev_settle;
5710
if (device != NULL && job_id != NULL)
5712
g_free (job->device->priv->job_id);
5713
job->device->priv->job_id = g_strdup (job_id);
5717
if (!g_spawn_async_with_pipes (NULL,
5720
G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
5724
stdin_str != NULL ? &(job->stdin_fd) : NULL,
5729
throw_error (context, ERROR_FAILED, "Error starting job: %s", error->message);
5730
g_error_free (error);
5734
g_child_watch_add (job->pid, job_child_watch_cb, job);
5736
job->error_string = g_string_new ("");
5737
job->error_channel = g_io_channel_unix_new (job->stderr_fd);
5739
if (g_io_channel_set_flags (job->error_channel, G_IO_FLAG_NONBLOCK, &error) != G_IO_STATUS_NORMAL)
5741
g_warning ("Cannon set stderr fd for child to be non blocking: %s", error->message);
5742
g_error_free (error);
5744
job->error_channel_source_id = g_io_add_watch (job->error_channel, G_IO_IN, job_read_error, job);
5746
job->out_channel = g_io_channel_unix_new (job->stdout_fd);
5748
if (g_io_channel_set_flags (job->out_channel, G_IO_FLAG_NONBLOCK, &error) != G_IO_STATUS_NORMAL)
5750
g_warning ("Cannon set stdout fd for child to be non blocking: %s", error->message);
5751
g_error_free (error);
5753
job->out_channel_source_id = g_io_add_watch (job->out_channel, G_IO_IN, job_read_out, job);
5755
if (job->stdin_fd >= 0)
5757
job->in_channel = g_io_channel_unix_new (job->stdin_fd);
5758
if (g_io_channel_set_flags (job->in_channel, G_IO_FLAG_NONBLOCK, &error) != G_IO_STATUS_NORMAL)
5760
g_warning ("Cannon set stdin fd for child to be non blocking: %s", error->message);
5761
g_error_free (error);
5763
job->in_channel_source_id = g_io_add_watch (job->in_channel, G_IO_OUT, job_write_in, job);
5768
if (device != NULL && job_id != NULL)
5770
device->priv->job_in_progress = TRUE;
5771
device->priv->job_is_cancellable = is_cancellable;
5772
device->priv->job_percentage = -1.0;
5773
device->priv->job_initiated_by_uid = 0;
5774
if (context != NULL)
5776
daemon_local_get_uid (device->priv->daemon, &(device->priv->job_initiated_by_uid), context);
5779
device->priv->job = job;
5781
emit_job_changed (device);
5786
g_print ("helper(pid %5d): launched job %s on %s\n", job->pid, argv[0], device->priv->device_file);
5790
g_print ("helper(pid %5d): launched job %s on daemon\n", job->pid, argv[0]);
5794
if (!ret && job != NULL)
5796
PROFILE ("job_new(id=%s, device=%s): end", job_id, device ? device->priv->device_file : "none");
5800
/*--------------------------------------------------------------------------------------------------------------*/
5801
/* exported methods */
5806
gboolean remove_dir_on_unmount;
5810
filesystem_mount_data_new (const char *mount_point,
5811
gboolean remove_dir_on_unmount)
5814
data = g_new0 (MountData, 1);
5815
data->mount_point = g_strdup (mount_point);
5816
data->remove_dir_on_unmount = remove_dir_on_unmount;
5821
filesystem_mount_data_free (MountData *data)
5823
g_free (data->mount_point);
5828
is_device_in_fstab (Device *device,
5829
char **out_mount_point)
5832
GList *mount_points;
5837
mount_points = g_unix_mount_points_get (NULL);
5838
for (l = mount_points; l != NULL; l = l->next)
5840
GUnixMountPoint *mount_point = l->data;
5841
char canonical_device_file[PATH_MAX];
5845
device_path = g_strdup (g_unix_mount_point_get_device_path (mount_point));
5847
/* get the canonical path; e.g. resolve
5849
* /dev/disk/by-path/pci-0000:00:1d.7-usb-0:3:1.0-scsi-0:0:0:3-part5
5850
* UUID=78af6939-adac-4ea5-a2a8-576e141da010
5853
* into something like /dev/sde5.
5855
if (g_str_has_prefix (device_path, "UUID="))
5858
device_path = g_strdup_printf ("/dev/disk/by-uuid/%s", device_path + 5);
5861
else if (g_str_has_prefix (device_path, "LABEL="))
5864
device_path = g_strdup_printf ("/dev/disk/by-label/%s", device_path + 6);
5868
if (realpath (device_path, canonical_device_file) == NULL)
5870
g_free (device_path);
5873
g_free (device_path);
5875
if (strcmp (device->priv->device_file, canonical_device_file) == 0)
5878
if (out_mount_point != NULL)
5879
*out_mount_point = g_strdup (g_unix_mount_point_get_mount_path (mount_point));
5883
g_list_foreach (mount_points, (GFunc) g_unix_mount_point_free, NULL);
5884
g_list_free (mount_points);
5892
const char * const *defaults;
5893
const char * const *allow;
5894
const char * const *allow_uid_self;
5895
const char * const *allow_gid_self;
5898
/* ---------------------- vfat -------------------- */
5900
static const char *vfat_defaults[] = { "uid=", "gid=", "shortname=mixed", "dmask=0077", "utf8=1", "showexec", NULL };
5901
static const char *vfat_allow[] = { "flush", "utf8=", "shortname=", "umask=", "dmask=", "fmask=", "codepage=", "iocharset=", "usefree", "showexec", NULL };
5902
static const char *vfat_allow_uid_self[] = { "uid=", NULL };
5903
static const char *vfat_allow_gid_self[] = { "gid=", NULL };
5905
/* ---------------------- ntfs -------------------- */
5906
/* this is assuming that ntfs-3g is used */
5908
static const char *ntfs_defaults[] = { "uid=", "gid=", "dmask=0077", "fmask=0177", NULL };
5909
static const char *ntfs_allow[] = { "umask=", "dmask=", "fmask=", NULL };
5910
static const char *ntfs_allow_uid_self[] = { "uid=", NULL };
5911
static const char *ntfs_allow_gid_self[] = { "gid=", NULL };
5913
/* ---------------------- iso9660 -------------------- */
5915
static const char *iso9660_defaults[] = { "uid=", "gid=", "iocharset=utf8", "mode=0400", "dmode=0500", NULL };
5916
static const char *iso9660_allow[] = { "norock", "nojoliet", "iocharset=", "mode=", "dmode=", NULL };
5917
static const char *iso9660_allow_uid_self[] = { "uid=", NULL };
5918
static const char *iso9660_allow_gid_self[] = { "gid=", NULL };
5920
/* ---------------------- udf -------------------- */
5922
static const char *udf_defaults[] = { "uid=", "gid=", "iocharset=utf8", "umask=0077", NULL };
5923
static const char *udf_allow[] = { "iocharset=", "umask=", "mode=", "dmode=", NULL };
5924
static const char *udf_allow_uid_self[] = { "uid=", NULL };
5925
static const char *udf_allow_gid_self[] = { "gid=", NULL };
5927
/* ------------------------------------------------ */
5928
/* TODO: support context= */
5930
static const char *any_allow[] = { "exec", "noexec", "nodev", "nosuid", "atime", "noatime", "nodiratime", "ro", "rw", "sync", "dirsync", NULL };
5932
static const FSMountOptions fs_mount_options[] =
5934
{ "vfat", vfat_defaults, vfat_allow, vfat_allow_uid_self, vfat_allow_gid_self },
5935
{ "ntfs", ntfs_defaults, ntfs_allow, ntfs_allow_uid_self, ntfs_allow_gid_self },
5936
{ "iso9660", iso9660_defaults, iso9660_allow, iso9660_allow_uid_self, iso9660_allow_gid_self },
5937
{ "udf", udf_defaults, udf_allow, udf_allow_uid_self, udf_allow_gid_self },
5940
static const gchar *well_known_filesystems[] =
5961
/* ------------------------------------------------ */
5963
static int num_fs_mount_options = sizeof(fs_mount_options) / sizeof(FSMountOptions);
5965
static const FSMountOptions *
5966
find_mount_options_for_fs (const char *fstype)
5969
const FSMountOptions *fsmo;
5971
for (n = 0; n < num_fs_mount_options; n++)
5973
fsmo = fs_mount_options + n;
5974
if (strcmp (fsmo->fstype, fstype) == 0)
5984
find_primary_gid (uid_t uid)
5991
pw = getpwuid (uid);
5994
g_warning ("Couldn't look up uid %d: %m", uid);
6004
is_uid_in_gid (uid_t uid,
6009
static gid_t supplementary_groups[128];
6010
int num_supplementary_groups = 128;
6013
/* TODO: use some #define instead of harcoding some random number like 128 */
6017
pw = getpwuid (uid);
6020
g_warning ("Couldn't look up uid %d: %m", uid);
6023
if (pw->pw_gid == gid)
6029
if (getgrouplist (pw->pw_name, pw->pw_gid, supplementary_groups, &num_supplementary_groups) < 0)
6031
g_warning ("Couldn't find supplementary groups for uid %d: %m", uid);
6035
for (n = 0; n < num_supplementary_groups; n++)
6037
if (supplementary_groups[n] == gid)
6049
is_mount_option_allowed (const FSMountOptions *fsmo,
6063
/* first run through the allowed mount options */
6066
for (n = 0; fsmo->allow != NULL && fsmo->allow[n] != NULL; n++)
6068
ep = strstr (fsmo->allow[n], "=");
6069
if (ep != NULL && ep[1] == '\0')
6071
ep_len = ep - fsmo->allow[n] + 1;
6072
if (strncmp (fsmo->allow[n], option, ep_len) == 0)
6080
if (strcmp (fsmo->allow[n], option) == 0)
6088
for (n = 0; any_allow[n] != NULL; n++)
6090
ep = strstr (any_allow[n], "=");
6091
if (ep != NULL && ep[1] == '\0')
6093
ep_len = ep - any_allow[n] + 1;
6094
if (strncmp (any_allow[n], option, ep_len) == 0)
6102
if (strcmp (any_allow[n], option) == 0)
6110
/* .. then check for mount options where the caller is allowed to pass
6115
for (n = 0; fsmo->allow_uid_self != NULL && fsmo->allow_uid_self[n] != NULL; n++)
6117
const char *r_mount_option = fsmo->allow_uid_self[n];
6118
if (g_str_has_prefix (option, r_mount_option))
6120
uid = strtol (option + strlen (r_mount_option), &endp, 10);
6123
if (uid == caller_uid)
6136
for (n = 0; fsmo->allow_gid_self != NULL && fsmo->allow_gid_self[n] != NULL; n++)
6138
const char *r_mount_option = fsmo->allow_gid_self[n];
6139
if (g_str_has_prefix (option, r_mount_option))
6141
gid = strtol (option + strlen (r_mount_option), &endp, 10);
6144
if (is_uid_in_gid (caller_uid, gid))
6158
prepend_default_mount_options (Device *device,
6159
const FSMountOptions *fsmo,
6161
char **given_options)
6168
/* static default options from FSMountOptions */
6169
options = g_ptr_array_new ();
6172
for (n = 0; fsmo->defaults != NULL && fsmo->defaults[n] != NULL; n++)
6174
const char *option = fsmo->defaults[n];
6176
if (strcmp (option, "uid=") == 0)
6178
s = g_strdup_printf ("uid=%d", caller_uid);
6179
g_ptr_array_add (options, s);
6181
else if (strcmp (option, "gid=") == 0)
6183
gid = find_primary_gid (caller_uid);
6184
if (gid != (gid_t) - 1)
6186
s = g_strdup_printf ("gid=%d", gid);
6187
g_ptr_array_add (options, s);
6192
g_ptr_array_add (options, g_strdup (option));
6197
/* dynamic default options */
6199
/* some broken DVDs come with 0400 directory permissions, making them
6200
* unreadable; overwrite readonly UDF media with a 0500 dmode. */
6201
if (g_strcmp0 (device->priv->id_type, "udf") == 0 && device->priv->device_is_optical_disc &&
6202
device->priv->drive_media != NULL &&
6203
strstr(device->priv->drive_media, "_rw") == NULL && strstr(device->priv->drive_media, "_ram") == NULL)
6205
g_ptr_array_add (options, g_strdup("dmode=0500"));
6208
/* user supplied options */
6209
for (n = 0; given_options[n] != NULL; n++)
6211
g_ptr_array_add (options, g_strdup (given_options[n]));
6214
g_ptr_array_add (options, NULL);
6216
return (char **) g_ptr_array_free (options, FALSE);
6220
unlock_cd_tray (Device *device)
6222
/* Unlock CD tray to keep the hardware eject button working */
6223
if (g_udev_device_has_property (device->priv->d, "ID_CDROM"))
6227
g_print ("**** Unlocking CD-ROM door for %s\n", device->priv->device_file);
6228
fd = open (device->priv->device_file, O_RDONLY);
6231
if (ioctl (fd, CDROM_LOCKDOOR, 0) != 0)
6232
g_warning ("Could not unlock CD-ROM door: %s", strerror (errno));
6237
g_warning ("Could not open CD-ROM device: %s", strerror (errno));
6243
filesystem_mount_completed_cb (DBusGMethodInvocation *context,
6245
gboolean job_was_cancelled,
6251
MountData *data = (MountData *) user_data;
6254
daemon_local_get_uid (device->priv->daemon, &uid, context);
6256
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
6259
update_info (device);
6260
drain_pending_changes (device, FALSE);
6261
/* If the kernel and device support sending EJECT_REQUEST change uevents
6262
* and we use in-kernel polling, keep the door locked, as udev calls
6263
* eject on pressing the button. Otherwise unlock it, to keep the
6264
* hardware button working without userspace support */
6265
if (!device->priv->using_in_kernel_polling)
6266
unlock_cd_tray (device);
6268
dbus_g_method_return (context, data->mount_point);
6272
if (data->remove_dir_on_unmount)
6274
mount_file_remove (device->priv->device_file, data->mount_point);
6275
if (g_rmdir (data->mount_point) != 0)
6277
g_warning ("Error removing dir in late mount error path: %m");
6281
if (job_was_cancelled)
6283
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
6285
else if (WEXITSTATUS (status) == 32)
6287
throw_error (context, ERROR_FILESYSTEM_DRIVER_MISSING, "Error mounting: %s", stderr);
6291
throw_error (context,
6293
"Error mounting: mount exited with exit code %d: %s",
6294
WEXITSTATUS (status),
6301
is_in_filesystem_file (const gchar *filesystems_file,
6302
const gchar *fstype)
6315
if (!g_file_get_contents (filesystems_file,
6317
NULL, /* gsize *out_length */
6320
g_warning ("Error reading %s: %s (%s %d)",
6323
g_quark_to_string (error->domain),
6325
g_error_free (error);
6329
lines = g_strsplit (filesystems, "\n", -1);
6330
for (n = 0; lines != NULL && lines[n] != NULL && !ret; n++)
6334
g_strdelimit (lines[n], " \t", ' ');
6335
g_strstrip (lines[n]);
6336
tokens = g_strsplit (lines[n], " ", -1);
6337
num_tokens = g_strv_length (tokens);
6338
if (num_tokens == 1 && g_strcmp0 (tokens[0], fstype) == 0)
6342
g_strfreev (tokens);
6347
g_free (filesystems);
6352
is_well_known_filesystem (const gchar *fstype)
6358
for (n = 0; well_known_filesystems[n] != NULL; n++)
6360
if (g_strcmp0 (well_known_filesystems[n], fstype) == 0)
6370
/* this is not a very efficient implementation but it's very rarely
6371
* called so no real point in optimizing it...
6374
is_allowed_filesystem (const gchar *fstype)
6376
return is_well_known_filesystem (fstype) ||
6377
is_in_filesystem_file ("/proc/filesystems", fstype) ||
6378
is_in_filesystem_file ("/etc/filesystems", fstype);
6382
device_filesystem_mount_authorized_cb (Daemon *daemon,
6384
DBusGMethodInvocation *context,
6385
const gchar *action_id,
6386
guint num_user_data,
6387
gpointer *user_data_elements)
6389
const gchar *filesystem_type = user_data_elements[0];
6390
gchar **given_options = user_data_elements[1];
6396
char *mount_options;
6399
gboolean remove_dir_on_unmount;
6400
const FSMountOptions *fsmo;
6406
mount_options = NULL;
6408
remove_dir_on_unmount = FALSE;
6411
/* If the user requests the filesystem type, error out unless the
6412
* filesystem type is
6414
* - well-known [1]; or
6415
* - in the /proc/filesystems file; or
6416
* - in the /etc/filesystems file
6418
* in that order. We do this because mount(8) on Linux allows
6419
* loading any arbitrary kernel module (when invoked as root) by
6420
* passing something appropriate to the -t option. So we have to
6421
* validate whatever we pass...
6423
* See https://bugs.freedesktop.org/show_bug.cgi?id=32232 for more
6426
* [1] : since /etc/filesystems may be horribly out of date and not
6429
if (filesystem_type != NULL && strlen (filesystem_type) > 0 &&
6430
g_strcmp0 (filesystem_type, "auto") != 0)
6432
if (!is_allowed_filesystem (filesystem_type))
6434
throw_error (context, ERROR_FAILED,
6435
"Requested filesystem type is neither well-known nor "
6436
"in /proc/filesystems nor in /etc/filesystems");
6441
daemon_local_get_uid (device->priv->daemon, &caller_uid, context);
6443
if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "filesystem") != 0)
6445
if ((g_strcmp0 (filesystem_type, "auto") == 0 || g_strcmp0 (filesystem_type, "") == 0) && device->priv->id_usage
6448
/* if we don't know the usage of the device and 'auto' or '' is passed for fstype
6449
* then just try that.. this is to make, for example, mounting /dev/fd0 work (we
6450
* don't probe such devices for filesystems in udev)
6455
throw_error (context, ERROR_FAILED, "Not a mountable file system");
6460
if (device_local_is_busy (device, FALSE, TRUE, &error))
6462
dbus_g_method_return_error (context, error);
6463
g_error_free (error);
6467
/* Check if the device is referenced in /etc/fstab; if so, attempt to
6468
* mount the device as the user
6470
if (is_device_in_fstab (device, &mount_point))
6473
snprintf (uid_buf, sizeof uid_buf, "%d", caller_uid);
6474
argv[n++] = "udisks-helper-fstab-mounter";
6475
argv[n++] = "mount";
6476
argv[n++] = device->priv->device_file;
6477
argv[n++] = uid_buf;
6482
/* set the fstype */
6484
if (strlen (filesystem_type) == 0)
6486
if (device->priv->id_type != NULL && strlen (device->priv->id_type) > 0)
6488
fstype = g_strdup (device->priv->id_type);
6492
fstype = g_strdup ("auto");
6497
fstype = g_strdup (filesystem_type);
6500
fsmo = find_mount_options_for_fs (fstype);
6502
/* always prepend some reasonable default mount options; these are
6503
* chosen here; the user can override them if he wants to
6505
options = prepend_default_mount_options (device, fsmo, caller_uid, given_options);
6507
/* validate mount options and check for authorizations */
6508
s = g_string_new ("uhelper=udisks,nodev,nosuid");
6509
for (n = 0; options[n] != NULL; n++)
6511
const char *option = options[n];
6513
/* avoid attacks like passing "shortname=lower,uid=0" as a single mount option */
6514
if (strstr (option, ",") != NULL)
6516
throw_error (context, ERROR_INVALID_OPTION, "Malformed mount option: ", option);
6517
g_string_free (s, TRUE);
6521
/* first check if the mount option is allowed */
6522
if (!is_mount_option_allowed (fsmo, option, caller_uid))
6524
throw_error (context, ERROR_INVALID_OPTION, "Mount option %s is not allowed", option);
6525
g_string_free (s, TRUE);
6529
g_string_append_c (s, ',');
6530
g_string_append (s, option);
6532
mount_options = g_string_free (s, FALSE);
6534
g_print ("**** USING MOUNT OPTIONS '%s' FOR DEVICE %s\n", mount_options, device->priv->device_file);
6536
if (device->priv->device_is_mounted)
6538
throw_error (context, ERROR_FAILED, "Device is already mounted");
6542
/* Determine the mount point to use.
6544
* TODO: use characteristics of the drive such as the name, connection etc.
6545
* to get better names (/media/disk is kinda lame).
6547
if (device->priv->id_label != NULL && strlen (device->priv->id_label) > 0)
6551
s = g_string_new ("/media/");
6552
for (n = 0; device->priv->id_label[n] != '\0'; n++)
6554
gint c = device->priv->id_label[n];
6556
g_string_append_c (s, '_');
6558
g_string_append_c (s, c);
6561
mount_point = g_string_free (s, FALSE);
6563
else if (device->priv->id_uuid != NULL && strlen (device->priv->id_uuid) > 0)
6568
s = g_string_new ("/media/");
6569
for (n = 0; device->priv->id_uuid[n] != '\0'; n++)
6571
gint c = device->priv->id_uuid[n];
6573
g_string_append_c (s, '_');
6575
g_string_append_c (s, c);
6578
mount_point = g_string_free (s, FALSE);
6583
mount_point = g_strdup ("/media/disk");
6586
try_another_mount_point:
6587
/* ... then uniqify the mount point and mkdir it */
6588
if (g_file_test (mount_point, G_FILE_TEST_EXISTS))
6590
char *s = mount_point;
6591
/* TODO: append numbers instead of _, __ and so on */
6592
mount_point = g_strdup_printf ("%s_", mount_point);
6594
goto try_another_mount_point;
6597
remove_dir_on_unmount = TRUE;
6599
if (g_mkdir (mount_point, 0700) != 0)
6601
throw_error (context, ERROR_FAILED, "Error creating moint point: %m");
6605
/* now that we have a mount point, immediately add it to the
6606
* /var/lib/udisks/mtab file.
6608
* If mounting fails we'll clean it up in filesystem_mount_completed_cb. If it
6609
* hangs we'll clean it up the next time we start up.
6611
mount_file_add (device->priv->device_file, mount_point, caller_uid, remove_dir_on_unmount);
6614
argv[n++] = "mount";
6618
argv[n++] = mount_options;
6619
argv[n++] = device->priv->device_file;
6620
argv[n++] = mount_point;
6626
if (!job_new (context,
6632
filesystem_mount_completed_cb,
6634
filesystem_mount_data_new (mount_point, remove_dir_on_unmount),
6635
(GDestroyNotify) filesystem_mount_data_free))
6637
if (remove_dir_on_unmount)
6639
mount_file_remove (device->priv->device_file, mount_point);
6640
if (g_rmdir (mount_point) != 0)
6642
g_warning ("Error removing dir in early mount error path: %m");
6650
g_free (mount_options);
6651
g_free (mount_point);
6652
g_strfreev (options);
6656
device_filesystem_mount (Device *device,
6657
const char *filesystem_type,
6658
char **given_options,
6659
DBusGMethodInvocation *context)
6661
const gchar *action_id;
6662
gboolean auth_no_user_interaction;
6663
gchar **options_to_pass;
6667
if (is_device_in_fstab (device, NULL))
6673
if (device->priv->device_is_system_internal)
6674
action_id = "org.freedesktop.udisks.filesystem-mount-system-internal";
6676
action_id = "org.freedesktop.udisks.filesystem-mount";
6679
auth_no_user_interaction = FALSE;
6680
options_to_pass = g_strdupv (given_options);
6681
for (n = 0; options_to_pass != NULL && options_to_pass[n] != NULL; n++)
6683
if (g_strcmp0 (options_to_pass[n], "auth_no_user_interaction") == 0)
6685
auth_no_user_interaction = TRUE;
6686
g_free (options_to_pass[n]);
6687
for (m = n; options_to_pass[m + 1] != NULL; m++)
6688
options_to_pass[m] = options_to_pass[m + 1];
6689
options_to_pass[m] = NULL;
6694
daemon_local_check_auth (device->priv->daemon,
6698
!auth_no_user_interaction,
6699
device_filesystem_mount_authorized_cb,
6702
g_strdup (filesystem_type),
6710
/*--------------------------------------------------------------------------------------------------------------*/
6713
filesystem_unmount_completed_cb (DBusGMethodInvocation *context,
6715
gboolean job_was_cancelled,
6721
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
6723
/* update_info_mount_state() will update the mounts file and clean up the directory if needed */
6724
update_info (device);
6725
if (context != NULL)
6726
dbus_g_method_return (context);
6730
if (job_was_cancelled)
6732
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
6736
if (strstr (stderr, "device is busy") != NULL)
6738
throw_error (context, ERROR_BUSY, "Cannot unmount because file system on device is busy");
6742
throw_error (context,
6744
"Error unmounting: umount exited with exit code %d: %s",
6745
WEXITSTATUS (status),
6753
device_filesystem_unmount_authorized_cb (Daemon *daemon,
6755
DBusGMethodInvocation *context,
6756
const gchar *action_id,
6757
guint num_user_data,
6758
gpointer *user_data_elements)
6760
gchar **options = user_data_elements[0];
6763
gboolean force_unmount;
6770
if (!device->priv->device_is_mounted || device->priv->device_mount_paths->len == 0)
6772
throw_error (context, ERROR_FAILED, "Device is not mounted");
6776
force_unmount = FALSE;
6777
for (n = 0; options[n] != NULL; n++)
6779
char *option = options[n];
6780
if (strcmp ("force", option) == 0)
6782
force_unmount = TRUE;
6786
throw_error (context, ERROR_INVALID_OPTION, "Unknown option %s", option);
6791
daemon_local_get_uid (device->priv->daemon, &uid, context);
6792
g_snprintf (uid_buf, sizeof uid_buf, "%d", uid);
6794
if (!mount_file_has_device (device->priv->device_file, NULL, NULL))
6796
if (is_device_in_fstab (device, &mount_path))
6800
argv[n++] = "udisks-helper-fstab-mounter";
6802
argv[n++] = "force_unmount";
6804
argv[n++] = "unmount";
6805
argv[n++] = device->priv->device_file;
6806
argv[n++] = uid_buf;
6811
/* otherwise the user will have the .unmount-others authorization per the logic in
6812
* device_filesystem_unmount()
6816
mount_path = g_strdup (((gchar **) device->priv->device_mount_paths->pdata)[0]);
6819
argv[n++] = "umount";
6822
/* on Linux we currently only have lazy unmount to emulate this */
6825
argv[n++] = mount_path;
6829
if (!job_new (context,
6830
"FilesystemUnmount",
6835
filesystem_unmount_completed_cb,
6837
g_strdup (mount_path),
6844
g_free (mount_path);
6848
device_filesystem_unmount (Device *device,
6850
DBusGMethodInvocation *context)
6852
const gchar *action_id;
6855
if (!device->priv->device_is_mounted || device->priv->device_mount_paths->len == 0)
6857
throw_error (context, ERROR_FAILED, "Device is not mounted");
6861
/* if device is in /etc/fstab, then we'll run unmount as the calling user */
6863
if (!mount_file_has_device (device->priv->device_file, &uid_of_mount, NULL))
6865
if (context != NULL && !is_device_in_fstab (device, NULL))
6867
action_id = "org.freedesktop.udisks.filesystem-unmount-others";
6873
daemon_local_get_uid (device->priv->daemon, &uid, context);
6874
if (context != NULL && uid_of_mount != uid)
6876
action_id = "org.freedesktop.udisks.filesystem-unmount-others";
6880
daemon_local_check_auth (device->priv->daemon,
6883
"FilesystemUnmount",
6885
device_filesystem_unmount_authorized_cb,
6888
g_strdupv (options),
6895
/*--------------------------------------------------------------------------------------------------------------*/
6898
get_uid_for_pid (pid_t pid)
6902
struct stat statbuf;
6906
snprintf (proc_name, sizeof(proc_name), "/proc/%d/stat", pid);
6907
if (stat (proc_name, &statbuf) == 0)
6909
ret = statbuf.st_uid;
6916
get_command_line_for_pid (pid_t pid)
6926
snprintf (proc_name, sizeof(proc_name), "/proc/%d/cmdline", pid);
6927
if (g_file_get_contents (proc_name, &buf, &len, NULL))
6929
for (n = 0; n < len; n++)
6942
lsof_parse (const char *stdout,
6943
GPtrArray *processes)
6948
tokens = g_strsplit (stdout, "\n", 0);
6949
for (n = 0; tokens[n] != NULL; n++)
6957
if (strlen (tokens[n]) == 0)
6960
pid = strtol (tokens[n], NULL, 0);
6961
uid = get_uid_for_pid (pid);
6962
command_line = get_command_line_for_pid (pid);
6964
g_value_init (&elem, LSOF_DATA_STRUCT_TYPE);
6965
g_value_take_boxed (&elem, dbus_g_type_specialized_construct (LSOF_DATA_STRUCT_TYPE));
6966
dbus_g_type_struct_set (&elem, 0, pid, 1, uid, 2, command_line != NULL ? command_line : "", G_MAXUINT);
6967
g_ptr_array_add (processes, g_value_get_boxed (&elem));
6969
g_free (command_line);
6971
g_strfreev (tokens);
6975
filesystem_list_open_files_completed_cb (DBusGMethodInvocation *context,
6977
gboolean job_was_cancelled,
6983
if ((WEXITSTATUS (status) == 0 || WEXITSTATUS (status) == 1) && !job_was_cancelled)
6985
GPtrArray *processes;
6987
processes = g_ptr_array_new ();
6988
lsof_parse (stdout, processes);
6989
dbus_g_method_return (context, processes);
6990
g_ptr_array_foreach (processes, (GFunc) g_value_array_free, NULL);
6991
g_ptr_array_free (processes, TRUE);
6995
throw_error (context,
6997
"Error listing open files: lsof exited with exit code %d: %s",
6998
WEXITSTATUS (status),
7004
device_filesystem_list_open_files_authorized_cb (Daemon *daemon,
7006
DBusGMethodInvocation *context,
7007
const gchar *action_id,
7008
guint num_user_data,
7009
gpointer *user_data_elements)
7014
if (!device->priv->device_is_mounted || device->priv->device_mount_paths->len == 0)
7016
throw_error (context, ERROR_FAILED, "Device is not mounted");
7023
argv[n++] = ((gchar **) device->priv->device_mount_paths->pdata)[0];
7026
if (!job_new (context, NULL, /* don't run this as a job */
7027
FALSE, device, argv, NULL, filesystem_list_open_files_completed_cb, FALSE, NULL, NULL))
7037
device_filesystem_list_open_files (Device *device,
7038
DBusGMethodInvocation *context)
7040
if (!device->priv->device_is_mounted || device->priv->device_mount_paths->len == 0)
7042
throw_error (context, ERROR_FAILED, "Device is not mounted");
7046
daemon_local_check_auth (device->priv->daemon,
7048
device->priv->device_is_system_internal ? "org.freedesktop.udisks.filesystem-lsof-system-internal"
7049
: "org.freedesktop.udisks.filesystem-lsof",
7050
"FilesystemListOpenFiles",
7052
device_filesystem_list_open_files_authorized_cb,
7060
/*--------------------------------------------------------------------------------------------------------------*/
7063
drive_eject_completed_cb (DBusGMethodInvocation *context,
7065
gboolean job_was_cancelled,
7071
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
7073
/* TODO: probably wait for has_media to change to FALSE */
7074
if (context != NULL)
7075
dbus_g_method_return (context);
7079
if (job_was_cancelled)
7081
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
7085
throw_error (context,
7087
"Error ejecting: eject exited with exit code %d: %s",
7088
WEXITSTATUS (status),
7095
device_drive_eject_authorized_cb (Daemon *daemon,
7097
DBusGMethodInvocation *context,
7098
const gchar *action_id,
7099
guint num_user_data,
7100
gpointer *user_data_elements)
7102
gchar **options = user_data_elements[0];
7106
gboolean unmount = FALSE;
7110
if (!device->priv->device_is_drive)
7112
throw_error (context, ERROR_FAILED, "Device is not a drive");
7116
if (!device->priv->device_is_media_available)
7118
throw_error (context, ERROR_FAILED, "No media in drive");
7122
for (n = 0; options[n] != NULL; n++)
7124
const char *option = options[n];
7125
if (strcmp ("unmount", option) == 0)
7131
throw_error (context, ERROR_INVALID_OPTION, "Unknown option %s", option);
7136
/* If we specify the unmount option, don't check if the device is mounted */
7137
if (device_local_is_busy (device, TRUE, !unmount, &error))
7139
throw_error (context, ERROR_BUSY, error->message);
7140
g_error_free (error);
7144
/* eject already unmounts the file systems on the ejected drive, so we do not
7145
* need any particular handling of the unmount flag here */
7147
argv[n++] = "eject";
7148
argv[n++] = device->priv->device_file;
7151
if (!job_new (context, "DriveEject", FALSE, device, argv, NULL, drive_eject_completed_cb, FALSE, NULL, NULL))
7161
device_drive_eject (Device *device,
7163
DBusGMethodInvocation *context)
7165
if (!device->priv->device_is_drive)
7167
throw_error (context, ERROR_FAILED, "Device is not a drive");
7171
if (!device->priv->device_is_media_available)
7173
throw_error (context, ERROR_FAILED, "No media in drive");
7177
daemon_local_check_auth (device->priv->daemon,
7179
context ? "org.freedesktop.udisks.drive-eject" : NULL,
7182
device_drive_eject_authorized_cb,
7185
g_strdupv (options),
7192
/*--------------------------------------------------------------------------------------------------------------*/
7195
drive_detach_completed_cb (DBusGMethodInvocation *context,
7197
gboolean job_was_cancelled,
7203
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
7205
/* TODO: probably wait for has_media to change to FALSE */
7206
dbus_g_method_return (context);
7210
if (job_was_cancelled)
7212
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
7216
throw_error (context,
7218
"Error detaching: helper exited with exit code %d: %s",
7219
WEXITSTATUS (status),
7226
device_drive_detach_authorized_cb (Daemon *daemon,
7228
DBusGMethodInvocation *context,
7229
const gchar *action_id,
7230
guint num_user_data,
7231
gpointer *user_data_elements)
7233
gchar **options = user_data_elements[0];
7240
if (!device->priv->device_is_drive)
7242
throw_error (context, ERROR_FAILED, "Device is not a drive");
7246
if (!device->priv->drive_can_detach)
7248
throw_error (context, ERROR_FAILED, "Device is not detachable");
7252
if (device_local_is_busy (device, TRUE, TRUE, &error))
7254
dbus_g_method_return_error (context, error);
7255
g_error_free (error);
7259
for (n = 0; options[n] != NULL; n++)
7261
const char *option = options[n];
7262
throw_error (context, ERROR_INVALID_OPTION, "Unknown option %s", option);
7267
argv[n++] = "udisks-helper-drive-detach";
7268
argv[n++] = device->priv->device_file;
7271
if (!job_new (context, "DriveDetach", FALSE, device, argv, NULL, drive_detach_completed_cb, FALSE, NULL, NULL))
7281
device_drive_detach (Device *device,
7283
DBusGMethodInvocation *context)
7285
if (!device->priv->device_is_drive)
7287
throw_error (context, ERROR_FAILED, "Device is not a drive");
7291
if (!device->priv->drive_can_detach)
7293
throw_error (context, ERROR_FAILED, "Device is not detachable");
7297
daemon_local_check_auth (device->priv->daemon,
7299
"org.freedesktop.udisks.drive-detach",
7302
device_drive_detach_authorized_cb,
7305
g_strdupv (options),
7312
/*--------------------------------------------------------------------------------------------------------------*/
7315
filesystem_check_completed_cb (DBusGMethodInvocation *context,
7317
gboolean job_was_cancelled,
7323
if (WIFEXITED (status) && !job_was_cancelled)
7326
gboolean fs_is_clean;
7328
fs_is_clean = FALSE;
7330
rc = WEXITSTATUS (status);
7331
if ((rc == 0) || (((rc & 1) != 0) && ((rc & 4) == 0)))
7336
dbus_g_method_return (context, fs_is_clean);
7340
if (job_was_cancelled)
7342
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
7346
throw_error (context,
7348
"Error fsck'ing: fsck exited with exit code %d: %s",
7349
WEXITSTATUS (status),
7356
device_filesystem_check_authorized_cb (Daemon *daemon,
7358
DBusGMethodInvocation *context,
7359
const gchar *action_id,
7360
guint num_user_data,
7361
gpointer *user_data_elements)
7363
/* TODO: use options! */
7364
//gchar **options = user_data_elements[0];
7368
/* TODO: change when we have a file system that supports online fsck */
7369
if (device->priv->device_is_mounted)
7371
throw_error (context, ERROR_BUSY, "Device is mounted and no online capability in fsck tool for file system");
7378
argv[n++] = device->priv->device_file;
7381
if (!job_new (context, "FilesystemCheck", FALSE, device, argv, NULL, filesystem_check_completed_cb, FALSE, NULL, NULL))
7391
device_filesystem_check (Device *device,
7393
DBusGMethodInvocation *context)
7395
daemon_local_check_auth (device->priv->daemon,
7397
device->priv->device_is_system_internal ?
7398
"org.freedesktop.udisks.filesystem-check-system-internal" :
7399
"org.freedesktop.udisks.filesystem-check",
7402
device_filesystem_check_authorized_cb,
7405
g_strdupv (options),
7410
/*--------------------------------------------------------------------------------------------------------------*/
7413
partition_delete_completed_cb (DBusGMethodInvocation *context,
7415
gboolean job_was_cancelled,
7421
Device *enclosing_device = DEVICE (user_data);
7423
/* poke the kernel about the enclosing disk so we can reread the partitioning table */
7424
device_generate_kernel_change_event (enclosing_device);
7426
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
7428
dbus_g_method_return (context);
7432
if (job_was_cancelled)
7434
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
7438
throw_error (context,
7440
"Error erasing: helper exited with exit code %d: %s",
7441
WEXITSTATUS (status),
7448
device_partition_delete_authorized_cb (Daemon *daemon,
7450
DBusGMethodInvocation *context,
7451
const gchar *action_id,
7452
guint num_user_data,
7453
gpointer *user_data_elements)
7455
gchar **options = user_data_elements[0];
7460
char *offset_as_string;
7461
char *size_as_string;
7462
char *part_number_as_string;
7463
Device *enclosing_device;
7464
const gchar *partition_scheme;
7465
gint partition_type;
7467
offset_as_string = NULL;
7468
size_as_string = NULL;
7469
part_number_as_string = NULL;
7472
if (device_local_is_busy (device, FALSE, TRUE, &error))
7474
dbus_g_method_return_error (context, error);
7475
g_error_free (error);
7479
if (!device->priv->device_is_partition)
7481
throw_error (context, ERROR_FAILED, "Device is not a partition");
7485
enclosing_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->partition_slave);
7486
if (enclosing_device == NULL)
7488
throw_error (context, ERROR_FAILED, "Cannot find enclosing device");
7492
if (device_local_is_busy (enclosing_device, FALSE, TRUE, &error))
7494
dbus_g_method_return_error (context, error);
7495
g_error_free (error);
7499
/* don't allow deleting an extended partition if we have any logical partitions */
7500
partition_scheme = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_SCHEME");
7501
partition_type = g_udev_device_get_property_as_int (device->priv->d, "UDISKS_PARTITION_TYPE");
7502
if (g_strcmp0 (partition_scheme, "mbr") == 0 && (partition_type == 0x05 || partition_type == 0x0f || partition_type
7505
if (device_has_logical_partitions (enclosing_device))
7507
throw_error (context, ERROR_FAILED, "Cannot delete extended partition while logical partitions exist");
7512
offset_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", device->priv->partition_offset);
7513
size_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", device->priv->partition_size);
7514
part_number_as_string = g_strdup_printf ("%d", device->priv->partition_number);
7517
argv[n++] = "udisks-helper-delete-partition";
7518
if (enclosing_device->priv->device_is_linux_dmmp)
7519
argv[n++] = (gchar *) get_dmmp_device_node (enclosing_device);
7521
argv[n++] = enclosing_device->priv->device_file;
7522
argv[n++] = device->priv->device_file;
7523
argv[n++] = offset_as_string;
7524
argv[n++] = size_as_string;
7525
argv[n++] = part_number_as_string;
7526
for (m = 0; options[m] != NULL; m++)
7528
if (n >= (int) sizeof(argv) - 1)
7530
throw_error (context, ERROR_FAILED, "Too many options");
7533
/* the helper will validate each option */
7534
argv[n++] = (char *) options[m];
7538
if (!job_new (context,
7544
partition_delete_completed_cb,
7546
g_object_ref (enclosing_device),
7553
g_free (offset_as_string);
7554
g_free (size_as_string);
7555
g_free (part_number_as_string);
7559
device_partition_delete (Device *device,
7561
DBusGMethodInvocation *context)
7563
daemon_local_check_auth (device->priv->daemon,
7565
device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
7566
: "org.freedesktop.udisks.change",
7569
device_partition_delete_authorized_cb,
7572
g_strdupv (options),
7577
/*--------------------------------------------------------------------------------------------------------------*/
7581
FilesystemCreateHookFunc hook_func;
7582
gpointer hook_user_data;
7586
mkfs_data_unref (MkfsData *data)
7592
filesystem_create_completed_cb (DBusGMethodInvocation *context,
7594
gboolean job_was_cancelled,
7600
MkfsData *data = user_data;
7602
/* poke the kernel so we can reread the data */
7603
device_generate_kernel_change_event (device);
7605
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
7607
if (data->hook_func != NULL)
7608
data->hook_func (context, device, TRUE, data->hook_user_data);
7610
dbus_g_method_return (context);
7614
if (job_was_cancelled)
7616
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
7618
else if (WEXITSTATUS (status) == 3)
7620
throw_error (context,
7621
ERROR_FILESYSTEM_TOOLS_MISSING,
7622
"Error creating file system: Cannot run mkfs: %s",
7627
throw_error (context,
7629
"Error creating file system: helper exited with exit code %d: %s\n%s",
7630
WEXITSTATUS (status),
7635
if (data->hook_func != NULL)
7636
data->hook_func (context, device, FALSE, data->hook_user_data);
7644
DBusGMethodInvocation *context;
7652
FilesystemCreateHookFunc mkfs_hook_func;
7653
gpointer mkfs_hook_user_data;
7655
guint device_changed_signal_handler_id;
7656
guint device_changed_timeout_id;
7659
static MkfsLuksData *
7660
mkfse_data_ref (MkfsLuksData *data)
7667
mkfse_data_unref (MkfsLuksData *data)
7670
if (data->refcount == 0)
7672
if (data->passphrase != NULL)
7674
memset (data->passphrase, '\0', strlen (data->passphrase));
7675
g_free (data->passphrase);
7677
if (data->device != NULL)
7678
g_object_unref (data->device);
7679
g_strfreev (data->options);
7680
g_free (data->fstype);
7686
filesystem_create_wait_for_cleartext_device_hook (DBusGMethodInvocation *context,
7690
MkfsLuksData *data = user_data;
7694
/* Dang, unlocking failed. The unlock method have already thrown an exception for us. */
7698
/* We're unlocked.. awesome.. Now we can _finally_ create the file system.
7699
* What a ride. We're returning to exactly to where we came from. Back to
7700
* the source. Only the device is different.
7703
device_filesystem_create_internal (device,
7706
data->mkfs_hook_func,
7707
data->mkfs_hook_user_data,
7709
mkfse_data_unref (data);
7714
filesystem_create_wait_for_luks_device_changed_cb (Daemon *daemon,
7715
const char *object_path,
7718
MkfsLuksData *data = user_data;
7721
/* check if we're now a LUKS crypto device */
7722
device = daemon_local_find_by_object_path (daemon, object_path);
7723
if (device == data->device && (device->priv->id_usage != NULL && strcmp (device->priv->id_usage, "crypto") == 0)
7724
&& (device->priv->id_type != NULL && strcmp (device->priv->id_type, "crypto_LUKS") == 0))
7727
/* yay! we are now set up the corresponding cleartext device */
7729
device_luks_unlock_internal (data->device,
7732
filesystem_create_wait_for_cleartext_device_hook,
7736
g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
7737
g_source_remove (data->device_changed_timeout_id);
7742
filesystem_create_wait_for_luks_device_not_seen_cb (gpointer user_data)
7744
MkfsLuksData *data = user_data;
7746
throw_error (data->context,
7748
"Error creating luks encrypted file system: timeout (10s) waiting for luks device to show up");
7750
g_signal_handler_disconnect (data->device->priv->daemon, data->device_changed_signal_handler_id);
7751
mkfse_data_unref (data);
7757
filesystem_create_create_luks_device_completed_cb (DBusGMethodInvocation *context,
7759
gboolean job_was_cancelled,
7765
MkfsLuksData *data = user_data;
7767
/* poke the kernel so we can reread the data (new uuid etc.) */
7768
device_generate_kernel_change_event (device);
7770
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
7773
/* OK! So we've got ourselves an luks device. Let's set it up so we can create a file
7774
* system. Sit and wait for the change event to appear so we can setup with the right UUID.
7777
data->device_changed_signal_handler_id
7778
= g_signal_connect_after (device->priv->daemon,
7780
(GCallback) filesystem_create_wait_for_luks_device_changed_cb,
7781
mkfse_data_ref (data));
7783
/* set up timeout for error reporting if waiting failed
7785
* (the signal handler and the timeout handler share the ref to data
7786
* as one will cancel the other)
7788
data->device_changed_timeout_id = g_timeout_add (10 * 1000,
7789
filesystem_create_wait_for_luks_device_not_seen_cb,
7795
if (job_was_cancelled)
7797
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
7801
throw_error (context,
7803
"Error creating file system: cryptsetup exited with exit code %d: %s",
7804
WEXITSTATUS (status),
7811
device_filesystem_create_internal (Device *device,
7814
FilesystemCreateHookFunc hook_func,
7815
gpointer hook_user_data,
7816
DBusGMethodInvocation *context)
7822
char *options_for_stdin;
7823
char *passphrase_stdin;
7824
MkfsData *mkfs_data;
7826
options_for_stdin = NULL;
7827
passphrase_stdin = NULL;
7830
if (device_local_is_busy (device, TRUE, TRUE, &error))
7832
dbus_g_method_return_error (context, error);
7833
g_error_free (error);
7837
if (strlen (fstype) == 0)
7839
throw_error (context, ERROR_FAILED, "fstype not specified");
7843
/* search for luks_encrypt=<passphrase> and do a detour if that's specified */
7844
for (n = 0; options[n] != NULL; n++)
7846
if (g_str_has_prefix (options[n], "luks_encrypt="))
7848
MkfsLuksData *mkfse_data;
7850
/* So this is a request to create an luks device to put the
7851
* file system on; save all options for mkfs (except luks_encrypt=) for
7852
* later invocation once we have a cleartext device.
7855
mkfse_data = g_new0 (MkfsLuksData, 1);
7856
mkfse_data->refcount = 1;
7857
mkfse_data->context = context;
7858
mkfse_data->device = g_object_ref (device);
7859
mkfse_data->passphrase = g_strdup (options[n] + sizeof("luks_encrypt=") - 1);
7860
mkfse_data->mkfs_hook_func = hook_func;
7861
mkfse_data->mkfs_hook_user_data = hook_user_data;
7862
mkfse_data->fstype = g_strdup (fstype);
7863
mkfse_data->options = g_strdupv (options);
7864
g_free (mkfse_data->options[n]);
7865
for (m = n; mkfse_data->options[m] != NULL; m++)
7867
mkfse_data->options[m] = mkfse_data->options[m + 1];
7870
passphrase_stdin = g_strdup_printf ("%s\n", mkfse_data->passphrase);
7873
argv[n++] = "cryptsetup";
7875
argv[n++] = "luksFormat";
7876
argv[n++] = device->priv->device_file;
7880
if (!job_new (context,
7886
filesystem_create_create_luks_device_completed_cb,
7889
(GDestroyNotify) mkfse_data_unref))
7898
mkfs_data = g_new (MkfsData, 1);
7899
mkfs_data->hook_func = hook_func;
7900
mkfs_data->hook_user_data = hook_user_data;
7902
/* pass options on stdin as it may contain secrets */
7903
s = g_strjoinv ("\n", options);
7904
options_for_stdin = g_strconcat (s, "\n\n", NULL);
7908
argv[n++] = "udisks-helper-mkfs";
7909
argv[n++] = (char *) fstype;
7910
argv[n++] = device->priv->device_file;
7911
argv[n++] = device->priv->device_is_partition_table ? "1" : "0";
7914
if (!job_new (context,
7920
filesystem_create_completed_cb,
7923
(GDestroyNotify) mkfs_data_unref))
7929
g_free (options_for_stdin);
7930
if (passphrase_stdin != NULL)
7932
memset (passphrase_stdin, '\0', strlen (passphrase_stdin));
7933
g_free (passphrase_stdin);
7939
device_filesystem_create_authorized_cb (Daemon *daemon,
7941
DBusGMethodInvocation *context,
7942
const gchar *action_id,
7943
guint num_user_data,
7944
gpointer *user_data_elements)
7946
const gchar *fstype = user_data_elements[0];
7947
gchar **options = user_data_elements[1];
7948
device_filesystem_create_internal (device, fstype, options, NULL, NULL, context);
7952
device_filesystem_create (Device *device,
7955
DBusGMethodInvocation *context)
7957
daemon_local_check_auth (device->priv->daemon,
7959
device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
7960
: "org.freedesktop.udisks.change",
7963
device_filesystem_create_authorized_cb,
7968
g_strdupv (options),
7973
/*--------------------------------------------------------------------------------------------------------------*/
7976
device_job_cancel_authorized_cb (Daemon *daemon,
7978
DBusGMethodInvocation *context,
7979
const gchar *action_id,
7980
guint num_user_data,
7981
gpointer *user_data_elements)
7984
if (!device->priv->job_in_progress)
7986
throw_error (context, ERROR_FAILED, "There is no job to cancel");
7990
if (!device->priv->job_is_cancellable)
7992
throw_error (context, ERROR_FAILED, "Job cannot be cancelled");
7996
job_cancel (device);
7998
/* TODO: wait returning once the job is actually cancelled? */
7999
dbus_g_method_return (context);
8005
device_job_cancel (Device *device,
8006
DBusGMethodInvocation *context)
8009
const gchar *action_id;
8011
if (!device->priv->job_in_progress)
8013
throw_error (context, ERROR_FAILED, "There is no job to cancel");
8017
if (!device->priv->job_is_cancellable)
8019
throw_error (context, ERROR_FAILED, "Job cannot be cancelled");
8023
daemon_local_get_uid (device->priv->daemon, &uid, context);
8026
if (device->priv->job_initiated_by_uid != uid)
8028
action_id = "org.freedesktop.udisks.cancel-job-others";
8031
daemon_local_check_auth (device->priv->daemon,
8036
device_job_cancel_authorized_cb,
8044
/*--------------------------------------------------------------------------------------------------------------*/
8050
guint device_added_signal_handler_id;
8051
guint device_added_timeout_id;
8053
DBusGMethodInvocation *context;
8058
guint64 created_offset;
8059
guint64 created_size;
8064
} CreatePartitionData;
8066
static CreatePartitionData *
8067
partition_create_data_new (DBusGMethodInvocation *context,
8074
CreatePartitionData *data;
8076
data = g_new0 (CreatePartitionData, 1);
8079
data->context = context;
8080
data->device = g_object_ref (device);
8081
data->offset = offset;
8083
data->fstype = g_strdup (fstype);
8084
data->fsoptions = g_strdupv (fsoptions);
8089
static CreatePartitionData *
8090
partition_create_data_ref (CreatePartitionData *data)
8097
partition_create_data_unref (CreatePartitionData *data)
8100
if (data->refcount == 0)
8102
g_object_unref (data->device);
8103
g_free (data->fstype);
8104
g_strfreev (data->fsoptions);
8110
partition_create_filesystem_create_hook (DBusGMethodInvocation *context,
8112
gboolean filesystem_create_succeeded,
8115
if (!filesystem_create_succeeded)
8117
/* dang.. FilesystemCreate already reported an error */
8122
dbus_g_method_return (context, device->priv->object_path);
8127
partition_create_found_device (Device *device,
8128
CreatePartitionData *data)
8130
if (strlen (data->fstype) > 0)
8132
device_filesystem_create_internal (device,
8135
partition_create_filesystem_create_hook,
8141
dbus_g_method_return (data->context, device->priv->object_path);
8146
partition_create_device_added_cb (Daemon *daemon,
8147
const char *object_path,
8150
CreatePartitionData *data = user_data;
8153
/* check the device added is the partition we've created */
8154
device = daemon_local_find_by_object_path (daemon, object_path);
8155
if (device != NULL && device->priv->device_is_partition && strcmp (device->priv->partition_slave,
8156
data->device->priv->object_path) == 0
8157
&& data->created_offset == device->priv->partition_offset && data->created_size == device->priv->partition_size)
8160
/* yay! it is.. now create the file system if requested */
8161
partition_create_found_device (device, data);
8163
g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
8164
g_source_remove (data->device_added_timeout_id);
8165
partition_create_data_unref (data);
8170
partition_create_device_not_seen_cb (gpointer user_data)
8172
CreatePartitionData *data = user_data;
8174
throw_error (data->context, ERROR_FAILED, "Error creating partition: timeout (10s) waiting for partition to show up");
8176
g_signal_handler_disconnect (data->device->priv->daemon, data->device_added_signal_handler_id);
8177
partition_create_data_unref (data);
8183
partition_create_completed_cb (DBusGMethodInvocation *context,
8185
gboolean job_was_cancelled,
8191
CreatePartitionData *data = user_data;
8193
/* poke the kernel so we can reread the data */
8194
device_generate_kernel_change_event (device);
8196
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
8206
* job-create-partition-offset:
8207
* job-create-partition-size:
8209
* lines and parse the new start and end. We need this
8210
* for waiting on the created partition (since the requested
8211
* start and size passed may not be honored due to disk/cylinder/sector
8212
* alignment reasons).
8217
tokens = g_strsplit (stderr, "\n", 0);
8218
for (n = 0; tokens[n] != NULL; n++)
8220
char *line = tokens[n];
8226
if (g_str_has_prefix (line, "job-create-partition-offset: "))
8228
offset = strtoll (line + sizeof("job-create-partition-offset: ") - 1, &endp, 10);
8232
else if (g_str_has_prefix (line, "job-create-partition-size: "))
8234
size = strtoll (line + sizeof("job-create-partition-size: ") - 1, &endp, 10);
8239
g_strfreev (tokens);
8243
throw_error (context, ERROR_FAILED, "Error creating partition: internal error, expected to find new "
8244
"start and end but m=%d", m);
8248
gboolean found_device;
8252
data->created_offset = offset;
8253
data->created_size = size;
8255
/* check if the device is already there */
8256
found_device = FALSE;
8257
devices = daemon_local_get_all_devices (device->priv->daemon);
8258
for (l = devices; l != NULL; l = l->next)
8260
Device *d = DEVICE (l->data);
8262
if (d->priv->device_is_partition && strcmp (d->priv->partition_slave, data->device->priv->object_path)
8263
== 0 && data->created_offset == d->priv->partition_offset && data->created_size
8264
== d->priv->partition_size)
8266
/* yay! it is.. now create the file system if requested */
8267
partition_create_found_device (d, data);
8268
found_device = TRUE;
8275
/* otherwise sit around and wait for the new partition to appear */
8276
data->device_added_signal_handler_id
8277
= g_signal_connect_after (device->priv->daemon,
8279
(GCallback) partition_create_device_added_cb,
8280
partition_create_data_ref (data));
8282
/* set up timeout for error reporting if waiting failed
8284
* (the signal handler and the timeout handler share the ref to data
8285
* as one will cancel the other)
8287
data->device_added_timeout_id = g_timeout_add (10 * 1000, partition_create_device_not_seen_cb, data);
8293
if (job_was_cancelled)
8295
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
8299
throw_error (context,
8301
"Error creating partition: helper exited with exit code %d: %s",
8302
WEXITSTATUS (status),
8309
device_partition_create_authorized_cb (Daemon *daemon,
8311
DBusGMethodInvocation *context,
8312
const gchar *action_id,
8313
guint num_user_data,
8314
gpointer *user_data_elements)
8316
guint64 offset = *((guint64*) user_data_elements[0]);
8317
guint64 size = *((guint64*) user_data_elements[1]);
8319
const char *type = user_data_elements[2];
8320
const char *label = user_data_elements[3];
8321
char **flags = user_data_elements[4];
8322
char **options = user_data_elements[5];
8323
const char *fstype = user_data_elements[6];
8324
char **fsoptions = user_data_elements[7];
8329
char *offset_as_string;
8330
char *size_as_string;
8331
char *flags_as_string;
8333
offset_as_string = NULL;
8334
size_as_string = NULL;
8335
flags_as_string = NULL;
8338
if (!device->priv->device_is_partition_table)
8340
throw_error (context, ERROR_FAILED, "Device is not partitioned");
8344
if (device_local_is_busy (device, FALSE, TRUE, &error))
8346
dbus_g_method_return_error (context, error);
8347
g_error_free (error);
8351
/* partutil.c / libparted will check there are no partitions in the requested slice */
8353
offset_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", offset);
8354
size_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", size);
8355
/* TODO: check that neither of the flags include ',' */
8356
flags_as_string = g_strjoinv (",", flags);
8359
argv[n++] = "udisks-helper-create-partition";
8360
if (device->priv->device_is_linux_dmmp)
8361
argv[n++] = (gchar *) get_dmmp_device_node (device);
8363
argv[n++] = device->priv->device_file;
8364
argv[n++] = offset_as_string;
8365
argv[n++] = size_as_string;
8366
argv[n++] = (char *) type;
8367
argv[n++] = (char *) label;
8368
argv[n++] = (char *) flags_as_string;
8369
for (m = 0; options[m] != NULL; m++)
8371
if (n >= (int) sizeof(argv) - 1)
8373
throw_error (context, ERROR_FAILED, "Too many options");
8376
/* the helper will validate each option */
8377
argv[n++] = (char *) options[m];
8381
if (!job_new (context,
8387
partition_create_completed_cb,
8389
partition_create_data_new (context, device, offset, size, fstype, fsoptions),
8390
(GDestroyNotify) partition_create_data_unref))
8396
g_free (offset_as_string);
8397
g_free (size_as_string);
8398
g_free (flags_as_string);
8402
device_partition_create (Device *device,
8411
DBusGMethodInvocation *context)
8413
if (!device->priv->device_is_partition_table)
8415
throw_error (context, ERROR_FAILED, "Device is not partitioned");
8419
daemon_local_check_auth (device->priv->daemon,
8421
device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
8422
: "org.freedesktop.udisks.change",
8425
device_partition_create_authorized_cb,
8428
g_memdup (&offset, sizeof(guint64)),
8430
g_memdup (&size, sizeof(guint64)),
8438
g_strdupv (options),
8442
g_strdupv (fsoptions),
8449
/*--------------------------------------------------------------------------------------------------------------*/
8453
DBusGMethodInvocation *context;
8455
Device *enclosing_device;
8460
} ModifyPartitionData;
8462
static ModifyPartitionData *
8463
partition_modify_data_new (DBusGMethodInvocation *context,
8465
Device *enclosing_device,
8470
ModifyPartitionData *data;
8472
data = g_new0 (ModifyPartitionData, 1);
8474
data->context = context;
8475
data->device = g_object_ref (device);
8476
data->enclosing_device = g_object_ref (enclosing_device);
8477
data->type = g_strdup (type);
8478
data->label = g_strdup (label);
8479
data->flags = g_strdupv (flags);
8485
partition_modify_data_unref (ModifyPartitionData *data)
8487
g_object_unref (data->device);
8488
g_object_unref (data->enclosing_device);
8489
g_free (data->type);
8490
g_free (data->label);
8491
g_free (data->flags);
8496
partition_modify_completed_cb (DBusGMethodInvocation *context,
8498
gboolean job_was_cancelled,
8504
ModifyPartitionData *data = user_data;
8506
/* poke the kernel so we can reread the data */
8507
device_generate_kernel_change_event (data->enclosing_device);
8508
device_generate_kernel_change_event (data->device);
8510
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
8512
/* update local copy, don't wait for the kernel */
8514
device_set_partition_type (device, data->type);
8515
device_set_partition_label (device, data->label);
8516
device_set_partition_flags (device, data->flags);
8518
drain_pending_changes (device, FALSE);
8520
dbus_g_method_return (context);
8525
if (job_was_cancelled)
8527
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
8531
throw_error (context,
8533
"Error modifying partition: helper exited with exit code %d: %s",
8534
WEXITSTATUS (status),
8541
device_partition_modify_authorized_cb (Daemon *daemon,
8543
DBusGMethodInvocation *context,
8544
const gchar *action_id,
8545
guint num_user_data,
8546
gpointer *user_data_elements)
8548
const char *type = user_data_elements[0];
8549
const char *label = user_data_elements[1];
8550
char **flags = user_data_elements[2];
8554
char *offset_as_string;
8555
char *size_as_string;
8556
char *flags_as_string;
8557
Device *enclosing_device;
8559
offset_as_string = NULL;
8560
size_as_string = NULL;
8561
flags_as_string = NULL;
8564
if (!device->priv->device_is_partition)
8566
throw_error (context, ERROR_FAILED, "Device is not a partition");
8570
enclosing_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->partition_slave);
8571
if (enclosing_device == NULL)
8573
throw_error (context, ERROR_FAILED, "Cannot find enclosing device");
8577
if (device_local_is_busy (enclosing_device, FALSE, TRUE, &error))
8579
dbus_g_method_return_error (context, error);
8580
g_error_free (error);
8584
if (strlen (type) == 0)
8586
throw_error (context, ERROR_FAILED, "type not specified");
8590
offset_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", device->priv->partition_offset);
8591
size_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", device->priv->partition_size);
8592
/* TODO: check that neither of the flags include ',' */
8593
flags_as_string = g_strjoinv (",", flags);
8596
argv[n++] = "udisks-helper-modify-partition";
8597
argv[n++] = enclosing_device->priv->device_file;
8598
argv[n++] = offset_as_string;
8599
argv[n++] = size_as_string;
8600
argv[n++] = (char *) type;
8601
argv[n++] = (char *) label;
8602
argv[n++] = (char *) flags_as_string;
8605
if (!job_new (context,
8611
partition_modify_completed_cb,
8613
partition_modify_data_new (context, device, enclosing_device, type, label, flags),
8614
(GDestroyNotify) partition_modify_data_unref))
8620
g_free (offset_as_string);
8621
g_free (size_as_string);
8622
g_free (flags_as_string);
8626
device_partition_modify (Device *device,
8630
DBusGMethodInvocation *context)
8632
if (!device->priv->device_is_partition)
8634
throw_error (context, ERROR_FAILED, "Device is not a partition");
8638
daemon_local_check_auth (device->priv->daemon,
8640
device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
8641
: "org.freedesktop.udisks.change",
8644
device_partition_modify_authorized_cb,
8658
/*--------------------------------------------------------------------------------------------------------------*/
8664
guint device_changed_signal_handler_id;
8665
guint device_changed_timeout_id;
8667
DBusGMethodInvocation *context;
8672
} CreatePartitionTableData;
8674
static CreatePartitionTableData *
8675
partition_table_create_data_new (DBusGMethodInvocation *context,
8679
CreatePartitionTableData *data;
8681
data = g_new0 (CreatePartitionTableData, 1);
8684
data->context = context;
8685
data->device = g_object_ref (device);
8686
data->scheme = g_strdup (scheme);
8691
static CreatePartitionTableData *
8692
partition_table_create_data_ref (CreatePartitionTableData *data)
8699
partition_table_create_data_unref (CreatePartitionTableData *data)
8702
if (data->refcount == 0)
8704
g_object_unref (data->device);
8705
g_free (data->scheme);
8711
partition_table_create_device_changed_cb (Daemon *daemon,
8712
const char *object_path,
8715
CreatePartitionTableData *data = user_data;
8718
device = daemon_local_find_by_object_path (daemon, object_path);
8719
if (device == data->device)
8721
if (g_strcmp0 (device->priv->partition_table_scheme, data->scheme) == 0 || (device->priv->partition_table_scheme
8722
== NULL && g_strcmp0 (data->scheme, "none") == 0))
8724
dbus_g_method_return (data->context);
8726
g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
8727
g_source_remove (data->device_changed_timeout_id);
8728
partition_table_create_data_unref (data);
8734
partition_table_create_device_not_changed_cb (gpointer user_data)
8736
CreatePartitionTableData *data = user_data;
8738
throw_error (data->context, ERROR_FAILED, "Error creating partition table: timeout (10s) waiting for change");
8740
g_signal_handler_disconnect (data->device->priv->daemon, data->device_changed_signal_handler_id);
8741
partition_table_create_data_unref (data);
8747
partition_table_create_completed_cb (DBusGMethodInvocation *context,
8749
gboolean job_was_cancelled,
8755
CreatePartitionTableData *data = user_data;
8757
/* poke the kernel so we can reread the data */
8758
device_generate_kernel_change_event (device);
8760
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
8763
if (g_strcmp0 (device->priv->partition_table_scheme, data->scheme) == 0)
8765
dbus_g_method_return (context);
8769
/* sit around and wait for the new partition table to appear */
8770
data->device_changed_signal_handler_id
8771
= g_signal_connect_after (device->priv->daemon,
8773
(GCallback) partition_table_create_device_changed_cb,
8774
partition_table_create_data_ref (data));
8776
/* set up timeout for error reporting if waiting failed
8778
* (the signal handler and the timeout handler share the ref to data
8779
* as one will cancel the other)
8781
data->device_changed_timeout_id = g_timeout_add (10 * 1000,
8782
partition_table_create_device_not_changed_cb,
8789
if (job_was_cancelled)
8791
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
8795
throw_error (context,
8797
"Error creating partition table: helper exited with exit code %d: %s",
8798
WEXITSTATUS (status),
8805
device_partition_table_create_authorized_cb (Daemon *daemon,
8807
DBusGMethodInvocation *context,
8808
const gchar *action_id,
8809
guint num_user_data,
8810
gpointer *user_data_elements)
8812
const char *scheme = user_data_elements[0];
8813
char **options = user_data_elements[1];
8821
if (device_local_is_busy (device, TRUE, TRUE, &error))
8823
dbus_g_method_return_error (context, error);
8824
g_error_free (error);
8828
if (strlen (scheme) == 0)
8830
throw_error (context, ERROR_FAILED, "type not specified");
8835
argv[n++] = "udisks-helper-create-partition-table";
8836
if (device->priv->device_is_linux_dmmp)
8837
argv[n++] = (gchar *) get_dmmp_device_node (device);
8839
argv[n++] = device->priv->device_file;
8840
argv[n++] = (char *) scheme;
8841
for (m = 0; options[m] != NULL; m++)
8843
if (n >= (int) sizeof(argv) - 1)
8845
throw_error (context, ERROR_FAILED, "Too many options");
8848
/* the helper will validate each option */
8849
argv[n++] = (char *) options[m];
8853
if (!job_new (context,
8854
"PartitionTableCreate",
8859
partition_table_create_completed_cb,
8861
partition_table_create_data_new (context, device, scheme),
8862
(GDestroyNotify) partition_table_create_data_unref))
8872
device_partition_table_create (Device *device,
8875
DBusGMethodInvocation *context)
8877
daemon_local_check_auth (device->priv->daemon,
8879
device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
8880
: "org.freedesktop.udisks.change",
8881
"PartitionTableCreate",
8883
device_partition_table_create_authorized_cb,
8888
g_strdupv (options),
8893
/*--------------------------------------------------------------------------------------------------------------*/
8896
find_cleartext_device (Device *device)
8904
/* check that there isn't a cleartext device already */
8905
devices = daemon_local_get_all_devices (device->priv->daemon);
8906
for (l = devices; l != NULL; l = l->next)
8908
Device *d = DEVICE (l->data);
8909
if (d->priv->device_is_luks_cleartext && d->priv->luks_cleartext_slave != NULL
8910
&& strcmp (d->priv->luks_cleartext_slave, device->priv->object_path) == 0)
8919
g_list_free (devices);
8928
gulong device_added_signal_handler_id;
8929
gulong device_changed_signal_handler_id;
8930
guint device_added_timeout_id;
8932
DBusGMethodInvocation *context;
8935
UnlockEncryptionHookFunc hook_func;
8936
gpointer hook_user_data;
8937
} UnlockEncryptionData;
8939
static UnlockEncryptionData *
8940
unlock_encryption_data_new (DBusGMethodInvocation *context,
8942
UnlockEncryptionHookFunc hook_func,
8943
gpointer hook_user_data)
8945
UnlockEncryptionData *data;
8947
data = g_new0 (UnlockEncryptionData, 1);
8950
data->context = context;
8951
data->device = g_object_ref (device);
8952
data->hook_func = hook_func;
8953
data->hook_user_data = hook_user_data;
8957
static UnlockEncryptionData *
8958
unlock_encryption_data_ref (UnlockEncryptionData *data)
8965
unlock_encryption_data_unref (UnlockEncryptionData *data)
8968
if (data->refcount == 0)
8970
g_object_unref (data->device);
8976
luks_unlock_device_added_cb (Daemon *daemon,
8977
const char *object_path,
8980
UnlockEncryptionData *data = user_data;
8983
/* check the device is a cleartext partition for us */
8984
device = daemon_local_find_by_object_path (daemon, object_path);
8986
if (device != NULL && device->priv->device_is_luks_cleartext && strcmp (device->priv->luks_cleartext_slave,
8987
data->device->priv->object_path) == 0)
8990
g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
8991
g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
8992
g_source_remove (data->device_added_timeout_id);
8994
/* update and emit a Changed() signal on the holder since the luks-holder
8995
* property indicates the cleartext device
8997
update_info (data->device);
8998
drain_pending_changes (data->device, FALSE);
9000
if (data->hook_func != NULL)
9002
data->hook_func (data->context, device, data->hook_user_data);
9006
dbus_g_method_return (data->context, object_path);
9009
unlock_encryption_data_unref (data);
9014
luks_unlock_device_not_seen_cb (gpointer user_data)
9016
UnlockEncryptionData *data = user_data;
9018
g_signal_handler_disconnect (data->device->priv->daemon, data->device_added_signal_handler_id);
9019
g_signal_handler_disconnect (data->device->priv->daemon, data->device_changed_signal_handler_id);
9021
throw_error (data->context,
9023
"Error unlocking device: timeout (10s) waiting for cleartext device to show up");
9025
if (data->hook_func != NULL)
9027
data->hook_func (data->context, NULL, data->hook_user_data);
9030
unlock_encryption_data_unref (data);
9035
luks_unlock_start_waiting_for_cleartext_device (UnlockEncryptionData *data)
9037
Device *cleartext_device;
9039
cleartext_device = find_cleartext_device (data->device);
9040
if (cleartext_device != NULL)
9042
/* update and emit a Changed() signal on the holder since the luks-holder
9043
* property indicates the cleartext device
9045
update_info (data->device);
9046
drain_pending_changes (data->device, FALSE);
9048
if (data->hook_func != NULL)
9050
data->hook_func (data->context, cleartext_device, data->hook_user_data);
9054
dbus_g_method_return (data->context, cleartext_device->priv->object_path);
9057
unlock_encryption_data_unref (data);
9061
/* sit around wait for the cleartext device to appear */
9062
data->device_added_signal_handler_id = g_signal_connect_after (data->device->priv->daemon,
9064
(GCallback) luks_unlock_device_added_cb,
9066
data->device_changed_signal_handler_id = g_signal_connect_after (data->device->priv->daemon,
9068
(GCallback) luks_unlock_device_added_cb,
9071
/* set up timeout for error reporting if waiting failed */
9072
data->device_added_timeout_id = g_timeout_add (15 * 1000, luks_unlock_device_not_seen_cb, data);
9074
/* Note that the signal and timeout handlers share the ref to data - one will cancel the other */
9079
luks_unlock_completed_cb (DBusGMethodInvocation *context,
9081
gboolean job_was_cancelled,
9087
UnlockEncryptionData *data = user_data;
9089
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
9092
luks_unlock_start_waiting_for_cleartext_device (unlock_encryption_data_ref (data));
9097
if (job_was_cancelled)
9099
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
9103
throw_error (context,
9105
"Error unlocking device: cryptsetup exited with exit code %d: %s",
9106
WEXITSTATUS (status),
9109
if (data->hook_func != NULL)
9111
data->hook_func (data->context, NULL, data->hook_user_data);
9117
device_luks_unlock_internal (Device *device,
9120
UnlockEncryptionHookFunc hook_func,
9121
gpointer hook_user_data,
9122
DBusGMethodInvocation *context)
9128
char *secret_as_stdin;
9132
secret_as_stdin = NULL;
9135
daemon_local_get_uid (device->priv->daemon, &uid, context);
9137
if (device_local_is_busy (device, FALSE, TRUE, &error))
9139
dbus_g_method_return_error (context, error);
9140
g_error_free (error);
9144
if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "crypto") != 0)
9146
throw_error (context, ERROR_FAILED, "Not a LUKS device");
9150
if (find_cleartext_device (device) != NULL)
9152
throw_error (context, ERROR_FAILED, "Cleartext device is already unlocked");
9156
luks_name = g_strdup_printf ("udisks-luks-uuid-%s-uid%d", device->priv->id_uuid, uid);
9157
secret_as_stdin = g_strdup_printf ("%s\n", secret);
9160
argv[n++] = "cryptsetup";
9163
argv[n++] = "luksOpen";
9164
argv[n++] = device->priv->device_file;
9165
argv[n++] = luks_name;
9168
/* yay, so it turns out /sbin/cryptsetup returns way too early; what happens is this
9170
* - invoke /sbin/cryptsetup
9171
* - temporary dm node with name temporary-cryptsetup-* appears. We ignore these,
9173
* - temporary dm node removed
9174
* - /sbin/cryptsetup returns with success (brings us here)
9175
* - proper dm node appears
9176
* - with the name we requested, e.g. udisks-luks-uuid-%s-uid%d
9177
* - proper dm node disappears
9178
* - proper dm node reappears
9180
* Obiviously /sbin/cryptsetup shouldn't return before the dm node we are
9181
* looking for is really there or ready to use. But that's not how things
9184
* This bug has been reported here:
9186
* https://bugzilla.redhat.com/show_bug.cgi?id=530721
9188
* WORKAROUND: wait for the udev queue to settle before returning. Long
9189
* term fix is device-mapper/udev integration.
9191
if (!job_new (context,
9197
luks_unlock_completed_cb,
9198
TRUE, /* see note above */
9199
unlock_encryption_data_new (context, device, hook_func, hook_user_data),
9200
(GDestroyNotify) unlock_encryption_data_unref))
9206
/* scrub the secret */
9207
if (secret_as_stdin != NULL)
9209
memset (secret_as_stdin, '\0', strlen (secret_as_stdin));
9211
g_free (secret_as_stdin);
9217
device_luks_unlock_authorized_cb (Daemon *daemon,
9219
DBusGMethodInvocation *context,
9220
const gchar *action_id,
9221
guint num_user_data,
9222
gpointer *user_data_elements)
9224
const char *secret = user_data_elements[0];
9225
char **options = user_data_elements[1];
9226
device_luks_unlock_internal (device, secret, options, NULL, NULL, context);
9230
device_luks_unlock (Device *device,
9233
DBusGMethodInvocation *context)
9235
if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "crypto") != 0)
9237
throw_error (context, ERROR_FAILED, "Not a LUKS device");
9241
daemon_local_check_auth (device->priv->daemon,
9243
"org.freedesktop.udisks.luks-unlock",
9246
device_luks_unlock_authorized_cb,
9251
g_strdupv (options),
9258
/*--------------------------------------------------------------------------------------------------------------*/
9263
DBusGMethodInvocation *context;
9264
Device *luks_device;
9265
Device *cleartext_device;
9266
guint device_removed_signal_handler_id;
9267
guint device_removed_timeout_id;
9268
} LockEncryptionData;
9270
static LockEncryptionData *
9271
lock_encryption_data_new (DBusGMethodInvocation *context,
9272
Device *luks_device,
9273
Device *cleartext_device)
9275
LockEncryptionData *data;
9277
data = g_new0 (LockEncryptionData, 1);
9280
data->context = context;
9281
data->luks_device = g_object_ref (luks_device);
9282
data->cleartext_device = g_object_ref (cleartext_device);
9286
static LockEncryptionData *
9287
lock_encryption_data_ref (LockEncryptionData *data)
9294
lock_encryption_data_unref (LockEncryptionData *data)
9297
if (data->refcount == 0)
9299
g_object_unref (data->luks_device);
9300
g_object_unref (data->cleartext_device);
9306
luks_lock_wait_for_cleartext_device_removed_cb (Daemon *daemon,
9307
const char *object_path,
9311
LockEncryptionData *data = user_data;
9313
device = daemon_local_find_by_object_path (daemon, object_path);
9314
if (device == data->cleartext_device)
9317
job_local_end (data->luks_device);
9319
/* update and emit a Changed() signal on the holder since the luks-holder
9320
* property indicates the cleartext device
9322
update_info (data->luks_device);
9323
drain_pending_changes (data->luks_device, FALSE);
9325
dbus_g_method_return (data->context);
9327
g_signal_handler_disconnect (daemon, data->device_removed_signal_handler_id);
9328
g_source_remove (data->device_removed_timeout_id);
9329
lock_encryption_data_unref (data);
9334
luks_lock_wait_for_cleartext_device_not_seen_cb (gpointer user_data)
9336
LockEncryptionData *data = user_data;
9338
job_local_end (data->luks_device);
9340
throw_error (data->context,
9342
"Error locking luks device: timeout (10s) waiting for cleartext device to be removed");
9344
g_signal_handler_disconnect (data->cleartext_device->priv->daemon, data->device_removed_signal_handler_id);
9345
lock_encryption_data_unref (data);
9350
luks_lock_completed_cb (DBusGMethodInvocation *context,
9352
gboolean job_was_cancelled,
9358
LockEncryptionData *data = user_data;
9360
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
9363
/* if device is already removed, just return */
9364
if (data->cleartext_device->priv->removed)
9366
/* update and emit a Changed() signal on the holder since the luks-holder
9367
* property indicates the cleartext device
9369
update_info (data->luks_device);
9370
drain_pending_changes (data->luks_device, FALSE);
9372
dbus_g_method_return (context);
9376
/* otherwise sit and wait for the device to disappear */
9378
data->device_removed_signal_handler_id
9379
= g_signal_connect_after (device->priv->daemon,
9381
(GCallback) luks_lock_wait_for_cleartext_device_removed_cb,
9382
lock_encryption_data_ref (data));
9384
/* set up timeout for error reporting if waiting failed
9386
* (the signal handler and the timeout handler share the ref to data
9387
* as one will cancel the other)
9389
data->device_removed_timeout_id = g_timeout_add (10 * 1000,
9390
luks_lock_wait_for_cleartext_device_not_seen_cb,
9393
job_local_start (device, "LuksLock");
9398
if (job_was_cancelled)
9400
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
9404
throw_error (context,
9406
"Error locking device: cryptsetup exited with exit code %d: %s",
9407
WEXITSTATUS (status),
9414
luks_get_uid_from_dm_name (const char *dm_name,
9424
if (!g_str_has_prefix (dm_name, "udisks-luks-uuid"))
9427
/* determine who unlocked the device */
9428
for (n = strlen (dm_name) - 1; n >= 0; n--)
9430
if (dm_name[n] == '-')
9433
if (strncmp (dm_name + n, "-uid", 4) != 0)
9436
uid = strtol (dm_name + n + 4, &endp, 10);
9437
if (endp == NULL || *endp != '\0')
9440
if (out_uid != NULL)
9449
device_luks_lock_authorized_cb (Daemon *daemon,
9451
DBusGMethodInvocation *context,
9452
const gchar *action_id,
9453
guint num_user_data,
9454
gpointer *user_data_elements)
9456
/* TODO: use options */
9457
//char **options = user_data_elements[0];
9458
Device *cleartext_device;
9462
if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "crypto") != 0)
9464
throw_error (context, ERROR_FAILED, "Not a LUKS crypto device");
9468
cleartext_device = find_cleartext_device (device);
9469
if (cleartext_device == NULL)
9471
throw_error (context, ERROR_FAILED, "Cleartext device is not unlocked");
9475
if (cleartext_device->priv->dm_name == NULL || strlen (cleartext_device->priv->dm_name) == 0)
9477
throw_error (context, ERROR_FAILED, "Cannot determine device-mapper name");
9482
argv[n++] = "cryptsetup";
9483
argv[n++] = "luksClose";
9484
argv[n++] = cleartext_device->priv->dm_name;
9487
if (!job_new (context,
9493
luks_lock_completed_cb,
9495
lock_encryption_data_new (context, device, cleartext_device),
9496
(GDestroyNotify) lock_encryption_data_unref))
9506
device_luks_lock (Device *device,
9508
DBusGMethodInvocation *context)
9510
uid_t unlocked_by_uid;
9512
Device *cleartext_device;
9513
const gchar *action_id;
9515
daemon_local_get_uid (device->priv->daemon, &uid, context);
9517
if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "crypto") != 0)
9519
throw_error (context, ERROR_FAILED, "Not a LUKS crypto device");
9523
cleartext_device = find_cleartext_device (device);
9524
if (cleartext_device == NULL)
9526
throw_error (context, ERROR_FAILED, "Cleartext device is not unlocked");
9530
if (cleartext_device->priv->dm_name == NULL || strlen (cleartext_device->priv->dm_name) == 0)
9532
throw_error (context, ERROR_FAILED, "Cannot determine device-mapper name");
9536
/* see if we (e.g. udisks) set up this clear text device */
9537
if (!luks_get_uid_from_dm_name (cleartext_device->priv->dm_name, &unlocked_by_uid))
9539
/* nope.. so assume uid 0 set it up.. we still allow locking
9540
* the device... given enough privilege
9542
unlocked_by_uid = 0;
9545
/* require authorization if unlocked by someone else */
9547
if (unlocked_by_uid != uid)
9549
action_id = "org.freedesktop.udisks.luks-lock-others";
9552
daemon_local_check_auth (device->priv->daemon,
9557
device_luks_lock_authorized_cb,
9560
g_strdupv (options),
9567
/*--------------------------------------------------------------------------------------------------------------*/
9570
luks_change_passphrase_completed_cb (DBusGMethodInvocation *context,
9572
gboolean job_was_cancelled,
9578
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
9580
dbus_g_method_return (context);
9584
if (job_was_cancelled)
9586
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
9588
else if (WEXITSTATUS (status) == 3)
9590
throw_error (context,
9591
ERROR_FILESYSTEM_TOOLS_MISSING,
9592
"Error changing fs label: tool not available: %s",
9597
throw_error (context,
9599
"Error changing secret on device: helper exited with exit code %d: %s",
9600
WEXITSTATUS (status),
9607
device_luks_change_passphrase_authorized_cb (Daemon *daemon,
9609
DBusGMethodInvocation *context,
9610
const gchar *action_id,
9611
guint num_user_data,
9612
gpointer *user_data_elements)
9614
const char *old_secret = user_data_elements[0];
9615
const char *new_secret = user_data_elements[1];
9618
char *secrets_as_stdin;
9620
secrets_as_stdin = NULL;
9622
if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "crypto") != 0)
9624
throw_error (context, ERROR_FAILED, "Not a LUKS crypto device");
9628
secrets_as_stdin = g_strdup_printf ("%s\n%s\n", old_secret, new_secret);
9631
argv[n++] = "udisks-helper-change-luks-password";
9632
argv[n++] = device->priv->device_file;
9635
if (!job_new (context,
9636
"LuksChangePassphrase",
9641
luks_change_passphrase_completed_cb,
9650
/* scrub the secrets */
9651
if (secrets_as_stdin != NULL)
9653
memset (secrets_as_stdin, '\0', strlen (secrets_as_stdin));
9655
g_free (secrets_as_stdin);
9659
device_luks_change_passphrase (Device *device,
9660
const char *old_secret,
9661
const char *new_secret,
9662
DBusGMethodInvocation *context)
9664
/* No need to check for busy; we can actually do this while the device is unlocked as
9665
* only LUKS metadata is modified.
9668
if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "crypto") != 0)
9670
throw_error (context, ERROR_FAILED, "Not a LUKS crypto device");
9674
daemon_local_check_auth (device->priv->daemon,
9676
device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
9677
: "org.freedesktop.udisks.change",
9678
"LuksChangePassphrase",
9680
device_luks_change_passphrase_authorized_cb,
9683
g_strdup (old_secret),
9685
g_strdup (new_secret),
9692
/*--------------------------------------------------------------------------------------------------------------*/
9695
filesystem_set_label_completed_cb (DBusGMethodInvocation *context,
9697
gboolean job_was_cancelled,
9703
char *new_label = user_data;
9705
/* poke the kernel so we can reread the data */
9706
device_generate_kernel_change_event (device);
9708
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
9711
/* update local copy, don't wait for the kernel */
9712
device_set_id_label (device, new_label);
9714
drain_pending_changes (device, FALSE);
9716
dbus_g_method_return (context);
9721
if (job_was_cancelled)
9723
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
9727
throw_error (context,
9729
"Error changing fslabel: helper exited with exit code %d: %s",
9730
WEXITSTATUS (status),
9737
device_filesystem_set_label_authorized_cb (Daemon *daemon,
9739
DBusGMethodInvocation *context,
9740
const gchar *action_id,
9741
guint num_user_data,
9742
gpointer *user_data_elements)
9744
const gchar *new_label = user_data_elements[0];
9747
const Filesystem *fs_details;
9752
if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "filesystem") != 0)
9754
throw_error (context, ERROR_FAILED, "Not a mountable file system");
9758
fs_details = daemon_local_get_fs_details (device->priv->daemon, device->priv->id_type);
9759
if (fs_details == NULL)
9761
throw_error (context, ERROR_BUSY, "Unknown filesystem");
9765
if (!fs_details->supports_online_label_rename)
9767
if (device_local_is_busy (device, FALSE, TRUE, &error))
9769
dbus_g_method_return_error (context, error);
9770
g_error_free (error);
9776
argv[n++] = "udisks-helper-change-filesystem-label";
9777
argv[n++] = device->priv->device_file;
9778
argv[n++] = device->priv->id_type;
9779
argv[n++] = (char *) new_label;
9782
if (!job_new (context,
9783
"FilesystemSetLabel",
9788
filesystem_set_label_completed_cb,
9790
g_strdup (new_label),
9801
device_filesystem_set_label (Device *device,
9802
const char *new_label,
9803
DBusGMethodInvocation *context)
9805
const Filesystem *fs_details;
9810
if (device->priv->id_usage == NULL || strcmp (device->priv->id_usage, "filesystem") != 0)
9812
throw_error (context, ERROR_FAILED, "Not a mountable file system");
9816
fs_details = daemon_local_get_fs_details (device->priv->daemon, device->priv->id_type);
9817
if (fs_details == NULL)
9819
throw_error (context, ERROR_BUSY, "Unknown filesystem");
9823
if (!fs_details->supports_online_label_rename)
9825
if (device_local_is_busy (device, FALSE, TRUE, &error))
9827
dbus_g_method_return_error (context, error);
9828
g_error_free (error);
9833
daemon_local_check_auth (device->priv->daemon,
9835
device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
9836
: "org.freedesktop.udisks.change",
9837
"FilesystemSetLabel",
9839
device_filesystem_set_label_authorized_cb,
9842
g_strdup (new_label),
9849
/*--------------------------------------------------------------------------------------------------------------*/
9851
/* may be called with context==NULL */
9853
drive_ata_smart_refresh_data_completed_cb (DBusGMethodInvocation *context,
9855
gboolean job_was_cancelled,
9865
time_t time_collected;
9866
SkSmartOverall overall;
9868
PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) start", device->priv->native_path);
9873
if (job_was_cancelled || stdout == NULL)
9875
if (job_was_cancelled)
9877
if (context != NULL)
9878
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
9882
if (context != NULL)
9883
throw_error (context,
9885
"Error retrieving ATA SMART data: no output",
9886
WEXITSTATUS (status),
9892
rc = WEXITSTATUS (status);
9898
if (context != NULL)
9900
throw_error (context, ERROR_ATA_SMART_WOULD_WAKEUP, "Error retrieving ATA SMART data: %s", stderr);
9905
if (context != NULL)
9907
throw_error (context,
9909
"Error retrieving ATA SMART data: helper failed with exit code %d: %s",
9917
PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) decode blob", device->priv->native_path);
9918
blob = (gchar *) g_base64_decode (stdout, &blob_size);
9920
PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) set blob", device->priv->native_path);
9923
if (context != NULL)
9925
throw_error (context, ERROR_FAILED, "Error decoding ATA SMART data: invalid base64 format: %s", stdout);
9929
g_warning ("Error decoding ATA SMART data: invalid base64 format: %s", stdout);
9934
if (sk_disk_open (NULL, &d) != 0)
9936
if (context != NULL)
9938
throw_error (context, ERROR_FAILED, "unable to open a SkDisk");
9943
if (sk_disk_set_blob (d, blob, blob_size) != 0)
9945
if (context != NULL)
9947
throw_error (context, ERROR_FAILED, "error parsing blob: %s", strerror (errno));
9952
PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) time collected", device->priv->native_path);
9953
time_collected = time (NULL);
9954
device_set_drive_ata_smart_time_collected (device, time_collected);
9956
PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) overall smart status", device->priv->native_path);
9957
if (sk_disk_smart_get_overall (d, &overall) != 0)
9959
device_set_drive_ata_smart_status (device, overall);
9960
device_set_drive_ata_smart_blob_steal (device, blob, blob_size);
9963
/* emit change event since we've updated the smart data */
9964
PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) drain pending changes", device->priv->native_path);
9965
drain_pending_changes (device, FALSE);
9967
if (context != NULL)
9968
dbus_g_method_return (context);
9974
PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) end", device->priv->native_path);
9978
device_drive_ata_smart_refresh_data_authorized_cb (Daemon *daemon,
9980
DBusGMethodInvocation *context,
9981
const gchar *action_id,
9982
guint num_user_data,
9983
gpointer *user_data_elements)
9985
char **options = user_data_elements[0];
9988
const char *simuldata;
9992
PROFILE ("device_drive_ata_smart_refresh_data_authorized_cb(device=%s) start", device->priv->native_path);
9993
daemon_local_get_uid (device->priv->daemon, &caller_uid, context);
9997
for (n = 0; options[n] != NULL; n++)
9999
if (g_str_has_prefix (options[n], "simulate="))
10001
if (context != NULL)
10003
if (caller_uid != 0)
10005
throw_error (context, ERROR_FAILED, "Only uid 0 may use the simulate= option");
10009
simuldata = (const char *) options[n] + 9;
10010
device_set_drive_ata_smart_is_available (device, TRUE);
10012
else if (strcmp (options[n], "nowakeup") == 0)
10018
if (!device->priv->drive_ata_smart_is_available)
10020
throw_error (context, ERROR_FAILED, "Device does not support ATA SMART");
10024
if (simuldata != NULL)
10027
argv[n++] = "base64"; /* provided by coreutils */
10028
argv[n++] = (char *) simuldata;
10034
argv[n++] = "udisks-helper-ata-smart-collect";
10035
argv[n++] = device->priv->device_file;
10036
argv[n++] = nowakeup ? "1" : "0";
10040
if (!job_new (context, NULL, /* don't run this as a job */
10041
FALSE, device, argv, NULL, drive_ata_smart_refresh_data_completed_cb, FALSE, NULL, NULL))
10048
PROFILE ("device_drive_ata_smart_refresh_data_authorized_cb(device=%s) end", device->priv->native_path);
10051
/* may be called with context==NULL */
10053
device_drive_ata_smart_refresh_data (Device *device,
10055
DBusGMethodInvocation *context)
10057
const gchar *action_id;
10060
if (context != NULL)
10062
action_id = "org.freedesktop.udisks.drive-ata-smart-refresh";
10065
daemon_local_check_auth (device->priv->daemon,
10068
"DriveAtaSmartRefreshData",
10070
device_drive_ata_smart_refresh_data_authorized_cb,
10073
g_strdupv (options),
10079
/*--------------------------------------------------------------------------------------------------------------*/
10082
drive_ata_smart_initiate_selftest_completed_cb (DBusGMethodInvocation *context,
10084
gboolean job_was_cancelled,
10086
const char *stderr,
10087
const char *stdout,
10088
gpointer user_data)
10093
/* no matter what happened, refresh the data */
10094
device_drive_ata_smart_refresh_data (device, options, NULL);
10096
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
10099
dbus_g_method_return (context);
10104
if (job_was_cancelled)
10106
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
10110
throw_error (context,
10112
"Error running self test: helper exited with exit code %d: %s",
10113
WEXITSTATUS (status),
10120
device_drive_ata_smart_initiate_selftest_authorized_cb (Daemon *daemon,
10122
DBusGMethodInvocation *context,
10123
const gchar *action_id,
10124
guint num_user_data,
10125
gpointer *user_data_elements)
10127
const gchar *test = user_data_elements[0];
10128
/* TODO: use options */
10129
//gchar **options = user_data_elements[1];
10132
const gchar *job_name;
10134
if (g_strcmp0 (test, "short") == 0)
10136
job_name = "DriveAtaSmartSelftestShort";
10138
else if (g_strcmp0 (test, "extended") == 0)
10140
job_name = "DriveAtaSmartSelftestExtended";
10142
else if (g_strcmp0 (test, "conveyance") == 0)
10144
job_name = "DriveAtaSmartSelftestConveyance";
10148
throw_error (context, ERROR_FAILED, "Malformed test");
10153
argv[n++] = "udisks-helper-ata-smart-selftest";
10154
argv[n++] = device->priv->device_file;
10155
argv[n++] = (char *) test;
10158
if (!job_new (context,
10164
drive_ata_smart_initiate_selftest_completed_cb,
10177
device_drive_ata_smart_initiate_selftest (Device *device,
10180
DBusGMethodInvocation *context)
10182
if (!device->priv->drive_ata_smart_is_available)
10184
throw_error (context, ERROR_FAILED, "Device does not support ATA SMART");
10188
daemon_local_check_auth (device->priv->daemon,
10190
"org.freedesktop.udisks.drive-ata-smart-selftest",
10191
"DriveAtaSmartInitiateSelftest",
10193
device_drive_ata_smart_initiate_selftest_authorized_cb,
10198
g_strdupv (options),
10205
/*--------------------------------------------------------------------------------------------------------------*/
10208
linux_md_stop_completed_cb (DBusGMethodInvocation *context,
10210
gboolean job_was_cancelled,
10212
const char *stderr,
10213
const char *stdout,
10214
gpointer user_data)
10216
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
10219
/* the kernel side of md currently doesn't emit a 'changed' event so
10220
* generate one such that the md device can disappear from our
10223
device_generate_kernel_change_event (device);
10225
dbus_g_method_return (context);
10230
if (job_was_cancelled)
10232
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
10236
throw_error (context,
10238
"Error stopping array: mdadm exited with exit code %d: %s",
10239
WEXITSTATUS (status),
10246
device_linux_md_stop_authorized_cb (Daemon *daemon,
10248
DBusGMethodInvocation *context,
10249
const gchar *action_id,
10250
guint num_user_data,
10251
gpointer *user_data_elements)
10253
/* TODO: use options */
10254
//gchar **options = user_data_elements[0];
10259
argv[n++] = "mdadm";
10260
argv[n++] = "--stop";
10261
argv[n++] = device->priv->device_file;
10264
if (!job_new (context, "LinuxMdStop", TRUE, device, argv, NULL, linux_md_stop_completed_cb, FALSE, NULL, NULL))
10274
device_linux_md_stop (Device *device,
10276
DBusGMethodInvocation *context)
10278
if (!device->priv->device_is_linux_md)
10280
throw_error (context, ERROR_FAILED, "Device is not a Linux md drive");
10284
daemon_local_check_auth (device->priv->daemon,
10286
"org.freedesktop.udisks.linux-md",
10289
device_linux_md_stop_authorized_cb,
10292
g_strdupv (options),
10299
/*--------------------------------------------------------------------------------------------------------------*/
10302
linux_md_check_completed_cb (DBusGMethodInvocation *context,
10304
gboolean job_was_cancelled,
10306
const char *stderr,
10307
const char *stdout,
10308
gpointer user_data)
10310
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
10312
guint64 num_errors;
10314
num_errors = sysfs_get_uint64 (device->priv->native_path, "md/mismatch_cnt");
10316
dbus_g_method_return (context, num_errors);
10320
if (job_was_cancelled)
10322
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
10326
throw_error (context,
10328
"Error checking array: helper exited with exit code %d: %s",
10329
WEXITSTATUS (status),
10336
device_linux_md_check_authorized_cb (Daemon *daemon,
10338
DBusGMethodInvocation *context,
10339
const gchar *action_id,
10340
guint num_user_data,
10341
gpointer *user_data_elements)
10343
gchar **options = user_data_elements[0];
10346
const gchar *job_name;
10348
if (!device->priv->device_is_linux_md)
10350
throw_error (context, ERROR_FAILED, "Device is not a Linux md drive");
10354
if (g_strcmp0 (device->priv->linux_md_sync_action, "idle") != 0)
10356
throw_error (context, ERROR_FAILED, "Array is not idle");
10361
argv[n++] = "udisks-helper-linux-md-check";
10362
argv[n++] = device->priv->device_file;
10363
argv[n++] = device->priv->native_path;
10364
for (m = 0; options[m] != NULL; m++)
10366
if (n >= (int) sizeof(argv) - 1)
10368
throw_error (context, ERROR_FAILED, "Too many options");
10371
/* the helper will validate each option */
10372
argv[n++] = (char *) options[m];
10376
job_name = "LinuxMdCheck";
10377
for (n = 0; options != NULL && options[n] != NULL; n++)
10378
if (strcmp (options[n], "repair") == 0)
10379
job_name = "LinuxMdRepair";
10381
if (!job_new (context, job_name, TRUE, device, argv, NULL, linux_md_check_completed_cb, FALSE, NULL, NULL))
10391
device_linux_md_check (Device *device,
10393
DBusGMethodInvocation *context)
10396
const gchar *job_name;
10398
job_name = "LinuxMdCheck";
10399
for (n = 0; options != NULL && options[n] != NULL; n++)
10400
if (strcmp (options[n], "repair") == 0)
10401
job_name = "LinuxMdRepair";
10403
if (!device->priv->device_is_linux_md)
10405
throw_error (context, ERROR_FAILED, "Device is not a Linux md drive");
10409
if (g_strcmp0 (device->priv->linux_md_sync_action, "idle") != 0)
10411
throw_error (context, ERROR_FAILED, "Array is not idle");
10415
daemon_local_check_auth (device->priv->daemon,
10417
"org.freedesktop.udisks.linux-md",
10420
device_linux_md_check_authorized_cb,
10423
g_strdupv (options),
10430
/*--------------------------------------------------------------------------------------------------------------*/
10433
linux_md_add_spare_completed_cb (DBusGMethodInvocation *context,
10435
gboolean job_was_cancelled,
10437
const char *stderr,
10438
const char *stdout,
10439
gpointer user_data)
10441
Device *slave = DEVICE (user_data);
10443
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
10446
/* the slave got new metadata on it; reread that */
10447
device_generate_kernel_change_event (slave);
10449
/* the kernel side of md currently doesn't emit a 'changed' event so
10450
* generate one since state may have changed (e.g. rebuild started etc.)
10452
device_generate_kernel_change_event (device);
10454
dbus_g_method_return (context);
10459
if (job_was_cancelled)
10461
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
10465
throw_error (context,
10467
"Error adding spare: mdadm exited with exit code %d: %s",
10468
WEXITSTATUS (status),
10475
device_linux_md_add_spare_authorized_cb (Daemon *daemon,
10477
DBusGMethodInvocation *context,
10478
const gchar *action_id,
10479
guint num_user_data,
10480
gpointer *user_data_elements)
10482
char *component = user_data_elements[0];
10483
/* TODO: use options */
10484
//char **options = user_data_elements[1];
10492
slave = daemon_local_find_by_object_path (device->priv->daemon, component);
10495
throw_error (context, ERROR_FAILED, "Component doesn't exist");
10499
/* it's fine if the given device isn't a Linux md component _yet_; think
10500
* hot adding a new disk if an old one failed
10503
if (device_local_is_busy (slave, TRUE, TRUE, &error))
10505
dbus_g_method_return_error (context, error);
10506
g_error_free (error);
10510
/* TODO: check component size is OK */
10513
argv[n++] = "mdadm";
10514
argv[n++] = "--manage";
10515
argv[n++] = device->priv->device_file;
10516
argv[n++] = "--add";
10517
argv[n++] = slave->priv->device_file;
10518
argv[n++] = "--force";
10521
if (!job_new (context,
10527
linux_md_add_spare_completed_cb,
10529
g_object_ref (slave),
10540
device_linux_md_add_spare (Device *device,
10543
DBusGMethodInvocation *context)
10545
if (!device->priv->device_is_linux_md)
10547
throw_error (context, ERROR_FAILED, "Device is not a Linux md drive");
10551
daemon_local_check_auth (device->priv->daemon,
10553
"org.freedesktop.udisks.linux-md",
10556
device_linux_md_add_spare_authorized_cb,
10559
g_strdup (component),
10561
g_strdupv (options),
10567
/*--------------------------------------------------------------------------------------------------------------*/
10570
linux_md_expand_completed_cb (DBusGMethodInvocation *context,
10572
gboolean job_was_cancelled,
10574
const char *stderr,
10575
const char *stdout,
10576
gpointer user_data)
10578
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
10580
/* the kernel side of md currently doesn't emit a 'changed' event so
10581
* generate one since state may have changed (e.g. rebuild started etc.)
10583
device_generate_kernel_change_event (device);
10585
dbus_g_method_return (context);
10590
if (job_was_cancelled)
10592
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
10596
throw_error (context,
10598
"Error expanding array: helper script exited with exit code %d: %s",
10599
WEXITSTATUS (status),
10606
device_linux_md_expand_authorized_cb (Daemon *daemon,
10608
DBusGMethodInvocation *context,
10609
const gchar *action_id,
10610
guint num_user_data,
10611
gpointer *user_data_elements)
10613
gchar **components = user_data_elements[0];
10614
/* TODO: use options */
10615
//char **options = user_data_elements[1];
10619
gint new_num_raid_devices;
10620
gchar *backup_filename;
10621
gchar *md_basename;
10625
args = g_ptr_array_new_with_free_func (g_free);
10626
g_ptr_array_add (args, g_strdup ("udisks-helper-mdadm-expand"));
10627
g_ptr_array_add (args, g_strdup (device->priv->device_file));
10629
new_num_raid_devices = device->priv->linux_md_num_raid_devices + g_strv_length (components);
10630
g_ptr_array_add (args, g_strdup_printf ("%d", new_num_raid_devices));
10632
/* TODO: choose a better name and better location */
10633
md_basename = g_path_get_basename (device->priv->device_file);
10634
backup_filename = g_strdup_printf ("/root/udisks-mdadm-expand-backup-file-%s-at-%" G_GUINT64_FORMAT,
10636
(guint64) time (NULL));
10637
g_free (md_basename);
10638
g_ptr_array_add (args, backup_filename);
10640
for (n = 0; components != NULL && components[n] != NULL; n++)
10644
slave = daemon_local_find_by_object_path (device->priv->daemon, components[n]);
10647
throw_error (context,
10649
"Component with object path %s doesn't exist",
10654
if (device_local_is_busy (slave, TRUE, TRUE, &error))
10656
dbus_g_method_return_error (context, error);
10657
g_error_free (error);
10661
g_ptr_array_add (args, g_strdup (slave->priv->device_file));
10663
g_ptr_array_add (args, NULL);
10666
if (!job_new (context,
10670
(char **) args->pdata,
10672
linux_md_expand_completed_cb,
10681
g_ptr_array_free (args, TRUE);
10685
device_linux_md_expand (Device *device,
10686
GPtrArray *components,
10688
DBusGMethodInvocation *context)
10693
if (!device->priv->device_is_linux_md)
10695
throw_error (context, ERROR_FAILED, "Device is not a Linux md drive");
10699
strv = (gchar **) g_new0 (gchar*, components->len + 1);
10700
for (n = 0; n < components->len; n++)
10701
strv[n] = g_strdup (components->pdata[n]);
10703
daemon_local_check_auth (device->priv->daemon,
10705
"org.freedesktop.udisks.linux-md",
10708
device_linux_md_expand_authorized_cb,
10713
g_strdupv (options),
10719
/*--------------------------------------------------------------------------------------------------------------*/
10725
DBusGMethodInvocation *context;
10729
guint device_changed_signal_handler_id;
10730
guint device_changed_timeout_id;
10732
} RemoveComponentData;
10734
static RemoveComponentData *
10735
remove_component_data_new (DBusGMethodInvocation *context,
10739
RemoveComponentData *data;
10741
data = g_new0 (RemoveComponentData, 1);
10742
data->refcount = 1;
10744
data->context = context;
10745
data->slave = g_object_ref (slave);
10746
data->options = g_strdupv (options);
10750
static RemoveComponentData *
10751
remove_component_data_ref (RemoveComponentData *data)
10758
remove_component_data_unref (RemoveComponentData *data)
10761
if (data->refcount == 0)
10763
g_object_unref (data->slave);
10764
g_free (data->options);
10770
linux_md_remove_component_device_changed_cb (Daemon *daemon,
10771
const char *object_path,
10772
gpointer user_data)
10774
RemoveComponentData *data = user_data;
10780
device = daemon_local_find_by_object_path (daemon, object_path);
10781
if (device == data->slave)
10784
if (device_local_is_busy (data->slave, FALSE, TRUE, &error))
10786
dbus_g_method_return_error (data->context, error);
10787
g_error_free (error);
10791
gchar *fs_create_options[] =
10794
/* yay! now scrub it! */
10795
device_filesystem_create (data->slave, "empty", fs_create_options, data->context);
10797
/* TODO: leaking data? */
10799
g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
10800
g_source_remove (data->device_changed_timeout_id);
10806
linux_md_remove_component_device_not_seen_cb (gpointer user_data)
10808
RemoveComponentData *data = user_data;
10810
throw_error (data->context,
10812
"Error removing component: timeout (10s) waiting for slave to stop being busy");
10814
g_signal_handler_disconnect (data->slave->priv->daemon, data->device_changed_signal_handler_id);
10815
remove_component_data_unref (data);
10821
linux_md_remove_component_completed_cb (DBusGMethodInvocation *context,
10823
gboolean job_was_cancelled,
10825
const char *stderr,
10826
const char *stdout,
10827
gpointer user_data)
10829
RemoveComponentData *data = user_data;
10831
/* the slave got new metadata on it; reread that */
10832
device_generate_kernel_change_event (data->slave);
10834
/* the kernel side of md currently doesn't emit a 'changed' event so
10835
* generate one since state may have changed (e.g. rebuild started etc.)
10837
device_generate_kernel_change_event (device);
10839
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
10842
/* wait for the slave to be busy, then start erasing it */
10844
data->device_changed_signal_handler_id
10845
= g_signal_connect_after (device->priv->daemon,
10847
(GCallback) linux_md_remove_component_device_changed_cb,
10848
remove_component_data_ref (data));
10850
/* set up timeout for error reporting if waiting failed
10852
* (the signal handler and the timeout handler share the ref to data
10853
* as one will cancel the other)
10855
data->device_changed_timeout_id = g_timeout_add (10 * 1000, linux_md_remove_component_device_not_seen_cb, data);
10860
if (job_was_cancelled)
10862
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
10866
throw_error (context,
10868
"Error removing component: helper exited with exit code %d: %s",
10869
WEXITSTATUS (status),
10876
device_linux_md_remove_component_authorized_cb (Daemon *daemon,
10878
DBusGMethodInvocation *context,
10879
const gchar *action_id,
10880
guint num_user_data,
10881
gpointer *user_data_elements)
10883
char *component = user_data_elements[0];
10884
char **options = user_data_elements[1];
10889
slave = daemon_local_find_by_object_path (device->priv->daemon, component);
10892
throw_error (context, ERROR_FAILED, "Component doesn't exist");
10896
/* check that it really is a component of the md device */
10897
for (n = 0; n < (int) device->priv->linux_md_slaves->len; n++)
10899
if (strcmp (component, device->priv->linux_md_slaves->pdata[n]) == 0)
10902
if (n == (int) device->priv->linux_md_slaves->len)
10904
throw_error (context, ERROR_FAILED, "Component isn't part of the running array");
10909
argv[n++] = "udisks-helper-linux-md-remove-component";
10910
argv[n++] = device->priv->device_file;
10911
argv[n++] = slave->priv->device_file;
10912
for (m = 0; options[m] != NULL; m++)
10914
if (n >= (int) sizeof(argv) - 1)
10916
throw_error (context, ERROR_FAILED, "Too many options");
10919
/* the helper will validate each option */
10920
argv[n++] = (char *) options[m];
10924
if (!job_new (context,
10925
"LinuxMdRemoveComponent",
10930
linux_md_remove_component_completed_cb,
10932
remove_component_data_new (context, slave, options),
10933
(GDestroyNotify) remove_component_data_unref))
10943
device_linux_md_remove_component (Device *device,
10946
DBusGMethodInvocation *context)
10948
if (!device->priv->device_is_linux_md)
10950
throw_error (context, ERROR_FAILED, "Device is not a Linux md drive");
10954
daemon_local_check_auth (device->priv->daemon,
10956
"org.freedesktop.udisks.linux-md",
10957
"LinuxMdRemoveComponent",
10959
device_linux_md_remove_component_authorized_cb,
10962
g_strdup (component),
10964
g_strdupv (options),
10970
/*--------------------------------------------------------------------------------------------------------------*/
10976
guint device_added_signal_handler_id;
10977
guint device_added_timeout_id;
10979
DBusGMethodInvocation *context;
10984
} LinuxMdStartData;
10986
static LinuxMdStartData *
10987
linux_md_start_data_new (DBusGMethodInvocation *context,
10991
LinuxMdStartData *data;
10993
data = g_new0 (LinuxMdStartData, 1);
10994
data->refcount = 1;
10996
data->context = context;
10997
data->daemon = g_object_ref (daemon);
10998
data->uuid = g_strdup (uuid);
11002
static LinuxMdStartData *
11003
linux_md_start_data_ref (LinuxMdStartData *data)
11010
linux_md_start_data_unref (LinuxMdStartData *data)
11013
if (data->refcount == 0)
11015
g_object_unref (data->daemon);
11016
g_free (data->uuid);
11022
linux_md_start_device_added_cb (Daemon *daemon,
11023
const char *object_path,
11024
gpointer user_data)
11026
LinuxMdStartData *data = user_data;
11029
/* check the device is the one we're looking for */
11030
device = daemon_local_find_by_object_path (daemon, object_path);
11032
if (device != NULL && device->priv->device_is_linux_md)
11035
/* TODO: actually check this properly by looking at slaves vs. components */
11037
/* yay! it is.. return value to the user */
11038
dbus_g_method_return (data->context, object_path);
11040
g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
11041
g_source_remove (data->device_added_timeout_id);
11042
linux_md_start_data_unref (data);
11047
linux_md_start_device_not_seen_cb (gpointer user_data)
11049
LinuxMdStartData *data = user_data;
11051
throw_error (data->context, ERROR_FAILED, "Error assembling array: timeout (10s) waiting for array to show up");
11053
g_signal_handler_disconnect (data->daemon, data->device_added_signal_handler_id);
11054
linux_md_start_data_unref (data);
11058
/* NOTE: This is job completion callback from a method on the daemon, not the device. */
11061
linux_md_start_completed_cb (DBusGMethodInvocation *context,
11063
gboolean job_was_cancelled,
11065
const char *stderr,
11066
const char *stdout,
11067
gpointer user_data)
11069
LinuxMdStartData *data = user_data;
11071
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
11077
/* see if the component appeared already */
11081
devices = daemon_local_get_all_devices (data->daemon);
11082
for (l = devices; l != NULL; l = l->next)
11084
Device *device = DEVICE (l->data);
11086
if (device->priv->device_is_linux_md)
11089
/* TODO: check properly */
11091
/* yup, return to caller */
11092
objpath = device->priv->object_path;
11097
g_list_free (devices);
11099
if (objpath != NULL)
11101
dbus_g_method_return (context, objpath);
11105
/* sit around and wait for the md array to appear */
11107
/* sit around wait for the cleartext device to appear */
11108
data->device_added_signal_handler_id = g_signal_connect_after (data->daemon,
11110
(GCallback) linux_md_start_device_added_cb,
11111
linux_md_start_data_ref (data));
11113
/* set up timeout for error reporting if waiting failed
11115
* (the signal handler and the timeout handler share the ref to data
11116
* as one will cancel the other)
11118
data->device_added_timeout_id = g_timeout_add (10 * 1000, linux_md_start_device_not_seen_cb, data);
11124
if (job_was_cancelled)
11126
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
11130
throw_error (context,
11132
"Error assembling array: mdadm exited with exit code %d: %s",
11133
WEXITSTATUS (status),
11139
/* NOTE: This is a method on the daemon, not the device. */
11141
daemon_linux_md_start_authorized_cb (Daemon *daemon,
11143
DBusGMethodInvocation *context,
11144
const gchar *action_id,
11145
guint num_user_data,
11146
gpointer *user_data_elements)
11148
gchar **components_as_strv = user_data_elements[0];
11149
/* TODO: use options */
11150
//gchar **options = user_data_elements[1];
11156
char *md_device_file;
11159
md_device_file = NULL;
11162
/* check that all given components exist, that they are indeed linux-md-components and
11163
* that their uuid agrees
11165
for (n = 0; components_as_strv[n] != NULL; n++)
11168
const char *component_objpath = components_as_strv[n];
11170
slave = daemon_local_find_by_object_path (daemon, component_objpath);
11173
throw_error (context, ERROR_FAILED, "Component %s doesn't exist", component_objpath);
11177
if (!slave->priv->device_is_linux_md_component)
11179
throw_error (context, ERROR_FAILED, "%s is not a linux-md component", component_objpath);
11185
uuid = g_strdup (slave->priv->linux_md_component_uuid);
11188
throw_error (context, ERROR_FAILED, "no uuid for one of the components");
11194
const char *this_uuid;
11195
this_uuid = slave->priv->linux_md_component_uuid;
11197
if (this_uuid == NULL || strcmp (uuid, this_uuid) != 0)
11199
throw_error (context, ERROR_FAILED, "uuid mismatch between given components");
11204
if (device_local_is_busy (slave, FALSE, TRUE, &error))
11206
dbus_g_method_return_error (context, error);
11207
g_error_free (error);
11212
/* find an unused md minor... Man, I wish mdadm could do this itself; this is slightly racy */
11213
for (n = 0; TRUE; n++)
11218
/* TODO: move to /sys/class/block instead */
11219
native_path = g_strdup_printf ("/sys/block/md%d", n);
11220
if (!sysfs_file_exists (native_path, "md/array_state"))
11222
/* Apparently this slot is free since there is no such file. So let's peruse it. */
11223
g_free (native_path);
11228
array_state = sysfs_get_string (native_path, "md/array_state");
11229
g_strstrip (array_state);
11230
if (strcmp (array_state, "clear") == 0)
11232
/* It's clear! Let's use it! */
11233
g_free (array_state);
11234
g_free (native_path);
11237
g_free (array_state);
11239
g_free (native_path);
11242
md_device_file = g_strdup_printf ("/dev/md%d", n);
11245
argv[n++] = "mdadm";
11246
argv[n++] = "--assemble";
11247
argv[n++] = md_device_file;
11248
argv[n++] = "--run";
11249
for (m = 0; components_as_strv[m] != NULL; m++)
11252
const char *component_objpath = components_as_strv[m];
11254
slave = daemon_local_find_by_object_path (daemon, component_objpath);
11257
throw_error (context, ERROR_FAILED, "Component %s doesn't exist", component_objpath);
11261
if (n >= (int) sizeof(argv) - 1)
11263
throw_error (context, ERROR_FAILED, "Too many components");
11267
argv[n++] = (char *) slave->priv->device_file;
11271
if (!job_new (context,
11277
linux_md_start_completed_cb,
11279
linux_md_start_data_new (context, daemon, uuid),
11280
(GDestroyNotify) linux_md_start_data_unref))
11287
g_free (md_device_file);
11290
/* NOTE: This is a method on the daemon, not the device. */
11292
daemon_linux_md_start (Daemon *daemon,
11293
GPtrArray *components,
11295
DBusGMethodInvocation *context)
11297
gchar **components_as_strv;
11300
components_as_strv = g_new0 (gchar *, components->len + 1);
11301
for (n = 0; n < components->len; n++)
11302
components_as_strv[n] = g_strdup (components->pdata[n]);
11304
daemon_local_check_auth (daemon,
11306
"org.freedesktop.udisks.linux-md",
11309
daemon_linux_md_start_authorized_cb,
11312
components_as_strv,
11314
g_strdupv (options),
11320
/*--------------------------------------------------------------------------------------------------------------*/
11326
guint device_added_signal_handler_id;
11327
guint device_added_timeout_id;
11329
DBusGMethodInvocation *context;
11332
char *first_component_objpath;
11334
} LinuxMdCreateData;
11336
static LinuxMdCreateData *
11337
linux_md_create_data_new (DBusGMethodInvocation *context,
11339
const char *first_component_objpath)
11341
LinuxMdCreateData *data;
11343
data = g_new0 (LinuxMdCreateData, 1);
11344
data->refcount = 1;
11346
data->context = context;
11347
data->daemon = g_object_ref (daemon);
11348
data->first_component_objpath = g_strdup (first_component_objpath);
11352
static LinuxMdCreateData *
11353
linux_md_create_data_ref (LinuxMdCreateData *data)
11360
linux_md_create_data_unref (LinuxMdCreateData *data)
11363
if (data->refcount == 0)
11365
g_object_unref (data->daemon);
11366
g_free (data->first_component_objpath);
11372
linux_md_create_device_added_cb (Daemon *daemon,
11373
const char *object_path,
11374
gpointer user_data)
11376
LinuxMdCreateData *data = user_data;
11379
/* check the device is the one we're looking for */
11380
device = daemon_local_find_by_object_path (daemon, object_path);
11382
if (device != NULL && device->priv->device_is_linux_md)
11385
/* TODO: actually check this properly by looking at slaves vs. components */
11387
/* yay! it is.. return value to the user */
11388
dbus_g_method_return (data->context, object_path);
11390
g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
11391
g_source_remove (data->device_added_timeout_id);
11392
linux_md_create_data_unref (data);
11397
linux_md_create_device_not_seen_cb (gpointer user_data)
11399
LinuxMdCreateData *data = user_data;
11401
throw_error (data->context, ERROR_FAILED, "Error assembling array: timeout (10s) waiting for array to show up");
11403
g_signal_handler_disconnect (data->daemon, data->device_added_signal_handler_id);
11404
linux_md_create_data_unref (data);
11408
/* NOTE: This is job completion callback from a method on the daemon, not the device. */
11411
linux_md_create_completed_cb (DBusGMethodInvocation *context,
11413
gboolean job_was_cancelled,
11415
const char *stderr,
11416
const char *stdout,
11417
gpointer user_data)
11419
LinuxMdCreateData *data = user_data;
11421
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
11427
/* see if the component appeared already */
11431
devices = daemon_local_get_all_devices (data->daemon);
11432
for (l = devices; l != NULL; l = l->next)
11434
Device *device = DEVICE (l->data);
11436
if (device->priv->device_is_linux_md)
11439
/* TODO: check properly */
11441
/* yup, return to caller */
11442
objpath = device->priv->object_path;
11447
g_list_free (devices);
11449
if (objpath != NULL)
11451
dbus_g_method_return (context, objpath);
11455
/* sit around and wait for the md array to appear */
11457
/* sit around wait for the cleartext device to appear */
11458
data->device_added_signal_handler_id = g_signal_connect_after (data->daemon,
11460
(GCallback) linux_md_create_device_added_cb,
11461
linux_md_create_data_ref (data));
11463
/* set up timeout for error reporting if waiting failed
11465
* (the signal handler and the timeout handler share the ref to data
11466
* as one will cancel the other)
11468
data->device_added_timeout_id = g_timeout_add (10 * 1000, linux_md_create_device_not_seen_cb, data);
11474
if (job_was_cancelled)
11476
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
11480
throw_error (context,
11482
"Error assembling array: mdadm exited with exit code %d: %s",
11483
WEXITSTATUS (status),
11489
/* NOTE: This is a method on the daemon, not the device. */
11491
daemon_linux_md_create_authorized_cb (Daemon *daemon,
11493
DBusGMethodInvocation *context,
11494
const gchar *action_id,
11495
guint num_user_data,
11496
gpointer *user_data_elements)
11498
gchar **components_as_strv = user_data_elements[0];
11499
gchar *level = user_data_elements[1];
11500
guint64 stripe_size = *((guint64*) user_data_elements[2]);
11501
gchar *name = user_data_elements[3];
11502
/* TODO: use options */
11503
//gchar **options = user_data_elements[4];
11508
gchar *md_device_file;
11509
gchar *num_raid_devices_as_str;
11510
gchar *stripe_size_as_str;
11511
gboolean use_bitmap;
11512
gboolean use_chunk;
11514
md_device_file = NULL;
11515
num_raid_devices_as_str = NULL;
11516
stripe_size_as_str = NULL;
11519
/* sanity-check level */
11520
use_bitmap = FALSE;
11522
if (g_strcmp0 (level, "raid0") == 0)
11526
else if (g_strcmp0 (level, "raid1") == 0)
11528
if (stripe_size > 0)
11530
throw_error (context, ERROR_FAILED, "Stripe size doesn't make sense for RAID-1");
11534
else if (g_strcmp0 (level, "raid4") == 0 || g_strcmp0 (level, "raid5") == 0 || g_strcmp0 (level, "raid6") == 0
11535
|| g_strcmp0 (level, "raid10") == 0)
11542
throw_error (context, ERROR_FAILED, "Invalid level `%s'", level);
11546
/* check that all given components exist and that they are not busy
11548
for (n = 0; components_as_strv[n] != NULL; n++)
11551
const char *component_objpath = components_as_strv[n];
11553
slave = daemon_local_find_by_object_path (daemon, component_objpath);
11556
throw_error (context, ERROR_FAILED, "Component %s doesn't exist", component_objpath);
11560
if (device_local_is_busy (slave, FALSE, TRUE, &error))
11562
dbus_g_method_return_error (context, error);
11563
g_error_free (error);
11568
/* find an unused md minor... Man, I wish mdadm could do this itself; this is slightly racy */
11569
for (n = 0; TRUE; n++)
11574
/* TODO: move to /sys/class/block instead */
11575
native_path = g_strdup_printf ("/sys/block/md%d", n);
11576
if (!sysfs_file_exists (native_path, "md/array_state"))
11578
/* Apparently this slot is free since there is no such file. So let's peruse it. */
11579
g_free (native_path);
11584
array_state = sysfs_get_string (native_path, "md/array_state");
11585
g_strstrip (array_state);
11586
if (strcmp (array_state, "clear") == 0)
11588
/* It's clear! Let's use it! */
11589
g_free (array_state);
11590
g_free (native_path);
11593
g_free (array_state);
11595
g_free (native_path);
11598
md_device_file = g_strdup_printf ("/dev/md%d", n);
11600
num_raid_devices_as_str = g_strdup_printf ("%d", g_strv_length (components_as_strv));
11602
if (stripe_size > 0)
11603
stripe_size_as_str = g_strdup_printf ("%d", ((gint) stripe_size) / 1024);
11606
argv[n++] = "mdadm";
11607
argv[n++] = "--create";
11608
argv[n++] = md_device_file;
11609
argv[n++] = "--level";
11611
argv[n++] = "--raid-devices";
11612
argv[n++] = num_raid_devices_as_str;
11613
argv[n++] = "--metadata";
11615
argv[n++] = "--name";
11617
argv[n++] = "--homehost";
11621
argv[n++] = "--bitmap";
11622
argv[n++] = "internal";
11624
if (use_chunk && stripe_size_as_str != NULL)
11626
argv[n++] = "--chunk";
11627
argv[n++] = stripe_size_as_str;
11629
for (m = 0; components_as_strv[m] != NULL; m++)
11632
const char *component_objpath = components_as_strv[m];
11634
slave = daemon_local_find_by_object_path (daemon, component_objpath);
11637
throw_error (context, ERROR_FAILED, "Component %s doesn't exist", component_objpath);
11641
if (n >= (int) sizeof(argv) - 1)
11643
throw_error (context, ERROR_FAILED, "Too many components");
11647
argv[n++] = (char *) slave->priv->device_file;
11651
//for (m = 0; argv[m] != NULL; m++)
11652
// g_debug ("arg[%d] = `%s'", m, argv[m]);
11654
if (!job_new (context,
11660
linux_md_create_completed_cb,
11662
linux_md_create_data_new (context, daemon, components_as_strv[0]),
11663
(GDestroyNotify) linux_md_create_data_unref))
11669
g_free (md_device_file);
11670
g_free (num_raid_devices_as_str);
11671
g_free (stripe_size_as_str);
11674
/* NOTE: This is a method on the daemon, not the device. */
11676
daemon_linux_md_create (Daemon *daemon,
11677
GPtrArray *components,
11679
guint64 stripe_size,
11682
DBusGMethodInvocation *context)
11684
gchar **components_as_strv;
11687
components_as_strv = g_new0 (gchar *, components->len + 1);
11688
for (n = 0; n < components->len; n++)
11689
components_as_strv[n] = g_strdup (components->pdata[n]);
11691
daemon_local_check_auth (daemon,
11693
"org.freedesktop.udisks.linux-md",
11696
daemon_linux_md_create_authorized_cb,
11699
components_as_strv,
11703
g_memdup (&stripe_size, sizeof(guint64)),
11707
g_strdupv (options),
11713
/*--------------------------------------------------------------------------------------------------------------*/
11718
ForceRemovalCompleteFunc fr_callback;
11719
gpointer fr_user_data;
11720
} ForceUnmountData;
11722
static ForceUnmountData *
11723
force_unmount_data_new (const gchar *mount_path,
11724
ForceRemovalCompleteFunc fr_callback,
11725
gpointer fr_user_data)
11727
ForceUnmountData *data;
11729
data = g_new0 (ForceUnmountData, 1);
11730
data->mount_path = g_strdup (mount_path);
11731
data->fr_callback = fr_callback;
11732
data->fr_user_data = fr_user_data;
11738
force_unmount_data_unref (ForceUnmountData *data)
11740
g_free (data->mount_path);
11745
force_unmount_completed_cb (DBusGMethodInvocation *context,
11747
gboolean job_was_cancelled,
11749
const char *stderr,
11750
const char *stdout,
11751
gpointer user_data)
11753
ForceUnmountData *data = user_data;
11755
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
11758
g_print ("**** NOTE: Successfully force unmounted device %s\n", device->priv->device_file);
11759
/* update_info_mount_state() will update the mounts file and clean up the directory if needed */
11760
update_info (device);
11762
if (data->fr_callback != NULL)
11763
data->fr_callback (device, TRUE, data->fr_user_data);
11767
g_print ("**** NOTE: force unmount failed: %s\n", stderr);
11768
if (data->fr_callback != NULL)
11769
data->fr_callback (device, FALSE, data->fr_user_data);
11774
force_unmount (Device *device,
11775
ForceRemovalCompleteFunc callback,
11776
gpointer user_data)
11780
const gchar *mount_path;
11782
mount_path = ((gchar **) device->priv->device_mount_paths->pdata)[0];
11785
argv[n++] = "umount";
11786
/* on Linux, we only have lazy unmount for now */
11788
argv[n++] = (gchar *) mount_path;
11791
if (!job_new (NULL,
11797
force_unmount_completed_cb,
11799
force_unmount_data_new (mount_path, callback, user_data),
11800
(GDestroyNotify) force_unmount_data_unref))
11802
g_warning ("Couldn't spawn unmount for force unmounting %s", mount_path);
11803
if (callback != NULL)
11804
callback (device, FALSE, user_data);
11808
/*--------------------------------------------------------------------------------------------------------------*/
11814
ForceRemovalCompleteFunc fr_callback;
11815
gpointer fr_user_data;
11816
} ForceLuksTeardownData;
11819
force_luks_teardown_completed_cb (DBusGMethodInvocation *context,
11821
gboolean job_was_cancelled,
11823
const char *stderr,
11824
const char *stdout,
11825
gpointer user_data)
11827
ForceLuksTeardownData *data = user_data;
11829
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
11832
g_print ("**** NOTE: Successfully teared down luks device %s\n", device->priv->device_file);
11834
if (data->fr_callback != NULL)
11835
data->fr_callback (device, TRUE, data->fr_user_data);
11839
g_print ("**** NOTE: force luks teardown failed: %s\n", stderr);
11840
if (data->fr_callback != NULL)
11841
data->fr_callback (device, FALSE, data->fr_user_data);
11845
static ForceLuksTeardownData *
11846
force_luks_teardown_data_new (Device *device,
11847
const char *dm_name,
11848
ForceRemovalCompleteFunc fr_callback,
11849
gpointer fr_user_data)
11851
ForceLuksTeardownData *data;
11853
data = g_new0 (ForceLuksTeardownData, 1);
11854
data->device = g_object_ref (device);
11855
data->dm_name = g_strdup (dm_name);
11856
data->fr_callback = fr_callback;
11857
data->fr_user_data = fr_user_data;
11862
force_luks_teardown_data_unref (ForceLuksTeardownData *data)
11864
if (data->device != NULL)
11865
g_object_unref (data->device);
11866
g_free (data->dm_name);
11871
force_luks_teardown_cleartext_done (Device *device,
11873
gpointer user_data)
11877
ForceLuksTeardownData *data = user_data;
11881
if (data->fr_callback != NULL)
11882
data->fr_callback (data->device, FALSE, data->fr_user_data);
11884
force_luks_teardown_data_unref (data);
11888
/* ok, clear text device is out of the way; now tear it down */
11891
argv[n++] = "cryptsetup";
11892
argv[n++] = "luksClose";
11893
argv[n++] = data->dm_name;
11896
//g_debug ("doing cryptsetup luksClose %s", data->dm_name);
11898
if (!job_new (NULL,
11899
"ForceLuksTeardown",
11904
force_luks_teardown_completed_cb,
11907
(GDestroyNotify) force_luks_teardown_data_unref))
11910
g_warning ("Couldn't spawn cryptsetup for force teardown for device %s", data->dm_name);
11911
if (data->fr_callback != NULL)
11912
data->fr_callback (data->device, FALSE, data->fr_user_data);
11914
force_luks_teardown_data_unref (data);
11921
force_luks_teardown (Device *device,
11922
Device *cleartext_device,
11923
ForceRemovalCompleteFunc callback,
11924
gpointer user_data)
11926
/* first we gotta force remove the clear text device */
11927
force_removal (cleartext_device,
11928
force_luks_teardown_cleartext_done,
11929
force_luks_teardown_data_new (device, cleartext_device->priv->dm_name, callback, user_data));
11932
/*--------------------------------------------------------------------------------------------------------------*/
11935
force_removal (Device *device,
11936
ForceRemovalCompleteFunc callback,
11937
gpointer user_data)
11939
//g_debug ("in force removal for %s", device->priv->device_file);
11941
/* Device is going bye bye. If this device is
11943
* - Mounted by us, then forcibly unmount it.
11945
* - If it's a luks device, check if there's cleartext
11946
* companion. If so, tear it down if it was setup by us.
11949
if (device->priv->device_is_mounted && device->priv->device_mount_paths->len > 0)
11951
gboolean remove_dir_on_unmount;
11953
if (mount_file_has_device (device->priv->device_file, NULL, &remove_dir_on_unmount) ||
11954
is_device_in_fstab (device, NULL))
11956
g_print ("**** NOTE: Force unmounting device %s\n", device->priv->device_file);
11957
force_unmount (device, callback, user_data);
11962
if (device->priv->id_usage != NULL && device->priv->luks_holder != NULL && strcmp (device->priv->id_usage, "crypto") == 0)
11966
/* look for cleartext device */
11967
d = daemon_local_find_by_object_path (device->priv->daemon, device->priv->luks_holder);
11968
if (strcmp (d->priv->object_path, device->priv->luks_holder) == 0)
11970
/* Check whether it is set up by us */
11971
if (d->priv->dm_name != NULL && g_str_has_prefix (d->priv->dm_name, "udisks-luks-uuid-"))
11974
g_print ("**** NOTE: Force luks teardown device %s (cleartext %s)\n",
11975
device->priv->device_file,
11976
d->priv->device_file);
11979
force_luks_teardown (device, d, callback, user_data);
11985
/* nothing to force remove */
11986
if (callback != NULL)
11987
callback (device, TRUE, user_data);
11993
/*--------------------------------------------------------------------------------------------------------------*/
11996
polling_inhibitor_disconnected_cb (Inhibitor *inhibitor,
11999
device->priv->polling_inhibitors = g_list_remove (device->priv->polling_inhibitors, inhibitor);
12000
g_signal_handlers_disconnect_by_func (inhibitor, polling_inhibitor_disconnected_cb, device);
12001
g_object_unref (inhibitor);
12003
update_info (device);
12004
drain_pending_changes (device, FALSE);
12005
daemon_local_update_poller (device->priv->daemon);
12009
device_drive_inhibit_polling_authorized_cb (Daemon *daemon,
12011
DBusGMethodInvocation *context,
12012
const gchar *action_id,
12013
guint num_user_data,
12014
gpointer *user_data_elements)
12016
gchar **options = user_data_elements[0];
12017
Inhibitor *inhibitor;
12020
for (n = 0; options[n] != NULL; n++)
12022
const char *option = options[n];
12023
throw_error (context, ERROR_INVALID_OPTION, "Unknown option %s", option);
12027
inhibitor = inhibitor_new (context);
12029
device->priv->polling_inhibitors = g_list_prepend (device->priv->polling_inhibitors, inhibitor);
12030
g_signal_connect (inhibitor, "disconnected", G_CALLBACK (polling_inhibitor_disconnected_cb), device);
12032
update_info (device);
12033
drain_pending_changes (device, FALSE);
12034
daemon_local_update_poller (device->priv->daemon);
12036
dbus_g_method_return (context, inhibitor_get_cookie (inhibitor));
12043
device_drive_inhibit_polling (Device *device,
12045
DBusGMethodInvocation *context)
12047
if (!device->priv->device_is_drive)
12049
throw_error (context, ERROR_FAILED, "Device is not a drive");
12053
if (!device->priv->device_is_media_change_detection_inhibitable)
12055
throw_error (context, ERROR_FAILED, "Media detection cannot be inhibited");
12059
daemon_local_check_auth (device->priv->daemon,
12061
"org.freedesktop.udisks.inhibit-polling",
12062
"DriveInhibitPolling",
12064
device_drive_inhibit_polling_authorized_cb,
12067
g_strdupv (options),
12074
/*--------------------------------------------------------------------------------------------------------------*/
12077
device_drive_uninhibit_polling (Device *device,
12079
DBusGMethodInvocation *context)
12081
const gchar *sender;
12082
Inhibitor *inhibitor;
12085
sender = dbus_g_method_get_sender (context);
12088
for (l = device->priv->polling_inhibitors; l != NULL; l = l->next)
12090
Inhibitor *i = INHIBITOR (l->data);
12092
if (g_strcmp0 (inhibitor_get_unique_dbus_name (i), sender) == 0 && g_strcmp0 (inhibitor_get_cookie (i), cookie)
12100
if (inhibitor == NULL)
12102
throw_error (context, ERROR_FAILED, "No such inhibitor");
12106
device->priv->polling_inhibitors = g_list_remove (device->priv->polling_inhibitors, inhibitor);
12107
g_object_unref (inhibitor);
12109
update_info (device);
12110
drain_pending_changes (device, FALSE);
12111
daemon_local_update_poller (device->priv->daemon);
12113
dbus_g_method_return (context);
12119
/*--------------------------------------------------------------------------------------------------------------*/
12122
drive_poll_media_completed_cb (DBusGMethodInvocation *context,
12124
gboolean job_was_cancelled,
12126
const char *stderr,
12127
const char *stdout,
12128
gpointer user_data)
12130
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
12133
device_generate_kernel_change_event (device);
12135
dbus_g_method_return (context);
12139
if (job_was_cancelled)
12141
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
12145
throw_error (context,
12147
"Error detaching: helper exited with exit code %d: %s",
12148
WEXITSTATUS (status),
12155
device_drive_poll_media_authorized_cb (Daemon *daemon,
12157
DBusGMethodInvocation *context,
12158
const gchar *action_id,
12159
guint num_user_data,
12160
gpointer *user_data_elements)
12166
argv[n++] = "udisks-helper-drive-poll";
12167
argv[n++] = device->priv->device_file;
12170
if (!job_new (context, "DrivePollMedia", FALSE, device, argv, NULL, drive_poll_media_completed_cb, FALSE, NULL, NULL))
12180
device_drive_poll_media (Device *device,
12181
DBusGMethodInvocation *context)
12183
if (!device->priv->device_is_drive)
12185
throw_error (context, ERROR_FAILED, "Device is not a drive");
12189
daemon_local_check_auth (device->priv->daemon,
12191
"org.freedesktop.udisks.inhibit-polling",
12194
device_drive_poll_media_authorized_cb,
12201
/*--------------------------------------------------------------------------------------------------------------*/
12204
spindown_inhibitor_disconnected_cb (Inhibitor *inhibitor,
12207
device->priv->spindown_inhibitors = g_list_remove (device->priv->spindown_inhibitors, inhibitor);
12208
g_signal_handlers_disconnect_by_func (inhibitor, spindown_inhibitor_disconnected_cb, device);
12209
g_object_unref (inhibitor);
12211
update_info (device);
12212
drain_pending_changes (device, FALSE);
12213
daemon_local_update_spindown (device->priv->daemon);
12217
device_drive_set_spindown_timeout_authorized_cb (Daemon *daemon,
12219
DBusGMethodInvocation *context,
12220
const gchar *action_id,
12221
guint num_user_data,
12222
gpointer *user_data_elements)
12224
gint timeout_seconds = GPOINTER_TO_INT (user_data_elements[0]);
12225
gchar **options = user_data_elements[1];
12226
Inhibitor *inhibitor;
12229
if (!device->priv->device_is_drive)
12231
throw_error (context, ERROR_FAILED, "Device is not a drive");
12235
if (!device->priv->drive_can_spindown)
12237
throw_error (context, ERROR_FAILED, "Cannot spindown device");
12241
if (timeout_seconds < 1)
12243
throw_error (context, ERROR_FAILED, "Timeout seconds must be at least 1");
12247
for (n = 0; options[n] != NULL; n++)
12249
const char *option = options[n];
12250
throw_error (context, ERROR_INVALID_OPTION, "Unknown option %s", option);
12254
inhibitor = inhibitor_new (context);
12256
g_object_set_data (G_OBJECT (inhibitor), "spindown-timeout-seconds", GINT_TO_POINTER (timeout_seconds));
12258
device->priv->spindown_inhibitors = g_list_prepend (device->priv->spindown_inhibitors, inhibitor);
12259
g_signal_connect (inhibitor, "disconnected", G_CALLBACK (spindown_inhibitor_disconnected_cb), device);
12261
update_info (device);
12262
drain_pending_changes (device, FALSE);
12263
daemon_local_update_spindown (device->priv->daemon);
12265
dbus_g_method_return (context, inhibitor_get_cookie (inhibitor));
12272
device_drive_set_spindown_timeout (Device *device,
12273
int timeout_seconds,
12275
DBusGMethodInvocation *context)
12277
if (!device->priv->device_is_drive)
12279
throw_error (context, ERROR_FAILED, "Device is not a drive");
12283
if (!device->priv->drive_can_spindown)
12285
throw_error (context, ERROR_FAILED, "Cannot spindown device");
12289
if (timeout_seconds < 1)
12291
throw_error (context, ERROR_FAILED, "Timeout seconds must be at least 1");
12295
daemon_local_check_auth (device->priv->daemon,
12297
"org.freedesktop.udisks.drive-set-spindown",
12298
"DriveSetSpindownTimeout",
12300
device_drive_set_spindown_timeout_authorized_cb,
12303
GINT_TO_POINTER (timeout_seconds),
12305
g_strdupv (options),
12312
/*--------------------------------------------------------------------------------------------------------------*/
12315
device_drive_unset_spindown_timeout (Device *device,
12317
DBusGMethodInvocation *context)
12319
const gchar *sender;
12320
Inhibitor *inhibitor;
12323
sender = dbus_g_method_get_sender (context);
12326
for (l = device->priv->spindown_inhibitors; l != NULL; l = l->next)
12328
Inhibitor *i = INHIBITOR (l->data);
12330
if (g_strcmp0 (inhibitor_get_unique_dbus_name (i), sender) == 0 && g_strcmp0 (inhibitor_get_cookie (i), cookie)
12338
if (inhibitor == NULL)
12340
throw_error (context, ERROR_FAILED, "No such spindown configurator");
12344
device->priv->spindown_inhibitors = g_list_remove (device->priv->spindown_inhibitors, inhibitor);
12345
g_object_unref (inhibitor);
12347
update_info (device);
12348
drain_pending_changes (device, FALSE);
12349
daemon_local_update_spindown (device->priv->daemon);
12351
dbus_g_method_return (context);
12357
/*--------------------------------------------------------------------------------------------------------------*/
12360
drive_benchmark_completed_cb (DBusGMethodInvocation *context,
12362
gboolean job_was_cancelled,
12364
const gchar *stderr,
12365
const gchar *stdout,
12366
gpointer user_data)
12368
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
12370
GPtrArray *read_transfer_rate_array;
12371
GPtrArray *write_transfer_rate_array;
12372
GPtrArray *access_time_array;
12377
elem_gtype = dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT64, G_TYPE_DOUBLE, G_TYPE_INVALID);
12379
read_transfer_rate_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free);
12380
write_transfer_rate_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free);
12381
access_time_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free);
12383
lines = g_strsplit (stdout, "\n", 0);
12384
for (n = 0; lines != NULL && lines[n] != NULL; n++)
12386
const gchar *line = lines[n];
12389
gdouble access_time;
12393
if (sscanf (line, "read_transfer_rate: offset %" G_GUINT64_FORMAT " rate %lf",
12398
g_value_init (&elem, elem_gtype);
12399
g_value_take_boxed (&elem, dbus_g_type_specialized_construct (elem_gtype));
12400
dbus_g_type_struct_set (&elem, 0, offset, 1, rate, G_MAXUINT);
12401
g_ptr_array_add (read_transfer_rate_array, g_value_get_boxed (&elem));
12404
else if (sscanf (line, "write_transfer_rate: offset %" G_GUINT64_FORMAT " rate %lf",
12409
g_value_init (&elem, elem_gtype);
12410
g_value_take_boxed (&elem, dbus_g_type_specialized_construct (elem_gtype));
12411
dbus_g_type_struct_set (&elem, 0, offset, 1, rate, G_MAXUINT);
12412
g_ptr_array_add (write_transfer_rate_array, g_value_get_boxed (&elem));
12415
else if (sscanf (line, "access_time: offset %" G_GUINT64_FORMAT " time %lf",
12417
&access_time) == 2)
12420
g_value_init (&elem, elem_gtype);
12421
g_value_take_boxed (&elem, dbus_g_type_specialized_construct (elem_gtype));
12422
dbus_g_type_struct_set (&elem, 0, offset, 1, access_time, G_MAXUINT);
12423
g_ptr_array_add (access_time_array, g_value_get_boxed (&elem));
12428
g_warning ("unhandled line %d: `%s'", n, line);
12432
g_strfreev (lines);
12434
dbus_g_method_return (context, read_transfer_rate_array, write_transfer_rate_array, access_time_array);
12436
g_ptr_array_unref (read_transfer_rate_array);
12437
g_ptr_array_unref (write_transfer_rate_array);
12438
g_ptr_array_unref (access_time_array);
12442
if (job_was_cancelled)
12444
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
12448
throw_error (context,
12450
"Error benchmarking: helper exited with exit code %d: %s",
12451
WEXITSTATUS (status),
12458
device_drive_benchmark_authorized_cb (Daemon *daemon,
12460
DBusGMethodInvocation *context,
12461
const gchar *action_id,
12462
guint num_user_data,
12463
gpointer *user_data_elements)
12465
gboolean do_write_benchmark = GPOINTER_TO_INT (user_data_elements[0]);
12466
gchar **options = user_data_elements[1];
12470
if (!device->priv->device_is_drive)
12472
throw_error (context, ERROR_FAILED, "Device is not a drive");
12476
if (do_write_benchmark)
12478
if (device->priv->device_is_partition_table)
12480
throw_error (context, ERROR_FAILED, "A partition table was detected - write benchmarking requires "
12481
"the disk to be completely empty");
12485
if (device->priv->id_usage != NULL)
12487
throw_error (context, ERROR_FAILED, "The disk seems to have usage `%s' - write benchmarking requires "
12488
"the disk to be completely empty", device->priv->id_usage);
12493
for (n = 0; options[n] != NULL; n++)
12495
const char *option = options[n];
12496
throw_error (context, ERROR_INVALID_OPTION, "Unknown option %s", option);
12501
argv[n++] = "udisks-helper-drive-benchmark";
12502
argv[n++] = device->priv->device_file;
12503
argv[n++] = do_write_benchmark ? "1" : "0";
12506
if (!job_new (context, "DriveBenchmark", TRUE, device, argv, NULL, drive_benchmark_completed_cb, FALSE, NULL, NULL))
12516
device_drive_benchmark (Device *device,
12517
gboolean do_write_benchmark,
12519
DBusGMethodInvocation *context)
12521
if (!device->priv->device_is_drive)
12523
throw_error (context, ERROR_FAILED, "Device is not a drive");
12527
daemon_local_check_auth (device->priv->daemon,
12529
"org.freedesktop.udisks.change",
12532
device_drive_benchmark_authorized_cb,
12535
GINT_TO_POINTER (do_write_benchmark),
12537
g_strdupv (options),
12544
/*--------------------------------------------------------------------------------------------------------------*/
12546
static const gchar *
12547
find_lvm2_vg_name_for_uuid (Daemon *daemon,
12552
const gchar *vg_name;
12556
devices = daemon_local_get_all_devices (daemon);
12557
for (l = devices; l != NULL; l = l->next)
12559
Device *d = DEVICE (l->data);
12561
if (d->priv->device_is_linux_lvm2_pv && g_strcmp0 (uuid, d->priv->linux_lvm2_pv_group_uuid) == 0)
12563
vg_name = d->priv->linux_lvm2_pv_group_name;
12567
g_list_free (devices);
12572
/*--------------------------------------------------------------------------------------------------------------*/
12575
linux_lvm2_vg_stop_completed_cb (DBusGMethodInvocation *context,
12577
gboolean job_was_cancelled,
12579
const char *stderr,
12580
const char *stdout,
12581
gpointer user_data)
12583
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
12585
dbus_g_method_return (context);
12589
if (job_was_cancelled)
12591
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
12595
throw_error (context,
12597
"Error stopping LVM2 Volume Group: vgchange exited with exit code %d: %s",
12598
WEXITSTATUS (status),
12605
daemon_linux_lvm2_vg_stop_authorized_cb (Daemon *daemon,
12607
DBusGMethodInvocation *context,
12608
const gchar *action_id,
12609
guint num_user_data,
12610
gpointer *user_data_elements)
12612
const gchar *uuid = user_data_elements[0];
12613
const gchar *vg_name;
12614
/* TODO: use options */
12615
//gchar **options = user_data_elements[1];
12619
/* Unfortunately vgchange does not (yet - file a bug) accept UUIDs - so find the VG name for this
12620
* UUID by looking at PVs
12622
vg_name = find_lvm2_vg_name_for_uuid (daemon, uuid);
12623
if (vg_name == NULL)
12625
throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", uuid);
12630
argv[n++] = "vgchange";
12632
argv[n++] = (gchar *) vg_name;
12635
if (!job_new (context, "LinuxLvm2VGStop", TRUE, NULL, argv, NULL, linux_lvm2_vg_stop_completed_cb, FALSE, NULL, NULL))
12645
daemon_linux_lvm2_vg_stop (Daemon *daemon,
12648
DBusGMethodInvocation *context)
12650
daemon_local_check_auth (daemon,
12652
"org.freedesktop.udisks.linux-lvm2",
12655
daemon_linux_lvm2_vg_stop_authorized_cb,
12660
g_strdupv (options),
12666
/*--------------------------------------------------------------------------------------------------------------*/
12669
linux_lvm2_vg_start_completed_cb (DBusGMethodInvocation *context,
12671
gboolean job_was_cancelled,
12673
const char *stderr,
12674
const char *stdout,
12675
gpointer user_data)
12677
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
12679
dbus_g_method_return (context);
12683
if (job_was_cancelled)
12685
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
12689
throw_error (context,
12691
"Error starting LVM2 Volume Group: vgchange exited with exit code %d: %s",
12692
WEXITSTATUS (status),
12699
daemon_linux_lvm2_vg_start_authorized_cb (Daemon *daemon,
12701
DBusGMethodInvocation *context,
12702
const gchar *action_id,
12703
guint num_user_data,
12704
gpointer *user_data_elements)
12706
const gchar *uuid = user_data_elements[0];
12707
const gchar *vg_name;
12708
/* TODO: use options */
12709
//gchar **options = user_data_elements[1];
12713
/* Unfortunately vgchange does not (yet - file a bug) accept UUIDs - so find the VG name for this
12714
* UUID by looking at PVs
12717
vg_name = find_lvm2_vg_name_for_uuid (daemon, uuid);
12718
if (vg_name == NULL)
12720
throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", uuid);
12725
argv[n++] = "vgchange";
12727
argv[n++] = (gchar *) vg_name;
12730
if (!job_new (context, "LinuxLvm2VGStart", TRUE, NULL, argv, NULL, linux_lvm2_vg_start_completed_cb, FALSE, NULL, NULL))
12740
daemon_linux_lvm2_vg_start (Daemon *daemon,
12743
DBusGMethodInvocation *context)
12745
daemon_local_check_auth (daemon,
12747
"org.freedesktop.udisks.linux-lvm2",
12748
"LinuxLvm2VGStart",
12750
daemon_linux_lvm2_vg_start_authorized_cb,
12755
g_strdupv (options),
12761
/*--------------------------------------------------------------------------------------------------------------*/
12764
find_lvm2_lv_name_for_uuids (Daemon *daemon,
12765
const gchar *group_uuid,
12774
devices = daemon_local_get_all_devices (daemon);
12775
for (l = devices; l != NULL; l = l->next)
12777
Device *d = DEVICE (l->data);
12779
if (d->priv->device_is_linux_lvm2_pv &&
12780
g_strcmp0 (group_uuid, d->priv->linux_lvm2_pv_group_uuid) == 0)
12784
for (n = 0; n < d->priv->linux_lvm2_pv_group_logical_volumes->len; n++)
12786
const gchar *lv_data = d->priv->linux_lvm2_pv_group_logical_volumes->pdata[n];
12790
tokens = g_strsplit (lv_data, ";", 0);
12791
for (m = 0; tokens != NULL && tokens[m] != NULL; m++)
12793
if (g_str_has_prefix (tokens[m], "uuid=") && g_strcmp0 (tokens[m] + 5, uuid) == 0)
12796
for (c = 0; tokens[c] != NULL; c++)
12798
if (g_str_has_prefix (tokens[c], "name="))
12800
ret = g_strdup_printf ("%s/%s",
12801
d->priv->linux_lvm2_pv_group_name,
12808
g_strfreev (tokens);
12817
g_list_free (devices);
12823
/*--------------------------------------------------------------------------------------------------------------*/
12826
linux_lvm2_lv_start_completed_cb (DBusGMethodInvocation *context,
12828
gboolean job_was_cancelled,
12830
const char *stderr,
12831
const char *stdout,
12832
gpointer user_data)
12834
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
12836
dbus_g_method_return (context);
12840
if (job_was_cancelled)
12842
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
12846
throw_error (context,
12848
"Error starting LVM2 Logical Volume: lvchange exited with exit code %d: %s",
12849
WEXITSTATUS (status),
12856
daemon_linux_lvm2_lv_start_authorized_cb (Daemon *daemon,
12858
DBusGMethodInvocation *context,
12859
const gchar *action_id,
12860
guint num_user_data,
12861
gpointer *user_data_elements)
12863
const gchar *group_uuid = user_data_elements[0];
12864
const gchar *uuid = user_data_elements[1];
12866
/* TODO: use options */
12867
//gchar **options = user_data_elements[2];
12871
/* Unfortunately vgchange does not (yet - file a bug) accept UUIDs - so find the VG name for this
12872
* UUID by looking at PVs
12875
lv_name = find_lvm2_lv_name_for_uuids (daemon, group_uuid, uuid);
12876
if (lv_name == NULL)
12878
throw_error (context, ERROR_FAILED, "Cannot find Logical Volume with Group UUID `%s' and UUID `%s'", group_uuid, uuid);
12883
argv[n++] = "lvchange";
12885
argv[n++] = lv_name;
12888
if (!job_new (context, "LinuxLvm2LVStart", TRUE, NULL, argv, NULL, linux_lvm2_lv_start_completed_cb, FALSE, NULL, NULL))
12898
daemon_linux_lvm2_lv_start (Daemon *daemon,
12899
const gchar *group_uuid,
12902
DBusGMethodInvocation *context)
12904
daemon_local_check_auth (daemon,
12906
"org.freedesktop.udisks.linux-lvm2",
12907
"LinuxLvm2LVStart",
12909
daemon_linux_lvm2_lv_start_authorized_cb,
12912
g_strdup (group_uuid),
12916
g_strdupv (options),
12922
/*--------------------------------------------------------------------------------------------------------------*/
12925
linux_lvm2_lv_stop_completed_cb (DBusGMethodInvocation *context,
12927
gboolean job_was_cancelled,
12929
const char *stderr,
12930
const char *stdout,
12931
gpointer user_data)
12933
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
12935
dbus_g_method_return (context);
12939
if (job_was_cancelled)
12941
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
12945
throw_error (context,
12947
"Error stopping LVM2 Logical Volume: lvchange exited with exit code %d: %s",
12948
WEXITSTATUS (status),
12955
daemon_linux_lvm2_lv_stop_authorized_cb (Daemon *daemon,
12957
DBusGMethodInvocation *context,
12958
const gchar *action_id,
12959
guint num_user_data,
12960
gpointer *user_data_elements)
12963
/* TODO: use options */
12964
//gchar **options = user_data_elements[0];
12970
if (!device->priv->device_is_linux_lvm2_lv)
12972
throw_error (context, ERROR_FAILED, "Device is not a Linux LVM2 Logical Volume");
12976
/* Unfortunately lvchange does not (yet - file a bug) accept UUIDs
12978
name = g_strdup_printf ("%s/%s", device->priv->linux_lvm2_lv_group_name, device->priv->linux_lvm2_lv_name);
12981
argv[n++] = "lvchange";
12986
if (!job_new (context, "LinuxLvm2LVStop", TRUE, NULL, argv, NULL, linux_lvm2_lv_stop_completed_cb, FALSE, NULL, NULL))
12996
device_linux_lvm2_lv_stop (Device *device,
12998
DBusGMethodInvocation *context)
13000
daemon_local_check_auth (device->priv->daemon,
13002
"org.freedesktop.udisks.linux-lvm2",
13005
daemon_linux_lvm2_lv_stop_authorized_cb,
13008
g_strdupv (options),
13015
/*--------------------------------------------------------------------------------------------------------------*/
13018
linux_lvm2_vg_set_name_completed_cb (DBusGMethodInvocation *context,
13020
gboolean job_was_cancelled,
13022
const char *stderr,
13023
const char *stdout,
13024
gpointer user_data)
13026
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
13028
dbus_g_method_return (context);
13032
if (job_was_cancelled)
13034
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
13038
throw_error (context,
13040
"Error setting name for LVM2 Volume Group: vgrename exited with exit code %d: %s",
13041
WEXITSTATUS (status),
13048
daemon_linux_lvm2_vg_set_name_authorized_cb (Daemon *daemon,
13050
DBusGMethodInvocation *context,
13051
const gchar *action_id,
13052
guint num_user_data,
13053
gpointer *user_data_elements)
13055
const gchar *uuid = user_data_elements[0];
13056
const gchar *new_name = user_data_elements[1];
13057
const gchar *vg_name;
13061
/* Unfortunately vgchange does not (yet - file a bug) accept UUIDs - so find the VG name for this
13062
* UUID by looking at PVs
13065
vg_name = find_lvm2_vg_name_for_uuid (daemon, uuid);
13066
if (vg_name == NULL)
13068
throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", uuid);
13073
argv[n++] = "vgrename";
13074
argv[n++] = (gchar *) vg_name;
13075
argv[n++] = (gchar *) new_name;
13078
if (!job_new (context, "LinuxLvm2VGSetName", TRUE, NULL, argv, NULL, linux_lvm2_vg_set_name_completed_cb, FALSE, NULL, NULL))
13088
daemon_linux_lvm2_vg_set_name (Daemon *daemon,
13090
const gchar *new_name,
13091
DBusGMethodInvocation *context)
13093
daemon_local_check_auth (daemon,
13095
"org.freedesktop.udisks.linux-lvm2",
13096
"LinuxLvm2VGSetName",
13098
daemon_linux_lvm2_vg_set_name_authorized_cb,
13103
g_strdup (new_name),
13109
/*--------------------------------------------------------------------------------------------------------------*/
13112
linux_lvm2_lv_set_name_completed_cb (DBusGMethodInvocation *context,
13114
gboolean job_was_cancelled,
13116
const char *stderr,
13117
const char *stdout,
13118
gpointer user_data)
13120
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
13122
dbus_g_method_return (context);
13126
if (job_was_cancelled)
13128
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
13132
throw_error (context,
13134
"Error setting name for LVM2 Logical Volume: lvrename exited with exit code %d: %s",
13135
WEXITSTATUS (status),
13142
daemon_linux_lvm2_lv_set_name_authorized_cb (Daemon *daemon,
13144
DBusGMethodInvocation *context,
13145
const gchar *action_id,
13146
guint num_user_data,
13147
gpointer *user_data_elements)
13149
const gchar *group_uuid = user_data_elements[0];
13150
const gchar *uuid = user_data_elements[1];
13151
const gchar *new_name = user_data_elements[2];
13152
const gchar *vg_name;
13157
/* Unfortunately lvchange does not (yet - file a bug) accept UUIDs - so find the LV name for this
13158
* UUID by looking at PVs
13163
vg_name = find_lvm2_vg_name_for_uuid (daemon, group_uuid);
13164
if (vg_name == NULL)
13166
throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", group_uuid);
13170
lv_name = find_lvm2_lv_name_for_uuids (daemon, group_uuid, uuid);
13171
if (lv_name == NULL)
13173
throw_error (context, ERROR_FAILED, "Cannot find LV with UUID `%s'", uuid);
13178
argv[n++] = "lvrename";
13179
argv[n++] = (gchar *) vg_name;
13180
argv[n++] = lv_name;
13181
argv[n++] = (gchar *) new_name;
13184
if (!job_new (context, "LinuxLvm2LVSetName", TRUE, NULL, argv, NULL, linux_lvm2_lv_set_name_completed_cb, FALSE, NULL, NULL))
13194
daemon_linux_lvm2_lv_set_name (Daemon *daemon,
13195
const gchar *group_uuid,
13197
const gchar *new_name,
13198
DBusGMethodInvocation *context)
13200
daemon_local_check_auth (daemon,
13202
"org.freedesktop.udisks.linux-lvm2",
13203
"LinuxLvm2LVSetName",
13205
daemon_linux_lvm2_lv_set_name_authorized_cb,
13208
g_strdup (group_uuid),
13212
g_strdup (new_name),
13218
/*--------------------------------------------------------------------------------------------------------------*/
13221
linux_lvm2_lv_remove_completed_cb (DBusGMethodInvocation *context,
13223
gboolean job_was_cancelled,
13225
const char *stderr,
13226
const char *stdout,
13227
gpointer user_data)
13229
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
13231
dbus_g_method_return (context);
13235
if (job_was_cancelled)
13237
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
13241
throw_error (context,
13243
"Error removing LVM2 Logical Volume: lvremove exited with exit code %d: %s",
13244
WEXITSTATUS (status),
13251
daemon_linux_lvm2_lv_remove_authorized_cb (Daemon *daemon,
13253
DBusGMethodInvocation *context,
13254
const gchar *action_id,
13255
guint num_user_data,
13256
gpointer *user_data_elements)
13258
const gchar *group_uuid = user_data_elements[0];
13259
const gchar *uuid = user_data_elements[1];
13260
/* TODO: use options: gchar **options = user_data_elements[2]; */
13265
/* Unfortunately lvchange does not (yet - file a bug) accept UUIDs - so find the LV name for this
13266
* UUID by looking at PVs
13268
lv_name = find_lvm2_lv_name_for_uuids (daemon, group_uuid, uuid);
13269
if (lv_name == NULL)
13271
throw_error (context, ERROR_FAILED, "Cannot find LV with UUID `%s'", uuid);
13276
argv[n++] = "lvremove";
13277
argv[n++] = lv_name;
13278
argv[n++] = "--force";
13281
if (!job_new (context, "LinuxLvm2LVRemove", TRUE, NULL, argv, NULL, linux_lvm2_lv_remove_completed_cb, FALSE, NULL, NULL))
13291
daemon_linux_lvm2_lv_remove (Daemon *daemon,
13292
const gchar *group_uuid,
13295
DBusGMethodInvocation *context)
13297
daemon_local_check_auth (daemon,
13299
"org.freedesktop.udisks.linux-lvm2",
13300
"LinuxLvm2LVRemove",
13302
daemon_linux_lvm2_lv_remove_authorized_cb,
13305
g_strdup (group_uuid),
13309
g_strdupv (options),
13315
/*--------------------------------------------------------------------------------------------------------------*/
13321
guint device_added_signal_handler_id;
13322
guint device_changed_signal_handler_id;
13323
guint device_added_timeout_id;
13325
DBusGMethodInvocation *context;
13333
} CreateLvm2LVData;
13335
static CreateLvm2LVData *
13336
lvm2_lv_create_data_new (DBusGMethodInvocation *context,
13338
const gchar *vg_uuid,
13339
const gchar *lv_name,
13340
const char *fstype,
13343
CreateLvm2LVData *data;
13345
data = g_new0 (CreateLvm2LVData, 1);
13346
data->refcount = 1;
13348
data->context = context;
13349
data->daemon = g_object_ref (daemon);
13350
data->vg_uuid = g_strdup (vg_uuid);
13351
data->lv_name = g_strdup (lv_name);
13352
data->fstype = g_strdup (fstype);
13353
data->fsoptions = g_strdupv (fsoptions);
13358
static CreateLvm2LVData *
13359
lvm2_lv_create_data_ref (CreateLvm2LVData *data)
13366
lvm2_lv_create_data_unref (CreateLvm2LVData *data)
13369
if (data->refcount == 0)
13371
g_object_unref (data->daemon);
13372
g_free (data->vg_uuid);
13373
g_free (data->lv_name);
13374
g_free (data->fstype);
13375
g_strfreev (data->fsoptions);
13381
lvm2_lv_create_filesystem_create_hook (DBusGMethodInvocation *context,
13383
gboolean filesystem_create_succeeded,
13384
gpointer user_data)
13386
if (!filesystem_create_succeeded)
13388
/* dang.. FilesystemCreate already reported an error */
13393
dbus_g_method_return (context, device->priv->object_path);
13398
lvm2_lv_create_found_device (Device *device,
13399
CreateLvm2LVData *data)
13401
if (strlen (data->fstype) > 0)
13403
device_filesystem_create_internal (device,
13406
lvm2_lv_create_filesystem_create_hook,
13412
dbus_g_method_return (data->context, device->priv->object_path);
13417
str_has_lv_uuid (const gchar *str,
13418
const gchar *lv_uuid)
13423
tokens = g_strsplit (str, ";", 0);
13424
for (n = 0; tokens != NULL && tokens[n] != NULL; n++)
13426
if (g_str_has_prefix (tokens[n], "uuid=") && g_strcmp0 (tokens[n] + 5, lv_uuid) == 0)
13436
lvm2_lv_create_has_lv (CreateLvm2LVData *data)
13444
devices = daemon_local_get_all_devices (data->daemon);
13445
for (l = devices; l != NULL; l = l->next)
13447
Device *d = DEVICE (l->data);
13448
if (d->priv->device_is_linux_lvm2_lv &&
13449
g_strcmp0 (d->priv->linux_lvm2_lv_group_uuid, data->vg_uuid) == 0 &&
13450
g_strcmp0 (d->priv->linux_lvm2_lv_name, data->lv_name) == 0)
13453
const gchar *lv_uuid;
13455
lv_uuid = d->priv->linux_lvm2_lv_uuid;
13457
/* OK, we've found the LV... now check that one of more PVs actually reference this LV */
13458
for (m = devices; m != NULL; m = m->next)
13460
Device *pv = DEVICE (m->data);
13461
if (pv->priv->device_is_linux_lvm2_pv &&
13462
g_strcmp0 (pv->priv->linux_lvm2_pv_group_uuid, data->vg_uuid) == 0)
13465
for (n = 0; n < pv->priv->linux_lvm2_pv_group_logical_volumes->len; n++)
13467
const gchar *str = pv->priv->linux_lvm2_pv_group_logical_volumes->pdata[n];
13468
if (str_has_lv_uuid (str, lv_uuid))
13470
/* Return the LV, not the PV */
13476
} /* for all PVs */
13479
} /* if (found LV) */
13485
lvm2_lv_create_device_added_cb (Daemon *daemon,
13486
const char *object_path,
13487
gpointer user_data)
13489
CreateLvm2LVData *data = user_data;
13492
g_debug ("added %s", object_path);
13494
device = lvm2_lv_create_has_lv (data);
13495
if (device != NULL)
13497
/* yay! it is.. now create the file system if requested */
13498
lvm2_lv_create_found_device (device, data);
13500
g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
13501
g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
13502
g_source_remove (data->device_added_timeout_id);
13503
lvm2_lv_create_data_unref (data);
13508
lvm2_lv_create_device_changed_cb (Daemon *daemon,
13509
const char *object_path,
13510
gpointer user_data)
13512
CreateLvm2LVData *data = user_data;
13515
g_debug ("changed %s", object_path);
13517
device = lvm2_lv_create_has_lv (data);
13518
if (device != NULL)
13520
/* yay! it is.. now create the file system if requested */
13521
lvm2_lv_create_found_device (device, data);
13523
g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
13524
g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
13525
g_source_remove (data->device_added_timeout_id);
13526
lvm2_lv_create_data_unref (data);
13531
lvm2_lv_create_device_not_seen_cb (gpointer user_data)
13533
CreateLvm2LVData *data = user_data;
13535
throw_error (data->context,
13537
"Error creating Logical Volume: timeout (10s) waiting for LV to show up");
13539
g_signal_handler_disconnect (data->daemon, data->device_added_signal_handler_id);
13540
g_signal_handler_disconnect (data->daemon, data->device_changed_signal_handler_id);
13541
lvm2_lv_create_data_unref (data);
13547
linux_lvm2_lv_create_completed_cb (DBusGMethodInvocation *context,
13549
gboolean job_was_cancelled,
13551
const char *stderr,
13552
const char *stdout,
13553
gpointer user_data)
13555
CreateLvm2LVData *data = user_data;
13557
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
13561
d = lvm2_lv_create_has_lv (data);
13564
/* yay! it is.. now create the file system if requested */
13565
lvm2_lv_create_found_device (device, data);
13569
/* otherwise sit around and wait for the new LV to appear */
13570
data->device_added_signal_handler_id = g_signal_connect_after (data->daemon,
13572
G_CALLBACK (lvm2_lv_create_device_added_cb),
13574
data->device_changed_signal_handler_id = g_signal_connect_after (data->daemon,
13576
G_CALLBACK (lvm2_lv_create_device_changed_cb),
13578
data->device_added_timeout_id = g_timeout_add (10 * 1000,
13579
lvm2_lv_create_device_not_seen_cb,
13582
lvm2_lv_create_data_ref (data);
13587
if (job_was_cancelled)
13589
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
13593
throw_error (context,
13595
"Error creating LVM2 Logical Volume: lvcreate exited with exit code %d: %s",
13596
WEXITSTATUS (status),
13603
daemon_linux_lvm2_lv_create_authorized_cb (Daemon *daemon,
13605
DBusGMethodInvocation *context,
13606
const gchar *action_id,
13607
guint num_user_data,
13608
gpointer *user_data_elements)
13610
const gchar *group_uuid = user_data_elements[0];
13611
const gchar *name = user_data_elements[1];
13612
guint64 size = *((guint64 *) user_data_elements[2]);
13613
guint num_stripes = GPOINTER_TO_UINT (user_data_elements[3]);
13614
guint64 stripe_size = *((guint64 *) user_data_elements[4]);
13615
guint num_mirrors = GPOINTER_TO_UINT (user_data_elements[5]);
13616
/* TODO: use options: gchar **options = user_data_elements[6]; */
13617
const gchar *fstype = user_data_elements[7];
13618
gchar **fsoptions = user_data_elements[8];
13619
const gchar *vg_name;
13626
/* Unfortunately lvcreate does not (yet - file a bug) accept UUIDs - so find the VG name for this
13627
* UUID by looking at PVs
13629
vg_name = find_lvm2_vg_name_for_uuid (daemon, group_uuid);
13630
if (vg_name == NULL)
13632
throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", group_uuid);
13636
if (name == NULL || strlen (name) == 0)
13638
throw_error (context, ERROR_FAILED, "Name cannot be blank");
13642
if (strstr (name, "\"") != NULL)
13644
throw_error (context, ERROR_FAILED, "Name cannot contain the double-quote (\") character");
13648
s = g_string_new ("lvcreate ");
13650
g_string_append_printf (s, "%s ", vg_name);
13651
if (num_stripes > 0)
13652
g_string_append_printf (s, "--stripes %d ", num_stripes);
13653
if (stripe_size > 0)
13654
g_string_append_printf (s, "--stripesize %" G_GUINT64_FORMAT " ", stripe_size);
13655
if (num_mirrors > 0)
13656
g_string_append_printf (s, "--mirrors %d ", num_mirrors);
13659
g_string_append_printf (s, "--size %" G_GUINT64_FORMAT "b ", size);
13660
if (name != NULL && strlen (name) > 0)
13661
g_string_append_printf (s, "--name \"%s\"", name);
13663
if (!g_shell_parse_argv (s->str, NULL, &argv, NULL))
13665
throw_error (context, ERROR_FAILED, "Unable to parse command line `%s'", s->str);
13669
if (!job_new (context,
13670
"LinuxLvm2LVCreate",
13675
linux_lvm2_lv_create_completed_cb,
13677
lvm2_lv_create_data_new (context, daemon, group_uuid, name, fstype, fsoptions),
13678
(GDestroyNotify) lvm2_lv_create_data_unref))
13685
g_string_free (s, FALSE);
13690
daemon_linux_lvm2_lv_create (Daemon *daemon,
13691
const gchar *group_uuid,
13695
guint64 stripe_size,
13700
DBusGMethodInvocation *context)
13702
daemon_local_check_auth (daemon,
13704
"org.freedesktop.udisks.linux-lvm2",
13705
"LinuxLvm2LVCreate",
13707
daemon_linux_lvm2_lv_create_authorized_cb,
13710
g_strdup (group_uuid),
13714
g_memdup (&size, sizeof (guint64)),
13716
GUINT_TO_POINTER (num_stripes),
13718
g_memdup (&stripe_size, sizeof (guint64)),
13720
GUINT_TO_POINTER (num_mirrors),
13722
g_strdupv (options),
13726
g_strdupv (fsoptions),
13732
/*--------------------------------------------------------------------------------------------------------------*/
13735
linux_lvm2_vg_add_pv_completed_cb (DBusGMethodInvocation *context,
13737
gboolean job_was_cancelled,
13739
const char *stderr,
13740
const char *stdout,
13741
gpointer user_data)
13743
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
13745
dbus_g_method_return (context);
13749
if (job_was_cancelled)
13751
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
13755
throw_error (context,
13757
"Error adding PV for LVM2 Volume Group: vgextend exited with exit code %d: %s",
13758
WEXITSTATUS (status),
13765
daemon_linux_lvm2_vg_add_pv_authorized_cb (Daemon *daemon,
13767
DBusGMethodInvocation *context,
13768
const gchar *action_id,
13769
guint num_user_data,
13770
gpointer *user_data_elements)
13772
const gchar *uuid = user_data_elements[0];
13773
const gchar *physical_volume = user_data_elements[1];
13774
/* TODO: use options: gchar **options = user_data_elements[2]; */
13775
const gchar *vg_name;
13781
/* Unfortunately vgchange does not (yet - file a bug) accept UUIDs - so find the VG name for this
13782
* UUID by looking at PVs
13785
vg_name = find_lvm2_vg_name_for_uuid (daemon, uuid);
13786
if (vg_name == NULL)
13788
throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", uuid);
13792
pv = daemon_local_find_by_object_path (daemon, physical_volume);
13795
throw_error (context, ERROR_FAILED, "physical volume doesn't exist");
13800
if (device_local_is_busy (pv, TRUE, TRUE, &error))
13802
dbus_g_method_return_error (context, error);
13803
g_error_free (error);
13809
argv[n++] = "vgextend";
13810
argv[n++] = (gchar *) vg_name;
13811
argv[n++] = (gchar *) pv->priv->device_file;
13814
if (!job_new (context, "LinuxLvm2VGAddPV", TRUE, NULL, argv, NULL, linux_lvm2_vg_add_pv_completed_cb, FALSE, NULL, NULL))
13824
daemon_linux_lvm2_vg_add_pv (Daemon *daemon,
13826
const gchar *object_path,
13828
DBusGMethodInvocation *context)
13830
daemon_local_check_auth (daemon,
13832
"org.freedesktop.udisks.linux-lvm2",
13833
"LinuxLvm2VGAddPV",
13835
daemon_linux_lvm2_vg_add_pv_authorized_cb,
13840
g_strdup (object_path),
13842
g_strdupv (options),
13848
/*--------------------------------------------------------------------------------------------------------------*/
13851
linux_lvm2_vg_remove_pv_completed_cb (DBusGMethodInvocation *context,
13853
gboolean job_was_cancelled,
13855
const char *stderr,
13856
const char *stdout,
13857
gpointer user_data)
13859
if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
13861
dbus_g_method_return (context);
13865
if (job_was_cancelled)
13867
throw_error (context, ERROR_CANCELLED, "Job was cancelled");
13871
throw_error (context,
13873
"Error removing PV for LVM2 Volume Group: vgreduce exited with exit code %d: %s",
13874
WEXITSTATUS (status),
13881
daemon_linux_lvm2_vg_remove_pv_authorized_cb (Daemon *daemon,
13883
DBusGMethodInvocation *context,
13884
const gchar *action_id,
13885
guint num_user_data,
13886
gpointer *user_data_elements)
13888
const gchar *vg_uuid = user_data_elements[0];
13889
const gchar *pv_uuid = user_data_elements[1];
13890
/* TODO: use options: gchar **options = user_data_elements[2]; */
13891
const gchar *vg_name;
13899
/* Unfortunately vgchange does not (yet - file a bug) accept UUIDs - so find the VG name for this
13900
* UUID by looking at PVs
13904
vg_name = find_lvm2_vg_name_for_uuid (daemon, vg_uuid);
13905
if (vg_name == NULL)
13907
throw_error (context, ERROR_FAILED, "Cannot find VG with UUID `%s'", vg_uuid);
13911
devices = daemon_local_get_all_devices (daemon);
13912
for (l = devices; l != NULL; l = l->next)
13914
Device *d = DEVICE (l->data);
13916
if (d->priv->device_is_linux_lvm2_pv && g_strcmp0 (d->priv->linux_lvm2_pv_uuid, pv_uuid) == 0)
13925
throw_error (context, ERROR_FAILED, "Cannot find PV with UUID `%s'", pv_uuid);
13930
if (device_local_is_busy (pv, TRUE, TRUE, &error))
13932
dbus_g_method_return_error (context, error);
13933
g_error_free (error);
13938
argv[n++] = "vgreduce";
13939
argv[n++] = (gchar *) vg_name;
13940
argv[n++] = (gchar *) pv->priv->device_file;
13943
if (!job_new (context, "LinuxLvm2VGRemovePV", TRUE, NULL, argv, NULL, linux_lvm2_vg_remove_pv_completed_cb, FALSE, NULL, NULL))
13953
daemon_linux_lvm2_vg_remove_pv (Daemon *daemon,
13954
const gchar *vg_uuid,
13955
const gchar *pv_uuid,
13957
DBusGMethodInvocation *context)
13959
daemon_local_check_auth (daemon,
13961
"org.freedesktop.udisks.linux-lvm2",
13962
"LinuxLvm2VGRemovePV",
13964
daemon_linux_lvm2_vg_remove_pv_authorized_cb,
13967
g_strdup (vg_uuid),
13969
g_strdup (pv_uuid),
13971
g_strdupv (options),
13977
/*--------------------------------------------------------------------------------------------------------------*/