container/initsymlink: unwrap mount errors
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 1m49s
Test / Hakurei (push) Successful in 3m17s
Test / Hpkg (push) Successful in 3m42s
Test / Sandbox (race detector) (push) Successful in 4m10s
Test / Hakurei (race detector) (push) Successful in 5m18s
Test / Flake checks (push) Successful in 1m38s

The mount function now wraps its own errors in a much more descriptive type with proper message formatting. Wrapping them no longer makes any sense.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-08-29 01:46:54 +09:00
parent b8669338da
commit eb3385d490
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
9 changed files with 20 additions and 34 deletions

View File

@ -377,7 +377,7 @@ func TestInitEntrypoint(t *testing.T) {
}, },
}, nil}, }, nil},
{"apply", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, [][]kexpect{ {"early unhandled error", func(k syscallDispatcher) error { initEntrypoint(k, assertPrefix, assertVerboseTrue); return nil }, [][]kexpect{
{ {
{"lockOSThread", expectArgs{}, nil, nil}, {"lockOSThread", expectArgs{}, nil, nil},
{"getpid", expectArgs{}, 1, nil}, {"getpid", expectArgs{}, 1, nil},
@ -759,10 +759,8 @@ func TestInitEntrypoint(t *testing.T) {
{"bindMount", expectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil}, {"bindMount", expectArgs{"/host", "/sysroot", uintptr(0x4001), false}, nil, nil},
{"verbosef", expectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil}, {"verbosef", expectArgs{"%s %s", []any{"mounting", &MountProcOp{Target: MustAbs("/proc/")}}}, nil, nil},
{"mkdirAll", expectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil}, {"mkdirAll", expectArgs{"/sysroot/proc", os.FileMode(0755)}, nil, nil},
{"mount", expectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, errUnique}, {"mount", expectArgs{"proc", "/sysroot/proc", "proc", uintptr(0xe), ""}, nil, &MountError{"proc", "/sysroot/proc", "proc", uintptr(0xe), "", syscall.ENOTRECOVERABLE}},
{"printBaseErr", expectArgs{wrapErrSuffix(errUnique, `cannot mount proc on "/proc/":`), "cannot apply op at index 1:"}, nil, nil}, {"fatal", expectArgs{[]any{"cannot mount proc on /sysroot/proc: state not recoverable"}}, nil, nil},
{"beforeExit", expectArgs{}, nil, nil},
{"exit", expectArgs{1}, nil, nil},
/* end apply */ /* end apply */
}, },
}, nil}, }, nil},

View File

@ -82,8 +82,7 @@ func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error {
if err := k.mount(SourceDevpts, devPtsPath, FstypeDevpts, MS_NOSUID|MS_NOEXEC, if err := k.mount(SourceDevpts, devPtsPath, FstypeDevpts, MS_NOSUID|MS_NOEXEC,
"newinstance,ptmxmode=0666,mode=620"); err != nil { "newinstance,ptmxmode=0666,mode=620"); err != nil {
return wrapErrSuffix(err, return err
fmt.Sprintf("cannot mount devpts on %q:", devPtsPath))
} }
if state.RetainSession { if state.RetainSession {
@ -111,7 +110,7 @@ func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error {
return wrapErrSelf(err) return wrapErrSelf(err)
} }
if err := k.mount(SourceMqueue, mqueueTarget, FstypeMqueue, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString); err != nil { if err := k.mount(SourceMqueue, mqueueTarget, FstypeMqueue, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString); err != nil {
return wrapErrSuffix(err, "cannot mount mqueue:") return err
} }
} }
@ -120,8 +119,7 @@ func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error {
} }
if err := k.remount(target, MS_RDONLY); err != nil { if err := k.remount(target, MS_RDONLY); err != nil {
return wrapErrSuffix(k.remount(target, MS_RDONLY), return err
fmt.Sprintf("cannot remount %q:", target))
} }
return k.mountTmpfs(SourceTmpfs, devShmPath, MS_NOSUID|MS_NODEV, 0, 01777) return k.mountTmpfs(SourceTmpfs, devShmPath, MS_NOSUID|MS_NODEV, 0, 01777)
} }

View File

