container/path: use syscall dispatcher
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 2m8s
Test / Hakurei (push) Successful in 3m14s
Test / Hpkg (push) Successful in 4m8s
Test / Sandbox (race detector) (push) Successful in 4m26s
Test / Hakurei (race detector) (push) Successful in 43s
Test / Flake checks (push) Successful in 1m39s
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 2m8s
Test / Hakurei (push) Successful in 3m14s
Test / Hpkg (push) Successful in 4m8s
Test / Sandbox (race detector) (push) Successful in 4m26s
Test / Hakurei (race detector) (push) Successful in 43s
Test / Flake checks (push) Successful in 1m39s
This allows path and mount functions to be instrumented. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
09d2844981
commit
afe23600d2
@ -77,6 +77,8 @@ type syscallDispatcher interface {
|
|||||||
mkdirAll(path string, perm os.FileMode) error
|
mkdirAll(path string, perm os.FileMode) error
|
||||||
// readdir provides [os.ReadDir].
|
// readdir provides [os.ReadDir].
|
||||||
readdir(name string) ([]os.DirEntry, error)
|
readdir(name string) ([]os.DirEntry, error)
|
||||||
|
// openNew provides [os.Open].
|
||||||
|
openNew(name string) (osFile, error)
|
||||||
// writeFile provides [os.WriteFile].
|
// writeFile provides [os.WriteFile].
|
||||||
writeFile(name string, data []byte, perm os.FileMode) error
|
writeFile(name string, data []byte, perm os.FileMode) error
|
||||||
// createTemp provides [os.CreateTemp].
|
// createTemp provides [os.CreateTemp].
|
||||||
@ -154,8 +156,8 @@ func (direct) bindMount(source, target string, flags uintptr, eq bool) error {
|
|||||||
func (direct) remount(target string, flags uintptr) error {
|
func (direct) remount(target string, flags uintptr) error {
|
||||||
return hostProc.remount(target, flags)
|
return hostProc.remount(target, flags)
|
||||||
}
|
}
|
||||||
func (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(fsname, target, flags, size, perm)
|
return mountTmpfs(k, fsname, target, flags, size, perm)
|
||||||
}
|
}
|
||||||
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)
|
||||||
@ -176,6 +178,7 @@ func (direct) mkdir(name string, perm os.FileMode) error { return os.Mkdir(n
|
|||||||
func (direct) mkdirTemp(dir, pattern string) (string, error) { return os.MkdirTemp(dir, pattern) }
|
func (direct) mkdirTemp(dir, pattern string) (string, error) { return os.MkdirTemp(dir, pattern) }
|
||||||
func (direct) mkdirAll(path string, perm os.FileMode) error { return os.MkdirAll(path, perm) }
|
func (direct) mkdirAll(path string, perm os.FileMode) error { return os.MkdirAll(path, perm) }
|
||||||
func (direct) readdir(name string) ([]os.DirEntry, error) { return os.ReadDir(name) }
|
func (direct) readdir(name string) ([]os.DirEntry, error) { return os.ReadDir(name) }
|
||||||
|
func (direct) openNew(name string) (osFile, error) { return os.Open(name) }
|
||||||
func (direct) writeFile(name string, data []byte, perm os.FileMode) error {
|
func (direct) writeFile(name string, data []byte, perm os.FileMode) error {
|
||||||
return os.WriteFile(name, data, perm)
|
return os.WriteFile(name, data, perm)
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,14 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
@ -101,6 +103,27 @@ func checkOpMeta(t *testing.T, testCases []opMetaTestCase) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type simpleTestCase struct {
|
||||||
|
name string
|
||||||
|
f func(k syscallDispatcher) error
|
||||||
|
want []kexpect
|
||||||
|
wantErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkSimple(t *testing.T, fname string, testCases []simpleTestCase) {
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
k := &kstub{t: t, want: tc.want}
|
||||||
|
if err := tc.f(k); !errors.Is(err, tc.wantErr) {
|
||||||
|
t.Errorf("%s: error = %v, want %v", fname, err, tc.wantErr)
|
||||||
|
}
|
||||||
|
if len(k.want) != k.pos {
|
||||||
|
t.Errorf("%s: %d calls, want %d", fname, k.pos, len(k.want))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type opBehaviourTestCase struct {
|
type opBehaviourTestCase struct {
|
||||||
name string
|
name string
|
||||||
params *Params
|
params *Params
|
||||||
@ -173,6 +196,24 @@ func (f *checkedOsFile) Close() error {
|
|||||||
return f.closeErr
|
return f.closeErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newConstFile(s string) osFile { return &readerOsFile{Reader: strings.NewReader(s)} }
|
||||||
|
|
||||||
|
type readerOsFile struct {
|
||||||
|
closed bool
|
||||||
|
io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*readerOsFile) Name() string { panic("unreachable") }
|
||||||
|
func (*readerOsFile) Write([]byte) (int, error) { panic("unreachable") }
|
||||||
|
func (*readerOsFile) Stat() (fs.FileInfo, error) { panic("unreachable") }
|
||||||
|
func (r *readerOsFile) Close() error {
|
||||||
|
if r.closed {
|
||||||
|
return os.ErrClosed
|
||||||
|
}
|
||||||
|
r.closed = true
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type writeErrOsFile struct{ err error }
|
type writeErrOsFile struct{ err error }
|
||||||
|
|
||||||
func (writeErrOsFile) Name() string { panic("unreachable") }
|
func (writeErrOsFile) Name() string { panic("unreachable") }
|
||||||
@ -437,6 +478,12 @@ func (k *kstub) readdir(name string) ([]os.DirEntry, error) {
|
|||||||
checkArg(k, "name", name, 0))
|
checkArg(k, "name", name, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k *kstub) openNew(name string) (osFile, error) {
|
||||||
|
expect := k.expect("openNew")
|
||||||
|
return expect.ret.(osFile), expect.error(
|
||||||
|
checkArg(k, "name", name, 0))
|
||||||
|
}
|
||||||
|
|
||||||
func (k *kstub) writeFile(name string, data []byte, perm os.FileMode) error {
|
func (k *kstub) writeFile(name string, data []byte, perm os.FileMode) error {
|
||||||
return k.expect("writeFile").error(
|
return k.expect("writeFile").error(
|
||||||
checkArg(k, "name", name, 0),
|
checkArg(k, "name", name, 0),
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
. "syscall"
|
. "syscall"
|
||||||
|
|
||||||
@ -96,29 +95,33 @@ const (
|
|||||||
|
|
||||||
// bindMount mounts source on target and recursively applies flags if MS_REC is set.
|
// bindMount mounts source on target and recursively applies flags if MS_REC is set.
|
||||||
func (p *procPaths) bindMount(source, target string, flags uintptr, eq bool) error {
|
func (p *procPaths) bindMount(source, target string, flags uintptr, eq bool) error {
|
||||||
|
// syscallDispatcher.bindMount and procPaths.remount must not be called from this function
|
||||||
|
|
||||||
if eq {
|
if eq {
|
||||||
msg.Verbosef("resolved %q flags %#x", target, flags)
|
p.k.verbosef("resolved %q flags %#x", target, flags)
|
||||||
} else {
|
} else {
|
||||||
msg.Verbosef("resolved %q on %q flags %#x", source, target, flags)
|
p.k.verbosef("resolved %q on %q flags %#x", source, target, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := 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 wrapErrSuffix(err,
|
||||||
fmt.Sprintf("cannot mount %q on %q:", source, target))
|
fmt.Sprintf("cannot mount %q on %q:", source, target))
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.remount(target, flags)
|
return p.k.remount(target, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// remount applies flags on target, recursively if MS_REC is set.
|
// remount applies flags on target, recursively if MS_REC is set.
|
||||||
func (p *procPaths) remount(target string, flags uintptr) error {
|
func (p *procPaths) remount(target string, flags uintptr) error {
|
||||||
|
// syscallDispatcher methods bindMount, remount must not be called from this function
|
||||||
|
|
||||||
var targetFinal string
|
var targetFinal string
|
||||||
if v, err := filepath.EvalSymlinks(target); err != nil {
|
if v, err := p.k.evalSymlinks(target); err != nil {
|
||||||
return wrapErrSelf(err)
|
return wrapErrSelf(err)
|
||||||
} else {
|
} else {
|
||||||
targetFinal = v
|
targetFinal = v
|
||||||
if targetFinal != target {
|
if targetFinal != target {
|
||||||
msg.Verbosef("target resolves to %q", targetFinal)
|
p.k.verbosef("target resolves to %q", targetFinal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,15 +130,15 @@ func (p *procPaths) remount(target string, flags uintptr) error {
|
|||||||
{
|
{
|
||||||
var destFd int
|
var destFd int
|
||||||
if err := IgnoringEINTR(func() (err error) {
|
if err := IgnoringEINTR(func() (err error) {
|
||||||
destFd, err = Open(targetFinal, O_PATH|O_CLOEXEC, 0)
|
destFd, err = p.k.open(targetFinal, O_PATH|O_CLOEXEC, 0)
|
||||||
return
|
return
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return wrapErrSuffix(err,
|
return wrapErrSuffix(err,
|
||||||
fmt.Sprintf("cannot open %q:", targetFinal))
|
fmt.Sprintf("cannot open %q:", targetFinal))
|
||||||
}
|
}
|
||||||
if v, err := os.Readlink(p.fd(destFd)); err != nil {
|
if v, err := p.k.readlink(p.fd(destFd)); err != nil {
|
||||||
return wrapErrSelf(err)
|
return wrapErrSelf(err)
|
||||||
} else if err = Close(destFd); err != nil {
|
} else if err = p.k.close(destFd); err != nil {
|
||||||
return wrapErrSuffix(err,
|
return wrapErrSuffix(err,
|
||||||
fmt.Sprintf("cannot close %q:", targetFinal))
|
fmt.Sprintf("cannot close %q:", targetFinal))
|
||||||
} else {
|
} else {
|
||||||
@ -144,7 +147,7 @@ func (p *procPaths) remount(target string, flags uintptr) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mf := MS_NOSUID | flags&MS_NODEV | flags&MS_RDONLY
|
mf := MS_NOSUID | flags&MS_NODEV | flags&MS_RDONLY
|
||||||
return hostProc.mountinfo(func(d *vfs.MountInfoDecoder) error {
|
return p.mountinfo(func(d *vfs.MountInfoDecoder) error {
|
||||||
n, err := d.Unfold(targetKFinal)
|
n, err := d.Unfold(targetKFinal)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, ESTALE) {
|
if errors.Is(err, ESTALE) {
|
||||||
@ -155,17 +158,25 @@ func (p *procPaths) remount(target string, flags uintptr) error {
|
|||||||
"cannot unfold mount hierarchy:")
|
"cannot unfold mount hierarchy:")
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = remountWithFlags(n, mf); err != nil {
|
if err = remountWithFlags(p.k, n, mf); err != nil {
|
||||||
return err
|
return wrapErrSuffix(err,
|
||||||
|
fmt.Sprintf("cannot remount %q:", n.Clean))
|
||||||
}
|
}
|
||||||
if flags&MS_REC == 0 {
|
if flags&MS_REC == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
for cur := range n.Collective() {
|
for cur := range n.Collective() {
|
||||||
err = remountWithFlags(cur, mf)
|
// avoid remounting twice
|
||||||
|
if cur == n {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
err = remountWithFlags(p.k, cur, mf)
|
||||||
|
|
||||||
if err != nil && !errors.Is(err, EACCES) {
|
if err != nil && !errors.Is(err, EACCES) {
|
||||||
return err
|
return wrapErrSuffix(err,
|
||||||
|
fmt.Sprintf("cannot propagate flags to %q:", cur.Clean))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,24 +185,26 @@ func (p *procPaths) remount(target string, flags uintptr) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remountWithFlags remounts mount point described by [vfs.MountInfoNode].
|
// remountWithFlags remounts mount point described by [vfs.MountInfoNode].
|
||||||
func remountWithFlags(n *vfs.MountInfoNode, mf uintptr) error {
|
func remountWithFlags(k syscallDispatcher, n *vfs.MountInfoNode, mf uintptr) error {
|
||||||
|
// syscallDispatcher methods bindMount, remount must not be called from this function
|
||||||
|
|
||||||
kf, unmatched := n.Flags()
|
kf, unmatched := n.Flags()
|
||||||
if len(unmatched) != 0 {
|
if len(unmatched) != 0 {
|
||||||
msg.Verbosef("unmatched vfs options: %q", unmatched)
|
k.verbosef("unmatched vfs options: %q", unmatched)
|
||||||
}
|
}
|
||||||
|
|
||||||
if kf&mf != mf {
|
if kf&mf != mf {
|
||||||
return wrapErrSuffix(
|
return k.mount(SourceNone, n.Clean, FstypeNULL, MS_SILENT|MS_BIND|MS_REMOUNT|kf|mf, zeroString)
|
||||||
Mount(SourceNone, n.Clean, FstypeNULL, MS_SILENT|MS_BIND|MS_REMOUNT|kf|mf, zeroString),
|
|
||||||
fmt.Sprintf("cannot remount %q:", n.Clean))
|
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// mountTmpfs mounts tmpfs on target;
|
// mountTmpfs mounts tmpfs on target;
|
||||||
// callers who wish to mount to sysroot must pass the return value of toSysroot.
|
// callers who wish to mount to sysroot must pass the return value of toSysroot.
|
||||||
func mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode) error {
|
func mountTmpfs(k syscallDispatcher, fsname, target string, flags uintptr, size int, perm os.FileMode) error {
|
||||||
if err := os.MkdirAll(target, parentPerm(perm)); err != nil {
|
// syscallDispatcher.mountTmpfs must not be called from this function
|
||||||
|
|
||||||
|
if err := k.mkdirAll(target, parentPerm(perm)); err != nil {
|
||||||
return wrapErrSelf(err)
|
return wrapErrSelf(err)
|
||||||
}
|
}
|
||||||
opt := fmt.Sprintf("mode=%#o", perm)
|
opt := fmt.Sprintf("mode=%#o", perm)
|
||||||
@ -199,7 +212,7 @@ func mountTmpfs(fsname, target string, flags uintptr, size int, perm os.FileMode
|
|||||||
opt += fmt.Sprintf(",size=%d", size)
|
opt += fmt.Sprintf(",size=%d", size)
|
||||||
}
|
}
|
||||||
return wrapErrSuffix(
|
return wrapErrSuffix(
|
||||||
Mount(fsname, target, FstypeTmpfs, flags, opt),
|
k.mount(fsname, target, FstypeTmpfs, flags, opt),
|
||||||
fmt.Sprintf("cannot mount tmpfs on %q:", target))
|
fmt.Sprintf("cannot mount tmpfs on %q:", target))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,9 +2,265 @@ package container
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"syscall"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"hakurei.app/container/vfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestBindMount(t *testing.T) {
|
||||||
|
checkSimple(t, "bindMount", []simpleTestCase{
|
||||||
|
{"mount", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).bindMount("/host/nix", "/sysroot/nix", syscall.MS_RDONLY, true)
|
||||||
|
}, []kexpect{
|
||||||
|
{"verbosef", expectArgs{"resolved %q flags %#x", []any{"/sysroot/nix", uintptr(1)}}, nil, nil},
|
||||||
|
{"mount", expectArgs{"/host/nix", "/sysroot/nix", "", uintptr(0x9000), ""}, nil, errUnique},
|
||||||
|
}, wrapErrSuffix(errUnique, `cannot mount "/host/nix" on "/sysroot/nix":`)},
|
||||||
|
|
||||||
|
{"success ne", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).bindMount("/host/nix", "/sysroot/.host-nix", syscall.MS_RDONLY, false)
|
||||||
|
}, []kexpect{
|
||||||
|
{"verbosef", expectArgs{"resolved %q on %q flags %#x", []any{"/host/nix", "/sysroot/.host-nix", uintptr(1)}}, nil, nil},
|
||||||
|
{"mount", expectArgs{"/host/nix", "/sysroot/.host-nix", "", uintptr(0x9000), ""}, nil, nil},
|
||||||
|
{"remount", expectArgs{"/sysroot/.host-nix", uintptr(1)}, nil, nil},
|
||||||
|
}, nil},
|
||||||
|
|
||||||
|
{"success", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).bindMount("/host/nix", "/sysroot/nix", syscall.MS_RDONLY, true)
|
||||||
|
}, []kexpect{
|
||||||
|
{"verbosef", expectArgs{"resolved %q flags %#x", []any{"/sysroot/nix", uintptr(1)}}, nil, nil},
|
||||||
|
{"mount", expectArgs{"/host/nix", "/sysroot/nix", "", uintptr(0x9000), ""}, nil, nil},
|
||||||
|
{"remount", expectArgs{"/sysroot/nix", uintptr(1)}, nil, nil},
|
||||||
|
}, nil},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemount(t *testing.T) {
|
||||||
|
const sampleMountinfoNix = `254 407 253:0 / /host rw,relatime master:1 - ext4 /dev/disk/by-label/nixos rw
|
||||||
|
255 254 0:28 / /host/mnt/.ro-cwd ro,noatime master:2 - 9p cwd ro,access=client,msize=16384,trans=virtio
|
||||||
|
256 254 0:29 / /host/nix/.ro-store rw,relatime master:3 - 9p nix-store rw,cache=f,access=client,msize=16384,trans=virtio
|
||||||
|
257 254 0:30 / /host/nix/store rw,relatime master:4 - overlay overlay rw,lowerdir=/mnt-root/nix/.ro-store,upperdir=/mnt-root/nix/.rw-store/upper,workdir=/mnt-root/nix/.rw-store/work
|
||||||
|
258 257 0:30 / /host/nix/store ro,relatime master:5 - overlay overlay rw,lowerdir=/mnt-root/nix/.ro-store,upperdir=/mnt-root/nix/.rw-store/upper,workdir=/mnt-root/nix/.rw-store/work
|
||||||
|
259 254 0:33 / /host/tmp/shared rw,relatime master:6 - 9p shared rw,access=client,msize=16384,trans=virtio
|
||||||
|
260 254 0:34 / /host/tmp/xchg rw,relatime master:7 - 9p xchg rw,access=client,msize=16384,trans=virtio
|
||||||
|
261 254 0:22 / /host/proc rw,nosuid,nodev,noexec,relatime master:8 - proc proc rw
|
||||||
|
262 254 0:25 / /host/sys rw,nosuid,nodev,noexec,relatime master:9 - sysfs sysfs rw
|
||||||
|
263 262 0:7 / /host/sys/kernel/security rw,nosuid,nodev,noexec,relatime master:10 - securityfs securityfs rw
|
||||||
|
264 262 0:35 /../../.. /host/sys/fs/cgroup rw,nosuid,nodev,noexec,relatime master:11 - cgroup2 cgroup2 rw,nsdelegate,memory_recursiveprot
|
||||||
|
265 262 0:36 / /host/sys/fs/pstore rw,nosuid,nodev,noexec,relatime master:12 - pstore pstore rw
|
||||||
|
266 262 0:37 / /host/sys/fs/bpf rw,nosuid,nodev,noexec,relatime master:13 - bpf bpf rw,mode=700
|
||||||
|
267 262 0:12 / /host/sys/kernel/tracing rw,nosuid,nodev,noexec,relatime master:20 - tracefs tracefs rw
|
||||||
|
268 262 0:8 / /host/sys/kernel/debug rw,nosuid,nodev,noexec,relatime master:21 - debugfs debugfs rw
|
||||||
|
269 262 0:44 / /host/sys/kernel/config rw,nosuid,nodev,noexec,relatime master:64 - configfs configfs rw
|
||||||
|
270 262 0:45 / /host/sys/fs/fuse/connections rw,nosuid,nodev,noexec,relatime master:66 - fusectl fusectl rw
|
||||||
|
271 254 0:6 / /host/dev rw,nosuid master:14 - devtmpfs devtmpfs rw,size=200532k,nr_inodes=498943,mode=755
|
||||||
|
324 271 0:20 / /host/dev/pts rw,nosuid,noexec,relatime master:15 - devpts devpts rw,gid=3,mode=620,ptmxmode=666
|
||||||
|
378 271 0:21 / /host/dev/shm rw,nosuid,nodev master:16 - tmpfs tmpfs rw
|
||||||
|
379 271 0:19 / /host/dev/mqueue rw,nosuid,nodev,noexec,relatime master:19 - mqueue mqueue rw
|
||||||
|
388 271 0:38 / /host/dev/hugepages rw,nosuid,nodev,relatime master:22 - hugetlbfs hugetlbfs rw,pagesize=2M
|
||||||
|
397 254 0:23 / /host/run rw,nosuid,nodev master:17 - tmpfs tmpfs rw,size=1002656k,mode=755
|
||||||
|
398 397 0:24 / /host/run/keys rw,nosuid,nodev,relatime master:18 - ramfs ramfs rw,mode=750
|
||||||
|
399 397 0:39 / /host/run/credentials/systemd-journald.service ro,nosuid,nodev,noexec,relatime,nosymfollow master:23 - tmpfs tmpfs rw,size=1024k,nr_inodes=1024,mode=700,noswap
|
||||||
|
400 397 0:43 / /host/run/wrappers rw,nodev,relatime master:93 - tmpfs tmpfs rw,mode=755
|
||||||
|
401 397 0:61 / /host/run/credentials/getty@tty1.service ro,nosuid,nodev,noexec,relatime,nosymfollow master:240 - tmpfs tmpfs rw,size=1024k,nr_inodes=1024,mode=700,noswap
|
||||||
|
402 397 0:62 / /host/run/credentials/serial-getty@ttyS0.service ro,nosuid,nodev,noexec,relatime,nosymfollow master:288 - tmpfs tmpfs rw,size=1024k,nr_inodes=1024,mode=700,noswap
|
||||||
|
403 397 0:63 / /host/run/user/1000 rw,nosuid,nodev,relatime master:295 - tmpfs tmpfs rw,size=401060k,nr_inodes=100265,mode=700,uid=1000,gid=100
|
||||||
|
404 254 0:46 / /host/mnt/cwd rw,relatime master:96 - overlay overlay rw,lowerdir=/mnt/.ro-cwd,upperdir=/tmp/.cwd/upper,workdir=/tmp/.cwd/work
|
||||||
|
405 254 0:47 / /host/mnt/src rw,relatime master:99 - overlay overlay rw,lowerdir=/nix/store/ihcrl3zwvp2002xyylri2wz0drwajx4z-ns0pa7q2b1jpx9pbf1l9352x6rniwxjn-source,upperdir=/tmp/.src/upper,workdir=/tmp/.src/work
|
||||||
|
407 253 0:65 / / rw,nosuid,nodev,relatime - tmpfs rootfs rw,uid=1000000,gid=1000000
|
||||||
|
408 407 0:65 /sysroot /sysroot rw,nosuid,nodev,relatime - tmpfs rootfs rw,uid=1000000,gid=1000000
|
||||||
|
409 408 253:0 /bin /sysroot/bin rw,nosuid,nodev,relatime master:1 - ext4 /dev/disk/by-label/nixos rw
|
||||||
|
410 408 253:0 /home /sysroot/home rw,nosuid,nodev,relatime master:1 - ext4 /dev/disk/by-label/nixos rw
|
||||||
|
411 408 253:0 /lib64 /sysroot/lib64 rw,nosuid,nodev,relatime master:1 - ext4 /dev/disk/by-label/nixos rw
|
||||||
|
412 408 253:0 /lost+found /sysroot/lost+found rw,nosuid,nodev,relatime master:1 - ext4 /dev/disk/by-label/nixos rw
|
||||||
|
413 408 253:0 /nix /sysroot/nix rw,relatime master:1 - ext4 /dev/disk/by-label/nixos rw
|
||||||
|
414 413 0:29 / /sysroot/nix/.ro-store rw,relatime master:3 - 9p nix-store rw,cache=f,access=client,msize=16384,trans=virtio
|
||||||
|
415 413 0:30 / /sysroot/nix/store rw,relatime master:4 - overlay overlay rw,lowerdir=/mnt-root/nix/.ro-store,upperdir=/mnt-root/nix/.rw-store/upper,workdir=/mnt-root/nix/.rw-store/work
|
||||||
|
416 415 0:30 / /sysroot/nix/store ro,relatime master:5 - overlay overlay rw,lowerdir=/mnt-root/nix/.ro-store,upperdir=/mnt-root/nix/.rw-store/upper,workdir=/mnt-root/nix/.rw-store/work`
|
||||||
|
|
||||||
|
checkSimple(t, "remount", []simpleTestCase{
|
||||||
|
{"evalSymlinks", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/nix"}, "/sysroot/nix", errUnique},
|
||||||
|
}, wrapErrSelf(errUnique)},
|
||||||
|
|
||||||
|
{"open", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/nix"}, "/sysroot/nix", nil},
|
||||||
|
{"open", expectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, errUnique},
|
||||||
|
}, wrapErrSuffix(errUnique, `cannot open "/sysroot/nix":`)},
|
||||||
|
|
||||||
|
{"readlink", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/nix"}, "/sysroot/nix", nil},
|
||||||
|
{"open", expectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil},
|
||||||
|
{"readlink", expectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", errUnique},
|
||||||
|
}, wrapErrSelf(errUnique)},
|
||||||
|
|
||||||
|
{"close", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/nix"}, "/sysroot/nix", nil},
|
||||||
|
{"open", expectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil},
|
||||||
|
{"readlink", expectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil},
|
||||||
|
{"close", expectArgs{0xdeadbeef}, nil, errUnique},
|
||||||
|
}, wrapErrSuffix(errUnique, `cannot close "/sysroot/nix":`)},
|
||||||
|
|
||||||
|
{"mountinfo stale", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/nix"}, "/sysroot/.hakurei", nil},
|
||||||
|
{"verbosef", expectArgs{"target resolves to %q", []any{"/sysroot/.hakurei"}}, nil, nil},
|
||||||
|
{"open", expectArgs{"/sysroot/.hakurei", 0x280000, uint32(0)}, 0xdeadbeef, nil},
|
||||||
|
{"readlink", expectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/.hakurei", nil},
|
||||||
|
{"close", expectArgs{0xdeadbeef}, nil, nil},
|
||||||
|
{"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil},
|
||||||
|
}, msg.WrapErr(syscall.ESTALE, `mount point "/sysroot/.hakurei" never appeared in mountinfo`)},
|
||||||
|
|
||||||
|
{"mountinfo", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/nix"}, "/sysroot/nix", nil},
|
||||||
|
{"open", expectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil},
|
||||||
|
{"readlink", expectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil},
|
||||||
|
{"close", expectArgs{0xdeadbeef}, nil, nil},
|
||||||
|
{"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile("\x00"), nil},
|
||||||
|
}, wrapErrSuffix(vfs.ErrMountInfoFields, `cannot parse mountinfo:`)},
|
||||||
|
|
||||||
|
{"mount", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/nix"}, "/sysroot/nix", nil},
|
||||||
|
{"open", expectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil},
|
||||||
|
{"readlink", expectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil},
|
||||||
|
{"close", expectArgs{0xdeadbeef}, nil, nil},
|
||||||
|
{"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, errUnique},
|
||||||
|
}, wrapErrSuffix(errUnique, `cannot remount "/sysroot/nix":`)},
|
||||||
|
|
||||||
|
{"mount propagate", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/nix"}, "/sysroot/nix", nil},
|
||||||
|
{"open", expectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil},
|
||||||
|
{"readlink", expectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil},
|
||||||
|
{"close", expectArgs{0xdeadbeef}, nil, nil},
|
||||||
|
{"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, errUnique},
|
||||||
|
}, wrapErrSuffix(errUnique, `cannot propagate flags to "/sysroot/nix/.ro-store":`)},
|
||||||
|
|
||||||
|
{"success toplevel", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/bin", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/bin"}, "/sysroot/bin", nil},
|
||||||
|
{"open", expectArgs{"/sysroot/bin", 0x280000, uint32(0)}, 0xbabe, nil},
|
||||||
|
{"readlink", expectArgs{"/host/proc/self/fd/47806"}, "/sysroot/bin", nil},
|
||||||
|
{"close", expectArgs{0xbabe}, nil, nil},
|
||||||
|
{"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/bin", "", uintptr(0x209027), ""}, nil, nil},
|
||||||
|
}, nil},
|
||||||
|
|
||||||
|
{"success EACCES", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/nix"}, "/sysroot/nix", nil},
|
||||||
|
{"open", expectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil},
|
||||||
|
{"readlink", expectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil},
|
||||||
|
{"close", expectArgs{0xdeadbeef}, nil, nil},
|
||||||
|
{"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, syscall.EACCES},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix/store", "", uintptr(0x209027), ""}, nil, nil},
|
||||||
|
}, nil},
|
||||||
|
|
||||||
|
{"success no propagate", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/nix"}, "/sysroot/nix", nil},
|
||||||
|
{"open", expectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil},
|
||||||
|
{"readlink", expectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil},
|
||||||
|
{"close", expectArgs{0xdeadbeef}, nil, nil},
|
||||||
|
{"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil},
|
||||||
|
}, nil},
|
||||||
|
|
||||||
|
{"success case sensitive", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/nix"}, "/sysroot/nix", nil},
|
||||||
|
{"open", expectArgs{"/sysroot/nix", 0x280000, uint32(0)}, 0xdeadbeef, nil},
|
||||||
|
{"readlink", expectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil},
|
||||||
|
{"close", expectArgs{0xdeadbeef}, nil, nil},
|
||||||
|
{"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix/store", "", uintptr(0x209027), ""}, nil, nil},
|
||||||
|
}, nil},
|
||||||
|
|
||||||
|
{"success", func(k syscallDispatcher) error {
|
||||||
|
return newProcPaths(k, hostPath).remount("/sysroot/.nix", syscall.MS_REC|syscall.MS_RDONLY|syscall.MS_NODEV)
|
||||||
|
}, []kexpect{
|
||||||
|
{"evalSymlinks", expectArgs{"/sysroot/.nix"}, "/sysroot/NIX", nil},
|
||||||
|
{"verbosef", expectArgs{"target resolves to %q", []any{"/sysroot/NIX"}}, nil, nil},
|
||||||
|
{"open", expectArgs{"/sysroot/NIX", 0x280000, uint32(0)}, 0xdeadbeef, nil},
|
||||||
|
{"readlink", expectArgs{"/host/proc/self/fd/3735928559"}, "/sysroot/nix", nil},
|
||||||
|
{"close", expectArgs{0xdeadbeef}, nil, nil},
|
||||||
|
{"openNew", expectArgs{"/host/proc/self/mountinfo"}, newConstFile(sampleMountinfoNix), nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix", "", uintptr(0x209027), ""}, nil, nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix/.ro-store", "", uintptr(0x209027), ""}, nil, nil},
|
||||||
|
{"mount", expectArgs{"none", "/sysroot/nix/store", "", uintptr(0x209027), ""}, nil, nil},
|
||||||
|
}, nil},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRemountWithFlags(t *testing.T) {
|
||||||
|
checkSimple(t, "remountWithFlags", []simpleTestCase{
|
||||||
|
{"noop unmatched", func(k syscallDispatcher) error {
|
||||||
|
return remountWithFlags(k, &vfs.MountInfoNode{MountInfoEntry: &vfs.MountInfoEntry{VfsOptstr: "rw,relatime,cat"}}, 0)
|
||||||
|
}, []kexpect{
|
||||||
|
{"verbosef", expectArgs{"unmatched vfs options: %q", []any{[]string{"cat"}}}, nil, nil},
|
||||||
|
}, nil},
|
||||||
|
|
||||||
|
{"noop", func(k syscallDispatcher) error {
|
||||||
|
return remountWithFlags(k, &vfs.MountInfoNode{MountInfoEntry: &vfs.MountInfoEntry{VfsOptstr: "rw,relatime"}}, 0)
|
||||||
|
}, nil, nil},
|
||||||
|
|
||||||
|
{"success", func(k syscallDispatcher) error {
|
||||||
|
return remountWithFlags(k, &vfs.MountInfoNode{MountInfoEntry: &vfs.MountInfoEntry{VfsOptstr: "rw,relatime"}}, syscall.MS_RDONLY)
|
||||||
|
}, []kexpect{
|
||||||
|
{"mount", expectArgs{"none", "", "", uintptr(0x209021), ""}, nil, nil},
|
||||||
|
}, nil},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMountTmpfs(t *testing.T) {
|
||||||
|
checkSimple(t, "mountTmpfs", []simpleTestCase{
|
||||||
|
{"mkdirAll", func(k syscallDispatcher) error {
|
||||||
|
return mountTmpfs(k, "ephemeral", "/sysroot/run/user/1000", 0, 1<<10, 0700)
|
||||||
|
}, []kexpect{
|
||||||
|
{"mkdirAll", expectArgs{"/sysroot/run/user/1000", os.FileMode(0700)}, nil, errUnique},
|
||||||
|
}, wrapErrSelf(errUnique)},
|
||||||
|
|
||||||
|
{"success no size", func(k syscallDispatcher) error {
|
||||||
|
return mountTmpfs(k, "ephemeral", "/sysroot/run/user/1000", 0, 0, 0710)
|
||||||
|
}, []kexpect{
|
||||||
|
{"mkdirAll", expectArgs{"/sysroot/run/user/1000", os.FileMode(0750)}, nil, nil},
|
||||||
|
{"mount", expectArgs{"ephemeral", "/sysroot/run/user/1000", "tmpfs", uintptr(0), "mode=0710"}, nil, nil},
|
||||||
|
}, nil},
|
||||||
|
|
||||||
|
{"success", func(k syscallDispatcher) error {
|
||||||
|
return mountTmpfs(k, "ephemeral", "/sysroot/run/user/1000", 0, 1<<10, 0700)
|
||||||
|
}, []kexpect{
|
||||||
|
{"mkdirAll", expectArgs{"/sysroot/run/user/1000", os.FileMode(0700)}, nil, nil},
|
||||||
|
{"mount", expectArgs{"ephemeral", "/sysroot/run/user/1000", "tmpfs", uintptr(0), "mode=0700,size=1024"}, nil, nil},
|
||||||
|
}, nil},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestParentPerm(t *testing.T) {
|
func TestParentPerm(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
perm os.FileMode
|
perm os.FileMode
|
||||||
|
@ -131,13 +131,14 @@ func ensureFile(name string, perm, pperm os.FileMode) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var hostProc = newProcPaths(hostPath)
|
var hostProc = newProcPaths(direct{}, hostPath)
|
||||||
|
|
||||||
func newProcPaths(prefix string) *procPaths {
|
func newProcPaths(k syscallDispatcher, prefix string) *procPaths {
|
||||||
return &procPaths{prefix + "/proc", prefix + "/proc/self"}
|
return &procPaths{k, prefix + "/proc", prefix + "/proc/self"}
|
||||||
}
|
}
|
||||||
|
|
||||||
type procPaths struct {
|
type procPaths struct {
|
||||||
|
k syscallDispatcher
|
||||||
prefix string
|
prefix string
|
||||||
self string
|
self string
|
||||||
}
|
}
|
||||||
@ -145,7 +146,7 @@ type procPaths struct {
|
|||||||
func (p *procPaths) stdout() string { return p.self + "/fd/1" }
|
func (p *procPaths) stdout() string { return p.self + "/fd/1" }
|
||||||
func (p *procPaths) fd(fd int) string { return p.self + "/fd/" + strconv.Itoa(fd) }
|
func (p *procPaths) fd(fd int) string { return p.self + "/fd/" + strconv.Itoa(fd) }
|
||||||
func (p *procPaths) mountinfo(f func(d *vfs.MountInfoDecoder) error) error {
|
func (p *procPaths) mountinfo(f func(d *vfs.MountInfoDecoder) error) error {
|
||||||
if r, err := os.Open(p.self + "/mountinfo"); err != nil {
|
if r, err := p.k.openNew(p.self + "/mountinfo"); err != nil {
|
||||||
return wrapErrSelf(err)
|
return wrapErrSelf(err)
|
||||||
} else {
|
} else {
|
||||||
d := vfs.NewMountInfoDecoder(r)
|
d := vfs.NewMountInfoDecoder(r)
|
||||||
|
@ -176,7 +176,7 @@ func TestProcPaths(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("mountinfo", func(t *testing.T) {
|
t.Run("mountinfo", func(t *testing.T) {
|
||||||
t.Run("nonexistent", func(t *testing.T) {
|
t.Run("nonexistent", func(t *testing.T) {
|
||||||
nonexistentProc := newProcPaths(t.TempDir())
|
nonexistentProc := newProcPaths(direct{}, t.TempDir())
|
||||||
wantErr := wrapErrSelf(&os.PathError{
|
wantErr := wrapErrSelf(&os.PathError{
|
||||||
Op: "open",
|
Op: "open",
|
||||||
Path: nonexistentProc.self + "/mountinfo",
|
Path: nonexistentProc.self + "/mountinfo",
|
||||||
@ -201,7 +201,7 @@ func TestProcPaths(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mountInfo *vfs.MountInfo
|
var mountInfo *vfs.MountInfo
|
||||||
if err := newProcPaths(tempDir).mountinfo(func(d *vfs.MountInfoDecoder) error { return d.Decode(&mountInfo) }); err != nil {
|
if err := newProcPaths(direct{}, tempDir).mountinfo(func(d *vfs.MountInfoDecoder) error { return d.Decode(&mountInfo) }); err != nil {
|
||||||
t.Fatalf("mountinfo: error = %v", err)
|
t.Fatalf("mountinfo: error = %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,7 +216,7 @@ func TestProcPaths(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("closed", func(t *testing.T) {
|
t.Run("closed", func(t *testing.T) {
|
||||||
p := newProcPaths(tempDir)
|
p := newProcPaths(direct{}, tempDir)
|
||||||
wantErr := wrapErrSelf(&os.PathError{
|
wantErr := wrapErrSelf(&os.PathError{
|
||||||
Op: "close",
|
Op: "close",
|
||||||
Path: p.self + "/mountinfo",
|
Path: p.self + "/mountinfo",
|
||||||
@ -243,7 +243,7 @@ func TestProcPaths(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wantErr := wrapErrSuffix(vfs.ErrMountInfoFields, "cannot parse mountinfo:")
|
wantErr := wrapErrSuffix(vfs.ErrMountInfoFields, "cannot parse mountinfo:")
|
||||||
if err := newProcPaths(tempDir).mountinfo(func(d *vfs.MountInfoDecoder) error { return d.Decode(new(*vfs.MountInfo)) }); !errors.Is(err, wantErr) {
|
if err := newProcPaths(direct{}, tempDir).mountinfo(func(d *vfs.MountInfoDecoder) error { return d.Decode(new(*vfs.MountInfo)) }); !errors.Is(err, wantErr) {
|
||||||
t.Fatalf("mountinfo: error = %v, want %v", err, wantErr)
|
t.Fatalf("mountinfo: error = %v, want %v", err, wantErr)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user