From da11b26ec16ef9ed61045fdbb03c4090286bfeba Mon Sep 17 00:00:00 2001 From: Ophestra Date: Mon, 4 May 2026 02:07:52 +0900 Subject: [PATCH] container/initoverlay: configure via fsconfig This works around the page size limit at the cost of negligible performance regressions. Closes #34. Signed-off-by: Ophestra --- check/overlay.go | 8 +++++ container/container_test.go | 24 ++++++++----- container/dispatcher.go | 5 +++ container/dispatcher_test.go | 8 +++++ container/initoverlay.go | 52 ++++++++++++++++++++------- container/initoverlay_test.go | 66 +++++++++++++++++------------------ container/path_test.go | 4 --- internal/pkg/testdata/main.go | 36 +++++-------------- test/sandbox/case/device.nix | 4 +-- test/sandbox/case/mapuid.nix | 4 +-- test/sandbox/case/tty.nix | 4 +-- 11 files changed, 124 insertions(+), 91 deletions(-) diff --git a/check/overlay.go b/check/overlay.go index fbbcd1e6..c417e709 100644 --- a/check/overlay.go +++ b/check/overlay.go @@ -4,15 +4,23 @@ import "strings" const ( // SpecialOverlayEscape is the escape string for overlay mount options. + // + // Deprecated: This is no longer used and will be removed in 0.5. SpecialOverlayEscape = `\` // SpecialOverlayOption is the separator string between overlay mount options. + // + // Deprecated: This is no longer used and will be removed in 0.5. SpecialOverlayOption = "," // SpecialOverlayPath is the separator string between overlay paths. + // + // Deprecated: This is no longer used and will be removed in 0.5. SpecialOverlayPath = ":" ) // EscapeOverlayDataSegment escapes a string for formatting into the data // argument of an overlay mount system call. +// +// Deprecated: This is no longer used and will be removed in 0.5. func EscapeOverlayDataSegment(s string) string { if s == "" { return "" diff --git a/container/container_test.go b/container/container_test.go index 41d39f68..1bdc28a1 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -16,6 +16,7 @@ import ( "strings" "syscall" "testing" + _ "unsafe" // for go:linkname "hakurei.app/check" "hakurei.app/command" @@ -233,6 +234,9 @@ func earlyMnt(mnt ...*vfs.MountInfoEntry) func(*testing.T, context.Context) []*v return func(*testing.T, context.Context) []*vfs.MountInfoEntry { return mnt } } +//go:linkname toHost hakurei.app/container.toHost +func toHost(name string) string + var containerTestCases = []struct { name string filter bool @@ -332,13 +336,15 @@ var containerTestCases = []struct { func(t *testing.T, ctx context.Context) []*vfs.MountInfoEntry { return []*vfs.MountInfoEntry{ ent("/", hst.PrivateTmp, "rw", "overlay", "overlay", - "rw,lowerdir="+ - container.InternalToHostOvlEscape(ctx.Value(testVal("lower0")).(*check.Absolute).String())+":"+ - container.InternalToHostOvlEscape(ctx.Value(testVal("lower1")).(*check.Absolute).String())+ + "rw"+ + ",lowerdir+="+ + toHost(ctx.Value(testVal("lower0")).(*check.Absolute).String())+ + ",lowerdir+="+ + toHost(ctx.Value(testVal("lower1")).(*check.Absolute).String())+ ",upperdir="+ - container.InternalToHostOvlEscape(ctx.Value(testVal("upper")).(*check.Absolute).String())+ + toHost(ctx.Value(testVal("upper")).(*check.Absolute).String())+ ",workdir="+ - container.InternalToHostOvlEscape(ctx.Value(testVal("work")).(*check.Absolute).String())+ + toHost(ctx.Value(testVal("work")).(*check.Absolute).String())+ ",redirect_dir=nofollow,uuid=on,userxattr"), } }, @@ -388,9 +394,11 @@ var containerTestCases = []struct { func(t *testing.T, ctx context.Context) []*vfs.MountInfoEntry { return []*vfs.MountInfoEntry{ ent("/", hst.PrivateTmp, "rw", "overlay", "overlay", - "ro,lowerdir="+ - container.InternalToHostOvlEscape(ctx.Value(testVal("lower0")).(*check.Absolute).String())+":"+ - container.InternalToHostOvlEscape(ctx.Value(testVal("lower1")).(*check.Absolute).String())+ + "ro"+ + ",lowerdir+="+ + toHost(ctx.Value(testVal("lower0")).(*check.Absolute).String())+ + ",lowerdir+="+ + toHost(ctx.Value(testVal("lower1")).(*check.Absolute).String())+ ",redirect_dir=nofollow,userxattr"), } }, diff --git a/container/dispatcher.go b/container/dispatcher.go index e583dc21..4636a469 100644 --- a/container/dispatcher.go +++ b/container/dispatcher.go @@ -65,6 +65,8 @@ type syscallDispatcher interface { remount(msg message.Msg, target string, flags uintptr) error // mountTmpfs provides mountTmpfs. mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error + // mountOverlay provides mountOverlay. + mountOverlay(target string, options [][2]string) error // ensureFile provides ensureFile. ensureFile(name string, perm, pperm os.FileMode) error // mustLoopback provides mustLoopback. @@ -169,6 +171,9 @@ func (direct) remount(msg message.Msg, target string, flags uintptr) error { func (k direct) mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error { return mountTmpfs(k, fsname, target, flags, size, perm) } +func (k direct) mountOverlay(target string, options [][2]string) error { + return mountOverlay(target, options) +} func (direct) ensureFile(name string, perm, pperm os.FileMode) error { return ensureFile(name, perm, pperm) } diff --git a/container/dispatcher_test.go b/container/dispatcher_test.go index c8a7b492..49631854 100644 --- a/container/dispatcher_test.go +++ b/container/dispatcher_test.go @@ -468,6 +468,14 @@ func (k *kstub) mountTmpfs(fsname, target string, flags uintptr, size int, perm stub.CheckArg(k.Stub, "perm", perm, 4)) } +func (k *kstub) mountOverlay(target string, options [][2]string) error { + k.Helper() + return k.Expects("mountOverlay").Error( + stub.CheckArg(k.Stub, "target", target, 0), + stub.CheckArgReflect(k.Stub, "options", options, 1), + ) +} + func (k *kstub) ensureFile(name string, perm, pperm os.FileMode) error { k.Helper() return k.Expects("ensureFile").Error( diff --git a/container/initoverlay.go b/container/initoverlay.go index 910ce425..e4cb0f5a 100644 --- a/container/initoverlay.go +++ b/container/initoverlay.go @@ -4,9 +4,9 @@ import ( "encoding/gob" "fmt" "slices" - "strings" "hakurei.app/check" + "hakurei.app/ext" "hakurei.app/fhs" ) @@ -150,7 +150,7 @@ func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error { if v, err := k.evalSymlinks(o.Upper.String()); err != nil { return err } else { - o.upper = check.EscapeOverlayDataSegment(toHost(v)) + o.upper = toHost(v) } } @@ -158,7 +158,7 @@ func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error { if v, err := k.evalSymlinks(o.Work.String()); err != nil { return err } else { - o.work = check.EscapeOverlayDataSegment(toHost(v)) + o.work = toHost(v) } } } @@ -168,12 +168,39 @@ func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error { if v, err := k.evalSymlinks(a.String()); err != nil { return err } else { - o.lower[i] = check.EscapeOverlayDataSegment(toHost(v)) + o.lower[i] = toHost(v) } } return nil } +// mountOverlay sets up an overlay mount via [ext.FS]. +func mountOverlay(target string, options [][2]string) error { + fs, err := ext.OpenFS(SourceOverlay, 0) + if err != nil { + return err + } + if err = fs.SetString("source", SourceOverlay); err != nil { + _ = fs.Close() + return err + } + for _, option := range options { + if err = fs.SetString(option[0], option[1]); err != nil { + _ = fs.Close() + return err + } + } + if err = fs.SetFlag(OptionOverlayUserxattr); err != nil { + _ = fs.Close() + return err + } + if err = fs.Mount(target, 0); err != nil { + _ = fs.Close() + return err + } + return fs.Close() +} + func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error { target := o.Target.String() if !o.noPrefix { @@ -194,7 +221,7 @@ func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error { } } - options := make([]string, 0, 4) + options := make([][2]string, 0, 2+len(o.lower)) if o.upper == zeroString && o.work == zeroString { // readonly if len(o.Lower) < 2 { @@ -205,15 +232,16 @@ func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error { if len(o.Lower) == 0 { return &OverlayArgumentError{OverlayEmptyLower, zeroString} } - options = append(options, - OptionOverlayUpperdir+"="+o.upper, - OptionOverlayWorkdir+"="+o.work) + options = append(options, [][2]string{ + {OptionOverlayUpperdir, o.upper}, + {OptionOverlayWorkdir, o.work}, + }...) + } + for _, lower := range o.lower { + options = append(options, [2]string{OptionOverlayLowerdir + "+", lower}) } - options = append(options, - OptionOverlayLowerdir+"="+strings.Join(o.lower, check.SpecialOverlayPath), - OptionOverlayUserxattr) - return k.mount(SourceOverlay, target, FstypeOverlay, 0, strings.Join(options, check.SpecialOverlayOption)) + return k.mountOverlay(target, options) } func (o *MountOverlayOp) late(*setupState, syscallDispatcher) error { return nil } diff --git a/container/initoverlay_test.go b/container/initoverlay_test.go index 30dd3237..f0cde7ff 100644 --- a/container/initoverlay_test.go +++ b/container/initoverlay_test.go @@ -97,13 +97,12 @@ func TestMountOverlayOp(t *testing.T) { call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0705)}, nil, nil), call("mkdirTemp", stub.ExpectArgs{"/", "overlay.upper.*"}, "overlay.upper.32768", nil), call("mkdirTemp", stub.ExpectArgs{"/", "overlay.work.*"}, "overlay.work.32768", nil), - call("mount", stub.ExpectArgs{"overlay", "/sysroot", "overlay", uintptr(0), "" + - "upperdir=overlay.upper.32768," + - "workdir=overlay.work.32768," + - "lowerdir=" + - `/host/var/lib/planterette/base/debian\:f92c9052:` + - `/host/var/lib/planterette/app/org.chromium.Chromium@debian\:f92c9052,` + - "userxattr"}, nil, nil), + call("mountOverlay", stub.ExpectArgs{"/sysroot", [][2]string{ + {"upperdir", "overlay.upper.32768"}, + {"workdir", "overlay.work.32768"}, + {"lowerdir+", `/host/var/lib/planterette/base/debian:f92c9052`}, + {"lowerdir+", `/host/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052`}, + }}, nil, nil), }, nil}, {"short lower ro", &Params{ParentPerm: 0755}, &MountOverlayOp{ @@ -129,11 +128,10 @@ func TestMountOverlayOp(t *testing.T) { call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store0"}, "/mnt-root/nix/.ro-store0", nil), }, nil, []stub.Call{ call("mkdirAll", stub.ExpectArgs{"/nix/store", os.FileMode(0755)}, nil, nil), - call("mount", stub.ExpectArgs{"overlay", "/nix/store", "overlay", uintptr(0), "" + - "lowerdir=" + - "/host/mnt-root/nix/.ro-store:" + - "/host/mnt-root/nix/.ro-store0," + - "userxattr"}, nil, nil), + call("mountOverlay", stub.ExpectArgs{"/nix/store", [][2]string{ + {"lowerdir+", "/host/mnt-root/nix/.ro-store"}, + {"lowerdir+", "/host/mnt-root/nix/.ro-store0"}, + }}, nil, nil), }, nil}, {"success ro", &Params{ParentPerm: 0755}, &MountOverlayOp{ @@ -147,11 +145,10 @@ func TestMountOverlayOp(t *testing.T) { call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store0"}, "/mnt-root/nix/.ro-store0", nil), }, nil, []stub.Call{ call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0755)}, nil, nil), - call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" + - "lowerdir=" + - "/host/mnt-root/nix/.ro-store:" + - "/host/mnt-root/nix/.ro-store0," + - "userxattr"}, nil, nil), + call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{ + {"lowerdir+", "/host/mnt-root/nix/.ro-store"}, + {"lowerdir+", "/host/mnt-root/nix/.ro-store0"}, + }}, nil, nil), }, nil}, {"nil lower", &Params{ParentPerm: 0700}, &MountOverlayOp{ @@ -219,7 +216,11 @@ func TestMountOverlayOp(t *testing.T) { call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil), }, nil, []stub.Call{ call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil), - call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "upperdir=/host/mnt-root/nix/.rw-store/.upper,workdir=/host/mnt-root/nix/.rw-store/.work,lowerdir=/host/mnt-root/nix/ro-store,userxattr"}, nil, stub.UniqueError(0)), + call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{ + {"upperdir", "/host/mnt-root/nix/.rw-store/.upper"}, + {"workdir", "/host/mnt-root/nix/.rw-store/.work"}, + {"lowerdir+", "/host/mnt-root/nix/ro-store"}, + }}, nil, stub.UniqueError(0)), }, stub.UniqueError(0)}, {"success single layer", &Params{ParentPerm: 0700}, &MountOverlayOp{ @@ -233,11 +234,11 @@ func TestMountOverlayOp(t *testing.T) { call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil), }, nil, []stub.Call{ call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil), - call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" + - "upperdir=/host/mnt-root/nix/.rw-store/.upper," + - "workdir=/host/mnt-root/nix/.rw-store/.work," + - "lowerdir=/host/mnt-root/nix/ro-store," + - "userxattr"}, nil, nil), + call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{ + {"upperdir", "/host/mnt-root/nix/.rw-store/.upper"}, + {"workdir", "/host/mnt-root/nix/.rw-store/.work"}, + {"lowerdir+", "/host/mnt-root/nix/ro-store"}, + }}, nil, nil), }, nil}, {"success", &Params{ParentPerm: 0700}, &MountOverlayOp{ @@ -261,16 +262,15 @@ func TestMountOverlayOp(t *testing.T) { call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store3"}, "/mnt-root/nix/ro-store3", nil), }, nil, []stub.Call{ call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil), - call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" + - "upperdir=/host/mnt-root/nix/.rw-store/.upper," + - "workdir=/host/mnt-root/nix/.rw-store/.work," + - "lowerdir=" + - "/host/mnt-root/nix/ro-store:" + - "/host/mnt-root/nix/ro-store0:" + - "/host/mnt-root/nix/ro-store1:" + - "/host/mnt-root/nix/ro-store2:" + - "/host/mnt-root/nix/ro-store3," + - "userxattr"}, nil, nil), + call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{ + {"upperdir", "/host/mnt-root/nix/.rw-store/.upper"}, + {"workdir", "/host/mnt-root/nix/.rw-store/.work"}, + {"lowerdir+", "/host/mnt-root/nix/ro-store"}, + {"lowerdir+", "/host/mnt-root/nix/ro-store0"}, + {"lowerdir+", "/host/mnt-root/nix/ro-store1"}, + {"lowerdir+", "/host/mnt-root/nix/ro-store2"}, + {"lowerdir+", "/host/mnt-root/nix/ro-store3"}, + }}, nil, nil), }, nil}, }) diff --git a/container/path_test.go b/container/path_test.go index 03406fb0..85e285e2 100644 --- a/container/path_test.go +++ b/container/path_test.go @@ -10,7 +10,6 @@ import ( "testing" "unsafe" - "hakurei.app/check" "hakurei.app/vfs" ) @@ -50,9 +49,6 @@ func TestToHost(t *testing.T) { } } -// InternalToHostOvlEscape exports toHost passed to [check.EscapeOverlayDataSegment]. -func InternalToHostOvlEscape(s string) string { return check.EscapeOverlayDataSegment(toHost(s)) } - func TestCreateFile(t *testing.T) { t.Run("nonexistent", func(t *testing.T) { t.Run("mkdir", func(t *testing.T) { diff --git a/internal/pkg/testdata/main.go b/internal/pkg/testdata/main.go index f79f7917..564a1736 100644 --- a/internal/pkg/testdata/main.go +++ b/internal/pkg/testdata/main.go @@ -14,7 +14,6 @@ import ( "strconv" "strings" - "hakurei.app/check" "hakurei.app/fhs" "hakurei.app/vfs" ) @@ -159,43 +158,24 @@ func main() { m.Source != "overlay" || m.FsType != "overlay" { log.Fatal("unexpected root mount entry") } - var lowerdir string + var lowerdir []string for _, o := range strings.Split(m.FsOptstr, ",") { - const lowerdirKey = "lowerdir=" + const lowerdirKey = "lowerdir+=" if strings.HasPrefix(o, lowerdirKey) { - lowerdir = o[len(lowerdirKey):] + lowerdir = append(lowerdir, o[len(lowerdirKey):]) } } if !layers { - if filepath.Base(lowerdir) != checksumEmptyDir { + if len(lowerdir) != 1 || filepath.Base(lowerdir[0]) != checksumEmptyDir { log.Fatal("unexpected artifact checksum") } } else { ident = "p1t_drXr34i-jZNuxDMLaMOdL6tZvQqhavNafGynGqxOZoXAUTSn7kqNh3Ovv3DT" - lowerdirsEscaped := strings.Split(lowerdir, ":") - lowerdirs := lowerdirsEscaped[:0] - // ignore the option separator since it does not appear in ident - for i, e := range lowerdirsEscaped { - if len(e) > 0 && - e[len(e)-1] == check.SpecialOverlayEscape[0] && - (len(e) == 1 || e[len(e)-2] != check.SpecialOverlayEscape[0]) { - // ignore escaped pathname separator since it does not - // appear in ident - - e = e[:len(e)-1] - if len(lowerdirsEscaped) != i { - lowerdirsEscaped[i+1] = e + lowerdirsEscaped[i+1] - continue - } - } - lowerdirs = append(lowerdirs, e) - } - - if len(lowerdirs) != 2 || - filepath.Base(lowerdirs[0]) != "MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU" || - filepath.Base(lowerdirs[1]) != "nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK" { - log.Fatalf("unexpected lowerdirs %s", strings.Join(lowerdirs, ", ")) + if len(lowerdir) != 2 || + filepath.Base(lowerdir[0]) != "MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU" || + filepath.Base(lowerdir[1]) != "nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK" { + log.Fatalf("unexpected lowerdirs %s", strings.Join(lowerdir, ", ")) } } } else { diff --git a/test/sandbox/case/device.nix b/test/sandbox/case/device.nix index b9dc4b33..d37768a4 100644 --- a/test/sandbox/case/device.nix +++ b/test/sandbox/case/device.nix @@ -237,8 +237,8 @@ in (ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") (ent "/var/cache" "/var/cache" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") - (ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr") - (ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,userxattr") + (ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr") + (ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,userxattr") (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") (ent "/var/lib/hakurei/u0/a4" "/var/lib/hakurei/u0/a4" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") (ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") diff --git a/test/sandbox/case/mapuid.nix b/test/sandbox/case/mapuid.nix index 8b2a635e..7aa78a9b 100644 --- a/test/sandbox/case/mapuid.nix +++ b/test/sandbox/case/mapuid.nix @@ -264,8 +264,8 @@ in (ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") (ent "/var/cache" "/var/cache" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") - (ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr") - (ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,userxattr") + (ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr") + (ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,userxattr") (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") (ent "/var/lib/hakurei/u0/a3" "/var/lib/hakurei/u0/a3" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") (ent ignore "/run/user/1000/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") diff --git a/test/sandbox/case/tty.nix b/test/sandbox/case/tty.nix index 7c00baed..ccd404a9 100644 --- a/test/sandbox/case/tty.nix +++ b/test/sandbox/case/tty.nix @@ -270,8 +270,8 @@ in (ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore) (ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") (ent "/var/cache" "/var/cache" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") - (ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr") - (ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir=/host/nix/.ro-store:/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,uuid=on,userxattr") + (ent "/" "/.hakurei/.ro-store" "rw,relatime" "overlay" "overlay" "ro,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,redirect_dir=nofollow,userxattr") + (ent "/" "/.hakurei/store" "rw,relatime" "overlay" "overlay" "rw,lowerdir+=/host/nix/.ro-store,lowerdir+=/host/nix/.rw-store/upper,upperdir=/host/tmp/.hakurei-store-rw/upper,workdir=/host/tmp/.hakurei-store-rw/work,redirect_dir=nofollow,uuid=on,userxattr") (ent "/etc" ignore "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") (ent "/var/lib/hakurei/u0/a2" "/var/lib/hakurei/u0/a2" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw") (ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")