aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-08-25 18:30:40 +0900
committerOphestra <cat@gensokyo.uk>2025-08-25 18:38:19 +0900
commit6d202d73b41d28166f7bea7da36d1ce054711ff9 (patch)
tree8af4f9212fe7c3c49c8035119e8a4405e2c97070
parent1438096339f49bdd466f3b057c7e695aa126fc3c (diff)
hst/fsbind: optional autoetc behaviour
This generalises the special field allowing any special behaviour to be matched from target. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--cmd/hakurei/print_test.go6
-rw-r--r--hst/fs.go10
-rw-r--r--hst/fs_test.go4
-rw-r--r--hst/fsbind.go68
-rw-r--r--hst/fsbind_test.go40
-rw-r--r--hst/fsephemeral.go6
-rw-r--r--hst/fsoverlay.go6
-rw-r--r--hst/hst_test.go2
-rw-r--r--internal/app/container_linux.go10
-rw-r--r--internal/app/seal_linux.go8
10 files changed, 107 insertions, 53 deletions
diff --git a/cmd/hakurei/print_test.go b/cmd/hakurei/print_test.go
index b55c1044..471cb358 100644
--- a/cmd/hakurei/print_test.go
+++ b/cmd/hakurei/print_test.go
@@ -284,7 +284,7 @@ App
"dst": "/",
"src": "/var/lib/hakurei/base/org.debian",
"write": true,
- "autoroot": true
+ "special": true
},
{
"type": "ephemeral",
@@ -438,7 +438,7 @@ App
"dst": "/",
"src": "/var/lib/hakurei/base/org.debian",
"write": true,
- "autoroot": true
+ "special": true
},
{
"type": "ephemeral",
@@ -646,7 +646,7 @@ func Test_printPs(t *testing.T) {
"dst": "/",
"src": "/var/lib/hakurei/base/org.debian",
"write": true,
- "autoroot": true
+ "special": true
},
{
"type": "ephemeral",
diff --git a/hst/fs.go b/hst/fs.go
index b33d0492..a2a75a78 100644
--- a/hst/fs.go
+++ b/hst/fs.go
@@ -18,11 +18,19 @@ type FilesystemConfig interface {
// Host returns a slice of all host paths used by this operation.
Host() []*container.Absolute
// Apply appends the [container.Op] implementing this operation.
- Apply(ops *container.Ops)
+ Apply(z *ApplyState)
fmt.Stringer
}
+// ApplyState holds the address of [container.Ops] and any relevant application state.
+type ApplyState struct {
+ // AutoEtcPrefix is the prefix for [container.AutoEtcOp].
+ AutoEtcPrefix string
+
+ *container.Ops
+}
+
var (
ErrFSNull = errors.New("unexpected null in mount point")
)
diff --git a/hst/fs_test.go b/hst/fs_test.go
index 43825c65..af8738f6 100644
--- a/hst/fs_test.go
+++ b/hst/fs_test.go
@@ -209,7 +209,7 @@ type stubFS struct {
func (s stubFS) Valid() bool { return false }
func (s stubFS) Path() *container.Absolute { panic("unreachable") }
func (s stubFS) Host() []*container.Absolute { panic("unreachable") }
-func (s stubFS) Apply(*container.Ops) { panic("unreachable") }
+func (s stubFS) Apply(*hst.ApplyState) { panic("unreachable") }
func (s stubFS) String() string { return "<invalid " + s.typeName + ">" }
type sCheck struct {
@@ -238,7 +238,7 @@ func checkFs(t *testing.T, testCases []fsTestCase) {
t.Run("ops", func(t *testing.T) {
ops := new(container.Ops)
- tc.fs.Apply(ops)
+ tc.fs.Apply(&hst.ApplyState{AutoEtcPrefix: ":3", Ops: ops})
if !reflect.DeepEqual(ops, &tc.ops) {
gotString := new(strings.Builder)
for _, op := range *ops {
diff --git a/hst/fsbind.go b/hst/fsbind.go
index 50e8da56..496453b3 100644
--- a/hst/fsbind.go
+++ b/hst/fsbind.go
@@ -25,17 +25,38 @@ type FSBind struct {
// skip this mount point if the host path does not exist
Optional bool `json:"optional,omitempty"`
- // enable autoroot behaviour;
- // this requires Target to be [container.AbsFHSRoot].
- AutoRoot bool `json:"autoroot,omitempty"`
+ // enable special behaviour:
+ // for autoroot, Target must be set to [container.AbsFHSRoot];
+ // for autoetc, Target must be set to [container.AbsFHSEtc]
+ Special bool `json:"special,omitempty"`
+}
+
+// IsAutoRoot returns whether this FSBind has autoroot behaviour enabled.
+func (b *FSBind) IsAutoRoot() bool {
+ return b.Valid() && b.Special && b.Target.String() == container.FHSRoot
+}
+
+// IsAutoEtc returns whether this FSBind has autoetc behaviour enabled.
+func (b *FSBind) IsAutoEtc() bool {
+ return b.Valid() && b.Special && b.Target.String() == container.FHSEtc
}
func (b *FSBind) Valid() bool {
if b == nil || b.Source == nil {
return false
}
- if b.AutoRoot && (b.Target == nil || b.Target.String() != container.FHSRoot) {
- return false
+ if b.Special {
+ if b.Target == nil {
+ return false
+ } else {
+ switch b.Target.String() {
+ case container.FHSRoot, container.FHSEtc:
+ break
+
+ default:
+ return false
+ }
+ }
}
return true
}
@@ -57,7 +78,7 @@ func (b *FSBind) Host() []*container.Absolute {
return []*container.Absolute{b.Source}
}
-func (b *FSBind) Apply(ops *container.Ops) {
+func (b *FSBind) Apply(z *ApplyState) {
if !b.Valid() {
return
}
@@ -77,10 +98,15 @@ func (b *FSBind) Apply(ops *container.Ops) {
flags |= container.BindOptional
}
- if !b.AutoRoot {
- ops.Bind(b.Source, target, flags)
- } else {
- ops.Root(b.Source, flags)
+ switch {
+ case b.IsAutoRoot():
+ z.Root(b.Source, flags)
+
+ case b.IsAutoEtc():
+ z.Etc(b.Source, z.AutoEtcPrefix)
+
+ default:
+ z.Bind(b.Source, target, flags)
}
}
@@ -96,15 +122,21 @@ func (b *FSBind) String() string {
flagSym = "w"
}
- if b.AutoRoot {
- prefix := "autoroot"
- if flagSym != "" {
- prefix += ":" + flagSym
- }
- if b.Source.String() != container.FHSRoot {
- return prefix + ":" + b.Source.String()
+ if b.Special {
+ switch {
+ case b.IsAutoRoot():
+ prefix := "autoroot"
+ if flagSym != "" {
+ prefix += ":" + flagSym
+ }
+ if b.Source.String() != container.FHSRoot {
+ return prefix + ":" + b.Source.String()
+ }
+ return prefix
+
+ case b.IsAutoEtc():
+ return "autoetc:" + b.Source.String()
}
- return prefix
}
g := 4 + len(b.Source.String())
diff --git a/hst/fsbind_test.go b/hst/fsbind_test.go
index 750dd93a..b2fb0f7a 100644
--- a/hst/fsbind_test.go
+++ b/hst/fsbind_test.go
@@ -63,35 +63,45 @@ func TestFSBind(t *testing.T) {
}}, m("/"), ms("/"),
"*/"},
- {"autoroot nil target", &hst.FSBind{
- Source: m("/"),
- AutoRoot: true,
+ {"special nil target", &hst.FSBind{
+ Source: m("/"),
+ Special: true,
}, false, nil, nil, nil, "<invalid>"},
- {"autoroot bad target", &hst.FSBind{
- Source: m("/"),
- Target: m("/etc/"),
- AutoRoot: true,
+ {"special bad target", &hst.FSBind{
+ Source: m("/"),
+ Target: m("/var/"),
+ Special: true,
}, false, nil, nil, nil, "<invalid>"},
{"autoroot pd", &hst.FSBind{
- Target: m("/"),
- Source: m("/"),
- Write: true,
- AutoRoot: true,
+ Target: m("/"),
+ Source: m("/"),
+ Write: true,
+ Special: true,
}, true, container.Ops{&container.AutoRootOp{
Host: m("/"),
Flags: container.BindWritable,
}}, m("/"), ms("/"), "autoroot:w"},
{"autoroot silly", &hst.FSBind{
- Target: m("/"),
- Source: m("/etc"),
- Write: true,
- AutoRoot: true,
+ Target: m("/"),
+ Source: m("/etc"),
+ Write: true,
+ Special: true,
}, true, container.Ops{&container.AutoRootOp{
Host: m("/etc"),
Flags: container.BindWritable,
}}, m("/"), ms("/etc"), "autoroot:w:/etc"},
+
+ {"autoetc", &hst.FSBind{
+ Target: m("/etc/"),
+ Source: m("/etc/"),
+ Special: true,
+ }, true, container.Ops{
+ &container.MkdirOp{Path: m("/etc/"), Perm: 0755},
+ &container.BindMountOp{Source: m("/etc/"), Target: m("/etc/.host/:3")},
+ &container.AutoEtcOp{Prefix: ":3"},
+ }, m("/etc/"), ms("/etc/"), "autoetc:/etc/"},
})
}
diff --git a/hst/fsephemeral.go b/hst/fsephemeral.go
index 424a058d..ad212fda 100644
--- a/hst/fsephemeral.go
+++ b/hst/fsephemeral.go
@@ -38,7 +38,7 @@ func (e *FSEphemeral) Host() []*container.Absolute { return nil }
const fsEphemeralDefaultPerm = os.FileMode(0755)
-func (e *FSEphemeral) Apply(ops *container.Ops) {
+func (e *FSEphemeral) Apply(z *ApplyState) {
if !e.Valid() {
return
}
@@ -54,9 +54,9 @@ func (e *FSEphemeral) Apply(ops *container.Ops) {
}
if e.Write {
- ops.Tmpfs(e.Target, size, perm)
+ z.Tmpfs(e.Target, size, perm)
} else {
- ops.Readonly(e.Target, perm)
+ z.Readonly(e.Target, perm)
}
}
diff --git a/hst/fsoverlay.go b/hst/fsoverlay.go
index 8d63e163..9b8e97f9 100644
--- a/hst/fsoverlay.go
+++ b/hst/fsoverlay.go
@@ -62,15 +62,15 @@ func (o *FSOverlay) Host() []*container.Absolute {
return p
}
-func (o *FSOverlay) Apply(op *container.Ops) {
+func (o *FSOverlay) Apply(z *ApplyState) {
if !o.Valid() {
return
}
if o.Upper != nil && o.Work != nil { // rw
- op.Overlay(o.Target, o.Upper, o.Work, o.Lower...)
+ z.Overlay(o.Target, o.Upper, o.Work, o.Lower...)
} else { // ro
- op.OverlayReadonly(o.Target, o.Lower...)
+ z.OverlayReadonly(o.Target, o.Lower...)
}
}
diff --git a/hst/hst_test.go b/hst/hst_test.go
index b8ec79c9..897bf930 100644
--- a/hst/hst_test.go
+++ b/hst/hst_test.go
@@ -107,7 +107,7 @@ func TestTemplate(t *testing.T) {
"dst": "/",
"src": "/var/lib/hakurei/base/org.debian",
"write": true,
- "autoroot": true
+ "special": true
},
{
"type": "ephemeral",
diff --git a/internal/app/container_linux.go b/internal/app/container_linux.go
index 33c0c72a..30477fee 100644
--- a/internal/app/container_linux.go
+++ b/internal/app/container_linux.go
@@ -40,9 +40,13 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
ForwardCancel: s.WaitDelay >= 0,
}
+ as := &hst.ApplyState{
+ AutoEtcPrefix: prefix,
+ }
{
ops := make(container.Ops, 0, preallocateOpsCount+len(s.Filesystem)+len(s.Link))
params.Ops = &ops
+ as.Ops = &ops
}
if s.Multiarch {
@@ -81,10 +85,10 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
// if the first element targets /, it is inserted early and excluded from path hiding
rootfs := filesystem[0].FilesystemConfig
filesystem = filesystem[1:]
- rootfs.Apply(params.Ops)
+ rootfs.Apply(as)
// autoroot requires special handling during path hiding
- if b, ok := rootfs.(*hst.FSBind); ok && b.Valid() && b.AutoRoot {
+ if b, ok := rootfs.(*hst.FSBind); ok && b.IsAutoRoot() {
autoroot = b
}
}
@@ -143,7 +147,7 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
if !c.Valid() {
return nil, nil, fmt.Errorf("invalid filesystem at index %d", i)
}
- c.Apply(params.Ops)
+ c.Apply(as)
// fs counter
hidePathSourceCount += len(c.Host())
diff --git a/internal/app/seal_linux.go b/internal/app/seal_linux.go
index fb6f39b6..4e77e79e 100644
--- a/internal/app/seal_linux.go
+++ b/internal/app/seal_linux.go
@@ -246,10 +246,10 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
Filesystem: []hst.FilesystemConfigJSON{
{&hst.FSBind{
- Target: container.AbsFHSRoot,
- Source: container.AbsFHSRoot,
- Write: true,
- AutoRoot: true,
+ Target: container.AbsFHSRoot,
+ Source: container.AbsFHSRoot,
+ Write: true,
+ Special: true,
}},
},
}