aboutsummaryrefslogtreecommitdiffhomepage
path: root/container/initplace.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-08-20 01:26:41 +0900
committerOphestra <cat@gensokyo.uk>2025-08-20 01:28:31 +0900
commitc81c9a9d75f179988cf858b85fe2de71bf9c2ff4 (patch)
tree157723a3f9a6f8a456fc939a1ef56e8e597d70f3 /container/initplace.go
parent339e4080dce73d372f6111773066b9c84308b6b7 (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.go81
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))
+}