Skip to content

Commit

Permalink
Merge pull request #933 from tbzatek/resolve_device
Browse files Browse the repository at this point in the history
Add support for resolving devices by partlabel and partuuid
  • Loading branch information
tbzatek authored Oct 21, 2022
2 parents 6f17b66 + cf47eee commit d6da015
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 22 deletions.
12 changes: 12 additions & 0 deletions data/org.freedesktop.UDisks2.xml
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,18 @@
Filesystem UUID. #org.freedesktop.UDisks2.Block:IdUUID is used.
</para></listitem>
</varlistentry>
<varlistentry>
<term>partuuid (type <literal>'s'</literal>)</term>
<listitem><para>
Partition UUID. #org.freedesktop.UDisks2.Partition:UUID is used.
</para></listitem>
</varlistentry>
<varlistentry>
<term>partlabel (type <literal>'s'</literal>)</term>
<listitem><para>
Partition Name. #org.freedesktop.UDisks2.Partition:Name is used.
</para></listitem>
</varlistentry>
</variablelist>
It is possbile to specify multiple keys. In this case, only devices matching all values will be returned.
Expand Down
49 changes: 49 additions & 0 deletions src/tests/dbus-tests/test_10_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down Expand Up @@ -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:
Expand Down
53 changes: 31 additions & 22 deletions src/udiskslinuxmanager.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand All @@ -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++;
}
}
Expand Down

0 comments on commit d6da015

Please sign in to comment.