From 8aa65f28c68815db9dd1f246ee2656759574c3bb Mon Sep 17 00:00:00 2001 From: Ophestra Date: Sun, 17 Aug 2025 01:29:54 +0900 Subject: [PATCH] container: allow additional state between ops This is useful for ops that need to be aware of previous instances of themselves. Signed-off-by: Ophestra --- container/autoetc.go | 4 +-- container/autoroot.go | 8 +++--- container/init.go | 6 ++-- container/ops.go | 64 +++++++++++++++++++++++-------------------- 4 files changed, 44 insertions(+), 38 deletions(-) diff --git a/container/autoetc.go b/container/autoetc.go index 5687912..f494d75 100644 --- a/container/autoetc.go +++ b/container/autoetc.go @@ -20,8 +20,8 @@ func (f *Ops) Etc(host *Absolute, prefix string) *Ops { type AutoEtcOp struct{ Prefix string } -func (e *AutoEtcOp) early(*Params) error { return nil } -func (e *AutoEtcOp) apply(*Params) error { +func (e *AutoEtcOp) early(*setupState) error { return nil } +func (e *AutoEtcOp) apply(*setupState) error { const target = sysrootPath + FHSEtc rel := e.hostRel() + "/" diff --git a/container/autoroot.go b/container/autoroot.go index 70b504e..b155145 100644 --- a/container/autoroot.go +++ b/container/autoroot.go @@ -28,7 +28,7 @@ type AutoRootOp struct { resolved []Op } -func (r *AutoRootOp) early(params *Params) error { +func (r *AutoRootOp) early(state *setupState) error { if r.Host == nil { return syscall.EBADE } @@ -45,7 +45,7 @@ func (r *AutoRootOp) early(params *Params) error { Target: AbsFHSRoot.Append(name), Flags: r.Flags, } - if err = op.early(params); err != nil { + if err = op.early(state); err != nil { return err } r.resolved = append(r.resolved, op) @@ -55,10 +55,10 @@ func (r *AutoRootOp) early(params *Params) error { } } -func (r *AutoRootOp) apply(params *Params) error { +func (r *AutoRootOp) apply(state *setupState) error { for _, op := range r.resolved { msg.Verbosef("%s %s", op.prefix(), op) - if err := op.apply(params); err != nil { + if err := op.apply(state); err != nil { return err } } diff --git a/container/init.go b/container/init.go index 03ec883..f162de2 100644 --- a/container/init.go +++ b/container/init.go @@ -121,6 +121,8 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { log.Fatalf("cannot make / rslave: %v", err) } + state := &setupState{Params: ¶ms.Params} + /* 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 @@ -130,7 +132,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { log.Fatalf("invalid op %d", i) } - if err := op.early(¶ms.Params); err != nil { + if err := op.early(state); err != nil { msg.PrintBaseErr(err, fmt.Sprintf("cannot prepare op %d:", i)) msg.BeforeExit() @@ -170,7 +172,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) { for i, op := range *params.Ops { // ops already checked during early setup msg.Verbosef("%s %s", op.prefix(), op) - if err := op.apply(¶ms.Params); err != nil { + if err := op.apply(state); err != nil { msg.PrintBaseErr(err, fmt.Sprintf("cannot apply op %d:", i)) msg.BeforeExit() diff --git a/container/ops.go b/container/ops.go index 518d115..efc925b 100644 --- a/container/ops.go +++ b/container/ops.go @@ -31,14 +31,18 @@ type ( // Implementations of this interface are sent as a stream of gobs. Op interface { // early is called in host root. - early(params *Params) error + early(state *setupState) error // apply is called in intermediate root. - apply(params *Params) error + apply(state *setupState) error prefix() string Is(op Op) bool fmt.Stringer } + + setupState struct { + *Params + } ) // Grow grows the slice Ops points to using [slices.Grow]. @@ -57,8 +61,8 @@ type RemountOp struct { Flags uintptr } -func (*RemountOp) early(*Params) error { return nil } -func (r *RemountOp) apply(*Params) error { +func (*RemountOp) early(*setupState) error { return nil } +func (r *RemountOp) apply(*setupState) error { if r.Target == nil { return EBADE } @@ -93,7 +97,7 @@ const ( BindDevice ) -func (b *BindMountOp) early(*Params) error { +func (b *BindMountOp) early(*setupState) error { if b.Source == nil || b.Target == nil { return EBADE } @@ -110,7 +114,7 @@ func (b *BindMountOp) early(*Params) error { } } -func (b *BindMountOp) apply(*Params) error { +func (b *BindMountOp) apply(*setupState) error { if b.sourceFinal == nil { if b.Flags&BindOptional == 0 { // unreachable @@ -166,13 +170,13 @@ type MountProcOp struct { Target *Absolute } -func (p *MountProcOp) early(*Params) error { return nil } -func (p *MountProcOp) apply(params *Params) error { +func (p *MountProcOp) early(*setupState) error { return nil } +func (p *MountProcOp) apply(state *setupState) error { if p.Target == nil { return EBADE } target := toSysroot(p.Target.String()) - if err := os.MkdirAll(target, params.ParentPerm); err != nil { + if err := os.MkdirAll(target, state.ParentPerm); err != nil { return wrapErrSelf(err) } return wrapErrSuffix(Mount(SourceProc, target, FstypeProc, MS_NOSUID|MS_NOEXEC|MS_NODEV, zeroString), @@ -207,20 +211,20 @@ type MountDevOp struct { Write bool } -func (d *MountDevOp) early(*Params) error { return nil } -func (d *MountDevOp) apply(params *Params) error { +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, params.ParentPerm); err != nil { + 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, params.ParentPerm); err != nil { + if err := ensureFile(targetPath, 0444, state.ParentPerm); err != nil { return err } if err := hostProc.bindMount( @@ -252,7 +256,7 @@ func (d *MountDevOp) apply(params *Params) error { devPtsPath := path.Join(target, "pts") for _, name := range []string{path.Join(target, "shm"), devPtsPath} { - if err := os.Mkdir(name, params.ParentPerm); err != nil { + if err := os.Mkdir(name, state.ParentPerm); err != nil { return wrapErrSelf(err) } } @@ -263,11 +267,11 @@ func (d *MountDevOp) apply(params *Params) error { fmt.Sprintf("cannot mount devpts on %q:", devPtsPath)) } - if params.RetainSession { + 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, params.ParentPerm); err != nil { + if err := ensureFile(consolePath, 0444, state.ParentPerm); err != nil { return err } if name, err := os.Readlink(hostProc.stdout()); err != nil { @@ -285,7 +289,7 @@ func (d *MountDevOp) apply(params *Params) error { if d.Mqueue { mqueueTarget := path.Join(target, "mqueue") - if err := os.Mkdir(mqueueTarget, params.ParentPerm); err != nil { + 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 { @@ -331,8 +335,8 @@ type MountTmpfsOp struct { Perm os.FileMode } -func (t *MountTmpfsOp) early(*Params) error { return nil } -func (t *MountTmpfsOp) apply(*Params) error { +func (t *MountTmpfsOp) early(*setupState) error { return nil } +func (t *MountTmpfsOp) apply(*setupState) error { if t.Path == nil { return EBADE } @@ -394,7 +398,7 @@ type MountOverlayOp struct { ephemeral bool } -func (o *MountOverlayOp) early(*Params) error { +func (o *MountOverlayOp) early(*setupState) error { if o.Work == nil && o.Upper != nil { switch o.Upper.String() { case FHSRoot: // ephemeral @@ -444,12 +448,12 @@ func (o *MountOverlayOp) early(*Params) error { return nil } -func (o *MountOverlayOp) apply(params *Params) error { +func (o *MountOverlayOp) apply(state *setupState) error { if o.Target == nil { return EBADE } target := toSysroot(o.Target.String()) - if err := os.MkdirAll(target, params.ParentPerm); err != nil { + if err := os.MkdirAll(target, state.ParentPerm); err != nil { return wrapErrSelf(err) } @@ -517,7 +521,7 @@ type SymlinkOp struct { Dereference bool } -func (l *SymlinkOp) early(*Params) error { +func (l *SymlinkOp) early(*setupState) error { if l.Dereference { if !isAbs(l.LinkName) { return msg.WrapErr(EBADE, fmt.Sprintf("path %q is not absolute", l.LinkName)) @@ -531,12 +535,12 @@ func (l *SymlinkOp) early(*Params) error { return nil } -func (l *SymlinkOp) apply(params *Params) error { +func (l *SymlinkOp) apply(state *setupState) error { if l.Target == nil { return EBADE } target := toSysroot(l.Target.String()) - if err := os.MkdirAll(path.Dir(target), params.ParentPerm); err != nil { + if err := os.MkdirAll(path.Dir(target), state.ParentPerm); err != nil { return wrapErrSelf(err) } if err := os.Symlink(l.LinkName, target); err != nil { @@ -564,8 +568,8 @@ type MkdirOp struct { Perm os.FileMode } -func (m *MkdirOp) early(*Params) error { return nil } -func (m *MkdirOp) apply(*Params) error { +func (m *MkdirOp) early(*setupState) error { return nil } +func (m *MkdirOp) apply(*setupState) error { if m.Path == nil { return EBADE } @@ -598,8 +602,8 @@ type TmpfileOp struct { Data []byte } -func (t *TmpfileOp) early(*Params) error { return nil } -func (t *TmpfileOp) apply(params *Params) error { +func (t *TmpfileOp) early(*setupState) error { return nil } +func (t *TmpfileOp) apply(state *setupState) error { if t.Path == nil { return EBADE } @@ -618,7 +622,7 @@ func (t *TmpfileOp) apply(params *Params) error { } target := toSysroot(t.Path.String()) - if err := ensureFile(target, 0444, params.ParentPerm); err != nil { + if err := ensureFile(target, 0444, state.ParentPerm); err != nil { return err } else if err = hostProc.bindMount( tmpPath,