Some checks failed
Test / Create distribution (push) Successful in 34s
Test / Flake checks (push) Has been cancelled
Test / Sandbox (race detector) (push) Has been cancelled
Test / Sandbox (push) Has been cancelled
Test / Hakurei (race detector) (push) Has been cancelled
Test / Hakurei (push) Has been cancelled
Test / Hpkg (push) Has been cancelled
This significantly increases readability. Signed-off-by: Ophestra <cat@gensokyo.uk>
137 lines
3.6 KiB
Go
137 lines
3.6 KiB
Go
package container
|
|
|
|
import (
|
|
"encoding/gob"
|
|
"fmt"
|
|
"os"
|
|
"path"
|
|
. "syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
func init() { gob.Register(new(MountDevOp)) }
|
|
|
|
// Dev appends an [Op] that mounts a subset of host /dev.
|
|
func (f *Ops) Dev(target *Absolute, mqueue bool) *Ops {
|
|
*f = append(*f, &MountDevOp{target, mqueue, false})
|
|
return f
|
|
}
|
|
|
|
// DevWritable appends an [Op] that mounts a writable subset of host /dev.
|
|
// There is usually no good reason to write to /dev, so this should always be followed by a [RemountOp].
|
|
func (f *Ops) DevWritable(target *Absolute, mqueue bool) *Ops {
|
|
*f = append(*f, &MountDevOp{target, mqueue, true})
|
|
return f
|
|
}
|
|
|
|
// MountDevOp mounts a subset of host /dev on container path Target.
|
|
// If Mqueue is true, a private instance of [FstypeMqueue] is mounted.
|
|
// If Write is true, the resulting mount point is left writable.
|
|
type MountDevOp struct {
|
|
Target *Absolute
|
|
Mqueue bool
|
|
Write bool
|
|
}
|
|
|
|
func (d *MountDevOp) early(*setupState) error { return nil }
|
|
func (d *MountDevOp) apply(state *setupState) error {
|
|
if d.Target == nil {
|
|
return EBADE
|
|
}
|
|
target := toSysroot(d.Target.String())
|
|
|
|
if err := mountTmpfs(SourceTmpfsDevtmpfs, target, MS_NOSUID|MS_NODEV, 0, state.ParentPerm); err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, name := range []string{"null", "zero", "full", "random", "urandom", "tty"} {
|
|
targetPath := path.Join(target, name)
|
|
if err := ensureFile(targetPath, 0444, state.ParentPerm); err != nil {
|
|
return err
|
|
}
|
|
if err := hostProc.bindMount(
|
|
toHost(FHSDev+name),
|
|
targetPath,
|
|
0,
|
|
true,
|
|
); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for i, name := range []string{"stdin", "stdout", "stderr"} {
|
|
if err := os.Symlink(
|
|
FHSProc+"self/fd/"+string(rune(i+'0')),
|
|
path.Join(target, name),
|
|
); err != nil {
|
|
return wrapErrSelf(err)
|
|
}
|
|
}
|
|
for _, pair := range [][2]string{
|
|
{FHSProc + "self/fd", "fd"},
|
|
{FHSProc + "kcore", "core"},
|
|
{"pts/ptmx", "ptmx"},
|
|
} {
|
|
if err := os.Symlink(pair[0], path.Join(target, pair[1])); err != nil {
|
|
return wrapErrSelf(err)
|
|
}
|
|
}
|
|
|
|
devPtsPath := path.Join(target, "pts")
|
|
for _, name := range []string{path.Join(target, "shm"), devPtsPath} {
|
|
if err := os.Mkdir(name, state.ParentPerm); err != nil {
|
|
return wrapErrSelf(err)
|
|
}
|
|
}
|
|
|
|
if err := Mount(SourceDevpts, devPtsPath, FstypeDevpts, MS_NOSUID|MS_NOEXEC,
|
|
"newinstance,ptmxmode=0666,mode=620"); err != nil {
|
|
return wrapErrSuffix(err,
|
|
fmt.Sprintf("cannot mount devpts on %q:", devPtsPath))
|
|
}
|
|
|
|
if state.RetainSession {
|
|
var buf [8]byte
|
|
if _, _, errno := Syscall(SYS_IOCTL, 1, TIOCGWINSZ, uintptr(unsafe.Pointer(&buf[0]))); errno == 0 {
|
|
consolePath := path.Join(target, "console")
|
|
if err := ensureFile(consolePath, 0444, state.ParentPerm); err != nil {
|
|
return err
|
|
}
|
|
if name, err := os.Readlink(hostProc.stdout()); err != nil {
|
|
return wrapErrSelf(err)
|
|
} else if err = hostProc.bindMount(
|
|
toHost(name),
|
|
consolePath,
|
|
0,
|
|
false,
|
|
); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
if d.Mqueue {
|
|
mqueueTarget := path.Join(target, "mqueue")
|
|
if err := os.Mkdir(mqueueTarget, state.ParentPerm); err != nil {
|
|
return wrapErrSelf(err)
|
|
}
|
|
if err := Mount(SourceMqueue, mqueueTarget, FstypeMqueue, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString); err != nil {
|
|
return wrapErrSuffix(err, "cannot mount mqueue:")
|
|
}
|
|
}
|
|
|
|
if d.Write {
|
|
return nil
|
|
}
|
|
return wrapErrSuffix(hostProc.remount(target, MS_RDONLY),
|
|
fmt.Sprintf("cannot remount %q:", target))
|
|
}
|
|
|
|
func (d *MountDevOp) Is(op Op) bool { vd, ok := op.(*MountDevOp); return ok && *d == *vd }
|
|
func (*MountDevOp) prefix() string { return "mounting" }
|
|
func (d *MountDevOp) String() string {
|
|
if d.Mqueue {
|
|
return fmt.Sprintf("dev on %q with mqueue", d.Target)
|
|
}
|
|
return fmt.Sprintf("dev on %q", d.Target)
|
|
}
|