From ed8146ce17deaf7325d569abcc4923b63a3e1ba3 Mon Sep 17 00:00:00 2001 From: Sanket Jadhav Date: Mon, 27 Jul 2026 05:07:16 +0000 Subject: [PATCH] Fix LVM device name parsing for escaped hyphens Signed-off-by: Sanket Jadhav --- snapper/LvmUtils.cc | 55 ++++++++++++++++++++++++++++++++++++++---- testsuite/lvm-utils.cc | 14 +++++++++++ 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/snapper/LvmUtils.cc b/snapper/LvmUtils.cc index 959a078f..bfcc4102 100644 --- a/snapper/LvmUtils.cc +++ b/snapper/LvmUtils.cc @@ -37,15 +37,60 @@ namespace snapper pair split_device_name(const string& name) { - static const std::regex rx(DEV_MAPPER_DIR "/(.*[^-])-([^-].*)", std::regex::extended); - std::smatch match; + // Device mapper uses /dev/mapper/- format where + // hyphens in names are escaped as "--" and a single "-" separates VG/LV. + // Parse the name left-to-right, treating "--" as an escaped hyphen and the + // first standalone "-" as the VG/LV separator. - if (!regex_match(name, match, rx)) + const string prefix = DEV_MAPPER_DIR "/"; + + if (!boost::starts_with(name, prefix)) throw std::runtime_error("failed to split device name into volume group and " "logical volume name"); - string vg_name = boost::replace_all_copy(match[1].str(), "--", "-"); - string lv_name = boost::replace_all_copy(match[2].str(), "--", "-"); + const string basename = name.substr(prefix.length()); + string vg_name, lv_name; + size_t i = 0; + + while (i < basename.length()) + { + if (basename[i] == '-') + { + if (i + 1 < basename.length() && basename[i + 1] == '-') + { + vg_name += '-'; + i += 2; + } + else + { + i++; + break; + } + } + else + { + vg_name += basename[i]; + i++; + } + } + + while (i < basename.length()) + { + if (basename[i] == '-' && i + 1 < basename.length() && basename[i + 1] == '-') + { + lv_name += '-'; + i += 2; + } + else + { + lv_name += basename[i]; + i++; + } + } + + if (vg_name.empty() || lv_name.empty()) + throw std::runtime_error("failed to split device name into volume group and " + "logical volume name"); return make_pair(vg_name, lv_name); } diff --git a/testsuite/lvm-utils.cc b/testsuite/lvm-utils.cc index ed4360da..65518ff4 100644 --- a/testsuite/lvm-utils.cc +++ b/testsuite/lvm-utils.cc @@ -22,4 +22,18 @@ BOOST_AUTO_TEST_CASE(split_device_name) std::pair n3 = LvmUtils::split_device_name("/dev/mapper/s-r"); BOOST_CHECK_EQUAL(n3.first, "s"); BOOST_CHECK_EQUAL(n3.second, "r"); + + // Regression tests for escaped hyphens. + + std::pair n4 = LvmUtils::split_device_name("/dev/mapper/vg---root"); + BOOST_CHECK_EQUAL(n4.first, "vg-"); + BOOST_CHECK_EQUAL(n4.second, "root"); + + std::pair n5 = LvmUtils::split_device_name("/dev/mapper/vg---lv--"); + BOOST_CHECK_EQUAL(n5.first, "vg-"); + BOOST_CHECK_EQUAL(n5.second, "lv-"); + + std::pair n6 = LvmUtils::split_device_name("/dev/mapper/a---b"); + BOOST_CHECK_EQUAL(n6.first, "a-"); + BOOST_CHECK_EQUAL(n6.second, "b"); } -- 2.47.3