]> git.ipfire.org Git - thirdparty/snapper.git/commitdiff
Fix LVM device name parsing for escaped hyphens 1172/head
authorSanket Jadhav <sj546400@gmail.com>
Mon, 27 Jul 2026 05:07:16 +0000 (05:07 +0000)
committerSanket Jadhav <sj546400@gmail.com>
Mon, 27 Jul 2026 10:07:58 +0000 (10:07 +0000)
Signed-off-by: Sanket Jadhav <sj546400@gmail.com>
snapper/LvmUtils.cc
testsuite/lvm-utils.cc

index 959a078f4527b30c289c78e909c00aeff7a7dcbf..bfcc4102fab2bde9e613e6def3c63889c8ff143a 100644 (file)
@@ -37,15 +37,60 @@ namespace snapper
        pair<string, string>
        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/<vg_name>-<lv_name> 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);
        }
index ed4360da8339a767fc728276cd51de132ebd82db..65518ff49d18ec68ab160f9ac148b2d22bda2de1 100644 (file)
@@ -22,4 +22,18 @@ BOOST_AUTO_TEST_CASE(split_device_name)
     std::pair<string, string> 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<string, string> n4 = LvmUtils::split_device_name("/dev/mapper/vg---root");
+    BOOST_CHECK_EQUAL(n4.first, "vg-");
+    BOOST_CHECK_EQUAL(n4.second, "root");
+
+    std::pair<string, string> n5 = LvmUtils::split_device_name("/dev/mapper/vg---lv--");
+    BOOST_CHECK_EQUAL(n5.first, "vg-");
+    BOOST_CHECK_EQUAL(n5.second, "lv-");
+
+    std::pair<string, string> n6 = LvmUtils::split_device_name("/dev/mapper/a---b");
+    BOOST_CHECK_EQUAL(n6.first, "a-");
+    BOOST_CHECK_EQUAL(n6.second, "b");
 }