diff options
| author | Ophestra <cat@gensokyo.uk> | 2025-08-20 01:26:41 +0900 |
|---|---|---|
| committer | Ophestra <cat@gensokyo.uk> | 2025-08-20 01:28:31 +0900 |
| commit | c81c9a9d75f179988cf858b85fe2de71bf9c2ff4 (patch) | |
| tree | 157723a3f9a6f8a456fc939a1ef56e8e597d70f3 /container/initplace.go | |
| parent | 339e4080dce73d372f6111773066b9c84308b6b7 (diff) | |
container/init: split setup ops into individual files
This significantly increases readability.
Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'container/initplace.go')
| -rw-r--r-- | container/initplace.go | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/container/initplace.go b/container/initplace.go new file mode 100644 index 00000000..ce7ad86b --- /dev/null +++ b/container/initplace.go @@ -0,0 +1,81 @@ +package container + +import ( + "encoding/gob" + "fmt" + "os" + "slices" + . "syscall" +) + +const ( + // intermediate root file name pattern for [TmpfileOp] + intermediatePatternTmpfile = "tmp.*" +) + +func init() { gob.Register(new(TmpfileOp)) } + +// Place appends an [Op] that places a file in container path [TmpfileOp.Path] containing [TmpfileOp.Data]. +func (f *Ops) Place(name *Absolute, data []byte) *Ops { + *f = append(*f, &TmpfileOp{name, data}) + return f +} + +// PlaceP is like Place but writes the address of [TmpfileOp.Data] to the pointer dataP points to. +func (f *Ops) PlaceP(name *Absolute, dataP **[]byte) *Ops { + t := &TmpfileOp{Path: name} + *dataP = &t.Data + + *f = append(*f, t) + return f +} + +// TmpfileOp places a file on container Path containing Data. +type TmpfileOp struct { + Path *Absolute + Data []byte +} + +func (t *TmpfileOp) early(*setupState) error { return nil } +func (t *TmpfileOp) apply(state *setupState) error { + if t.Path == nil { + return EBADE + } + + var tmpPath string + if f, err := os.CreateTemp(FHSRoot, intermediatePatternTmpfile); err != nil { + return wrapErrSelf(err) + } else if _, err = f.Write(t.Data); err != nil { + return wrapErrSuffix(err, + "cannot write to intermediate file:") + } else if err = f.Close(); err != nil { + return wrapErrSuffix(err, + "cannot close intermediate file:") + } else { + tmpPath = f.Name() + } + + target := toSysroot(t.Path.String()) + if err := ensureFile(target, 0444, state.ParentPerm); err != nil { + return err + } else if err = hostProc.bindMount( + tmpPath, + target, + MS_RDONLY|MS_NODEV, + false, + ); err != nil { + return err + } else if err = os.Remove(tmpPath); err != nil { + return wrapErrSelf(err) + } + return nil +} + +func (t *TmpfileOp) Is(op Op) bool { + vt, ok := op.(*TmpfileOp) + return ok && t.Path == vt.Path && slices.Equal(t.Data, vt.Data) +} +func (*TmpfileOp) prefix() string { return "placing" } +func (t *TmpfileOp) String() string { + return fmt.Sprintf("tmpfile %q (%d bytes)", t.Path, len(t.Data)) +} |
