aboutsummaryrefslogtreecommitdiffhomepage
path: root/container
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-10-07 21:29:16 +0900
committerOphestra <cat@gensokyo.uk>2025-10-07 21:29:16 +0900
commit5d18af00077ae6ba8ef686d1fd93d888f69681b2 (patch)
treeeff32422fe3ef095c6a915ccb41c2a10a06990f7 /container
parent0e6c1a50260de141c50bb50fd3f2b2bcf9a3fe64 (diff)
container/fhs: move pathname constants
This allows referencing FHS pathnames without importing container. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'container')
-rw-r--r--container/autoetc.go9
-rw-r--r--container/autoroot.go3
-rw-r--r--container/container.go5
-rw-r--r--container/fhs/abs.go41
-rw-r--r--container/fhs/fhs.go38
-rw-r--r--container/init.go17
-rw-r--r--container/initdev.go9
-rw-r--r--container/initoverlay.go11
-rw-r--r--container/initplace.go3
-rw-r--r--container/mount.go1
-rw-r--r--container/path.go79
-rw-r--r--container/sysctl.go8
12 files changed, 120 insertions, 104 deletions
diff --git a/container/autoetc.go b/container/autoetc.go
index 295bdf71..65ab9a2c 100644
--- a/container/autoetc.go
+++ b/container/autoetc.go
@@ -5,6 +5,7 @@ import (
"fmt"
"hakurei.app/container/check"
+ "hakurei.app/container/fhs"
)
func init() { gob.Register(new(AutoEtcOp)) }
@@ -13,7 +14,7 @@ func init() { gob.Register(new(AutoEtcOp)) }
// This is not a generic setup op. It is implemented here to reduce ipc overhead.
func (f *Ops) Etc(host *check.Absolute, prefix string) *Ops {
e := &AutoEtcOp{prefix}
- f.Mkdir(AbsFHSEtc, 0755)
+ f.Mkdir(fhs.AbsEtc, 0755)
f.Bind(host, e.hostPath(), 0)
*f = append(*f, e)
return f
@@ -29,7 +30,7 @@ func (e *AutoEtcOp) apply(state *setupState, k syscallDispatcher) error {
}
state.nonrepeatable |= nrAutoEtc
- const target = sysrootPath + FHSEtc
+ const target = sysrootPath + fhs.Etc
rel := e.hostRel() + "/"
if err := k.mkdirAll(target, 0755); err != nil {
@@ -44,7 +45,7 @@ func (e *AutoEtcOp) apply(state *setupState, k syscallDispatcher) error {
case ".host", "passwd", "group":
case "mtab":
- if err = k.symlink(FHSProc+"mounts", target+n); err != nil {
+ if err = k.symlink(fhs.Proc+"mounts", target+n); err != nil {
return err
}
@@ -59,7 +60,7 @@ func (e *AutoEtcOp) apply(state *setupState, k syscallDispatcher) error {
return nil
}
-func (e *AutoEtcOp) hostPath() *check.Absolute { return AbsFHSEtc.Append(e.hostRel()) }
+func (e *AutoEtcOp) hostPath() *check.Absolute { return fhs.AbsEtc.Append(e.hostRel()) }
func (e *AutoEtcOp) hostRel() string { return ".host/" + e.Prefix }
func (e *AutoEtcOp) Is(op Op) bool {
diff --git a/container/autoroot.go b/container/autoroot.go
index 519aadaf..0ebe6b2b 100644
--- a/container/autoroot.go
+++ b/container/autoroot.go
@@ -5,6 +5,7 @@ import (
"fmt"
"hakurei.app/container/check"
+ "hakurei.app/container/fhs"
)
func init() { gob.Register(new(AutoRootOp)) }
@@ -40,7 +41,7 @@ func (r *AutoRootOp) early(state *setupState, k syscallDispatcher) error {
// careful: the Valid method is skipped, make sure this is always valid
op := &BindMountOp{
Source: r.Host.Append(name),
- Target: AbsFHSRoot.Append(name),
+ Target: fhs.AbsRoot.Append(name),
Flags: r.Flags,
}
if err = op.early(state, k); err != nil {
diff --git a/container/container.go b/container/container.go
index 08dc9e45..5b6514d4 100644
--- a/container/container.go
+++ b/container/container.go
@@ -16,6 +16,7 @@ import (
"hakurei.app/container/bits"
"hakurei.app/container/check"
+ "hakurei.app/container/fhs"
"hakurei.app/container/seccomp"
)
@@ -200,7 +201,7 @@ func (p *Container) Start() error {
} else {
p.cmd.Cancel = func() error { return p.cmd.Process.Signal(CancelSignal) }
}
- p.cmd.Dir = FHSRoot
+ p.cmd.Dir = fhs.Root
p.cmd.SysProcAttr = &SysProcAttr{
Setsid: !p.RetainSession,
Pdeathsig: SIGKILL,
@@ -316,7 +317,7 @@ func (p *Container) Serve() error {
// do not transmit nil
if p.Dir == nil {
- p.Dir = AbsFHSRoot
+ p.Dir = fhs.AbsRoot
}
if p.SeccompRules == nil {
p.SeccompRules = make([]seccomp.NativeRule, 0)
diff --git a/container/fhs/abs.go b/container/fhs/abs.go
new file mode 100644
index 00000000..af3588ba
--- /dev/null
+++ b/container/fhs/abs.go
@@ -0,0 +1,41 @@
+package fhs
+
+import (
+ _ "unsafe"
+
+ "hakurei.app/container/check"
+)
+
+/* constants in this file bypass abs check, be extremely careful when changing them! */
+
+//go:linkname unsafeAbs hakurei.app/container/check.unsafeAbs
+func unsafeAbs(_ string) *check.Absolute
+
+var (
+ // AbsRoot is [Root] as [check.Absolute].
+ AbsRoot = unsafeAbs(Root)
+ // AbsEtc is [Etc] as [check.Absolute].
+ AbsEtc = unsafeAbs(Etc)
+ // AbsTmp is [Tmp] as [check.Absolute].
+ AbsTmp = unsafeAbs(Tmp)
+
+ // AbsRun is [Run] as [check.Absolute].
+ AbsRun = unsafeAbs(Run)
+ // AbsRunUser is [RunUser] as [check.Absolute].
+ AbsRunUser = unsafeAbs(RunUser)
+
+ // AbsUsrBin is [UsrBin] as [check.Absolute].
+ AbsUsrBin = unsafeAbs(UsrBin)
+
+ // AbsVar is [Var] as [check.Absolute].
+ AbsVar = unsafeAbs(Var)
+ // AbsVarLib is [VarLib] as [check.Absolute].
+ AbsVarLib = unsafeAbs(VarLib)
+
+ // AbsDev is [Dev] as [check.Absolute].
+ AbsDev = unsafeAbs(Dev)
+ // AbsProc is [Proc] as [check.Absolute].
+ AbsProc = unsafeAbs(Proc)
+ // AbsSys is [Sys] as [check.Absolute].
+ AbsSys = unsafeAbs(Sys)
+)
diff --git a/container/fhs/fhs.go b/container/fhs/fhs.go
new file mode 100644
index 00000000..6a3a3041
--- /dev/null
+++ b/container/fhs/fhs.go
@@ -0,0 +1,38 @@
+// Package fhs provides constant and checked pathname values for common FHS paths.
+package fhs
+
+const (
+ // Root points to the file system root.
+ Root = "/"
+ // Etc points to the directory for system-specific configuration.
+ Etc = "/etc/"
+ // Tmp points to the place for small temporary files.
+ Tmp = "/tmp/"
+
+ // Run points to a "tmpfs" file system for system packages to place runtime data, socket files, and similar.
+ Run = "/run/"
+ // RunUser points to a directory containing per-user runtime directories,
+ // each usually individually mounted "tmpfs" instances.
+ RunUser = Run + "user/"
+
+ // Usr points to vendor-supplied operating system resources.
+ Usr = "/usr/"
+ // UsrBin points to binaries and executables for user commands that shall appear in the $PATH search path.
+ UsrBin = Usr + "bin/"
+
+ // Var points to persistent, variable system data. Writable during normal system operation.
+ Var = "/var/"
+ // VarLib points to persistent system data.
+ VarLib = Var + "lib/"
+ // VarEmpty points to a nonstandard directory that is usually empty.
+ VarEmpty = Var + "empty/"
+
+ // Dev points to the root directory for device nodes.
+ Dev = "/dev/"
+ // Proc points to a virtual kernel file system exposing the process list and other functionality.
+ Proc = "/proc/"
+ // ProcSys points to a hierarchy below /proc/ that exposes a number of kernel tunables.
+ ProcSys = Proc + "sys/"
+ // Sys points to a virtual kernel file system exposing discovered devices and other functionality.
+ Sys = "/sys/"
+)
diff --git a/container/init.go b/container/init.go
index e65472e7..9481acd1 100644
--- a/container/init.go
+++ b/container/init.go
@@ -12,6 +12,7 @@ import (
. "syscall"
"time"
+ "hakurei.app/container/fhs"
"hakurei.app/container/seccomp"
)
@@ -30,7 +31,7 @@ const (
it should be noted that none of this should become relevant at any point since the resulting
intermediate root tmpfs should be effectively anonymous */
- intermediateHostPath = FHSProc + "self/fd"
+ intermediateHostPath = fhs.Proc + "self/fd"
// setup params file descriptor
setupEnv = "HAKUREI_SETUP"
@@ -146,17 +147,17 @@ func initEntrypoint(k syscallDispatcher, msg Msg) {
if err := k.setDumpable(SUID_DUMP_USER); err != nil {
k.fatalf(msg, "cannot set SUID_DUMP_USER: %v", err)
}
- if err := k.writeFile(FHSProc+"self/uid_map",
+ if err := k.writeFile(fhs.Proc+"self/uid_map",
append([]byte{}, strconv.Itoa(params.Uid)+" "+strconv.Itoa(params.HostUid)+" 1\n"...),
0); err != nil {
k.fatalf(msg, "%v", err)
}
- if err := k.writeFile(FHSProc+"self/setgroups",
+ if err := k.writeFile(fhs.Proc+"self/setgroups",
[]byte("deny\n"),
0); err != nil && !os.IsNotExist(err) {
k.fatalf(msg, "%v", err)
}
- if err := k.writeFile(FHSProc+"self/gid_map",
+ if err := k.writeFile(fhs.Proc+"self/gid_map",
append([]byte{}, strconv.Itoa(params.Gid)+" "+strconv.Itoa(params.HostGid)+" 1\n"...),
0); err != nil {
k.fatalf(msg, "%v", err)
@@ -175,7 +176,7 @@ func initEntrypoint(k syscallDispatcher, msg Msg) {
// cache sysctl before pivot_root
lastcap := k.lastcap(msg)
- if err := k.mount(zeroString, FHSRoot, zeroString, MS_SILENT|MS_SLAVE|MS_REC, zeroString); err != nil {
+ if err := k.mount(zeroString, fhs.Root, zeroString, MS_SILENT|MS_SLAVE|MS_REC, zeroString); err != nil {
k.fatalf(msg, "cannot make / rslave: %v", err)
}
@@ -220,7 +221,7 @@ func initEntrypoint(k syscallDispatcher, msg Msg) {
if err := k.pivotRoot(intermediateHostPath, hostDir); err != nil {
k.fatalf(msg, "cannot pivot into intermediate root: %v", err)
}
- if err := k.chdir(FHSRoot); err != nil {
+ if err := k.chdir(fhs.Root); err != nil {
k.fatalf(msg, "cannot enter intermediate root: %v", err)
}
@@ -253,7 +254,7 @@ func initEntrypoint(k syscallDispatcher, msg Msg) {
{
var fd int
if err := IgnoringEINTR(func() (err error) {
- fd, err = k.open(FHSRoot, O_DIRECTORY|O_RDONLY, 0)
+ fd, err = k.open(fhs.Root, O_DIRECTORY|O_RDONLY, 0)
return
}); err != nil {
k.fatalf(msg, "cannot open intermediate root: %v", err)
@@ -271,7 +272,7 @@ func initEntrypoint(k syscallDispatcher, msg Msg) {
if err := k.unmount(".", MNT_DETACH); err != nil {
k.fatalf(msg, "cannot unmount intermediate root: %v", err)
}
- if err := k.chdir(FHSRoot); err != nil {
+ if err := k.chdir(fhs.Root); err != nil {
k.fatalf(msg, "cannot enter root: %v", err)
}
diff --git a/container/initdev.go b/container/initdev.go
index e7c4eabf..89a66138 100644
--- a/container/initdev.go
+++ b/container/initdev.go
@@ -7,6 +7,7 @@ import (
. "syscall"
"hakurei.app/container/check"
+ "hakurei.app/container/fhs"
)
func init() { gob.Register(new(MountDevOp)) }
@@ -49,7 +50,7 @@ func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error {
}
if err := k.bindMount(
state,
- toHost(FHSDev+name),
+ toHost(fhs.Dev+name),
targetPath,
0,
); err != nil {
@@ -58,15 +59,15 @@ func (d *MountDevOp) apply(state *setupState, k syscallDispatcher) error {
}
for i, name := range []string{"stdin", "stdout", "stderr"} {
if err := k.symlink(
- FHSProc+"self/fd/"+string(rune(i+'0')),
+ fhs.Proc+"self/fd/"+string(rune(i+'0')),
path.Join(target, name),
); err != nil {
return err
}
}
for _, pair := range [][2]string{
- {FHSProc + "self/fd", "fd"},
- {FHSProc + "kcore", "core"},
+ {fhs.Proc + "self/fd", "fd"},
+ {fhs.Proc + "kcore", "core"},
{"pts/ptmx", "ptmx"},
} {
if err := k.symlink(pair[0], path.Join(target, pair[1])); err != nil {
diff --git a/container/initoverlay.go b/container/initoverlay.go
index 74d925a7..74ae7d00 100644
--- a/container/initoverlay.go
+++ b/container/initoverlay.go
@@ -7,6 +7,7 @@ import (
"strings"
"hakurei.app/container/check"
+ "hakurei.app/container/fhs"
)
const (
@@ -67,7 +68,7 @@ func (f *Ops) Overlay(target, state, work *check.Absolute, layers ...*check.Abso
// OverlayEphemeral appends an [Op] that mounts the overlay pseudo filesystem on [MountOverlayOp.Target]
// with an ephemeral upperdir and workdir.
func (f *Ops) OverlayEphemeral(target *check.Absolute, layers ...*check.Absolute) *Ops {
- return f.Overlay(target, AbsFHSRoot, nil, layers...)
+ return f.Overlay(target, fhs.AbsRoot, nil, layers...)
}
// OverlayReadonly appends an [Op] that mounts the overlay pseudo filesystem readonly on [MountOverlayOp.Target]
@@ -85,7 +86,7 @@ type MountOverlayOp struct {
lower []string
// The upperdir is normally on a writable filesystem.
//
- // If Work is nil and Upper holds the special value [AbsFHSRoot],
+ // If Work is nil and Upper holds the special value [fhs.AbsRoot],
// an ephemeral upperdir and workdir will be set up.
//
// If both Work and Upper are nil, upperdir and workdir is omitted and the overlay is mounted readonly.
@@ -119,7 +120,7 @@ func (o *MountOverlayOp) Valid() bool {
func (o *MountOverlayOp) early(_ *setupState, k syscallDispatcher) error {
if o.Work == nil && o.Upper != nil {
switch o.Upper.String() {
- case FHSRoot: // ephemeral
+ case fhs.Root: // ephemeral
o.ephemeral = true // intermediate root not yet available
default:
@@ -174,10 +175,10 @@ func (o *MountOverlayOp) apply(state *setupState, k syscallDispatcher) error {
if o.ephemeral {
var err error
// these directories are created internally, therefore early (absolute, symlink, prefix, escape) is bypassed
- if o.upper, err = k.mkdirTemp(FHSRoot, intermediatePatternOverlayUpper); err != nil {
+ if o.upper, err = k.mkdirTemp(fhs.Root, intermediatePatternOverlayUpper); err != nil {
return err
}
- if o.work, err = k.mkdirTemp(FHSRoot, intermediatePatternOverlayWork); err != nil {
+ if o.work, err = k.mkdirTemp(fhs.Root, intermediatePatternOverlayWork); err != nil {
return err
}
}
diff --git a/container/initplace.go b/container/initplace.go
index 1f41846b..d08cf653 100644
--- a/container/initplace.go
+++ b/container/initplace.go
@@ -6,6 +6,7 @@ import (
"syscall"
"hakurei.app/container/check"
+ "hakurei.app/container/fhs"
)
const (
@@ -40,7 +41,7 @@ func (t *TmpfileOp) Valid() bool { return t != ni
func (t *TmpfileOp) early(*setupState, syscallDispatcher) error { return nil }
func (t *TmpfileOp) apply(state *setupState, k syscallDispatcher) error {
var tmpPath string
- if f, err := k.createTemp(FHSRoot, intermediatePatternTmpfile); err != nil {
+ if f, err := k.createTemp(fhs.Root, intermediatePatternTmpfile); err != nil {
return err
} else if _, err = f.Write(t.Data); err != nil {
return err
diff --git a/container/mount.go b/container/mount.go
index dbd39cb9..2749d0ec 100644
--- a/container/mount.go
+++ b/container/mount.go
@@ -59,7 +59,6 @@ const (
FstypeNULL = zeroString
// FstypeProc represents the proc pseudo-filesystem.
// A fully visible instance of proc must be available in the mount namespace for proc to be mounted.
- // This filesystem type is usually mounted on [FHSProc].
FstypeProc = "proc"
// FstypeDevpts represents the devpts pseudo-filesystem.
// This type of filesystem is usually mounted on /dev/pts.
diff --git a/container/path.go b/container/path.go
index bf3f870d..bc0000ad 100644
--- a/container/path.go
+++ b/container/path.go
@@ -8,90 +8,19 @@ import (
"strconv"
"strings"
"syscall"
- _ "unsafe"
- "hakurei.app/container/check"
+ "hakurei.app/container/fhs"
"hakurei.app/container/vfs"
)
-/* constants in this file bypass abs check, be extremely careful when changing them! */
-
-//go:linkname unsafeAbs hakurei.app/container/check.unsafeAbs
-func unsafeAbs(_ string) *check.Absolute
-
-const (
- // FHSRoot points to the file system root.
- FHSRoot = "/"
- // FHSEtc points to the directory for system-specific configuration.
- FHSEtc = "/etc/"
- // FHSTmp points to the place for small temporary files.
- FHSTmp = "/tmp/"
-
- // FHSRun points to a "tmpfs" file system for system packages to place runtime data, socket files, and similar.
- FHSRun = "/run/"
- // FHSRunUser points to a directory containing per-user runtime directories,
- // each usually individually mounted "tmpfs" instances.
- FHSRunUser = FHSRun + "user/"
-
- // FHSUsr points to vendor-supplied operating system resources.
- FHSUsr = "/usr/"
- // FHSUsrBin points to binaries and executables for user commands that shall appear in the $PATH search path.
- FHSUsrBin = FHSUsr + "bin/"
-
- // FHSVar points to persistent, variable system data. Writable during normal system operation.
- FHSVar = "/var/"
- // FHSVarLib points to persistent system data.
- FHSVarLib = FHSVar + "lib/"
- // FHSVarEmpty points to a nonstandard directory that is usually empty.
- FHSVarEmpty = FHSVar + "empty/"
-
- // FHSDev points to the root directory for device nodes.
- FHSDev = "/dev/"
- // FHSProc points to a virtual kernel file system exposing the process list and other functionality.
- FHSProc = "/proc/"
- // FHSProcSys points to a hierarchy below /proc/ that exposes a number of kernel tunables.
- FHSProcSys = FHSProc + "sys/"
- // FHSSys points to a virtual kernel file system exposing discovered devices and other functionality.
- FHSSys = "/sys/"
-)
-
-var (
- // AbsFHSRoot is [FHSRoot] as [Absolute].
- AbsFHSRoot = unsafeAbs(FHSRoot)
- // AbsFHSEtc is [FHSEtc] as [Absolute].
- AbsFHSEtc = unsafeAbs(FHSEtc)
- // AbsFHSTmp is [FHSTmp] as [Absolute].
- AbsFHSTmp = unsafeAbs(FHSTmp)
-
- // AbsFHSRun is [FHSRun] as [Absolute].
- AbsFHSRun = unsafeAbs(FHSRun)
- // AbsFHSRunUser is [FHSRunUser] as [Absolute].
- AbsFHSRunUser = unsafeAbs(FHSRunUser)
-
- // AbsFHSUsrBin is [FHSUsrBin] as [Absolute].
- AbsFHSUsrBin = unsafeAbs(FHSUsrBin)
-
- // AbsFHSVar is [FHSVar] as [Absolute].
- AbsFHSVar = unsafeAbs(FHSVar)
- // AbsFHSVarLib is [FHSVarLib] as [Absolute].
- AbsFHSVarLib = unsafeAbs(FHSVarLib)
-
- // AbsFHSDev is [FHSDev] as [Absolute].
- AbsFHSDev = unsafeAbs(FHSDev)
- // AbsFHSProc is [FHSProc] as [Absolute].
- AbsFHSProc = unsafeAbs(FHSProc)
- // AbsFHSSys is [FHSSys] as [Absolute].
- AbsFHSSys = unsafeAbs(FHSSys)
-)
-
const (
// Nonexistent is a path that cannot exist.
// /proc is chosen because a system with covered /proc is unsupported by this package.
- Nonexistent = FHSProc + "nonexistent"
+ Nonexistent = fhs.Proc + "nonexistent"
- hostPath = FHSRoot + hostDir
+ hostPath = fhs.Root + hostDir
hostDir = "host"
- sysrootPath = FHSRoot + sysrootDir
+ sysrootPath = fhs.Root + sysrootDir
sysrootDir = "sysroot"
)
diff --git a/container/sysctl.go b/container/sysctl.go
index 327872b5..9a1e818e 100644
--- a/container/sysctl.go
+++ b/container/sysctl.go
@@ -5,6 +5,8 @@ import (
"os"
"strconv"
"sync"
+
+ "hakurei.app/container/fhs"
)
var (
@@ -16,9 +18,9 @@ var (
)
const (
- kernelOverflowuidPath = FHSProcSys + "kernel/overflowuid"
- kernelOverflowgidPath = FHSProcSys + "kernel/overflowgid"
- kernelCapLastCapPath = FHSProcSys + "kernel/cap_last_cap"
+ kernelOverflowuidPath = fhs.ProcSys + "kernel/overflowuid"
+ kernelOverflowgidPath = fhs.ProcSys + "kernel/overflowgid"
+ kernelCapLastCapPath = fhs.ProcSys + "kernel/cap_last_cap"
)
func mustReadSysctl(msg Msg) {