From ed17dc91d3f00efa398b88f97006168dfbb97b03 Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Wed, 3 Nov 2021 18:59:42 +0100 Subject: [PATCH 1/2] udiskslinuxmanager: Add resolving devices by partuuid/partlabel Also fixes the wrong logic about "matching all values". Note that unmangled/unescaped strings should be provided as appearing on the org.freedesktop.UDisks2.Block and org.freedesktop.UDisks2.Partition interfaces. --- data/org.freedesktop.UDisks2.xml | 12 ++++++++ src/udiskslinuxmanager.c | 53 +++++++++++++++++++------------- 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/data/org.freedesktop.UDisks2.xml b/data/org.freedesktop.UDisks2.xml index 2b16f0c701..888b0b08d0 100644 --- a/data/org.freedesktop.UDisks2.xml +++ b/data/org.freedesktop.UDisks2.xml @@ -261,6 +261,18 @@ Filesystem UUID. #org.freedesktop.UDisks2.Block:IdUUID is used. + + partuuid (type 's') + + Partition UUID. #org.freedesktop.UDisks2.Partition:UUID is used. + + + + partlabel (type 's') + + Partition Name. #org.freedesktop.UDisks2.Partition:Name is used. + + It is possbile to specify multiple keys. In this case, only devices matching all values will be returned. diff --git a/src/udiskslinuxmanager.c b/src/udiskslinuxmanager.c index e46d416f9d..62eb2a4e23 100644 --- a/src/udiskslinuxmanager.c +++ b/src/udiskslinuxmanager.c @@ -43,6 +43,7 @@ #include "udisksdaemonutil.h" #include "udisksstate.h" #include "udiskslinuxblockobject.h" +#include "udiskslinuxblock.h" #include "udiskslinuxdevice.h" #include "udisksmodulemanager.h" #include "udiskssimplejob.h" @@ -1193,25 +1194,17 @@ handle_get_block_devices (UDisksManager *object, return TRUE; /* returning TRUE means that we handled the method invocation */ } -static gboolean -compare_paths (UDisksManager *object, - UDisksBlock *block, - const gchar *path) +static inline gboolean +match_id_format (UDisksLinuxBlock *block, const gchar *key, const gchar *val) { - const gchar *const *symlinks = NULL; + gchar *s; + gboolean ret; - if (g_strcmp0 (udisks_block_get_device (block), path) == 0) - return TRUE; + s = g_strdup_printf ("%s=%s", key, val); + ret = udisks_linux_block_matches_id (block, s); + g_free (s); - symlinks = udisks_block_get_symlinks (block); - if (symlinks != NULL) - { - for (guint i = 0; symlinks[i] != NULL; i++) - if (g_strcmp0 (symlinks[i], path) == 0) - return TRUE; - } - - return FALSE; + return ret; } static gboolean @@ -1223,6 +1216,8 @@ handle_resolve_device (UDisksManager *object, const gchar *devpath = NULL; const gchar *devuuid = NULL; const gchar *devlabel = NULL; + const gchar *partuuid = NULL; + const gchar *partlabel = NULL; GSList *blocks = NULL; GSList *blocks_p = NULL; @@ -1233,28 +1228,42 @@ handle_resolve_device (UDisksManager *object, guint num_found = 0; const gchar **ret_paths = NULL; - gboolean found = FALSE; guint i = 0; g_variant_lookup (arg_devspec, "path", "&s", &devpath); g_variant_lookup (arg_devspec, "uuid", "&s", &devuuid); g_variant_lookup (arg_devspec, "label", "&s", &devlabel); + g_variant_lookup (arg_devspec, "partuuid", "&s", &partuuid); + g_variant_lookup (arg_devspec, "partlabel", "&s", &partlabel); + + if (!devpath && !devuuid && !devlabel && !partuuid && !partlabel) + { + g_dbus_method_invocation_return_error_literal (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED, + "Invalid device specification provided"); + return TRUE; + } blocks = get_block_objects (object, &num_blocks); for (blocks_p = blocks; blocks_p != NULL; blocks_p = blocks_p->next) { - if (devpath != NULL) - found = compare_paths (object, blocks_p->data, devpath); + UDisksLinuxBlock *block = UDISKS_LINUX_BLOCK (blocks_p->data); + gboolean found = TRUE; + if (devpath != NULL) + found = udisks_linux_block_matches_id (block, devpath); if (devuuid != NULL) - found = g_strcmp0 (udisks_block_get_id_uuid (blocks_p->data), devuuid) == 0; + found = found && match_id_format (block, "UUID", devuuid); if (devlabel != NULL) - found = g_strcmp0 (udisks_block_get_id_label (blocks_p->data), devlabel) == 0; + found = found && match_id_format (block, "LABEL", devlabel); + if (partuuid != NULL) + found = found && match_id_format (block, "PARTUUID", partuuid); + if (partlabel != NULL) + found = found && match_id_format (block, "PARTLABEL", partlabel); if (found) { - ret = g_slist_prepend (ret, blocks_p->data); + ret = g_slist_prepend (ret, block); num_found++; } } From cf47eeeae1e8c23697fabc769cb90a8589fc7adc Mon Sep 17 00:00:00 2001 From: Tomas Bzatek Date: Wed, 3 Nov 2021 19:03:18 +0100 Subject: [PATCH 2/2] tests: Add tests for resolving partlabel/partuuid --- src/tests/dbus-tests/test_10_basic.py | 49 +++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/tests/dbus-tests/test_10_basic.py b/src/tests/dbus-tests/test_10_basic.py index d46f53d585..3d61d14082 100644 --- a/src/tests/dbus-tests/test_10_basic.py +++ b/src/tests/dbus-tests/test_10_basic.py @@ -215,10 +215,31 @@ def _wipe(self, device, retry=True): def test_60_resolve_device(self): manager = self.get_interface(self.manager_obj, '.Manager') + # empty/invalid devspec supplied + spec = dbus.Dictionary({}, signature='sv') + msg = r'Invalid device specification provided' + with six.assertRaisesRegex(self, dbus.exceptions.DBusException, msg): + manager.ResolveDevice(spec, self.no_options) + spec = dbus.Dictionary({'PATH': '/dev/i-dont-exist'}, signature='sv') + with six.assertRaisesRegex(self, dbus.exceptions.DBusException, msg): + manager.ResolveDevice(spec, self.no_options) + # try some non-existing device first spec = dbus.Dictionary({'path': '/dev/i-dont-exist'}, signature='sv') devices = manager.ResolveDevice(spec, self.no_options) self.assertEqual(len(devices), 0) + spec = dbus.Dictionary({'uuid': 'I-DONT-EXIST'}, signature='sv') + devices = manager.ResolveDevice(spec, self.no_options) + self.assertEqual(len(devices), 0) + spec = dbus.Dictionary({'label': 'I-DONT-EXIST'}, signature='sv') + devices = manager.ResolveDevice(spec, self.no_options) + self.assertEqual(len(devices), 0) + spec = dbus.Dictionary({'partuuid': 'I-DONT-EXIST'}, signature='sv') + devices = manager.ResolveDevice(spec, self.no_options) + self.assertEqual(len(devices), 0) + spec = dbus.Dictionary({'partlabel': 'I-DONT-EXIST'}, signature='sv') + devices = manager.ResolveDevice(spec, self.no_options) + self.assertEqual(len(devices), 0) # get our first virtual disk by path spec = dbus.Dictionary({'path': self.vdevs[0]}, signature='sv') @@ -297,6 +318,34 @@ def test_60_resolve_device(self): self.assertEqual(len(devices), 1) self.assertIn(object_path, devices) + # create a partition on another device + disk = self.get_object('/block_devices/' + os.path.basename(self.vdevs[2])) + self.assertIsNotNone(disk) + disk.Format('gpt', self.no_options, dbus_interface=self.iface_prefix + '.Block') + self.addCleanup(self._wipe, self.vdevs[2]) + part_label = 'PRTLBLX' + path = disk.CreatePartition(dbus.UInt64(1024**2), dbus.UInt64(100 * 1024**2), + '', part_label, self.no_options, + dbus_interface=self.iface_prefix + '.PartitionTable') + part = self.bus.get_object(self.iface_prefix, path) + self.assertIsNotNone(part) + part_uuid = self.get_property_raw(part, '.Partition', 'UUID') + self.assertIsNotNone(part_uuid) + part_name_val = self.get_property_raw(part, '.Partition', 'Name') + self.assertEquals(part_name_val, part_label) + + # check that partlabel and partuuid can be resolved + spec = dbus.Dictionary({'partlabel': part_label}, signature='sv') + devices = manager.ResolveDevice(spec, self.no_options) + object_path = '%s/block_devices/%s1' % (self.path_prefix, os.path.basename(self.vdevs[2])) + self.assertEqual(len(devices), 1) + self.assertIn(object_path, devices) + spec = dbus.Dictionary({'partuuid': part_uuid}, signature='sv') + devices = manager.ResolveDevice(spec, self.no_options) + object_path = '%s/block_devices/%s1' % (self.path_prefix, os.path.basename(self.vdevs[2])) + self.assertEqual(len(devices), 1) + self.assertIn(object_path, devices) + def test_80_device_presence(self): '''Test the debug devices are present on the bus''' for d in self.vdevs: