diff --git a/pkg/osbuild/device.go b/pkg/osbuild/device.go index b2e43c4e76..feba2c8342 100644 --- a/pkg/osbuild/device.go +++ b/pkg/osbuild/device.go @@ -153,7 +153,7 @@ func deviceName(p disk.Entity) string { switch payload := p.(type) { case disk.Mountable: - return pathdot(payload.GetMountpoint()) + return pathEscape(payload.GetMountpoint()) case *disk.LUKSContainer: return "luks-" + payload.UUID[:4] case *disk.LVMVolumeGroup: @@ -206,12 +206,21 @@ func getDevices(path []disk.Entity, filename string, lockLoopback bool) (map[str return do, parent } -func pathdot(path string) string { - if path == "/" { - return "root" +// pathEscape implements similar path escaping as used by systemd-escape +// https://github.com/systemd/systemd/blob/c57ff6230e4e199d40f35a356e834ba99f3f8420/src/basic/unit-name.c#L389 +func pathEscape(path string) string { + if len(path) == 0 || path == "/" { + return "-" } - path = strings.TrimLeft(path, "/") + path = strings.Trim(path, "/") - return strings.ReplaceAll(path, "/", ".") + escapeChars := func(s, char string) string { + return strings.ReplaceAll(s, char, fmt.Sprintf("\\x%x", char[0])) + } + + path = escapeChars(path, "\\") + path = escapeChars(path, "-") + + return strings.ReplaceAll(path, "/", "-") } diff --git a/pkg/osbuild/device_test.go b/pkg/osbuild/device_test.go index 0f40da20eb..f2348f09b9 100644 --- a/pkg/osbuild/device_test.go +++ b/pkg/osbuild/device_test.go @@ -140,3 +140,29 @@ func TestGenDeviceFinishStagesOrderWithLVMClevisBind(t *testing.T) { // followed by "org.osbuild.luks2.remove-key" assert.Equal("org.osbuild.luks2.remove-key", luks.Type) } + +func TestPathEscape(t *testing.T) { + testCases := []struct { + path string + expected string + }{ + {"", "-"}, + {"/", "-"}, + {"/root", "root"}, + {"/root/", "root"}, + {"/home/shadowman", "home-shadowman"}, + {"/home/s.o.s", "home-s.o.s"}, + {"/path/to/dir", "path-to-dir"}, + {"/path/with\\backslash", "path-with\\x5cbackslash"}, + {"/path-with-dash", "path\\x2dwith\\x2ddash"}, + } + + for _, tc := range testCases { + t.Run(tc.path, func(t *testing.T) { + result := pathEscape(tc.path) + if result != tc.expected { + t.Errorf("pathEscape(%q) = %q; expected %q", tc.path, result, tc.expected) + } + }) + } +}