diff --git a/src/lib/plugin_apis/dm.api b/src/lib/plugin_apis/dm.api index c8807e35..469fe5a1 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 3b704d5f..2c90d73a 100644 --- a/src/plugins/dm.c +++ b/src/plugins/dm.c @@ -18,6 +18,7 @@ */ #include +#include #include #include #include @@ -236,17 +237,67 @@ 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 */ + if (geteuid () != 0) { + g_set_error (error, BD_DM_ERROR, BD_DM_ERROR_NOT_ROOT, + "Not running as root, cannot query DM device"); return NULL; + } + + 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 9455c402..f009dbfd 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 537bab3c..0ef3f7bf 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,38 @@ 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) + + # 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): @@ -83,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): @@ -115,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""" @@ -125,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):