From f2eadd39e1a02320ba1dbf09586686286d30fb77 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 9 Jan 2026 12:17:07 +0100 Subject: [PATCH 1/3] dm: Use libdevmapper instead of dmsetup to get subsystem from name --- src/lib/plugin_apis/dm.api | 1 + src/plugins/dm.c | 61 +++++++++++++++++++++++++++++++++----- src/plugins/dm.h | 1 + tests/dm_test.py | 25 ++++++++++++++++ 4 files changed, 80 insertions(+), 8 deletions(-) diff --git a/src/lib/plugin_apis/dm.api b/src/lib/plugin_apis/dm.api index c8807e356..469fe5a19 100644 --- a/src/lib/plugin_apis/dm.api +++ b/src/lib/plugin_apis/dm.api @@ -17,6 +17,7 @@ typedef enum { BD_DM_ERROR_RAID_FAIL, BD_DM_ERROR_RAID_NO_DEVS, BD_DM_ERROR_RAID_NO_EXIST, + BD_DM_ERROR_DEVICE_NOEXIST, } BDDMError; typedef enum { diff --git a/src/plugins/dm.c b/src/plugins/dm.c index 3b704d5f0..18024e4f7 100644 --- a/src/plugins/dm.c +++ b/src/plugins/dm.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -236,17 +237,61 @@ gchar* bd_dm_node_from_name (const gchar *map_name, GError **error) { * Tech category: %BD_DM_TECH_MAP-%BD_DM_TECH_MODE_QUERY */ gchar* bd_dm_get_subsystem_from_name (const gchar *device_name, GError **error) { - gchar *output = NULL; - gboolean success = FALSE; - const gchar *argv[] = {"dmsetup", "info", "-co", "subsystem", "--noheadings", device_name, NULL}; + struct dm_task *task = NULL; + struct dm_info info; + const gchar *uuid = NULL; + gchar *subsystem = NULL; + gchar *hyphen_pos = NULL; - success = bd_utils_exec_and_capture_output (argv, NULL, &output, error); - if (!success) - /* error is already populated */ + task = dm_task_create (DM_DEVICE_INFO); + if (!task) { + g_set_error (error, BD_DM_ERROR, BD_DM_ERROR_TASK, + "Failed to create DM task"); + return NULL; + } + + if (!dm_task_set_name (task, device_name)) { + g_set_error (error, BD_DM_ERROR, BD_DM_ERROR_TASK, + "Failed to set device name for DM task"); + dm_task_destroy (task); + return NULL; + } + + if (!dm_task_run (task)) { + g_set_error (error, BD_DM_ERROR, BD_DM_ERROR_TASK, + "Failed to run DM task"); + dm_task_destroy (task); + return NULL; + } + + if (!dm_task_get_info (task, &info)) { + g_set_error (error, BD_DM_ERROR, BD_DM_ERROR_TASK, + "Failed to get info from DM task"); + dm_task_destroy (task); + return NULL; + } + + if (!info.exists) { + g_set_error (error, BD_DM_ERROR, BD_DM_ERROR_DEVICE_NOEXIST, + "DM device %s does not exist", device_name); + dm_task_destroy (task); return NULL; + } + + uuid = dm_task_get_uuid (task); + if (!uuid || !(*uuid)) { + dm_task_destroy (task); + return g_strdup (""); + } + + hyphen_pos = strchr (uuid, '-'); + if (hyphen_pos) + subsystem = g_strndup (uuid, hyphen_pos - uuid); + else + subsystem = g_strdup (""); - output = g_strstrip (output); - return output; + dm_task_destroy (task); + return subsystem; } /** diff --git a/src/plugins/dm.h b/src/plugins/dm.h index 9455c4024..f009dbfd2 100644 --- a/src/plugins/dm.h +++ b/src/plugins/dm.h @@ -13,6 +13,7 @@ typedef enum { BD_DM_ERROR_RAID_FAIL, BD_DM_ERROR_RAID_NO_DEVS, BD_DM_ERROR_RAID_NO_EXIST, + BD_DM_ERROR_DEVICE_NOEXIST, } BDDMError; typedef enum { diff --git a/tests/dm_test.py b/tests/dm_test.py index 537bab3c1..fe9fa8a2e 100644 --- a/tests/dm_test.py +++ b/tests/dm_test.py @@ -76,6 +76,31 @@ def test_get_subsystem_from_name_crypt(self): subsystem = BlockDev.dm_get_subsystem_from_name("libbd_dm_tests-subsystem_crypt") self.assertEqual(subsystem, "CRYPT") + def test_get_subsystem_from_name_linear(self): + succ = BlockDev.dm_create_linear("testMap", self.loop_dev, 100, None) + self.assertTrue(succ) + + # no UUID -- subsystem should be empty + subsystem = BlockDev.dm_get_subsystem_from_name("testMap") + self.assertEqual(subsystem, "") + + succ = BlockDev.dm_remove("testMap") + self.assertTrue(succ) + + # "UUID" without "prefix" -- subsystem should be empty + succ = BlockDev.dm_create_linear("testMap", self.loop_dev, 100, "TEST") + self.assertTrue(succ) + + subsystem = BlockDev.dm_get_subsystem_from_name("testMap") + self.assertEqual(subsystem, "") + + succ = BlockDev.dm_remove("testMap") + self.assertTrue(succ) + + # non-existing device --> error + with self.assertRaisesRegex(GLib.GError, "does not exist"): + BlockDev.dm_get_subsystem_from_name("testMap") + class DevMapperCreateRemoveLinear(DevMapperTestCase): @tag_test(TestTags.CORE) def test_create_remove_linear(self): From bdbbc996351969999678e82d5a15d81785bd5392 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Fri, 9 Jan 2026 12:36:22 +0100 Subject: [PATCH 2/3] tests: Various improvements in DM tests Faster pbkdf when creating LUKS device for testing, reducing number of test cases and adding some additional checks. --- tests/dm_test.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tests/dm_test.py b/tests/dm_test.py index fe9fa8a2e..0ef3f7bf2 100644 --- a/tests/dm_test.py +++ b/tests/dm_test.py @@ -22,10 +22,6 @@ def setUpClass(cls): else: BlockDev.reinit(cls.requested_plugins, True, None) -class DevMapperPluginVersionCase(DevMapperTest): - @tag_test(TestTags.NOSTORAGE) - def test_plugin_version(self): - self.assertEqual(BlockDev.get_plugin_soname(BlockDev.Plugin.DM), "libbd_dm.so.3") class DevMapperTestCase(DevMapperTest): @@ -51,6 +47,7 @@ def _clean_up(self): os.unlink(self.dev_file) + class DevMapperGetSubsystemFromName(DevMapperTestCase): def _destroy_lvm(self): run("vgremove --yes libbd_dm_tests --config \"devices {use_devicesfile = 0}\" >/dev/null 2>&1") @@ -71,11 +68,12 @@ def test_get_subsystem_from_name_lvm(self): def test_get_subsystem_from_name_crypt(self): """Verify that it is possible to get luks device subsystem from its name""" self.addCleanup(self._destroy_crypt) - run("echo \"supersecretkey\" | cryptsetup luksFormat %s -" %self.loop_dev) + run("echo \"supersecretkey\" | cryptsetup luksFormat --pbkdf=pbkdf2 --pbkdf-force-iterations=1000 %s -" %self.loop_dev) run("echo \"supersecretkey\" | cryptsetup open %s libbd_dm_tests-subsystem_crypt --key-file=-" %self.loop_dev) subsystem = BlockDev.dm_get_subsystem_from_name("libbd_dm_tests-subsystem_crypt") self.assertEqual(subsystem, "CRYPT") + def test_get_subsystem_from_name_linear(self): succ = BlockDev.dm_create_linear("testMap", self.loop_dev, 100, None) self.assertTrue(succ) @@ -101,6 +99,7 @@ def test_get_subsystem_from_name_linear(self): with self.assertRaisesRegex(GLib.GError, "does not exist"): BlockDev.dm_get_subsystem_from_name("testMap") + class DevMapperCreateRemoveLinear(DevMapperTestCase): @tag_test(TestTags.CORE) def test_create_remove_linear(self): @@ -108,9 +107,12 @@ def test_create_remove_linear(self): succ = BlockDev.dm_create_linear("testMap", self.loop_dev, 100, None) self.assertTrue(succ) + self.assertTrue(os.path.exists("/dev/mapper/testMap")) succ = BlockDev.dm_remove("testMap") self.assertTrue(succ) + self.assertFalse(os.path.exists("/dev/mapper/testMap")) + class DevMapperMapExists(DevMapperTestCase): def test_map_exists(self): @@ -140,6 +142,7 @@ def test_map_exists(self): succ = BlockDev.dm_map_exists("testMap", False, False) self.assertFalse(succ) + class DevMapperNameNodeBijection(DevMapperTestCase): def test_name_node_bijection(self): """Verify that the map's node and map name points to each other""" @@ -150,9 +153,11 @@ def test_name_node_bijection(self): self.assertEqual(BlockDev.dm_name_from_node(BlockDev.dm_node_from_name("testMap")), "testMap") - self.assertTrue(succ) -class DMDepsTest(DevMapperTest): +class DMNoStorageTest(DevMapperTest): + @tag_test(TestTags.NOSTORAGE) + def test_plugin_version(self): + self.assertEqual(BlockDev.get_plugin_soname(BlockDev.Plugin.DM), "libbd_dm.so.3") @tag_test(TestTags.NOSTORAGE) def test_missing_dependencies(self): From 80ba38c1fa183b1fb19dd43cd4496df1cdaa2a39 Mon Sep 17 00:00:00 2001 From: Vojtech Trefny Date: Tue, 13 Jan 2026 13:38:49 +0100 Subject: [PATCH 3/3] dm: Remove root permission check in bd_dm_map_exists Checking only EUID is not enough and we don't really support running without root privileges. If someone tries to run this function as non-root, the first dm_task_create will fail and the reason is logged, so that should be good enough. --- src/plugins/dm.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/plugins/dm.c b/src/plugins/dm.c index 18024e4f7..b88afa1c3 100644 --- a/src/plugins/dm.c +++ b/src/plugins/dm.c @@ -315,12 +315,6 @@ gboolean bd_dm_map_exists (const gchar *map_name, gboolean live_only, gboolean a guint64 next = 0; gboolean ret = FALSE; - if (geteuid () != 0) { - g_set_error (error, BD_DM_ERROR, BD_DM_ERROR_NOT_ROOT, - "Not running as root, cannot query DM maps"); - return FALSE; - } - task_list = dm_task_create (DM_DEVICE_LIST); if (!task_list) { g_set_error (error, BD_DM_ERROR, BD_DM_ERROR_TASK,