Skip to content

Commit

Permalink
osbuild/device: use systemd-escape like escaping for mountable paths
Browse files Browse the repository at this point in the history
Previously, the function used to escape filesystem paths of mountable
entities, which are used as device names, could generate the same name
for different devices. Specifically, it returned `root` as the device
name for entity with `/` and `/root` mount point. This results in
invalid osbuild manifests being generated.

Rework the escaping function by implementing a similar escaping
algorithm as used by systemd-escape, which will ensure that we always
generate a unique device name for devices with different mountpoints,
while still generating the same device name for the same device (with
the same mountponit path).

Signed-off-by: Tomáš Hozza <[email protected]>
  • Loading branch information
thozza authored and achilleas-k committed Nov 3, 2023
1 parent 430cb77 commit 960e802
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 6 deletions.
21 changes: 15 additions & 6 deletions pkg/osbuild/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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, "/", "-")
}
26 changes: 26 additions & 0 deletions pkg/osbuild/device_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
})
}
}

0 comments on commit 960e802

Please sign in to comment.