aboutsummaryrefslogtreecommitdiffhomepage
path: root/sandbox/mount.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-03-17 02:55:36 +0900
committerOphestra <cat@gensokyo.uk>2025-03-17 02:55:36 +0900
commit24618ab9a1524e8b8986a9bf67667288e642fcf1 (patch)
treeb3f2a71a2c9bedf937d0fec00092ad9133cb3ec9 /sandbox/mount.go
parent9ce4706a0766880c072cccd2643d66f614a6a16b (diff)
sandbox: move out of internal
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'sandbox/mount.go')
-rw-r--r--sandbox/mount.go95
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))
+}