container/initoverlay: configure via fsconfig
All checks were successful
Test / ShareFS (push) Successful in 40s
Test / Hakurei (push) Successful in 53s
Test / Hakurei (race detector) (push) Successful in 51s
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 1m48s
Test / Sandbox (race detector) (push) Successful in 2m37s
Test / Flake checks (push) Successful in 1m20s
All checks were successful
Test / ShareFS (push) Successful in 40s
Test / Hakurei (push) Successful in 53s
Test / Hakurei (race detector) (push) Successful in 51s
Test / Create distribution (push) Successful in 1m1s
Test / Sandbox (push) Successful in 1m48s
Test / Sandbox (race detector) (push) Successful in 2m37s
Test / Flake checks (push) Successful in 1m20s
This works around the page size limit at the cost of negligible performance regressions. Closes #34. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
@@ -4,15 +4,23 @@ import "strings"
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// SpecialOverlayEscape is the escape string for overlay mount options.
|
// SpecialOverlayEscape is the escape string for overlay mount options.
|
||||||
|
//
|
||||||
|
// Deprecated: This is no longer used and will be removed in 0.5.
|
||||||
SpecialOverlayEscape = `\`
|
SpecialOverlayEscape = `\`
|
||||||
// SpecialOverlayOption is the separator string between overlay mount options.
|
// SpecialOverlayOption is the separator string between overlay mount options.
|
||||||
|
//
|
||||||
|
// Deprecated: This is no longer used and will be removed in 0.5.
|
||||||
SpecialOverlayOption = ","
|
SpecialOverlayOption = ","
|
||||||
// SpecialOverlayPath is the separator string between overlay paths.
|
// SpecialOverlayPath is the separator string between overlay paths.
|
||||||
|
//
|
||||||
|
// Deprecated: This is no longer used and will be removed in 0.5.
|
||||||
SpecialOverlayPath = ":"
|
SpecialOverlayPath = ":"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EscapeOverlayDataSegment escapes a string for formatting into the data
|
// EscapeOverlayDataSegment escapes a string for formatting into the data
|
||||||
// argument of an overlay mount system call.
|
// 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 {
|
func EscapeOverlayDataSegment(s string) string {
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return ""
|
return ""
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
_ "unsafe" // for go:linkname
|
||||||
|
|
||||||
"hakurei.app/check"
|
"hakurei.app/check"
|
||||||
"hakurei.app/command"
|
"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 }
|
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 {
|
var containerTestCases = []struct {
|
||||||
name string
|
name string
|
||||||
filter bool
|
filter bool
|
||||||
@@ -332,13 +336,15 @@ var containerTestCases = []struct {
|
|||||||
func(t *testing.T, ctx context.Context) []*vfs.MountInfoEntry {
|
func(t *testing.T, ctx context.Context) []*vfs.MountInfoEntry {
|
||||||
return []*vfs.MountInfoEntry{
|
return []*vfs.MountInfoEntry{
|
||||||
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay",
|
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay",
|
||||||
"rw,lowerdir="+
|
"rw"+
|
||||||
container.InternalToHostOvlEscape(ctx.Value(testVal("lower0")).(*check.Absolute).String())+":"+
|
",lowerdir+="+
|
||||||
container.InternalToHostOvlEscape(ctx.Value(testVal("lower1")).(*check.Absolute).String())+
|
toHost(ctx.Value(testVal("lower0")).(*check.Absolute).String())+
|
||||||
|
",lowerdir+="+
|
||||||
|
toHost(ctx.Value(testVal("lower1")).(*check.Absolute).String())+
|
||||||
",upperdir="+
|
",upperdir="+
|
||||||
container.InternalToHostOvlEscape(ctx.Value(testVal("upper")).(*check.Absolute).String())+
|
toHost(ctx.Value(testVal("upper")).(*check.Absolute).String())+
|
||||||
",workdir="+
|
",workdir="+
|
||||||
container.InternalToHostOvlEscape(ctx.Value(testVal("work")).(*check.Absolute).String())+
|
toHost(ctx.Value(testVal("work")).(*check.Absolute).String())+
|
||||||
",redirect_dir=nofollow,uuid=on,userxattr"),
|
",redirect_dir=nofollow,uuid=on,userxattr"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -388,9 +394,11 @@ var containerTestCases = []struct {
|
|||||||
func(t *testing.T, ctx context.Context) []*vfs.MountInfoEntry {
|
func(t *testing.T, ctx context.Context) []*vfs.MountInfoEntry {
|
||||||
return []*vfs.MountInfoEntry{
|
return []*vfs.MountInfoEntry{
|
||||||
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay",
|
ent("/", hst.PrivateTmp, "rw", "overlay", "overlay",
|
||||||
"ro,lowerdir="+
|
"ro"+
|
||||||
container.InternalToHostOvlEscape(ctx.Value(testVal("lower0")).(*check.Absolute).String())+":"+
|
",lowerdir+="+
|
||||||
container.InternalToHostOvlEscape(ctx.Value(testVal("lower1")).(*check.Absolute).String())+
|
toHost(ctx.Value(testVal("lower0")).(*check.Absolute).String())+
|
||||||
|
",lowerdir+="+
|
||||||
|
toHost(ctx.Value(testVal("lower1")).(*check.Absolute).String())+
|
||||||
",redirect_dir=nofollow,userxattr"),
|
",redirect_dir=nofollow,userxattr"),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -65,6 +65,8 @@ type syscallDispatcher interface {
|
|||||||
remount(msg message.Msg, target string, flags uintptr) error
|
remount(msg message.Msg, target string, flags uintptr) error
|
||||||
// mountTmpfs provides mountTmpfs.
|
// mountTmpfs provides mountTmpfs.
|
||||||
mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error
|
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 provides ensureFile.
|
||||||
ensureFile(name string, perm, pperm os.FileMode) error
|
ensureFile(name string, perm, pperm os.FileMode) error
|
||||||
// mustLoopback provides mustLoopback.
|
// 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 {
|
func (k direct) mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error {
|
||||||
return mountTmpfs(k, fsname, target, flags, size, perm)
|
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 {
|
func (direct) ensureFile(name string, perm, pperm os.FileMode) error {
|
||||||
return ensureFile(name, perm, pperm)
|
return ensureFile(name, perm, pperm)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -468,6 +468,14 @@ func (k *kstub) mountTmpfs(fsname, target string, flags uintptr, size int, perm
|
|||||||
stub.CheckArg(k.Stub, "perm", perm, 4))
|
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 {
|
func (k *kstub) ensureFile(name string, perm, pperm os.FileMode) error {
|
||||||
k.Helper()
|
k.Helper()
|
||||||
return k.Expects("ensureFile").Error(
|
return k.Expects("ensureFile").Error(
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import (
|
|||||||
"encoding/gob"
|
"encoding/gob"
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"hakurei.app/check"
|
"hakurei.app/check"
|
||||||
|
"hakurei.app/ext"
|
||||||
"hakurei.app/fhs"
|
"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 {
|
if v, err := k.evalSymlinks(o.Upper.String()); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} 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 {
|
if v, err := k.evalSymlinks(o.Work.String()); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} 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 {
|
if v, err := k.evalSymlinks(a.String()); err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
} else {
|
||||||
o.lower[i] = check.EscapeOverlayDataSegment(toHost(v))
|
o.lower[i] = toHost(v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
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 {
|
func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error {
|
||||||
target := o.Target.String()
|
target := o.Target.String()
|
||||||
if !o.noPrefix {
|
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 o.upper == zeroString && o.work == zeroString { // readonly
|
||||||
if len(o.Lower) < 2 {
|
if len(o.Lower) < 2 {
|
||||||
@@ -205,15 +232,16 @@ func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error {
|
|||||||
if len(o.Lower) == 0 {
|
if len(o.Lower) == 0 {
|
||||||
return &OverlayArgumentError{OverlayEmptyLower, zeroString}
|
return &OverlayArgumentError{OverlayEmptyLower, zeroString}
|
||||||
}
|
}
|
||||||
options = append(options,
|
options = append(options, [][2]string{
|
||||||
OptionOverlayUpperdir+"="+o.upper,
|
{OptionOverlayUpperdir, o.upper},
|
||||||
OptionOverlayWorkdir+"="+o.work)
|
{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 }
|
func (o *MountOverlayOp) late(*setupState, syscallDispatcher) error { return nil }
|
||||||
|
|||||||
@@ -97,13 +97,12 @@ func TestMountOverlayOp(t *testing.T) {
|
|||||||
call("mkdirAll", stub.ExpectArgs{"/sysroot", os.FileMode(0705)}, nil, nil),
|
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.upper.*"}, "overlay.upper.32768", nil),
|
||||||
call("mkdirTemp", stub.ExpectArgs{"/", "overlay.work.*"}, "overlay.work.32768", nil),
|
call("mkdirTemp", stub.ExpectArgs{"/", "overlay.work.*"}, "overlay.work.32768", nil),
|
||||||
call("mount", stub.ExpectArgs{"overlay", "/sysroot", "overlay", uintptr(0), "" +
|
call("mountOverlay", stub.ExpectArgs{"/sysroot", [][2]string{
|
||||||
"upperdir=overlay.upper.32768," +
|
{"upperdir", "overlay.upper.32768"},
|
||||||
"workdir=overlay.work.32768," +
|
{"workdir", "overlay.work.32768"},
|
||||||
"lowerdir=" +
|
{"lowerdir+", `/host/var/lib/planterette/base/debian:f92c9052`},
|
||||||
`/host/var/lib/planterette/base/debian\:f92c9052:` +
|
{"lowerdir+", `/host/var/lib/planterette/app/org.chromium.Chromium@debian:f92c9052`},
|
||||||
`/host/var/lib/planterette/app/org.chromium.Chromium@debian\:f92c9052,` +
|
}}, nil, nil),
|
||||||
"userxattr"}, nil, nil),
|
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
{"short lower ro", &Params{ParentPerm: 0755}, &MountOverlayOp{
|
{"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),
|
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store0"}, "/mnt-root/nix/.ro-store0", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("mkdirAll", stub.ExpectArgs{"/nix/store", os.FileMode(0755)}, nil, nil),
|
call("mkdirAll", stub.ExpectArgs{"/nix/store", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"overlay", "/nix/store", "overlay", uintptr(0), "" +
|
call("mountOverlay", stub.ExpectArgs{"/nix/store", [][2]string{
|
||||||
"lowerdir=" +
|
{"lowerdir+", "/host/mnt-root/nix/.ro-store"},
|
||||||
"/host/mnt-root/nix/.ro-store:" +
|
{"lowerdir+", "/host/mnt-root/nix/.ro-store0"},
|
||||||
"/host/mnt-root/nix/.ro-store0," +
|
}}, nil, nil),
|
||||||
"userxattr"}, nil, nil),
|
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
{"success ro", &Params{ParentPerm: 0755}, &MountOverlayOp{
|
{"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),
|
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store0"}, "/mnt-root/nix/.ro-store0", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0755)}, nil, nil),
|
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0755)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" +
|
call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{
|
||||||
"lowerdir=" +
|
{"lowerdir+", "/host/mnt-root/nix/.ro-store"},
|
||||||
"/host/mnt-root/nix/.ro-store:" +
|
{"lowerdir+", "/host/mnt-root/nix/.ro-store0"},
|
||||||
"/host/mnt-root/nix/.ro-store0," +
|
}}, nil, nil),
|
||||||
"userxattr"}, nil, nil),
|
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
{"nil lower", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
{"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),
|
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
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)},
|
}, stub.UniqueError(0)},
|
||||||
|
|
||||||
{"success single layer", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
{"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),
|
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store"}, "/mnt-root/nix/ro-store", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" +
|
call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{
|
||||||
"upperdir=/host/mnt-root/nix/.rw-store/.upper," +
|
{"upperdir", "/host/mnt-root/nix/.rw-store/.upper"},
|
||||||
"workdir=/host/mnt-root/nix/.rw-store/.work," +
|
{"workdir", "/host/mnt-root/nix/.rw-store/.work"},
|
||||||
"lowerdir=/host/mnt-root/nix/ro-store," +
|
{"lowerdir+", "/host/mnt-root/nix/ro-store"},
|
||||||
"userxattr"}, nil, nil),
|
}}, nil, nil),
|
||||||
}, nil},
|
}, nil},
|
||||||
|
|
||||||
{"success", &Params{ParentPerm: 0700}, &MountOverlayOp{
|
{"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),
|
call("evalSymlinks", stub.ExpectArgs{"/mnt-root/nix/.ro-store3"}, "/mnt-root/nix/ro-store3", nil),
|
||||||
}, nil, []stub.Call{
|
}, nil, []stub.Call{
|
||||||
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
call("mkdirAll", stub.ExpectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil),
|
||||||
call("mount", stub.ExpectArgs{"overlay", "/sysroot/nix/store", "overlay", uintptr(0), "" +
|
call("mountOverlay", stub.ExpectArgs{"/sysroot/nix/store", [][2]string{
|
||||||
"upperdir=/host/mnt-root/nix/.rw-store/.upper," +
|
{"upperdir", "/host/mnt-root/nix/.rw-store/.upper"},
|
||||||
"workdir=/host/mnt-root/nix/.rw-store/.work," +
|
{"workdir", "/host/mnt-root/nix/.rw-store/.work"},
|
||||||
"lowerdir=" +
|
{"lowerdir+", "/host/mnt-root/nix/ro-store"},
|
||||||
"/host/mnt-root/nix/ro-store:" +
|
{"lowerdir+", "/host/mnt-root/nix/ro-store0"},
|
||||||
"/host/mnt-root/nix/ro-store0:" +
|
{"lowerdir+", "/host/mnt-root/nix/ro-store1"},
|
||||||
"/host/mnt-root/nix/ro-store1:" +
|
{"lowerdir+", "/host/mnt-root/nix/ro-store2"},
|
||||||
"/host/mnt-root/nix/ro-store2:" +
|
{"lowerdir+", "/host/mnt-root/nix/ro-store3"},
|
||||||
"/host/mnt-root/nix/ro-store3," +
|
}}, nil, nil),
|
||||||
"userxattr"}, nil, nil),
|
|
||||||
}, nil},
|
}, nil},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
"hakurei.app/check"
|
|
||||||
"hakurei.app/vfs"
|
"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) {
|
func TestCreateFile(t *testing.T) {
|
||||||
t.Run("nonexistent", func(t *testing.T) {
|
t.Run("nonexistent", func(t *testing.T) {
|
||||||
t.Run("mkdir", func(t *testing.T) {
|
t.Run("mkdir", func(t *testing.T) {
|
||||||
|
|||||||
36
internal/pkg/testdata/main.go
vendored
36
internal/pkg/testdata/main.go
vendored
@@ -14,7 +14,6 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"hakurei.app/check"
|
|
||||||
"hakurei.app/fhs"
|
"hakurei.app/fhs"
|
||||||
"hakurei.app/vfs"
|
"hakurei.app/vfs"
|
||||||
)
|
)
|
||||||
@@ -159,43 +158,24 @@ func main() {
|
|||||||
m.Source != "overlay" || m.FsType != "overlay" {
|
m.Source != "overlay" || m.FsType != "overlay" {
|
||||||
log.Fatal("unexpected root mount entry")
|
log.Fatal("unexpected root mount entry")
|
||||||
}
|
}
|
||||||
var lowerdir string
|
var lowerdir []string
|
||||||
for _, o := range strings.Split(m.FsOptstr, ",") {
|
for _, o := range strings.Split(m.FsOptstr, ",") {
|
||||||
const lowerdirKey = "lowerdir="
|
const lowerdirKey = "lowerdir+="
|
||||||
if strings.HasPrefix(o, lowerdirKey) {
|
if strings.HasPrefix(o, lowerdirKey) {
|
||||||
lowerdir = o[len(lowerdirKey):]
|
lowerdir = append(lowerdir, o[len(lowerdirKey):])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !layers {
|
if !layers {
|
||||||
if filepath.Base(lowerdir) != checksumEmptyDir {
|
if len(lowerdir) != 1 || filepath.Base(lowerdir[0]) != checksumEmptyDir {
|
||||||
log.Fatal("unexpected artifact checksum")
|
log.Fatal("unexpected artifact checksum")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ident = "p1t_drXr34i-jZNuxDMLaMOdL6tZvQqhavNafGynGqxOZoXAUTSn7kqNh3Ovv3DT"
|
ident = "p1t_drXr34i-jZNuxDMLaMOdL6tZvQqhavNafGynGqxOZoXAUTSn7kqNh3Ovv3DT"
|
||||||
|
|
||||||
lowerdirsEscaped := strings.Split(lowerdir, ":")
|
if len(lowerdir) != 2 ||
|
||||||
lowerdirs := lowerdirsEscaped[:0]
|
filepath.Base(lowerdir[0]) != "MGWmEfjut2QE2xPJwTsmUzpff4BN_FEnQ7T0j7gvUCCiugJQNwqt9m151fm9D1yU" ||
|
||||||
// ignore the option separator since it does not appear in ident
|
filepath.Base(lowerdir[1]) != "nY_CUdiaUM1OL4cPr5TS92FCJ3rCRV7Hm5oVTzAvMXwC03_QnTRfQ5PPs7mOU9fK" {
|
||||||
for i, e := range lowerdirsEscaped {
|
log.Fatalf("unexpected lowerdirs %s", strings.Join(lowerdir, ", "))
|
||||||
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, ", "))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -237,8 +237,8 @@ in
|
|||||||
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
(ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
(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 "/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/.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:/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/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 "/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 "/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")
|
(ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||||
|
|||||||
@@ -264,8 +264,8 @@ in
|
|||||||
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
(ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
(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 "/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/.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:/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/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 "/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 "/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")
|
(ent ignore "/run/user/1000/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||||
|
|||||||
@@ -270,8 +270,8 @@ in
|
|||||||
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
(ent "/dri" "/dev/dri" "rw,nosuid" "devtmpfs" "devtmpfs" ignore)
|
||||||
(ent "/var/tmp" "/var/tmp" "rw,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
(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 "/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/.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:/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/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 "/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 "/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")
|
(ent ignore "/run/user/65534/pulse/native" "ro,nosuid,nodev,relatime" "ext4" "/dev/vda" "rw")
|
||||||
|
|||||||
Reference in New Issue
Block a user