hst/fs: interface filesystem config
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m14s
Test / Hakurei (push) Successful in 3m37s
Test / Hpkg (push) Successful in 4m27s
Test / Sandbox (race detector) (push) Successful in 4m23s
Test / Hakurei (race detector) (push) Successful in 5m22s
Test / Flake checks (push) Successful in 1m22s

This allows mount points to be represented by different underlying structs.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2025-08-12 04:38:45 +09:00
parent e99d7affb0
commit 99ac96511b
22 changed files with 927 additions and 223 deletions

View File

@@ -13,6 +13,9 @@ import (
)
func m(pathname string) *container.Absolute { return container.MustAbs(pathname) }
func f(c hst.FilesystemConfig) hst.FilesystemConfigJSON {
return hst.FilesystemConfigJSON{FilesystemConfig: c}
}
var testCasesNixos = []sealTestCase{
{
@@ -25,11 +28,18 @@ var testCasesNixos = []sealTestCase{
Container: &hst.ContainerConfig{
Userns: true, Net: true, MapRealUID: true, Env: nil, AutoEtc: true,
Filesystem: []hst.FilesystemConfig{
{Src: m("/bin"), Must: true}, {Src: m("/usr/bin/"), Must: true},
{Src: m("/nix/store"), Must: true}, {Src: m("/run/current-system"), Must: true},
{Src: m("/sys/block")}, {Src: m("/sys/bus")}, {Src: m("/sys/class")}, {Src: m("/sys/dev")}, {Src: m("/sys/devices")},
{Src: m("/run/opengl-driver"), Must: true}, {Src: m("/dev/dri"), Device: true},
Filesystem: []hst.FilesystemConfigJSON{
f(&hst.FSBind{Src: m("/bin")}),
f(&hst.FSBind{Src: m("/usr/bin/")}),
f(&hst.FSBind{Src: m("/nix/store")}),
f(&hst.FSBind{Src: m("/run/current-system")}),
f(&hst.FSBind{Src: m("/sys/block"), Optional: true}),
f(&hst.FSBind{Src: m("/sys/bus"), Optional: true}),
f(&hst.FSBind{Src: m("/sys/class"), Optional: true}),
f(&hst.FSBind{Src: m("/sys/dev"), Optional: true}),
f(&hst.FSBind{Src: m("/sys/devices"), Optional: true}),
f(&hst.FSBind{Src: m("/run/opengl-driver")}),
f(&hst.FSBind{Src: m("/dev/dri"), Device: true, Optional: true}),
},
},
SystemBus: &dbus.Config{

View File

@@ -6,7 +6,6 @@ import (
"io/fs"
"maps"
"path"
"slices"
"syscall"
"hakurei.app/container"
@@ -126,73 +125,63 @@ func newContainer(s *hst.ContainerConfig, os sys.State, prefix string, uid, gid
return nil, nil, err
}
}
// evaluated path, input path
hidePathSource := make([][2]string, 0, len(s.Filesystem))
var hidePathSourceCount int
for i, c := range s.Filesystem {
if !c.Valid() {
return nil, nil, fmt.Errorf("invalid filesystem at index %d", i)
}
c.Apply(params.Ops)
// fs counter
hidePathSourceCount += len(c.Host())
}
// AutoRoot is a collection of many BindMountOp internally
var autoRootEntries []fs.DirEntry
if s.AutoRoot != nil {
if d, err := os.ReadDir(s.AutoRoot.String()); err != nil {
return nil, nil, err
} else {
hidePathSource = slices.Grow(hidePathSource, len(d))
for _, ent := range d {
name := ent.Name()
if container.IsAutoRootBindable(name) {
name = path.Join(s.AutoRoot.String(), name)
srcP := [2]string{name, name}
if err = evalSymlinks(os, &srcP[0]); err != nil {
return nil, nil, err
}
hidePathSource = append(hidePathSource, srcP)
}
// autoroot counter
hidePathSourceCount += len(d)
autoRootEntries = d
}
}
hidePathSource := make([]*container.Absolute, 0, hidePathSourceCount)
// fs append
for _, c := range s.Filesystem {
// all entries already checked above
hidePathSource = append(hidePathSource, c.Host()...)
}
// autoroot append
if s.AutoRoot != nil {
for _, ent := range autoRootEntries {
name := ent.Name()
if container.IsAutoRootBindable(name) {
hidePathSource = append(hidePathSource, s.AutoRoot.Append(name))
}
}
}
for i, c := range s.Filesystem {
if c.Src == nil {
return nil, nil, fmt.Errorf("invalid filesystem at index %d", i)
// evaluated path, input path
hidePathSourceEval := make([][2]string, len(hidePathSource))
for i, a := range hidePathSource {
if a == nil {
// unreachable
return nil, nil, syscall.ENOTRECOVERABLE
}
// special filesystems
switch c.Src.String() {
case container.Nonexistent:
if c.Dst == nil {
return nil, nil, errors.New("tmpfs dst must not be nil")
}
if c.Write {
params.Tmpfs(c.Dst, hst.TmpfsSize, hst.TmpfsPerm)
} else {
params.Readonly(c.Dst, hst.TmpfsPerm)
}
continue
}
dst := c.Dst
if dst == nil {
dst = c.Src
}
p := [2]string{c.Src.String(), c.Src.String()}
if err := evalSymlinks(os, &p[0]); err != nil {
hidePathSourceEval[i] = [2]string{a.String(), a.String()}
if err := evalSymlinks(os, &hidePathSourceEval[i][0]); err != nil {
return nil, nil, err
}
hidePathSource = append(hidePathSource, p)
var flags int
if c.Write {
flags |= container.BindWritable
}
if c.Device {
flags |= container.BindDevice | container.BindWritable
}
if !c.Must {
flags |= container.BindOptional
}
params.Bind(c.Src, dst, flags)
}
for _, p := range hidePathSource {
for _, p := range hidePathSourceEval {
for i := range hidePaths {
// skip matched entries
if hidePathMatch[i] {

View File

@@ -248,15 +248,15 @@ func (seal *outcome) finalise(ctx context.Context, sys sys.State, config *hst.Co
// bind GPU stuff
if config.Enablements&(system.EX11|system.EWayland) != 0 {
conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfig{Src: container.AbsFHSDev.Append("dri"), Device: true})
conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{Src: container.AbsFHSDev.Append("dri"), Device: true, Optional: true}})
}
// opportunistically bind kvm
conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfig{Src: container.AbsFHSDev.Append("kvm"), Device: true})
conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSBind{Src: container.AbsFHSDev.Append("kvm"), Device: true, Optional: true}})
// hide nscd from container if present
nscd := container.AbsFHSVar.Append("run/nscd")
if _, err := sys.Stat(nscd.String()); !errors.Is(err, fs.ErrNotExist) {
conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfig{Dst: nscd, Src: container.AbsNonexistent})
conf.Filesystem = append(conf.Filesystem, hst.FilesystemConfigJSON{FilesystemConfig: &hst.FSEphemeral{Dst: nscd}})
}
config.Container = conf