container/path: fhs path constants
All checks were successful
Test / Create distribution (push) Successful in 33s
Test / Sandbox (push) Successful in 2m6s
Test / Hakurei (push) Successful in 3m6s
Test / Sandbox (race detector) (push) Successful in 4m14s
Test / Hpkg (push) Successful in 4m11s
Test / Hakurei (race detector) (push) Successful in 4m40s
Test / Flake checks (push) Successful in 1m18s

This increases readability since this can help disambiguate absolute paths from similarly named path segments.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
2025-08-03 20:46:41 +09:00
parent 38245559dc
commit c6be82bcf9
23 changed files with 164 additions and 123 deletions

View File

@@ -12,7 +12,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, prefix string) *Ops {
e := &AutoEtcOp{prefix}
f.Mkdir("/etc", 0755)
f.Mkdir(FHSEtc, 0755)
f.Bind(host, e.hostPath(), 0)
*f = append(*f, e)
return f
@@ -22,7 +22,7 @@ type AutoEtcOp struct{ Prefix string }
func (e *AutoEtcOp) early(*Params) error { return nil }
func (e *AutoEtcOp) apply(*Params) error {
const target = sysrootPath + "/etc/"
const target = sysrootPath + FHSEtc
rel := e.hostRel() + "/"
if err := os.MkdirAll(target, 0755); err != nil {
@@ -40,7 +40,7 @@ func (e *AutoEtcOp) apply(*Params) error {
case "group":
case "mtab":
if err = os.Symlink("/proc/mounts", target+n); err != nil {
if err = os.Symlink(FHSProc+"mounts", target+n); err != nil {
return wrapErrSelf(err)
}
@@ -54,7 +54,7 @@ func (e *AutoEtcOp) apply(*Params) error {
return nil
}
func (e *AutoEtcOp) hostPath() string { return "/etc/" + e.hostRel() }
func (e *AutoEtcOp) hostPath() string { return FHSEtc + e.hostRel() }
func (e *AutoEtcOp) hostRel() string { return ".host/" + e.Prefix }
func (e *AutoEtcOp) Is(op Op) bool {

View File

@@ -42,7 +42,7 @@ func (r *AutoRootOp) early(params *Params) error {
if IsAutoRootBindable(name) {
op := &BindMountOp{
Source: path.Join(r.Host, name),
Target: "/" + name,
Target: FHSRoot + name,
Flags: r.Flags,
}
if err = op.early(params); err != nil {

View File

@@ -18,10 +18,6 @@ import (
)
const (
// Nonexistent is a path that cannot exist.
// /proc is chosen because a system with covered /proc is unsupported by this package.
Nonexistent = "/proc/nonexistent"
// CancelSignal is the signal expected by container init on context cancel.
// A custom [Container.Cancel] function must eventually deliver this signal.
CancelSignal = SIGTERM
@@ -142,7 +138,7 @@ func (p *Container) Start() error {
} else {
p.cmd.Cancel = func() error { return p.cmd.Process.Signal(CancelSignal) }
}
p.cmd.Dir = "/"
p.cmd.Dir = FHSRoot
p.cmd.SysProcAttr = &SysProcAttr{
Setsid: !p.RetainSession,
Pdeathsig: SIGKILL,
@@ -251,6 +247,6 @@ func (p *Container) ProcessState() *os.ProcessState {
func New(ctx context.Context, name string, args ...string) *Container {
return &Container{name: name, ctx: ctx,
Params: Params{Args: append([]string{name}, args...), Dir: "/", Ops: new(Ops)},
Params: Params{Args: append([]string{name}, args...), Dir: FHSRoot, Ops: new(Ops)},
}
}

View File

@@ -31,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 = "/proc/self/fd"
intermediateHostPath = FHSProc + "self/fd"
// setup params file descriptor
setupEnv = "HAKUREI_SETUP"
@@ -88,17 +88,17 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
if err := SetDumpable(SUID_DUMP_USER); err != nil {
log.Fatalf("cannot set SUID_DUMP_USER: %s", err)
}
if err := os.WriteFile("/proc/self/uid_map",
if err := os.WriteFile(FHSProc+"self/uid_map",
append([]byte{}, strconv.Itoa(params.Uid)+" "+strconv.Itoa(params.HostUid)+" 1\n"...),
0); err != nil {
log.Fatalf("%v", err)
}
if err := os.WriteFile("/proc/self/setgroups",
if err := os.WriteFile(FHSProc+"self/setgroups",
[]byte("deny\n"),
0); err != nil && !os.IsNotExist(err) {
log.Fatalf("%v", err)
}
if err := os.WriteFile("/proc/self/gid_map",
if err := os.WriteFile(FHSProc+"self/gid_map",
append([]byte{}, strconv.Itoa(params.Gid)+" "+strconv.Itoa(params.HostGid)+" 1\n"...),
0); err != nil {
log.Fatalf("%v", err)
@@ -117,7 +117,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
// cache sysctl before pivot_root
LastCap()
if err := Mount("", "/", "", MS_SILENT|MS_SLAVE|MS_REC, ""); err != nil {
if err := Mount("", FHSRoot, "", MS_SILENT|MS_SLAVE|MS_REC, ""); err != nil {
log.Fatalf("cannot make / rslave: %v", err)
}
@@ -159,7 +159,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
if err := PivotRoot(intermediateHostPath, hostDir); err != nil {
log.Fatalf("cannot pivot into intermediate root: %v", err)
}
if err := os.Chdir("/"); err != nil {
if err := os.Chdir(FHSRoot); err != nil {
log.Fatalf("%v", err)
}
@@ -189,7 +189,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
{
var fd int
if err := IgnoringEINTR(func() (err error) {
fd, err = Open("/", O_DIRECTORY|O_RDONLY, 0)
fd, err = Open(FHSRoot, O_DIRECTORY|O_RDONLY, 0)
return
}); err != nil {
log.Fatalf("cannot open intermediate root: %v", err)
@@ -207,7 +207,7 @@ func Init(prepare func(prefix string), setVerbose func(verbose bool)) {
if err := Unmount(".", MNT_DETACH); err != nil {
log.Fatalf("cannot unmount intemediate root: %v", err)
}
if err := os.Chdir("/"); err != nil {
if err := os.Chdir(FHSRoot); err != nil {
log.Fatalf("%v", err)
}

View File

@@ -53,7 +53,7 @@ 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 /proc.
// 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.

View File

@@ -215,7 +215,7 @@ func (d *MountDevOp) apply(params *Params) error {
return err
}
if err := hostProc.bindMount(
toHost("/dev/"+name),
toHost(FHSDev+name),
targetPath,
0,
true,
@@ -225,15 +225,15 @@ func (d *MountDevOp) apply(params *Params) error {
}
for i, name := range []string{"stdin", "stdout", "stderr"} {
if err := os.Symlink(
"/proc/self/fd/"+string(rune(i+'0')),
FHSProc+"self/fd/"+string(rune(i+'0')),
path.Join(target, name),
); err != nil {
return wrapErrSelf(err)
}
}
for _, pair := range [][2]string{
{"/proc/self/fd", "fd"},
{"/proc/kcore", "core"},
{FHSProc + "self/fd", "fd"},
{FHSProc + "kcore", "core"},
{"pts/ptmx", "ptmx"},
} {
if err := os.Symlink(pair[0], path.Join(target, pair[1])); err != nil {
@@ -436,7 +436,7 @@ func (t *TmpfileOp) apply(params *Params) error {
}
var tmpPath string
if f, err := os.CreateTemp("/", "tmp.*"); err != nil {
if f, err := os.CreateTemp(FHSRoot, "tmp.*"); err != nil {
return wrapErrSelf(err)
} else if _, err = f.Write(t.Data); err != nil {
return wrapErrSuffix(err,

View File

@@ -14,9 +14,49 @@ import (
)
const (
hostPath = "/" + hostDir
// 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/"
)
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"
hostPath = FHSRoot + hostDir
hostDir = "host"
sysrootPath = "/" + sysrootDir
sysrootPath = FHSRoot + sysrootDir
sysrootDir = "sysroot"
)

View File

@@ -17,9 +17,9 @@ var (
)
const (
kernelOverflowuidPath = "/proc/sys/kernel/overflowuid"
kernelOverflowgidPath = "/proc/sys/kernel/overflowgid"
kernelCapLastCapPath = "/proc/sys/kernel/cap_last_cap"
kernelOverflowuidPath = FHSProcSys + "kernel/overflowuid"
kernelOverflowgidPath = FHSProcSys + "kernel/overflowgid"
kernelCapLastCapPath = FHSProcSys + "kernel/cap_last_cap"
)
func mustReadSysctl() {