diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-08-01 04:04:36 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-08-01 04:04:36 +0900 |
| commit | 4e856438656ea0a1b30d52975f6b5415568df9a8 (patch) | |
| tree | 35874cf877c9c68d95e8d7e5c570b0b29d1039dc /container/autoroot.go | |
| parent | 987981df7313d0a121121be36f5c8cf86ffeacd1 (diff) | |
container: implement autoroot as setup op
This code is useful beyond just pd behaviour, and implementing it this way also reduces IPC overhead.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'container/autoroot.go')
| -rw-r--r-- | container/autoroot.go | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/container/autoroot.go b/container/autoroot.go new file mode 100644 index 00000000..b6375b8c --- /dev/null +++ b/container/autoroot.go @@ -0,0 +1,91 @@ +package container + +import ( + "encoding/gob" + "fmt" + "os" + "path" + . "syscall" +) + +func init() { gob.Register(new(AutoRootOp)) } + +// Root appends an [Op] that expands a directory into a toplevel bind mount mirror on container root. +// This is not a generic setup op. It is implemented here to reduce ipc overhead. +func (f *Ops) Root(host, prefix string, flags int) *Ops { + *f = append(*f, &AutoRootOp{host, prefix, flags, nil}) + return f +} + +type AutoRootOp struct { + Host, Prefix string + // passed through to bindMount + Flags int + + // obtained during early; + // these wrap the underlying Op because BindMountOp is relatively complex, + // so duplicating that code would be unwise + resolved []Op +} + +func (r *AutoRootOp) early(params *Params) error { + if !path.IsAbs(r.Host) { + return msg.WrapErr(EBADE, fmt.Sprintf("path %q is not absolute", r.Host)) + } + + if d, err := os.ReadDir(r.Host); err != nil { + return wrapErrSelf(err) + } else { + r.resolved = make([]Op, 0, len(d)) + for _, ent := range d { + name := ent.Name() + if IsAutoRootBindable(name) { + op := &BindMountOp{ + Source: path.Join(r.Host, name), + Target: "/" + name, + Flags: r.Flags, + } + if err = op.early(params); err != nil { + return err + } + r.resolved = append(r.resolved, op) + } + } + return nil + } +} + +func (r *AutoRootOp) apply(params *Params) error { + for _, op := range r.resolved { + msg.Verbosef("%s %s", op.prefix(), op) + if err := op.apply(params); err != nil { + return err + } + } + return nil +} + +func (r *AutoRootOp) Is(op Op) bool { + vr, ok := op.(*AutoRootOp) + return ok && ((r == nil && vr == nil) || (r != nil && vr != nil && + r.Host == vr.Host && r.Prefix == vr.Prefix && r.Flags == vr.Flags)) +} +func (*AutoRootOp) prefix() string { return "setting up" } +func (r *AutoRootOp) String() string { + return fmt.Sprintf("auto root %q prefix %s flags %#x", r.Host, r.Prefix, r.Flags) +} + +// IsAutoRootBindable returns whether a dir entry name is selected for AutoRoot. +func IsAutoRootBindable(name string) bool { + switch name { + case "proc": + case "dev": + case "tmp": + case "mnt": + case "etc": + + default: + return true + } + return false +} |
