1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
3
* Copyright (C) 2011 David Zeuthen <zeuthen@gmail.com>
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
23
#include <glib/gi18n-lib.h>
25
#include <glib/gstdio.h>
29
#include <sys/ioctl.h>
30
#include <linux/loop.h>
32
#include "udisksdaemon.h"
33
#include "udisksstate.h"
34
#include "udisksmount.h"
35
#include "udisksmountmonitor.h"
36
#include "udiskslogging.h"
37
#include "udiskslinuxprovider.h"
38
#include "udisksdaemonutil.h"
43
* @short_description: Object used for recording state and cleaning up
45
* This type is used for recording actions done by users and cleaning
46
* up when devices set up via the udisks interfaces are removed while
47
* still in use - for example, a USB stick being yanked.
49
* The following files are used:
51
* <title>Persistent information and state</title>
52
* <tgroup cols='2' align='left' colsep='1' rowsep='1'>
56
* <entry>Usage</entry>
61
* <entry><filename>/run/udisks2/mounted-fs</filename></entry>
63
* A serialized 'a{sa{sv}}' #GVariant mapping from the
64
* mount point (e.g. <filename>/media/EOS_DIGITAL</filename>) into a set of details.
65
* Known details include
66
* <literal>block-device</literal>
67
* (of type <link linkend="G-VARIANT-TYPE-UINT64:CAPS">'t'</link>) that is the #dev_t
68
* for the mounted device,
69
* <literal>mounted-by-uid</literal>
70
* (of type <link linkend="G-VARIANT-TYPE-UINT32:CAPS">'u'</link>) that is the #uid_t
71
* of the user who mounted the device, and
72
* <literal>fstab-mount</literal>
73
* (of type <link linkend="G-VARIANT-TYPE-BOOLEAN:CAPS">'b'</link>) that is %TRUE
74
* if the device was mounted via an entry in /etc/fstab.
78
* <entry><filename>/run/udisks2/unlocked-luks</filename></entry>
80
* A serialized 'a{ta{sv}}' #GVariant mapping from the
81
* #dev_t of the clear-text device (e.g. <filename>/dev/dm-0</filename>) into a set of details.
82
* Known details include
83
* <literal>crypto-device</literal>
84
* (of type <link linkend="G-VARIANT-TYPE-UINT64:CAPS">'t'</link>) that is the #dev_t
85
* for the crypto-text device,
86
* <literal>dm-uuid</literal>
87
* (of type <link linkend="G-VARIANT-TYPE-ARRAY:CAPS">'ay'</link>) that is the device mapper UUID
88
* for the clear-text device and
89
* <literal>unlocked-by-uid</literal>
90
* (of type <link linkend="G-VARIANT-TYPE-UINT32:CAPS">'u'</link>) that is the #uid_t
91
* of the user who unlocked the device.
95
* <entry><filename>/run/udisks2/loop</filename></entry>
97
* A serialized 'a{sa{sv}}' #GVariant mapping from the
98
* loop device name (e.g. <filename>/dev/loop0</filename>) into a set of details.
99
* Known details include
100
* <literal>backing-file</literal>
101
* (of type <link linkend="G-VARIANT-TYPE-ARRAY:CAPS">'ay'</link>) for the name of the backing file and
102
* <literal>backing-file-device</literal>
103
* (of type <link linkend="G-VARIANT-TYPE-UINT64:CAPS">'t'</link>) for the #dev_t
104
* for of the device holding the backing file (or 0 if unknown) and
105
* <literal>setup-by-uid</literal>
106
* (of type <link linkend="G-VARIANT-TYPE-UINT32:CAPS">'u'</link>) that is the #uid_t
107
* of the user who set up the loop device.
111
* <entry><filename>/run/udisks2/mdraid</filename></entry>
113
* A serialized 'a{ta{sv}}' #GVariant mapping from the
114
* #dev_t of the raid device (e.g. <filename>/dev/md127</filename>) into a set of details.
115
* Known details include
116
* <literal>started-by-uid</literal>
117
* (of type <link linkend="G-VARIANT-TYPE-UINT32:CAPS">'u'</link>) that is the #uid_t
118
* of the user who started the array.
124
* Cleaning up is implemented by running a thread (to ensure that
125
* actions are serialized) that checks all data in the files mentioned
126
* above and cleans up the entry in question by e.g. unmounting a
127
* filesystem, removing a mount point or tearing down a device-mapper
128
* device when needed. The clean-up thread itself needs to be manually
129
* kicked using e.g. udisks_state_check() from suitable places in
130
* the #UDisksDaemon and #UDisksProvider implementations.
132
* Since cleaning up is only necessary when a device has been removed
133
* without having been properly stopped or shut down, the fact that it
134
* was cleaned up is logged to ensure that the information is brought
135
* to the attention of the system administrator.
141
* The #UDisksState structure contains only private data and should
142
* only be accessed using the provided API.
146
GObject parent_instance;
150
UDisksDaemon *daemon;
153
GMainContext *context;
156
/* key-path -> GVariant */
160
typedef struct _UDisksStateClass UDisksStateClass;
162
struct _UDisksStateClass
164
GObjectClass parent_class;
173
static void udisks_state_check_in_thread (UDisksState *state);
174
static void udisks_state_check_mounted_fs (UDisksState *state,
175
GArray *devs_to_clean);
176
static void udisks_state_check_unlocked_luks (UDisksState *state,
178
GArray *devs_to_clean);
179
static void udisks_state_check_loop (UDisksState *state,
181
GArray *devs_to_clean);
182
static void udisks_state_check_mdraid (UDisksState *state,
184
GArray *devs_to_clean);
185
static GVariant *udisks_state_get (UDisksState *state,
187
const GVariantType *type,
189
static gboolean udisks_state_set (UDisksState *state,
191
const GVariantType *type,
195
G_DEFINE_TYPE (UDisksState, udisks_state, G_TYPE_OBJECT);
198
udisks_state_init (UDisksState *state)
200
g_mutex_init (&state->lock);
201
state->cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref);
205
udisks_state_finalize (GObject *object)
207
UDisksState *state = UDISKS_STATE (object);
209
g_hash_table_unref (state->cache);
210
g_mutex_clear (&state->lock);
212
G_OBJECT_CLASS (udisks_state_parent_class)->finalize (object);
216
udisks_state_get_property (GObject *object,
221
UDisksState *state = UDISKS_STATE (object);
226
g_value_set_object (value, udisks_state_get_daemon (state));
230
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
236
udisks_state_set_property (GObject *object,
241
UDisksState *state = UDISKS_STATE (object);
246
g_assert (state->daemon == NULL);
247
/* we don't take a reference to the daemon */
248
state->daemon = g_value_get_object (value);
249
g_assert (state->daemon != NULL);
253
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
259
udisks_state_class_init (UDisksStateClass *klass)
261
GObjectClass *gobject_class;
263
gobject_class = G_OBJECT_CLASS (klass);
264
gobject_class->finalize = udisks_state_finalize;
265
gobject_class->set_property = udisks_state_set_property;
266
gobject_class->get_property = udisks_state_get_property;
269
* UDisksState:daemon:
271
* The #UDisksDaemon object.
273
g_object_class_install_property (gobject_class,
275
g_param_spec_object ("daemon",
281
G_PARAM_CONSTRUCT_ONLY |
282
G_PARAM_STATIC_STRINGS));
287
* @daemon: A #UDisksDaemon.
289
* Creates a new #UDisksState object.
291
* Returns: A #UDisksState that should be freed with g_object_unref().
294
udisks_state_new (UDisksDaemon *daemon)
296
return UDISKS_STATE (g_object_new (UDISKS_TYPE_STATE,
302
udisks_state_thread_func (gpointer user_data)
304
UDisksState *state = UDISKS_STATE (user_data);
306
udisks_info ("Entering cleanup thread");
308
g_main_loop_run (state->loop);
310
state->thread = NULL;
311
g_main_loop_unref (state->loop);
313
g_main_context_unref (state->context);
314
state->context = NULL;
315
g_object_unref (state);
317
udisks_info ("Exiting cleanup thread");
323
* udisks_state_start_cleanup:
324
* @state: A #UDisksState.
326
* Starts the clean-up thread.
328
* The clean-up thread will hold a reference to @state for as long as
329
* it's running - use udisks_state_stop_cleanup() to stop it.
332
udisks_state_start_cleanup (UDisksState *state)
334
g_return_if_fail (UDISKS_IS_STATE (state));
335
g_return_if_fail (state->thread == NULL);
337
state->context = g_main_context_new ();
338
state->loop = g_main_loop_new (state->context, FALSE);
339
state->thread = g_thread_new ("cleanup",
340
udisks_state_thread_func,
341
g_object_ref (state));
345
* udisks_state_stop_cleanup:
346
* @state: A #UDisksState.
348
* Stops the clean-up thread. Blocks the calling thread until it has stopped.
351
udisks_state_stop_cleanup (UDisksState *state)
355
g_return_if_fail (UDISKS_IS_STATE (state));
356
g_return_if_fail (state->thread != NULL);
358
thread = state->thread;
359
g_main_loop_quit (state->loop);
360
g_thread_join (thread);
364
udisks_state_check_func (gpointer user_data)
366
UDisksState *state = UDISKS_STATE (user_data);
367
udisks_state_check_in_thread (state);
372
* udisks_state_check:
373
* @state: A #UDisksState.
375
* Causes the clean-up thread for @state to check if anything should be cleaned up.
377
* This can be called from any thread and will not block the calling thread.
380
udisks_state_check (UDisksState *state)
382
g_return_if_fail (UDISKS_IS_STATE (state));
383
g_return_if_fail (state->thread != NULL);
385
g_main_context_invoke (state->context,
386
udisks_state_check_func,
391
* udisks_state_get_daemon:
392
* @state: A #UDisksState.
394
* Gets the daemon used by @state.
396
* Returns: A #UDisksDaemon. Do not free, the object is owned by @state.
399
udisks_state_get_daemon (UDisksState *state)
401
g_return_val_if_fail (UDISKS_IS_STATE (state), NULL);
402
return state->daemon;
405
/* ---------------------------------------------------------------------------------------------------- */
407
/* must be called from state thread */
409
udisks_state_check_in_thread (UDisksState *state)
411
GArray *devs_to_clean;
413
g_mutex_lock (&state->lock);
415
/* We have to do a two-stage clean-up since fake block devices
416
* can't be stopped if they are in use
419
udisks_info ("Cleanup check start");
421
/* First go through all block devices we might tear down
422
* but only check + record devices marked for cleaning
424
devs_to_clean = g_array_new (FALSE, FALSE, sizeof (dev_t));
425
udisks_state_check_unlocked_luks (state,
426
TRUE, /* check_only */
428
udisks_state_check_loop (state,
429
TRUE, /* check_only */
432
udisks_state_check_mdraid (state,
433
TRUE, /* check_only */
436
/* Then go through all mounted filesystems and pass the
437
* devices that we intend to clean...
439
udisks_state_check_mounted_fs (state, devs_to_clean);
441
/* Then go through all block devices and clear them up
442
* ... for real this time
444
udisks_state_check_unlocked_luks (state,
445
FALSE, /* check_only */
447
udisks_state_check_loop (state,
448
FALSE, /* check_only */
451
udisks_state_check_mdraid (state,
452
FALSE, /* check_only */
455
g_array_unref (devs_to_clean);
457
udisks_info ("Cleanup check end");
459
g_mutex_unlock (&state->lock);
462
/* ---------------------------------------------------------------------------------------------------- */
465
lookup_asv (GVariant *asv,
469
const gchar *iter_key;
475
g_variant_iter_init (&iter, asv);
476
while (g_variant_iter_next (&iter,
481
if (g_strcmp0 (key, iter_key) == 0)
483
ret = g_variant_get_variant (value);
484
g_variant_unref (value);
487
g_variant_unref (value);
494
/* ---------------------------------------------------------------------------------------------------- */
497
trigger_change_uevent (const gchar *sysfs_path)
502
g_return_if_fail (sysfs_path != NULL);
504
path = g_strconcat (sysfs_path, "/uevent", NULL);
505
fd = open (path, O_WRONLY);
508
udisks_warning ("Error opening %s: %m", path);
512
if (write (fd, "change", sizeof "change" - 1) != sizeof "change" - 1)
514
udisks_warning ("Error writing 'change' to file %s: %m", path);
524
/* returns TRUE if the entry should be kept */
526
udisks_state_check_mounted_fs_entry (UDisksState *state,
528
GArray *devs_to_clean)
530
const gchar *mount_point;
532
GVariant *block_device_value;
534
GVariant *fstab_mount_value;
535
gboolean fstab_mount;
541
gboolean device_exists;
542
gboolean device_to_be_cleaned;
543
gboolean attempt_no_cleanup;
544
UDisksMountMonitor *monitor;
545
GUdevClient *udev_client;
546
GUdevDevice *udev_device;
548
gchar *change_sysfs_path = NULL;
552
device_exists = FALSE;
553
device_to_be_cleaned = FALSE;
554
attempt_no_cleanup = FALSE;
555
block_device_value = NULL;
556
fstab_mount_value = NULL;
560
monitor = udisks_daemon_get_mount_monitor (state->daemon);
561
udev_client = udisks_linux_provider_get_udev_client (udisks_daemon_get_linux_provider (state->daemon));
563
g_variant_get (value,
568
block_device_value = lookup_asv (details, "block-device");
569
if (block_device_value == NULL)
571
s = g_variant_print (value, TRUE);
572
udisks_error ("mounted-fs entry %s is invalid: no block-device key/value pair", s);
574
attempt_no_cleanup = FALSE;
577
block_device = g_variant_get_uint64 (block_device_value);
579
fstab_mount_value = lookup_asv (details, "fstab-mount");
580
if (fstab_mount_value == NULL)
582
s = g_variant_print (value, TRUE);
583
udisks_error ("mounted-fs entry %s is invalid: no fstab-mount key/value pair", s);
585
attempt_no_cleanup = FALSE;
588
fstab_mount = g_variant_get_boolean (fstab_mount_value);
590
/* udisks_debug ("Validating mounted-fs entry for mount point %s", mount_point); */
592
/* Figure out if still mounted */
593
mounts = udisks_mount_monitor_get_mounts_for_dev (monitor, block_device);
594
for (l = mounts; l != NULL; l = l->next)
596
UDisksMount *mount = UDISKS_MOUNT (l->data);
597
if (udisks_mount_get_mount_type (mount) == UDISKS_MOUNT_TYPE_FILESYSTEM &&
598
g_strcmp0 (udisks_mount_get_mount_path (mount), mount_point) == 0)
604
g_list_foreach (mounts, (GFunc) g_object_unref, NULL);
605
g_list_free (mounts);
607
/* Figure out if block device still exists */
608
udev_device = g_udev_client_query_by_device_number (udev_client,
609
G_UDEV_DEVICE_TYPE_BLOCK,
611
if (udev_device != NULL)
613
/* If media is pulled from a device with removable media (say,
614
* /dev/sdc being a CF reader connected via USB) and a device
615
* (say, /dev/sdc1) on the media is mounted, the kernel won't
616
* necessarily send 'remove' uevent for /dev/sdc1 even though
617
* media removal was detected (we will get a 'change' uevent
620
* Therefore, we need to sanity-check the device - it appears
621
* that it's good enough to just check the 'size' sysfs
622
* attribute of the device (or its enclosing device if a
625
* Additionally, if we conclude that the device is not valid
626
* (e.g. still there but size of device or its enclosing device
627
* is 0), we also need to poke the kernel (via a 'change'
628
* uevent) to make the device go away. We do that after
629
* unmounting the device.
632
/* if umounting, issue 'change' event on the device after unmounting it */
633
change_sysfs_path = g_strdup (g_udev_device_get_sysfs_path (udev_device));
635
if (g_udev_device_get_sysfs_attr_as_uint64 (udev_device, "size") > 0)
637
/* for partition, also check enclosing device */
638
if (g_strcmp0 (g_udev_device_get_devtype (udev_device), "partition") == 0)
640
GUdevDevice *udev_device_disk;
641
udev_device_disk = g_udev_device_get_parent_with_subsystem (udev_device, "block", "disk");
642
if (udev_device_disk != NULL)
644
if (g_udev_device_get_sysfs_attr_as_uint64 (udev_device_disk, "size") > 0)
646
device_exists = TRUE;
648
/* if unmounting, issue 'change' uevent on the enclosing device after unmounting the device */
649
g_free (change_sysfs_path);
650
change_sysfs_path = g_strdup (g_udev_device_get_sysfs_path (udev_device_disk));
651
g_object_unref (udev_device_disk);
656
device_exists = TRUE;
659
g_object_unref (udev_device);
662
/* Figure out if the device is about to be cleaned up */
663
for (n = 0; n < devs_to_clean->len; n++)
665
dev_t dev_to_clean = g_array_index (devs_to_clean, dev_t, n);
666
if (dev_to_clean == block_device)
668
device_to_be_cleaned = TRUE;
673
if (is_mounted && device_exists && !device_to_be_cleaned)
678
if (!keep && !attempt_no_cleanup)
682
udisks_notice ("Cleaning up mount point %s (device %d:%d no longer exist)",
683
mount_point, major (block_device), minor (block_device));
685
else if (device_to_be_cleaned)
687
udisks_notice ("Cleaning up mount point %s (device %d:%d is about to be cleaned up)",
688
mount_point, major (block_device), minor (block_device));
690
else if (!is_mounted)
692
udisks_notice ("Cleaning up mount point %s (device %d:%d is not mounted)",
693
mount_point, major (block_device), minor (block_device));
698
gchar *escaped_mount_point;
699
gchar *error_message;
701
error_message = NULL;
702
escaped_mount_point = udisks_daemon_util_escape_and_quote (mount_point);
703
/* right now -l is the only way to "force unmount" file systems... */
704
if (!udisks_daemon_launch_spawned_job_sync (state->daemon,
705
NULL, /* UDisksObject */
706
"cleanup", 0, /* StartedByUID */
707
NULL, /* GCancellable */
708
0, /* uid_t run_as_uid */
709
0, /* uid_t run_as_euid */
710
NULL, /* gint *out_status */
712
NULL, /* input_string */
714
escaped_mount_point))
716
udisks_error ("Error cleaning up mount point %s: Error unmounting: %s",
717
mount_point, error_message);
718
g_free (escaped_mount_point);
719
g_free (error_message);
720
/* keep the entry so we can clean it up later */
724
g_free (escaped_mount_point);
725
g_free (error_message);
727
/* just unmounting the device does not make the kernel revalidate media
728
* so we issue a 'change' uevent to request that
730
if (change_sysfs_path != NULL)
732
trigger_change_uevent (change_sysfs_path);
736
/* remove directory */
739
if (g_file_test (mount_point, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
741
if (g_rmdir (mount_point) != 0)
743
udisks_error ("Error cleaning up mount point %s: Error removing directory: %m",
745
/* keep the entry so we can clean it up later */
754
if (fstab_mount_value != NULL)
755
g_variant_unref (fstab_mount_value);
756
if (block_device_value != NULL)
757
g_variant_unref (block_device_value);
759
g_variant_unref (details);
761
g_free (change_sysfs_path);
766
/* called with mutex->lock held */
768
udisks_state_check_mounted_fs (UDisksState *state,
769
GArray *devs_to_clean)
774
GVariantBuilder builder;
779
/* load existing entries */
781
value = udisks_state_get (state,
783
G_VARIANT_TYPE ("a{sa{sv}}"),
787
udisks_warning ("Error getting mounted-fs: %s (%s, %d)",
788
error->message, g_quark_to_string (error->domain), error->code);
789
g_error_free (error);
793
/* check valid entries */
794
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sa{sv}}"));
799
g_variant_iter_init (&iter, value);
800
while ((child = g_variant_iter_next_value (&iter)) != NULL)
802
if (udisks_state_check_mounted_fs_entry (state, child, devs_to_clean))
803
g_variant_builder_add_value (&builder, child);
806
g_variant_unref (child);
808
g_variant_unref (value);
811
new_value = g_variant_builder_end (&builder);
813
/* save new entries */
817
if (!udisks_state_set (state,
819
G_VARIANT_TYPE ("a{sa{sv}}"),
820
new_value, /* consumes new_value */
823
udisks_warning ("Error setting mounted-fs: %s (%s, %d)",
825
g_quark_to_string (error->domain),
827
g_error_free (error);
833
g_variant_unref (new_value);
840
/* ---------------------------------------------------------------------------------------------------- */
843
* udisks_state_add_mounted_fs:
844
* @state: A #UDisksState.
845
* @block_device: The block device.
846
* @mount_point: The mount point.
847
* @uid: The user id of the process requesting the device to be mounted.
848
* @fstab_mount: %TRUE if the device was mounted via /etc/fstab.
850
* Adds a new entry to the
851
* <filename>/run/udisks2/mounted-fs</filename> file.
854
udisks_state_add_mounted_fs (UDisksState *state,
855
const gchar *mount_point,
858
gboolean fstab_mount)
862
GVariant *details_value;
863
GVariantBuilder builder;
864
GVariantBuilder details_builder;
867
g_return_if_fail (UDISKS_IS_STATE (state));
868
g_return_if_fail (mount_point != NULL);
870
g_mutex_lock (&state->lock);
872
/* load existing entries */
874
value = udisks_state_get (state,
876
G_VARIANT_TYPE ("a{sa{sv}}"),
880
udisks_warning ("Error getting mounted-fs: %s (%s, %d)",
881
error->message, g_quark_to_string (error->domain), error->code);
882
g_error_free (error);
886
/* start by including existing entries */
887
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sa{sv}}"));
893
g_variant_iter_init (&iter, value);
894
while ((child = g_variant_iter_next_value (&iter)) != NULL)
896
const gchar *entry_mount_point;
897
g_variant_get (child, "{&s@a{sv}}", &entry_mount_point, NULL);
898
/* Skip/remove stale entries */
899
if (g_strcmp0 (entry_mount_point, mount_point) == 0)
901
udisks_warning ("Removing stale entry for mount point `%s' in /run/udisks2/mounted-fs file",
906
g_variant_builder_add_value (&builder, child);
908
g_variant_unref (child);
910
g_variant_unref (value);
913
/* build the details */
914
g_variant_builder_init (&details_builder, G_VARIANT_TYPE ("a{sv}"));
915
g_variant_builder_add (&details_builder,
918
g_variant_new_uint64 (block_device));
919
g_variant_builder_add (&details_builder,
922
g_variant_new_uint32 (uid));
923
g_variant_builder_add (&details_builder,
926
g_variant_new_boolean (fstab_mount));
927
details_value = g_variant_builder_end (&details_builder);
929
/* finally add the new entry */
930
g_variant_builder_add (&builder,
933
details_value); /* consumes details_value */
934
new_value = g_variant_builder_end (&builder);
936
/* save new entries */
938
if (!udisks_state_set (state,
940
G_VARIANT_TYPE ("a{sa{sv}}"),
941
new_value, /* consumes new_value */
944
udisks_warning ("Error setting mounted-fs: %s (%s, %d)",
945
error->message, g_quark_to_string (error->domain), error->code);
946
g_error_free (error);
951
g_mutex_unlock (&state->lock);
955
* udisks_state_find_mounted_fs:
956
* @state: A #UDisksState.
957
* @block_device: The block device.
958
* @out_uid: Return location for the user id who mounted the device or %NULL.
959
* @out_fstab_mount: Return location for whether the device was a fstab mount or %NULL.
961
* Gets the mount point for @block_device, if it exists in the
962
* <filename>/run/udisks2/mounted-fs</filename> file.
964
* Returns: The mount point for @block_device or %NULL if not found.
967
udisks_state_find_mounted_fs (UDisksState *state,
970
gboolean *out_fstab_mount)
976
g_return_val_if_fail (UDISKS_IS_STATE (state), NULL);
978
g_mutex_lock (&state->lock);
983
/* load existing entries */
985
value = udisks_state_get (state,
987
G_VARIANT_TYPE ("a{sa{sv}}"),
991
udisks_warning ("Error getting mounted-fs: %s (%s, %d)",
992
error->message, g_quark_to_string (error->domain), error->code);
993
g_error_free (error);
997
/* look through list */
1002
g_variant_iter_init (&iter, value);
1003
while ((child = g_variant_iter_next_value (&iter)) != NULL)
1005
const gchar *mount_point;
1007
GVariant *block_device_value;
1009
g_variant_get (child,
1014
block_device_value = lookup_asv (details, "block-device");
1015
if (block_device_value != NULL)
1017
dev_t iter_block_device;
1018
iter_block_device = g_variant_get_uint64 (block_device_value);
1019
if (iter_block_device == block_device)
1021
ret = g_strdup (mount_point);
1022
if (out_uid != NULL)
1024
GVariant *lookup_value;
1025
lookup_value = lookup_asv (details, "mounted-by-uid");
1027
if (lookup_value != NULL)
1029
*out_uid = g_variant_get_uint32 (lookup_value);
1030
g_variant_unref (lookup_value);
1033
if (out_fstab_mount != NULL)
1035
GVariant *lookup_value;
1036
lookup_value = lookup_asv (details, "fstab-mount");
1037
*out_fstab_mount = FALSE;
1038
if (lookup_value != NULL)
1040
*out_fstab_mount = g_variant_get_boolean (lookup_value);
1041
g_variant_unref (lookup_value);
1044
g_variant_unref (block_device_value);
1045
g_variant_unref (details);
1046
g_variant_unref (child);
1049
g_variant_unref (block_device_value);
1051
g_variant_unref (details);
1052
g_variant_unref (child);
1058
g_variant_unref (value);
1059
g_mutex_unlock (&state->lock);
1063
/* ---------------------------------------------------------------------------------------------------- */
1065
/* returns TRUE if the entry should be kept */
1067
udisks_state_check_unlocked_luks_entry (UDisksState *state,
1069
gboolean check_only,
1070
GArray *devs_to_clean)
1072
guint64 cleartext_device;
1074
GVariant *crypto_device_value;
1075
dev_t crypto_device;
1076
GVariant *dm_uuid_value;
1077
const gchar *dm_uuid;
1078
gchar *device_file_cleartext;
1081
gboolean is_unlocked;
1082
gboolean crypto_device_exists;
1083
gboolean attempt_no_cleanup;
1084
GUdevClient *udev_client;
1085
GUdevDevice *udev_cleartext_device;
1086
GUdevDevice *udev_crypto_device;
1089
is_unlocked = FALSE;
1090
crypto_device_exists = FALSE;
1091
attempt_no_cleanup = FALSE;
1092
device_file_cleartext = NULL;
1093
crypto_device_value = NULL;
1094
dm_uuid_value = NULL;
1097
udev_client = udisks_linux_provider_get_udev_client (udisks_daemon_get_linux_provider (state->daemon));
1099
g_variant_get (value,
1104
crypto_device_value = lookup_asv (details, "crypto-device");
1105
if (crypto_device_value == NULL)
1107
s = g_variant_print (value, TRUE);
1108
udisks_error ("unlocked-luks entry %s is invalid: no crypto-device key/value pair", s);
1110
attempt_no_cleanup = TRUE;
1113
crypto_device = g_variant_get_uint64 (crypto_device_value);
1115
dm_uuid_value = lookup_asv (details, "dm-uuid");
1116
if (dm_uuid_value == NULL)
1118
s = g_variant_print (value, TRUE);
1119
udisks_error ("unlocked-luks entry %s is invalid: no dm-uuid key/value pair", s);
1121
attempt_no_cleanup = TRUE;
1124
dm_uuid = g_variant_get_bytestring (dm_uuid_value);
1126
/*udisks_debug ("Validating luks entry for device %d:%d (backed by %d:%d) with uuid %s",
1127
major (cleartext_device), minor (cleartext_device),
1128
major (crypto_device), minor (crypto_device), dm_uuid);*/
1130
udev_cleartext_device = g_udev_client_query_by_device_number (udev_client,
1131
G_UDEV_DEVICE_TYPE_BLOCK,
1133
if (udev_cleartext_device != NULL)
1135
const gchar *current_dm_uuid;
1136
device_file_cleartext = g_strdup (g_udev_device_get_device_file (udev_cleartext_device));
1137
current_dm_uuid = g_udev_device_get_sysfs_attr (udev_cleartext_device, "dm/uuid");
1138
/* if the UUID doesn't match, then the dm device might have been reused... */
1139
if (g_strcmp0 (current_dm_uuid, dm_uuid) != 0)
1141
s = g_variant_print (value, TRUE);
1142
udisks_warning ("Removing unlocked-luks entry %s because %s now has another dm-uuid %s",
1143
s, device_file_cleartext,
1144
current_dm_uuid != NULL ? current_dm_uuid : "(NULL)");
1146
attempt_no_cleanup = TRUE;
1152
g_object_unref (udev_cleartext_device);
1155
udev_crypto_device = g_udev_client_query_by_device_number (udev_client,
1156
G_UDEV_DEVICE_TYPE_BLOCK,
1158
if (udev_crypto_device != NULL)
1160
crypto_device_exists = TRUE;
1161
g_object_unref (udev_crypto_device);
1164
/* OK, entry is valid - keep it around */
1165
if (is_unlocked && crypto_device_exists)
1170
if (check_only && !keep)
1172
dev_t cleartext_device_dev_t = cleartext_device; /* !@#!$# array type */
1173
g_array_append_val (devs_to_clean, cleartext_device_dev_t);
1178
if (!keep && !attempt_no_cleanup)
1182
gchar *escaped_device_file;
1183
gchar *error_message;
1185
udisks_notice ("Cleaning up LUKS device %s (backing device %d:%d no longer exist)",
1186
device_file_cleartext,
1187
major (crypto_device), minor (crypto_device));
1189
error_message = NULL;
1190
escaped_device_file = udisks_daemon_util_escape_and_quote (device_file_cleartext);
1191
if (!udisks_daemon_launch_spawned_job_sync (state->daemon,
1192
NULL, /* UDisksObject */
1193
"cleanup", 0, /* StartedByUID */
1194
NULL, /* GCancellable */
1195
0, /* uid_t run_as_uid */
1196
0, /* uid_t run_as_euid */
1197
NULL, /* gint *out_status */
1199
NULL, /* input_string */
1200
"cryptsetup luksClose %s",
1201
escaped_device_file))
1203
udisks_error ("Error cleaning up LUKS device %s: %s",
1204
device_file_cleartext, error_message);
1205
g_free (escaped_device_file);
1206
g_free (error_message);
1207
/* keep the entry so we can clean it up later */
1211
g_free (escaped_device_file);
1212
g_free (error_message);
1216
udisks_notice ("LUKS device %d:%d was manually removed",
1217
major (cleartext_device), minor (cleartext_device));
1222
g_free (device_file_cleartext);
1223
if (crypto_device_value != NULL)
1224
g_variant_unref (crypto_device_value);
1225
if (dm_uuid_value != NULL)
1226
g_variant_unref (dm_uuid_value);
1227
if (details != NULL)
1228
g_variant_unref (details);
1232
/* called with mutex->lock held */
1234
udisks_state_check_unlocked_luks (UDisksState *state,
1235
gboolean check_only,
1236
GArray *devs_to_clean)
1240
GVariant *new_value;
1241
GVariantBuilder builder;
1246
/* load existing entries */
1248
value = udisks_state_get (state,
1250
G_VARIANT_TYPE ("a{ta{sv}}"),
1254
udisks_warning ("Error getting unlocked-luks: %s (%s, %d)",
1255
error->message, g_quark_to_string (error->domain), error->code);
1256
g_error_free (error);
1260
/* check valid entries */
1261
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ta{sv}}"));
1266
g_variant_iter_init (&iter, value);
1267
while ((child = g_variant_iter_next_value (&iter)) != NULL)
1269
if (udisks_state_check_unlocked_luks_entry (state, child, check_only, devs_to_clean))
1270
g_variant_builder_add_value (&builder, child);
1273
g_variant_unref (child);
1275
g_variant_unref (value);
1278
new_value = g_variant_builder_end (&builder);
1280
/* save new entries */
1284
if (!udisks_state_set (state,
1286
G_VARIANT_TYPE ("a{ta{sv}}"),
1287
new_value, /* consumes new_value */
1290
udisks_warning ("Error setting unlocked-luks: %s (%s, %d)",
1292
g_quark_to_string (error->domain),
1294
g_error_free (error);
1300
g_variant_unref (new_value);
1307
/* ---------------------------------------------------------------------------------------------------- */
1310
* udisks_state_add_unlocked_luks:
1311
* @state: A #UDisksState.
1312
* @cleartext_device: The clear-text device.
1313
* @crypto_device: The crypto device.
1314
* @dm_uuid: The UUID of the unlocked dm device.
1315
* @uid: The user id of the process requesting the device to be unlocked.
1317
* Adds a new entry to the
1318
* <filename>/run/udisks2/unlocked-luks</filename> file.
1321
udisks_state_add_unlocked_luks (UDisksState *state,
1322
dev_t cleartext_device,
1323
dev_t crypto_device,
1324
const gchar *dm_uuid,
1328
GVariant *new_value;
1329
GVariant *details_value;
1330
GVariantBuilder builder;
1331
GVariantBuilder details_builder;
1334
g_return_if_fail (UDISKS_IS_STATE (state));
1335
g_return_if_fail (dm_uuid != NULL);
1337
g_mutex_lock (&state->lock);
1339
/* load existing entries */
1341
value = udisks_state_get (state,
1343
G_VARIANT_TYPE ("a{ta{sv}}"),
1347
udisks_warning ("Error getting unlocked-luks: %s (%s, %d)",
1348
error->message, g_quark_to_string (error->domain), error->code);
1349
g_error_free (error);
1353
/* start by including existing entries */
1354
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ta{sv}}"));
1359
g_variant_iter_init (&iter, value);
1360
while ((child = g_variant_iter_next_value (&iter)) != NULL)
1362
guint64 entry_cleartext_device;
1363
g_variant_get (child, "{t@a{sv}}", &entry_cleartext_device, NULL);
1364
/* Skip/remove stale entries */
1365
if ((dev_t) entry_cleartext_device == cleartext_device)
1367
udisks_warning ("Removing stale entry for cleartext device %d:%d in /run/udisks2/unlocked-luks file",
1368
(gint) major (entry_cleartext_device),
1369
(gint) minor (entry_cleartext_device));
1373
g_variant_builder_add_value (&builder, child);
1375
g_variant_unref (child);
1377
g_variant_unref (value);
1380
/* build the details */
1381
g_variant_builder_init (&details_builder, G_VARIANT_TYPE ("a{sv}"));
1382
g_variant_builder_add (&details_builder,
1385
g_variant_new_uint64 (crypto_device));
1386
g_variant_builder_add (&details_builder,
1389
g_variant_new_bytestring (dm_uuid));
1390
g_variant_builder_add (&details_builder,
1393
g_variant_new_uint32 (uid));
1394
details_value = g_variant_builder_end (&details_builder);
1396
/* finally add the new entry */
1397
g_variant_builder_add (&builder,
1399
(guint64) cleartext_device,
1400
details_value); /* consumes details_value */
1401
new_value = g_variant_builder_end (&builder);
1403
/* save new entries */
1405
if (!udisks_state_set (state,
1407
G_VARIANT_TYPE ("a{ta{sv}}"),
1408
new_value, /* consumes new_value */
1411
udisks_warning ("Error setting unlocked-luks: %s (%s, %d)",
1412
error->message, g_quark_to_string (error->domain), error->code);
1413
g_error_free (error);
1418
g_mutex_unlock (&state->lock);
1422
* udisks_state_find_unlocked_luks:
1423
* @state: A #UDisksState.
1424
* @crypto_device: The block device.
1425
* @out_uid: Return location for the user id who mounted the device or %NULL.
1427
* Gets the clear-text device for @crypto_device, if it exists in the
1428
* <filename>/run/udisks2/unlocked-luks</filename> file.
1430
* Returns: The cleartext device for @crypto_device or 0 if not found.
1433
udisks_state_find_unlocked_luks (UDisksState *state,
1434
dev_t crypto_device,
1441
g_return_val_if_fail (UDISKS_IS_STATE (state), 0);
1443
g_mutex_lock (&state->lock);
1448
/* load existing entries */
1450
value = udisks_state_get (state,
1452
G_VARIANT_TYPE ("a{ta{sv}}"),
1456
udisks_warning ("Error getting unlocked-luks: %s (%s, %d)",
1457
error->message, g_quark_to_string (error->domain), error->code);
1458
g_error_free (error);
1462
/* look through list */
1467
g_variant_iter_init (&iter, value);
1468
while ((child = g_variant_iter_next_value (&iter)) != NULL)
1470
guint64 cleartext_device;
1472
GVariant *crypto_device_value;
1474
g_variant_get (child,
1479
crypto_device_value = lookup_asv (details, "crypto-device");
1480
if (crypto_device_value != NULL)
1482
dev_t iter_crypto_device;
1483
iter_crypto_device = g_variant_get_uint64 (crypto_device_value);
1484
if (iter_crypto_device == crypto_device)
1486
ret = cleartext_device;
1487
if (out_uid != NULL)
1489
GVariant *lookup_value;
1490
lookup_value = lookup_asv (details, "unlocked-by-uid");
1492
if (lookup_value != NULL)
1494
*out_uid = g_variant_get_uint32 (lookup_value);
1495
g_variant_unref (lookup_value);
1498
g_variant_unref (crypto_device_value);
1499
g_variant_unref (details);
1500
g_variant_unref (child);
1503
g_variant_unref (crypto_device_value);
1505
g_variant_unref (details);
1506
g_variant_unref (child);
1512
g_variant_unref (value);
1513
g_mutex_unlock (&state->lock);
1517
/* ---------------------------------------------------------------------------------------------------- */
1519
/* returns TRUE if the entry should be kept */
1521
udisks_state_check_loop_entry (UDisksState *state,
1523
gboolean check_only,
1524
GArray *devs_to_clean)
1526
const gchar *loop_device;
1527
GVariant *details = NULL;
1528
gboolean keep = FALSE;
1529
GVariant *backing_file_value = NULL;
1530
const gchar *backing_file;
1531
GUdevClient *udev_client;
1532
GUdevDevice *device = NULL;
1533
const gchar *sysfs_backing_file;
1535
udev_client = udisks_linux_provider_get_udev_client (udisks_daemon_get_linux_provider (state->daemon));
1537
g_variant_get (value,
1542
backing_file_value = lookup_asv (details, "backing-file");
1543
if (backing_file_value == NULL)
1546
s = g_variant_print (value, TRUE);
1547
udisks_error ("loop entry %s is invalid: no backing-file key/value pair", s);
1551
backing_file = g_variant_get_bytestring (backing_file_value);
1553
/* check the loop device is still set up */
1554
device = g_udev_client_query_by_device_file (udev_client, loop_device);
1557
udisks_info ("no udev device for %s", loop_device);
1560
if (g_udev_device_get_sysfs_attr (device, "loop/offset") == NULL)
1562
udisks_info ("loop device %s is not setup (no loop/offset sysfs file)", loop_device);
1566
/* Check the loop device set up, is the one that _we_ set up
1568
* Note that drivers/block/loop.c:loop_attr_backing_file_show() uses d_path()
1569
* on lo_file_name so in the event that the underlying fs was unmounted
1570
* (just 'umount -l /path/to/fs/holding/backing/file to try) it cuts
1571
* off the mount path.... in this case we simply just give up managing
1574
sysfs_backing_file = g_udev_device_get_sysfs_attr (device, "loop/backing_file");
1575
if (g_strcmp0 (sysfs_backing_file, backing_file) != 0)
1577
udisks_notice ("unexpected name for %s - expected `%s' but got `%s'",
1578
loop_device, backing_file, sysfs_backing_file);
1582
/* OK, entry is valid - keep it around */
1587
if (check_only && !keep)
1591
dev_t dev_number = g_udev_device_get_device_number (device);
1592
g_array_append_val (devs_to_clean, dev_number);
1600
udisks_notice ("No longer watching loop device %s", loop_device);
1604
g_clear_object (&device);
1605
if (backing_file_value != NULL)
1606
g_variant_unref (backing_file_value);
1607
if (details != NULL)
1608
g_variant_unref (details);
1613
udisks_state_check_loop (UDisksState *state,
1614
gboolean check_only,
1615
GArray *devs_to_clean)
1619
GVariant *new_value;
1620
GVariantBuilder builder;
1625
/* load existing entries */
1627
value = udisks_state_get (state,
1629
G_VARIANT_TYPE ("a{sa{sv}}"),
1633
udisks_warning ("Error getting loop: %s (%s, %d)",
1634
error->message, g_quark_to_string (error->domain), error->code);
1635
g_error_free (error);
1639
/* check valid entries */
1640
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sa{sv}}"));
1645
g_variant_iter_init (&iter, value);
1646
while ((child = g_variant_iter_next_value (&iter)) != NULL)
1648
if (udisks_state_check_loop_entry (state, child, check_only, devs_to_clean))
1649
g_variant_builder_add_value (&builder, child);
1652
g_variant_unref (child);
1654
g_variant_unref (value);
1657
new_value = g_variant_builder_end (&builder);
1659
/* save new entries */
1663
if (!udisks_state_set (state,
1665
G_VARIANT_TYPE ("a{sa{sv}}"),
1666
new_value, /* consumes new_value */
1669
udisks_warning ("Error setting loop: %s (%s, %d)",
1671
g_quark_to_string (error->domain),
1673
g_error_free (error);
1679
g_variant_unref (new_value);
1686
/* ---------------------------------------------------------------------------------------------------- */
1689
* udisks_state_add_loop:
1690
* @state: A #UDisksState.
1691
* @device_file: The loop device file.
1692
* @backing_file: The backing file.
1693
* @backing_file_device: The #dev_t of the backing file or 0 if unknown.
1694
* @uid: The user id of the process requesting the loop device.
1696
* Adds a new entry to the <filename>/run/udisks2/loop</filename>
1700
udisks_state_add_loop (UDisksState *state,
1701
const gchar *device_file,
1702
const gchar *backing_file,
1703
dev_t backing_file_device,
1707
GVariant *new_value;
1708
GVariant *details_value;
1709
GVariantBuilder builder;
1710
GVariantBuilder details_builder;
1713
g_return_if_fail (UDISKS_IS_STATE (state));
1714
g_return_if_fail (device_file != NULL);
1715
g_return_if_fail (backing_file != NULL);
1717
g_mutex_lock (&state->lock);
1719
/* load existing entries */
1721
value = udisks_state_get (state,
1723
G_VARIANT_TYPE ("a{sa{sv}}"),
1727
udisks_warning ("Error getting loop: %s (%s, %d)",
1728
error->message, g_quark_to_string (error->domain), error->code);
1729
g_error_free (error);
1733
/* start by including existing entries */
1734
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sa{sv}}"));
1739
g_variant_iter_init (&iter, value);
1740
while ((child = g_variant_iter_next_value (&iter)) != NULL)
1742
const gchar *entry_loop_device;
1743
g_variant_get (child, "{&s@a{sv}}", &entry_loop_device, NULL);
1744
/* Skip/remove stale entries */
1745
if (g_strcmp0 (entry_loop_device, device_file) == 0)
1747
udisks_warning ("Removing stale entry for loop device `%s' in /run/udisks2/loop file",
1752
g_variant_builder_add_value (&builder, child);
1754
g_variant_unref (child);
1756
g_variant_unref (value);
1759
/* build the details */
1760
g_variant_builder_init (&details_builder, G_VARIANT_TYPE ("a{sv}"));
1761
g_variant_builder_add (&details_builder,
1764
g_variant_new_bytestring (backing_file));
1765
g_variant_builder_add (&details_builder,
1767
"backing-file-device",
1768
g_variant_new_uint64 (backing_file_device));
1769
g_variant_builder_add (&details_builder,
1772
g_variant_new_uint32 (uid));
1773
details_value = g_variant_builder_end (&details_builder);
1775
/* finally add the new entry */
1776
g_variant_builder_add (&builder,
1779
details_value); /* consumes details_value */
1780
new_value = g_variant_builder_end (&builder);
1782
/* save new entries */
1784
if (!udisks_state_set (state,
1786
G_VARIANT_TYPE ("a{sa{sv}}"),
1787
new_value, /* consumes new_value */
1790
udisks_warning ("Error setting loop: %s (%s, %d)",
1791
error->message, g_quark_to_string (error->domain), error->code);
1792
g_error_free (error);
1797
g_mutex_unlock (&state->lock);
1801
* udisks_state_has_loop:
1802
* @state: A #UDisksState
1803
* @device_file: A loop device file.
1804
* @out_uid: Return location for the user id who setup the loop device or %NULL.
1805
* @error: Return location for error or %NULL.
1807
* Checks if @device_file is set up via udisks.
1809
* Returns: %TRUE if set up via udisks, otherwise %FALSE or if @error is set.
1812
udisks_state_has_loop (UDisksState *state,
1813
const gchar *device_file,
1820
g_return_val_if_fail (UDISKS_IS_STATE (state), FALSE);
1822
g_mutex_lock (&state->lock);
1827
/* load existing entries */
1829
value = udisks_state_get (state,
1831
G_VARIANT_TYPE ("a{sa{sv}}"),
1835
udisks_warning ("Error getting loop: %s (%s, %d)",
1836
error->message, g_quark_to_string (error->domain), error->code);
1837
g_error_free (error);
1841
/* look through list */
1846
g_variant_iter_init (&iter, value);
1847
while ((child = g_variant_iter_next_value (&iter)) != NULL)
1849
const gchar *iter_device_file;
1852
g_variant_get (child,
1857
if (g_strcmp0 (iter_device_file, device_file) == 0)
1860
if (out_uid != NULL)
1862
GVariant *lookup_value;
1863
lookup_value = lookup_asv (details, "setup-by-uid");
1865
if (lookup_value != NULL)
1867
*out_uid = g_variant_get_uint32 (lookup_value);
1868
g_variant_unref (lookup_value);
1871
g_variant_unref (details);
1872
g_variant_unref (child);
1875
g_variant_unref (details);
1876
g_variant_unref (child);
1882
g_variant_unref (value);
1883
g_mutex_unlock (&state->lock);
1887
/* ---------------------------------------------------------------------------------------------------- */
1889
/* returns TRUE if the entry should be kept */
1891
udisks_state_check_mdraid_entry (UDisksState *state,
1893
gboolean check_only,
1894
GArray *devs_to_clean)
1897
GVariant *details = NULL;
1898
gboolean keep = FALSE;
1899
GUdevClient *udev_client;
1900
GUdevDevice *device = NULL;
1901
const gchar *array_state;
1903
udev_client = udisks_linux_provider_get_udev_client (udisks_daemon_get_linux_provider (state->daemon));
1905
g_variant_get (value,
1910
/* check if the RAID device is still set up */
1911
device = g_udev_client_query_by_device_number (udev_client, G_UDEV_DEVICE_TYPE_BLOCK, raid_device);
1914
udisks_info ("no udev device for raid device %d:%d", major (raid_device), minor (raid_device));
1917
array_state = g_udev_device_get_sysfs_attr (device, "md/array_state");
1918
if (array_state == NULL)
1920
udisks_info ("raid device %d:%d is not setup (no md/array_state sysfs file)",
1921
major (raid_device), minor (raid_device));
1925
if (g_strcmp0 (array_state, "clear") == 0)
1927
/* 'clear' means that the array is not set up any more */
1931
/* OK, entry is valid - keep it around */
1936
if (check_only && !keep)
1940
g_array_append_val (devs_to_clean, raid_device);
1948
udisks_notice ("No longer watching mdraid device %d:%d", major (raid_device), minor (raid_device));
1952
g_clear_object (&device);
1953
if (details != NULL)
1954
g_variant_unref (details);
1959
udisks_state_check_mdraid (UDisksState *state,
1960
gboolean check_only,
1961
GArray *devs_to_clean)
1965
GVariant *new_value;
1966
GVariantBuilder builder;
1971
/* load existing entries */
1973
value = udisks_state_get (state,
1975
G_VARIANT_TYPE ("a{ta{sv}}"),
1979
udisks_warning ("Error getting mdraid: %s (%s, %d)",
1980
error->message, g_quark_to_string (error->domain), error->code);
1981
g_error_free (error);
1985
/* check valid entries */
1986
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ta{sv}}"));
1991
g_variant_iter_init (&iter, value);
1992
while ((child = g_variant_iter_next_value (&iter)) != NULL)
1994
if (udisks_state_check_mdraid_entry (state, child, check_only, devs_to_clean))
1995
g_variant_builder_add_value (&builder, child);
1998
g_variant_unref (child);
2000
g_variant_unref (value);
2003
new_value = g_variant_builder_end (&builder);
2005
/* save new entries */
2009
if (!udisks_state_set (state,
2011
G_VARIANT_TYPE ("a{ta{sv}}"),
2012
new_value, /* consumes new_value */
2015
udisks_warning ("Error setting mdraid: %s (%s, %d)",
2017
g_quark_to_string (error->domain),
2019
g_error_free (error);
2025
g_variant_unref (new_value);
2033
* udisks_state_add_mdraid:
2034
* @state: A #UDisksState.
2035
* @raid_device: The #dev_t for the RAID device.
2036
* @uid: The user id of the process requesting the loop device.
2038
* Adds a new entry to the <filename>/run/udisks2/mdraid</filename>
2042
udisks_state_add_mdraid (UDisksState *state,
2047
GVariant *new_value;
2048
GVariant *details_value;
2049
GVariantBuilder builder;
2050
GVariantBuilder details_builder;
2053
g_return_if_fail (UDISKS_IS_STATE (state));
2055
g_mutex_lock (&state->lock);
2057
/* load existing entries */
2059
value = udisks_state_get (state,
2061
G_VARIANT_TYPE ("a{ta{sv}}"),
2065
udisks_warning ("Error getting mdraid: %s (%s, %d)",
2066
error->message, g_quark_to_string (error->domain), error->code);
2067
g_error_free (error);
2071
/* start by including existing entries */
2072
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ta{sv}}"));
2077
g_variant_iter_init (&iter, value);
2078
while ((child = g_variant_iter_next_value (&iter)) != NULL)
2080
guint64 entry_raid_device;
2081
g_variant_get (child, "{t@a{sv}}", &entry_raid_device, NULL);
2082
/* Skip/remove stale entries */
2083
if (entry_raid_device == raid_device)
2085
udisks_warning ("Removing stale entry for raid device %d:%d in /run/udisks2/mdraid file",
2086
major (raid_device), minor (raid_device));
2090
g_variant_builder_add_value (&builder, child);
2092
g_variant_unref (child);
2094
g_variant_unref (value);
2097
/* build the details */
2098
g_variant_builder_init (&details_builder, G_VARIANT_TYPE ("a{sv}"));
2099
g_variant_builder_add (&details_builder,
2102
g_variant_new_uint32 (uid));
2103
details_value = g_variant_builder_end (&details_builder);
2105
/* finally add the new entry */
2106
g_variant_builder_add (&builder,
2109
details_value); /* consumes details_value */
2110
new_value = g_variant_builder_end (&builder);
2112
/* save new entries */
2114
if (!udisks_state_set (state,
2116
G_VARIANT_TYPE ("a{ta{sv}}"),
2117
new_value, /* consumes new_value */
2120
udisks_warning ("Error setting mdraid: %s (%s, %d)",
2121
error->message, g_quark_to_string (error->domain), error->code);
2122
g_error_free (error);
2127
g_mutex_unlock (&state->lock);
2131
* udisks_state_has_mdraid:
2132
* @state: A #UDisksState
2133
* @raid_device: A #dev_t for the RAID device.
2134
* @out_uid: Return location for the user id who setup the loop device or %NULL.
2135
* @error: Return location for error or %NULL.
2137
* Checks if @raid_device is set up via udisks.
2139
* Returns: %TRUE if set up via udisks, otherwise %FALSE or if @error is set.
2142
udisks_state_has_mdraid (UDisksState *state,
2146
gboolean ret = FALSE;
2147
GVariant *value = NULL;
2148
GError *error = NULL;
2150
g_return_val_if_fail (UDISKS_IS_STATE (state), FALSE);
2152
g_mutex_lock (&state->lock);
2154
/* load existing entries */
2155
value = udisks_state_get (state,
2157
G_VARIANT_TYPE ("a{ta{sv}}"),
2161
udisks_warning ("Error getting mdraid: %s (%s, %d)",
2162
error->message, g_quark_to_string (error->domain), error->code);
2163
g_clear_error (&error);
2167
/* look through list */
2172
g_variant_iter_init (&iter, value);
2173
while ((child = g_variant_iter_next_value (&iter)) != NULL)
2175
guint64 iter_raid_device;
2178
g_variant_get (child,
2183
if (iter_raid_device == raid_device)
2186
if (out_uid != NULL)
2188
GVariant *lookup_value;
2189
lookup_value = lookup_asv (details, "started-by-uid");
2191
if (lookup_value != NULL)
2193
*out_uid = g_variant_get_uint32 (lookup_value);
2194
g_variant_unref (lookup_value);
2197
g_variant_unref (details);
2198
g_variant_unref (child);
2201
g_variant_unref (details);
2202
g_variant_unref (child);
2208
g_variant_unref (value);
2209
g_mutex_unlock (&state->lock);
2213
/* ---------------------------------------------------------------------------------------------------- */
2216
udisks_state_get (UDisksState *state,
2218
const GVariantType *type,
2222
GVariant *ret = NULL;
2223
gchar *contents = NULL;
2224
GError *local_error = NULL;
2227
g_return_val_if_fail (UDISKS_IS_STATE (state), NULL);
2228
g_return_val_if_fail (key != NULL, NULL);
2229
g_return_val_if_fail (g_variant_type_is_definite (type), NULL);
2230
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
2234
* - could use a cache here to avoid loading files all the time
2235
* - could also mmap the file
2238
path = g_strdup_printf ("/run/udisks2/%s", key);
2240
/* see if it's already in the cache */
2241
ret = g_hash_table_lookup (state->cache, path);
2244
g_variant_ref (ret);
2248
if (!g_file_get_contents (path,
2253
if (local_error->domain == G_FILE_ERROR && local_error->code == G_FILE_ERROR_NOENT)
2255
/* this is not an error */
2256
g_clear_error (&local_error);
2259
g_propagate_error (error, local_error);
2263
ret = g_variant_new_from_data (type,
2264
(gconstpointer) contents,
2269
g_variant_ref_sink (ret);
2271
contents = NULL; /* ownership transfered to the returned GVariant */
2280
udisks_state_set (UDisksState *state,
2282
const GVariantType *type,
2286
gboolean ret = FALSE;
2290
GVariant *normalized = NULL;
2292
g_return_val_if_fail (UDISKS_IS_STATE (state), FALSE);
2293
g_return_val_if_fail (key != NULL, FALSE);
2294
g_return_val_if_fail (g_variant_type_is_definite (type), FALSE);
2295
g_return_val_if_fail (g_variant_is_of_type (value, type), FALSE);
2296
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
2298
g_variant_ref_sink (value);
2299
normalized = g_variant_get_normal_form (value);
2300
size = g_variant_get_size (normalized);
2301
data = g_malloc (size);
2302
g_variant_store (normalized, data);
2304
path = g_strdup_printf ("/run/udisks2/%s", key);
2306
g_hash_table_insert (state->cache, g_strdup (path), g_variant_ref (value));
2308
if (!g_file_set_contents (path,
2320
g_variant_unref (normalized);
2321
g_variant_unref (value);
2325
/* ---------------------------------------------------------------------------------------------------- */