diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-03-17 02:55:36 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-03-17 02:55:36 +0900 |
| commit | 24618ab9a1524e8b8986a9bf67667288e642fcf1 (patch) | |
| tree | b3f2a71a2c9bedf937d0fec00092ad9133cb3ec9 /sandbox/mount.go | |
| parent | 9ce4706a0766880c072cccd2643d66f614a6a16b (diff) | |
sandbox: move out of internal
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'sandbox/mount.go')
| -rw-r--r-- | sandbox/mount.go | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/sandbox/mount.go b/sandbox/mount.go new file mode 100644 index 00000000..e47e7f5d --- /dev/null +++ b/sandbox/mount.go @@ -0,0 +1,95 @@ +package sandbox + +import ( + "errors" + "fmt" + "os" + "strings" + "syscall" +) + +const ( + BindOptional = 1 << iota + BindSource + BindRecursive + BindWritable + BindDevices +) + +func bindMount(src, dest string, flags int) error { + target := toSysroot(dest) + var source string + + if flags&BindSource == 0 { + // this is what bwrap does, so the behaviour is kept for now, + // however recursively resolving links might improve user experience + if rp, err := realpathHost(src); err != nil { + if os.IsNotExist(err) { + if flags&BindOptional != 0 { + return nil + } else { + return msg.WrapErr(err, + fmt.Sprintf("path %q does not exist", src)) + } + } + return msg.WrapErr(err, err.Error()) + } else { + source = toHost(rp) + } + } else if flags&BindOptional != 0 { + return msg.WrapErr(syscall.EINVAL, + "flag source excludes optional") + } else { + source = toHost(src) + } + + if fi, err := os.Stat(source); err != nil { + return msg.WrapErr(err, err.Error()) + } else if fi.IsDir() { + if err = os.MkdirAll(target, 0755); err != nil { + return wrapErrSuffix(err, + fmt.Sprintf("cannot create directory %q:", dest)) + } + } else if err = ensureFile(target, 0444); err != nil { + if errors.Is(err, syscall.EISDIR) { + return msg.WrapErr(err, + fmt.Sprintf("path %q is a directory", dest)) + } + return wrapErrSuffix(err, + fmt.Sprintf("cannot create %q:", dest)) + } + + var mf uintptr = syscall.MS_SILENT | syscall.MS_BIND + if flags&BindRecursive != 0 { + mf |= syscall.MS_REC + } + if flags&BindWritable == 0 { + mf |= syscall.MS_RDONLY + } + if flags&BindDevices == 0 { + mf |= syscall.MS_NODEV + } + if msg.IsVerbose() { + if strings.TrimPrefix(source, hostPath) == strings.TrimPrefix(target, sysrootPath) { + msg.Verbosef("resolved %q flags %#x", target, mf) + } else { + msg.Verbosef("resolved %q on %q flags %#x", source, target, mf) + } + } + return wrapErrSuffix(syscall.Mount(source, target, "", mf, ""), + fmt.Sprintf("cannot bind %q on %q:", src, dest)) +} + +func mountTmpfs(fsname, name string, size int, perm os.FileMode) error { + target := toSysroot(name) + if err := os.MkdirAll(target, perm); err != nil { + return err + } + opt := fmt.Sprintf("mode=%#o", perm) + if size > 0 { + opt += fmt.Sprintf(",size=%d", size) + } + return wrapErrSuffix(syscall.Mount(fsname, target, "tmpfs", + syscall.MS_NOSUID|syscall.MS_NODEV, opt), + fmt.Sprintf("cannot mount tmpfs on %q:", name)) +} |