@ -390,7 +390,7 @@ func TestMountDevOp(t *testing.T) {
{"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil}, {"mkdir", expectArgs{"/sysroot/dev/shm", os.FileMode(0750)}, nil, nil},
{"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, nil}, {"mkdir", expectArgs{"/sysroot/dev/pts", os.FileMode(0750)}, nil, nil},
{"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, errUnique}, {"mount", expectArgs{"devpts", "/sysroot/dev/pts", "devpts", uintptr(0xa), "newinstance,ptmxmode=0666,mode=620"}, nil, errUnique},
}, wrapErrSuffix(errUnique, `cannot mount devpts on "/sysroot/dev/pts":`)}, }, errUnique},
{"ensureFile stdout", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{ {"ensureFile stdout", &Params{ParentPerm: 0750, RetainSession: true}, &MountDevOp{
Target: MustAbs("/dev/"), Target: MustAbs("/dev/"),
@ -550,7 +550,7 @@ func TestMountDevOp(t *testing.T) {
{"bindMount", expectArgs{"/host/dev/pts/2", "/sysroot/dev/console", uintptr(0), false}, nil, nil}, {"bindMount", expectArgs{"/host/dev/pts/2", "/sysroot/dev/console", uintptr(0), false}, nil, nil},
{"mkdir", expectArgs{"/sysroot/dev/mqueue", os.FileMode(0750)}, nil, nil}, {"mkdir", expectArgs{"/sysroot/dev/mqueue", os.FileMode(0750)}, nil, nil},
{"mount", expectArgs{"mqueue", "/sysroot/dev/mqueue", "mqueue", uintptr(0xe), ""}, nil, errUnique}, {"mount", expectArgs{"mqueue", "/sysroot/dev/mqueue", "mqueue", uintptr(0xe), ""}, nil, errUnique},
}, wrapErrSuffix(errUnique, "cannot mount mqueue:")}, }, errUnique},
{"success no session", &Params{ParentPerm: 0755}, &MountDevOp{ {"success no session", &Params{ParentPerm: 0755}, &MountDevOp{
Target: MustAbs("/dev/"), Target: MustAbs("/dev/"),

View File

@ -167,8 +167,7 @@ func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error {
OptionOverlayLowerdir+"="+strings.Join(o.lower, SpecialOverlayPath), OptionOverlayLowerdir+"="+strings.Join(o.lower, SpecialOverlayPath),
OptionOverlayUserxattr) OptionOverlayUserxattr)
return wrapErrSuffix(k.mount(SourceOverlay, target, FstypeOverlay, 0, strings.Join(options, SpecialOverlayOption)), return k.mount(SourceOverlay, target, FstypeOverlay, 0, strings.Join(options, SpecialOverlayOption))
fmt.Sprintf("cannot mount overlay on %q:", o.Target))
} }
func (o *MountOverlayOp) Is(op Op) bool { func (o *MountOverlayOp) Is(op Op) bool {

View File

@ -186,7 +186,7 @@ func TestMountOverlayOp(t *testing.T) {
}, nil, []kexpect{ }, nil, []kexpect{
{"mkdirAll", expectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil}, {"mkdirAll", expectArgs{"/sysroot/nix/store", os.FileMode(0700)}, nil, nil},
{"mount", 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, errUnique}, {"mount", 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, errUnique},
}, wrapErrSuffix(errUnique, `cannot mount overlay on "/nix/store":`)}, }, errUnique},
{"success single layer", &Params{ParentPerm: 0700}, &MountOverlayOp{ {"success single layer", &Params{ParentPerm: 0700}, &MountOverlayOp{
Target: MustAbs("/nix/store"), Target: MustAbs("/nix/store"),

View File

@ -24,8 +24,7 @@ func (p *MountProcOp) apply(state *setupState, k syscallDispatcher) error {
if err := k.mkdirAll(target, state.ParentPerm); err != nil { if err := k.mkdirAll(target, state.ParentPerm); err != nil {
return wrapErrSelf(err) return wrapErrSelf(err)
} }
return wrapErrSuffix(k.mount(SourceProc, target, FstypeProc, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString), return k.mount(SourceProc, target, FstypeProc, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString)
fmt.Sprintf("cannot mount proc on %q:", p.Target.String()))
} }
func (p *MountProcOp) Is(op Op) bool { func (p *MountProcOp) Is(op Op) bool {

View File

@ -22,8 +22,7 @@ type RemountOp struct {
func (r *RemountOp) Valid() bool { return r != nil && r.Target != nil } func (r *RemountOp) Valid() bool { return r != nil && r.Target != nil }
func (*RemountOp) early(*setupState, syscallDispatcher) error { return nil } func (*RemountOp) early(*setupState, syscallDispatcher) error { return nil }
func (r *RemountOp) apply(_ *setupState, k syscallDispatcher) error { func (r *RemountOp) apply(_ *setupState, k syscallDispatcher) error {
return wrapErrSuffix(k.remount(toSysroot(r.Target.String()), r.Flags), return k.remount(toSysroot(r.Target.String()), r.Flags)
fmt.Sprintf("cannot remount %q:", r.Target))
} }
func (r *RemountOp) Is(op Op) bool { func (r *RemountOp) Is(op Op) bool {

View File

@ -106,8 +106,7 @@ func (p *procPaths) bindMount(source, target string, flags uintptr, eq bool) err
} }
if err := p.k.mount(source, target, FstypeNULL, MS_SILENT|MS_BIND|flags&MS_REC, zeroString); err != nil { if err := p.k.mount(source, target, FstypeNULL, MS_SILENT|MS_BIND|flags&MS_REC, zeroString); err != nil {
return wrapErrSuffix(err, return err
fmt.Sprintf("cannot mount %q on %q:", source, target))
} }
return p.k.remount(target, flags) return p.k.remount(target, flags)
@ -161,8 +160,7 @@ func (p *procPaths) remount(target string, flags uintptr) error {
} }
if err = remountWithFlags(p.k, n, mf); err != nil { if err = remountWithFlags(p.k, n, mf); err != nil {
return wrapErrSuffix(err, return err
fmt.Sprintf("cannot remount %q:", n.Clean))
} }
if flags&MS_REC == 0 { if flags&MS_REC == 0 {
return nil return nil
@ -174,11 +172,8 @@ func (p *procPaths) remount(target string, flags uintptr) error {
continue continue
} }
err = remountWithFlags(p.k, cur, mf) if err = remountWithFlags(p.k, cur, mf); err != nil && !errors.Is(err, EACCES) {
return err
if err != nil && !errors.Is(err, EACCES) {
return wrapErrSuffix(err,
fmt.Sprintf("cannot propagate flags to %q:", cur.Clean))
} }
} }
@ -213,9 +208,7 @@ func mountTmpfs(k syscallDispatcher, fsname, target string, flags uintptr, size
if size > 0 { if size > 0 {
opt += fmt.Sprintf(",size=%d", size) opt += fmt.Sprintf(",size=%d", size)
} }
return wrapErrSuffix( return k.mount(fsname, target, FstypeTmpfs, flags, opt)
k.mount(fsname, target, FstypeTmpfs, flags, opt),
fmt.Sprintf("cannot mount tmpfs on %q:", target))
} }
func parentPerm(perm os.FileMode) os.FileMode { func parentPerm(perm os.FileMode) os.FileMode {

View File

@ -15,7 +15,7 @@ func TestBindMount(t *testing.T) {
}, [][]kexpect{{ }, [][]kexpect{{
{"verbosef", expectArgs{"resolved %q flags %#x", []any{"/sysroot/nix", uintptr(1)}}, nil, nil}, {"verbosef", expectArgs{"resolved %q flags %#x", []any{"/sysroot/nix", uintptr(1)}}, nil, nil},
{"mount", expectArgs{"/host/nix", "/sysroot/nix", "", uintptr(0x9000), ""}, nil, errUnique}, {"mount", expectArgs{"/host/nix", "/sysroot/nix", "", uintptr(0x9000), ""}, nil, errUnique},
}}, wrapErrSuffix(errUnique, `cannot mount "/host/nix" on "/sysroot/nix":`)}, }}, errUnique},
{"success ne", func(k syscallDispatcher) error { {"success ne", func(k syscallDispatcher) error {
return newProcPaths(k, hostPath).bindMount("/host/nix", "/sysroot/.host-nix", syscall.MS_RDONLY, false) return newProcPaths(k, hostPath).bindMount("/host/nix", "/sysroot/.host-nix", syscall.MS_RDONLY, false)
@ -139,7 +139,7 @@ func TestRemount(t *testing.T) {
{"close", expectArgs{0xdeadbeef}, nil, nil}, {"close", expectArgs{0xdeadbeef}, nil, nil},
{"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil}, {"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil},
{"mount", expectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, errUnique}, {"mount", expectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, errUnique},
}}, wrapErrSuffix(errUnique, `cannot remount "/sysroot/nix":`)}, }}, errUnique},
{"mount propagate", func(k syscallDispatcher) error { {"mount propagate", func(k syscallDispatcher) error {
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV) return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
@ -151,7 +151,7 @@ func TestRemount(t *testing.T) {
{"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil}, {"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil},
{"mount", expectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil}, {"mount", expectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil},
{"mount", expectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, errUnique}, {"mount", expectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, errUnique},
}}, wrapErrSuffix(errUnique, `cannot propagate flags to "/sysroot/nix/.ro-store":`)}, }}, errUnique},
{"success toplevel", func(k syscallDispatcher) error { {"success toplevel", func(k syscallDispatcher) error {
return newProcPaths(k, hostPath).remount("/sysroot/bin", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV) return newProcPaths(k, hostPath).remount("/sysroot/bin", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)