container: implement autoroot as setup op
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m10s
Test / Hakurei (push) Successful in 3m7s
Test / Sandbox (race detector) (push) Successful in 4m1s
Test / Hpkg (push) Successful in 4m5s
Test / Hakurei (race detector) (push) Successful in 4m43s
Test / Flake checks (push) Successful in 1m22s
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m10s
Test / Hakurei (push) Successful in 3m7s
Test / Sandbox (race detector) (push) Successful in 4m1s
Test / Hpkg (push) Successful in 4m5s
Test / Hakurei (race detector) (push) Successful in 4m43s
Test / Flake checks (push) Successful in 1m22s
This code is useful beyond just pd behaviour, and implementing it this way also reduces IPC overhead. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
parent
987981df73
commit
4e85643865
91
container/autoroot.go
Normal file
91
container/autoroot.go
Normal file
@ -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
|
||||||
|
}
|
@ -121,6 +121,10 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
|||||||
log.Fatalf("cannot make / rslave: %v", err)
|
log.Fatalf("cannot make / rslave: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* early is called right before pivot_root into intermediate root;
|
||||||
|
this step is mostly for gathering information that would otherwise be difficult to obtain
|
||||||
|
via library functions after pivot_root, and implementations are expected to avoid changing
|
||||||
|
the state of the mount namespace */
|
||||||
for i, op := range *params.Ops {
|
for i, op := range *params.Ops {
|
||||||
if op == nil {
|
if op == nil {
|
||||||
log.Fatalf("invalid op %d", i)
|
log.Fatalf("invalid op %d", i)
|
||||||
@ -159,6 +163,10 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
|
|||||||
log.Fatalf("%v", err)
|
log.Fatalf("%v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* apply is called right after pivot_root and entering the new root;
|
||||||
|
this step sets up the container filesystem, and implementations are expected to keep the host root
|
||||||
|
and sysroot mount points intact but otherwise can do whatever they need to;
|
||||||
|
chdir is allowed but discouraged */
|
||||||
for i, op := range *params.Ops {
|
for i, op := range *params.Ops {
|
||||||
// ops already checked during early setup
|
// ops already checked during early setup
|
||||||
msg.Verbosef("%s %s", op.prefix(), op)
|
msg.Verbosef("%s %s", op.prefix(), op)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user