From 31073f67ad4ee24cbba42d6edf4b8d26c11465a5 Mon Sep 17 00:00:00 2001 From: Geert Geurts Date: Wed, 21 Oct 2026 09:20:31 +0200 Subject: [PATCH] utils: Resolve symlinks with an absolute target in bd_utils_resolve_device Only relative symlink targets were handled. An absolute target such as /dev/mapper/vg-swap -> /dev/dm-1, as created by udev rules in some environments, was turned into "/dev//dev/dm-1" and the resolution failed. bd_swap_swapstatus() then took the device for inactive and callers such as blivet tried to activate an already active swap, which failed with "Device or resource busy". Resolve absolute targets with realpath() so chains of symlinks work too. Co-Authored-By: Claude Sonnet 5.5 --- src/utils/dev_utils.c | 11 ++++++++++- tests/utils_test.py | 7 +++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/utils/dev_utils.c b/src/utils/dev_utils.c index 9280b8078..8587bedec 100644 --- a/src/utils/dev_utils.c +++ b/src/utils/dev_utils.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "dev_utils.h" @@ -94,7 +95,15 @@ gchar* bd_utils_resolve_device (const gchar *dev_spec, GError **error) { } g_free (path); - if (g_str_has_prefix (symlink, "../")) + if (g_path_is_absolute (symlink)) { + /* the target may be another symlink, resolve it completely */ + path = realpath (symlink, NULL); + if (!path) { + g_set_error (error, BD_UTILS_DEV_UTILS_ERROR, BD_UTILS_DEV_UTILS_ERROR_FAILED, + "Failed to resolve '%s': %s", dev_spec, strerror_l (errno, _C_LOCALE)); + return NULL; + } + } else if (g_str_has_prefix (symlink, "../")) path = g_strdup_printf ("/dev/%s", symlink + 3); else path = g_strdup_printf ("/dev/%s", symlink); diff --git a/tests/utils_test.py b/tests/utils_test.py index b1756aee4..32a6aa6e1 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -468,6 +468,13 @@ def test_resolve_device(self): # should resolve the other symlink even without the "/dev" prefix self.assertEqual(BlockDev.utils_resolve_device(dev_link2[5:]), dev_node) + # should resolve a symlink with an absolute target + abs_link = "/dev/utilsTestAbsoluteLink" + os.symlink(dev_node, abs_link) + self.addCleanup(os.unlink, abs_link) + self.assertEqual(BlockDev.utils_resolve_device(abs_link), dev_node) + self.assertEqual(BlockDev.utils_resolve_device(abs_link[5:]), dev_node) + # vg is not a block device, shouldn't be resolved with self.assertRaisesRegex(GLib.GError, "not a block device"): BlockDev.utils_resolve_device("/dev/utilsTestVG")