From a6714295d78e6e7189e79f2ea2562250294e3308 Mon Sep 17 00:00:00 2001 From: Chen Benjamin Date: Sun, 10 Mar 2024 19:17:26 +0200 Subject: [PATCH] Device number parsing: Handle decimal/hexadecimal representations The device number (major:minor) is being represented in different bases across different sources: - procfs `maps`: hexadecimal - procfs `mountinfo`: decimal - sysfs `block/dev`: decimal This commit handles parsing of these different representations. Changes: - Explicitly setting the wanted base for each parsing flow - Added UT case to cover the new functionality --- include/pfs/parsers/common.hpp | 3 ++- src/block.cpp | 2 +- src/parsers/common.cpp | 6 +++--- src/parsers/maps.cpp | 2 +- src/parsers/mountinfo.cpp | 2 +- test/test_common.cpp | 14 +++++++++++--- test/test_maps.cpp | 2 +- test/test_mountinfo.cpp | 4 ++-- test/test_utils.hpp | 8 +++++--- 9 files changed, 27 insertions(+), 16 deletions(-) diff --git a/include/pfs/parsers/common.hpp b/include/pfs/parsers/common.hpp index f2818ce..4fc2a81 100644 --- a/include/pfs/parsers/common.hpp +++ b/include/pfs/parsers/common.hpp @@ -20,12 +20,13 @@ #include #include "pfs/types.hpp" +#include "pfs/utils.hpp" namespace pfs { namespace impl { namespace parsers { -dev_t parse_device(const std::string& device_str); +dev_t parse_device(const std::string& device_str, utils::base base); task_state parse_task_state(char state_char); diff --git a/src/block.cpp b/src/block.cpp index 806b2a6..db3bd6c 100644 --- a/src/block.cpp +++ b/src/block.cpp @@ -71,7 +71,7 @@ dev_t block::get_dev() const auto path = _block_root + DEV_FILE; auto line = utils::readline(path); - return parsers::parse_device(line); + return parsers::parse_device(line, utils::base::decimal); } block_stat block::get_stat() const diff --git a/src/parsers/common.cpp b/src/parsers/common.cpp index 6cdc0aa..fb77568 100644 --- a/src/parsers/common.cpp +++ b/src/parsers/common.cpp @@ -24,7 +24,7 @@ namespace pfs { namespace impl { namespace parsers { -dev_t parse_device(const std::string& device_str) +dev_t parse_device(const std::string& device_str, utils::base base) { // Device format must be ':' @@ -47,10 +47,10 @@ dev_t parse_device(const std::string& device_str) try { int major; - utils::stot(tokens[MAJOR], major, utils::base::hex); + utils::stot(tokens[MAJOR], major, base); int minor; - utils::stot(tokens[MINOR], minor, utils::base::hex); + utils::stot(tokens[MINOR], minor, base); return MKDEV(major, minor); } diff --git a/src/parsers/maps.cpp b/src/parsers/maps.cpp index b72f7eb..770d695 100644 --- a/src/parsers/maps.cpp +++ b/src/parsers/maps.cpp @@ -181,7 +181,7 @@ mem_region parse_maps_line(const std::string& line) region.offset = parse_mem_region_offset(tokens[OFFSET]); - region.device = parse_device(tokens[DEVICE]); + region.device = parse_device(tokens[DEVICE], utils::base::hex); region.inode = parse_mem_region_inode(tokens[INODE]); diff --git a/src/parsers/mountinfo.cpp b/src/parsers/mountinfo.cpp index e09856a..1e044c6 100644 --- a/src/parsers/mountinfo.cpp +++ b/src/parsers/mountinfo.cpp @@ -75,7 +75,7 @@ mount parse_mountinfo_line(const std::string& line) utils::stot(tokens[MOUNT_ID], mnt.id); utils::stot(tokens[PARENT_ID], mnt.parent_id); - mnt.device = parse_device(tokens[DEVICE]); + mnt.device = parse_device(tokens[DEVICE], utils::base::decimal); mnt.root = tokens[ROOT]; mnt.point = tokens[MOUNT_POINT]; diff --git a/test/test_common.cpp b/test/test_common.cpp index e34018a..c7fe781 100644 --- a/test/test_common.cpp +++ b/test/test_common.cpp @@ -1,6 +1,9 @@ +#include + #include "catch.hpp" #include "test_utils.hpp" +#include "pfs/utils.hpp" #include "pfs/parser_error.hpp" #include "pfs/parsers/common.hpp" @@ -25,16 +28,21 @@ TEST_CASE("Parse task state", "[common][state]") TEST_CASE("Parse device", "[common][device]") { + using base = pfs::impl::utils::base; + dev_t dev; SECTION("Zero") { dev = 0x00; } SECTION("Random") { dev = generate_random(); } - auto device_str = build_device_string(dev); - INFO(device_str); + auto device_hex_str = build_hex_device_string(major(dev), minor(dev)); + INFO("Device (hexadecimal representation): " << device_hex_str); + REQUIRE(parse_device(device_hex_str, base::hex) == dev); - REQUIRE(parse_device(device_str) == dev); + auto device_dec_str = build_dec_device_string(major(dev), minor(dev)); + INFO("Device (decimal representation): " << device_dec_str); + REQUIRE(parse_device(device_dec_str, base::decimal) == dev); } TEST_CASE("Parse uid_map", "[common][uid_map]") diff --git a/test/test_maps.cpp b/test/test_maps.cpp index e24c410..b37ac8e 100644 --- a/test/test_maps.cpp +++ b/test/test_maps.cpp @@ -173,7 +173,7 @@ TEST_CASE("Parse maps", "[task][maps]") out << (is_private ? 'p' : 's'); out << " "; out << std::setfill('0') << std::setw(8) << offset << " "; - out << build_device_string(dev_major, dev_minor) << " "; + out << build_hex_device_string(dev_major, dev_minor) << " "; out << inode << " "; while (out.tellp() == 73) out << " "; diff --git a/test/test_mountinfo.cpp b/test/test_mountinfo.cpp index c9762b6..edc5b6a 100644 --- a/test/test_mountinfo.cpp +++ b/test/test_mountinfo.cpp @@ -18,7 +18,7 @@ TEST_CASE("Parse mountinfo", "[task][mountinfo]") expected.id = 27; expected.parent_id = 0; - expected.device = MKDEV(0x253, 0x00); + expected.device = MKDEV(253, 0); expected.root = "/"; expected.point = "/"; expected.options = {"rw", "relatime"}; @@ -37,7 +37,7 @@ TEST_CASE("Parse mountinfo", "[task][mountinfo]") expected.id = 46; expected.parent_id = 22; - expected.device = MKDEV(0x00, 0x41); + expected.device = MKDEV(0, 41); expected.root = "/"; expected.point = "/proc/sys/fs/binfmt_misc"; expected.options = {"rw", "relatime"}; diff --git a/test/test_utils.hpp b/test/test_utils.hpp index 0012128..9773df2 100644 --- a/test/test_utils.hpp +++ b/test/test_utils.hpp @@ -30,16 +30,18 @@ inline T generate_random() return dist(rd); } -inline std::string build_device_string(dev_t dev_major, dev_t dev_minor) +inline std::string build_hex_device_string(dev_t dev_major, dev_t dev_minor) { std::ostringstream out; out << std::hex << dev_major << ":" << dev_minor; return out.str(); } -inline std::string build_device_string(dev_t dev) +inline std::string build_dec_device_string(dev_t dev_major, dev_t dev_minor) { - return build_device_string(MAJOR(dev), MINOR(dev)); + std::ostringstream out; + out << dev_major << ":" << dev_minor; + return out.str(); } inline std::string create_temp_file(const std::vector& lines)