Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/lib/plugin_apis/dm.api
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
67 changes: 59 additions & 8 deletions src/plugins/dm.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

#include <glib.h>
#include <string.h>
#include <unistd.h>
#include <blockdev/utils.h>
#include <libdevmapper.h>
Expand Down Expand Up @@ -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;
}

/**
Expand Down
1 change: 1 addition & 0 deletions src/plugins/dm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
44 changes: 37 additions & 7 deletions tests/dm_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):

Expand All @@ -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")
Expand All @@ -71,21 +68,51 @@ 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):
"""Verify that it is possible to create new linear mapping and remove it"""

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):
Expand Down Expand Up @@ -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"""
Expand All @@ -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):
Expand Down