From 1c3761bb53c95d75751f95e8f77d9d1e5928b968 Mon Sep 17 00:00:00 2001 From: Ophestra Date: Tue, 25 Aug 2026 14:48:27 +0900 Subject: [PATCH] container: enter init path early There is generally no use case where any setup is required before init, and requiring the explicit function call is error-prone and unnecessary. It also causes trouble with packages using a similar trick. This change moves argv0 check early and makes it an import side effect. The stub will be removed in v0.5. Signed-off-by: Ophestra --- cmd/hakurei/main.go | 4 ---- cmd/mbf/main.go | 3 --- cmd/sharefs/fuse.go | 1 - container/autoetc.go | 3 --- container/autoroot.go | 3 --- container/container_test.go | 5 ----- container/init.go | 40 +++++++++++++++++++++++++++--------- container/initbind.go | 3 --- container/initdaemon.go | 3 --- container/initdev.go | 3 --- container/initmkdir.go | 3 --- container/initoverlay.go | 3 --- container/initplace.go | 3 --- container/initproc.go | 3 --- container/initremount.go | 3 --- container/initsymlink.go | 3 --- container/inittmpfs.go | 3 --- internal/dbus/proc_test.go | 3 +-- internal/helper/stub_test.go | 3 +-- internal/pkg/pkg_test.go | 2 -- internal/rosa/rosa_test.go | 3 --- ldd/exec_test.go | 4 ---- 22 files changed, 32 insertions(+), 72 deletions(-) diff --git a/cmd/hakurei/main.go b/cmd/hakurei/main.go index 19ffdb68..6f54390d 100644 --- a/cmd/hakurei/main.go +++ b/cmd/hakurei/main.go @@ -46,7 +46,6 @@ import ( "os/signal" "syscall" - "hakurei.app/container" "hakurei.app/ext" "hakurei.app/message" ) @@ -59,9 +58,6 @@ var license string type earlyHardeningErrs struct{ yamaLSM, dumpable error } func main() { - // early init path, skips root check and duplicate PR_SET_DUMPABLE - container.TryArgv0(nil) - log.SetFlags(0) log.SetPrefix("hakurei: ") msg := message.New(log.Default()) diff --git a/cmd/mbf/main.go b/cmd/mbf/main.go index 4beefe68..c6e1940f 100644 --- a/cmd/mbf/main.go +++ b/cmd/mbf/main.go @@ -37,7 +37,6 @@ import ( "hakurei.app/check" "hakurei.app/command" - "hakurei.app/container" "hakurei.app/ext" "hakurei.app/fhs" "hakurei.app/internal/pkg" @@ -67,8 +66,6 @@ func writeFileExcl(name string, data []byte, perm os.FileMode) error { } func main() { - container.TryArgv0(nil) - log.SetFlags(0) log.SetPrefix("mbf: ") msg := message.New(log.Default()) diff --git a/cmd/sharefs/fuse.go b/cmd/sharefs/fuse.go index 5dfbf385..458e1919 100644 --- a/cmd/sharefs/fuse.go +++ b/cmd/sharefs/fuse.go @@ -287,7 +287,6 @@ func unsafeAddArgument(args *fuseArgs, arg string) { func _main(s ...string) (exitCode int) { msg := message.New(log.Default()) - container.TryArgv0(msg) runtime.LockOSThread() // don't mask creation mode, kernel already did that diff --git a/container/autoetc.go b/container/autoetc.go index 3634d296..91789404 100644 --- a/container/autoetc.go +++ b/container/autoetc.go @@ -1,15 +1,12 @@ package container import ( - "encoding/gob" "fmt" "hakurei.app/check" "hakurei.app/fhs" ) -func init() { gob.Register(new(AutoEtcOp)) } - // Etc is a helper for appending [AutoEtcOp] to [Ops]. func (f *Ops) Etc(host *check.Absolute, prefix string) *Ops { e := &AutoEtcOp{prefix} diff --git a/container/autoroot.go b/container/autoroot.go index a982e879..13d48257 100644 --- a/container/autoroot.go +++ b/container/autoroot.go @@ -1,7 +1,6 @@ package container import ( - "encoding/gob" "fmt" "hakurei.app/check" @@ -9,8 +8,6 @@ import ( "hakurei.app/message" ) -func init() { gob.Register(new(AutoRootOp)) } - // Root is a helper for appending [AutoRootOp] to [Ops]. func (f *Ops) Root(host *check.Absolute, flags int) *Ops { *f = append(*f, &AutoRootOp{host, flags, nil}) diff --git a/container/container_test.go b/container/container_test.go index 787720a8..ca00fe7a 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -37,9 +37,6 @@ import ( // Note: this package requires cgo, which is unavailable in the Go playground. func Example() { - // Must be called early if the current process starts containers. - container.TryArgv0(nil) - // Configure the container. z := container.New(context.Background(), nil) z.Hostname = "hakurei-example" @@ -876,8 +873,6 @@ var ( var helperCommands []func(c command.Command) func TestMain(m *testing.M) { - container.TryArgv0(nil) - if os.Getenv(envDoCheck) == "1" { c := command.New(os.Stderr, log.Printf, "helper", func(args []string) error { log.SetFlags(0) diff --git a/container/init.go b/container/init.go index 41de58cd..510d9f59 100644 --- a/container/init.go +++ b/container/init.go @@ -2,6 +2,7 @@ package container import ( "context" + "encoding/gob" "errors" "fmt" "log" @@ -130,7 +131,7 @@ type initParams struct { Verbose bool } -// Init is called by [TryArgv0] if the current process is the container init. +// Init is called if the current process is the container init. func Init(msg message.Msg) { initEntrypoint(direct{}, msg) } func initEntrypoint(k syscallDispatcher, msg message.Msg) { @@ -642,18 +643,37 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) { // initName is the prefix used by log.std in the init process. const initName = "init" -// TryArgv0 calls [Init] if the last element of argv0 is "init". -// If a nil msg is passed, the system logger is used instead. -func TryArgv0(msg message.Msg) { - if msg == nil { - log.SetPrefix(initName + ": ") - log.SetFlags(0) - msg = message.New(log.Default()) +var _ = func() struct{} { + for _, v := range []any{ + (*AutoEtcOp)(nil), + (*AutoRootOp)(nil), + (*BindMountOp)(nil), + (*DaemonOp)(nil), + (*MkdirOp)(nil), + (*MountDevOp)(nil), + (*MountOverlayOp)(nil), + (*MountProcOp)(nil), + (*MountTmpfsOp)(nil), + (*RemountOp)(nil), + (*SymlinkOp)(nil), + (*TmpfileOp)(nil), + } { + gob.Register(v) } - if len(os.Args) > 0 && filepath.Base(os.Args[0]) == initName { + if len(os.Args) == 1 && filepath.Base(os.Args[0]) == initName { + log.SetPrefix(initName + ": ") + log.SetFlags(0) + msg := message.New(log.Default()) + Init(msg) msg.BeforeExit() os.Exit(0) } -} + return struct{}{} +}() + +// TryArgv0 is a noop. +// +// Deprecated: init is now implemented as an import side effect. +func TryArgv0(_ message.Msg) {} diff --git a/container/initbind.go b/container/initbind.go index 8fa0fc06..475a737b 100644 --- a/container/initbind.go +++ b/container/initbind.go @@ -1,7 +1,6 @@ package container import ( - "encoding/gob" "fmt" "os" "syscall" @@ -10,8 +9,6 @@ import ( "hakurei.app/container/std" ) -func init() { gob.Register(new(BindMountOp)) } - // Bind is a helper for appending [BindMountOp] to [Ops]. func (f *Ops) Bind(source, target *check.Absolute, flags int) *Ops { *f = append(*f, &BindMountOp{nil, source, target, flags}) diff --git a/container/initdaemon.go b/container/initdaemon.go index 92b68bf0..ab6f29cd 100644 --- a/container/initdaemon.go +++ b/container/initdaemon.go @@ -2,7 +2,6 @@ package container import ( "context" - "encoding/gob" "errors" "fmt" "os" @@ -16,8 +15,6 @@ import ( "hakurei.app/fhs" ) -func init() { gob.Register(new(DaemonOp)) } - const ( // daemonTimeout is the duration a [DaemonOp] is allowed to block before the // [DaemonOp.Target] marker becomes available. diff --git a/container/initdev.go b/container/initdev.go index 0847f587..95bdb293 100644 --- a/container/initdev.go +++ b/container/initdev.go @@ -1,7 +1,6 @@ package container import ( - "encoding/gob" "fmt" "path/filepath" . "syscall" @@ -10,8 +9,6 @@ import ( "hakurei.app/fhs" ) -func init() { gob.Register(new(MountDevOp)) } - // Dev appends an [Op] that mounts a subset of host /dev. func (f *Ops) Dev(target *check.Absolute, mqueue bool) *Ops { *f = append(*f, &MountDevOp{target, mqueue, false}) diff --git a/container/initmkdir.go b/container/initmkdir.go index 4a131af5..bde0c01a 100644 --- a/container/initmkdir.go +++ b/container/initmkdir.go @@ -1,15 +1,12 @@ package container import ( - "encoding/gob" "fmt" "os" "hakurei.app/check" ) -func init() { gob.Register(new(MkdirOp)) } - // Mkdir is a helper for appending [MkdirOp] to [Ops]. func (f *Ops) Mkdir(name *check.Absolute, perm os.FileMode) *Ops { *f = append(*f, &MkdirOp{name, perm}) diff --git a/container/initoverlay.go b/container/initoverlay.go index e4cb0f5a..96308921 100644 --- a/container/initoverlay.go +++ b/container/initoverlay.go @@ -1,7 +1,6 @@ package container import ( - "encoding/gob" "fmt" "slices" @@ -19,8 +18,6 @@ const ( intermediatePatternOverlayWork = "overlay.work.*" ) -func init() { gob.Register(new(MountOverlayOp)) } - const ( // OverlayEphemeralUnexpectedUpper is set when [MountOverlayOp.Work] is nil // and [MountOverlayOp.Upper] holds an unexpected value. diff --git a/container/initplace.go b/container/initplace.go index ab477139..4993d0b3 100644 --- a/container/initplace.go +++ b/container/initplace.go @@ -1,7 +1,6 @@ package container import ( - "encoding/gob" "fmt" "syscall" @@ -14,8 +13,6 @@ const ( intermediatePatternTmpfile = "tmp.*" ) -func init() { gob.Register(new(TmpfileOp)) } - // Place is a helper for appending [TmpfileOp] to [Ops]. func (f *Ops) Place(name *check.Absolute, data []byte) *Ops { *f = append(*f, &TmpfileOp{name, data}) diff --git a/container/initproc.go b/container/initproc.go index d568e88e..052812b8 100644 --- a/container/initproc.go +++ b/container/initproc.go @@ -1,15 +1,12 @@ package container import ( - "encoding/gob" "fmt" . "syscall" "hakurei.app/check" ) -func init() { gob.Register(new(MountProcOp)) } - // Proc is a helper for appending [MountProcOp] to [Ops]. func (f *Ops) Proc(target *check.Absolute) *Ops { *f = append(*f, &MountProcOp{target}) diff --git a/container/initremount.go b/container/initremount.go index fba0c2b7..33844b13 100644 --- a/container/initremount.go +++ b/container/initremount.go @@ -1,14 +1,11 @@ package container import ( - "encoding/gob" "fmt" "hakurei.app/check" ) -func init() { gob.Register(new(RemountOp)) } - // Remount is a helper for appending [RemountOp] to [Ops]. func (f *Ops) Remount(target *check.Absolute, flags uintptr) *Ops { *f = append(*f, &RemountOp{target, flags}) diff --git a/container/initsymlink.go b/container/initsymlink.go index e72e5ef4..09e74ec2 100644 --- a/container/initsymlink.go +++ b/container/initsymlink.go @@ -1,15 +1,12 @@ package container import ( - "encoding/gob" "fmt" "path/filepath" "hakurei.app/check" ) -func init() { gob.Register(new(SymlinkOp)) } - // Link appends an [Op] that creates a symlink in the container filesystem. func (f *Ops) Link(target *check.Absolute, linkName string, dereference bool) *Ops { *f = append(*f, &SymlinkOp{target, linkName, dereference}) diff --git a/container/inittmpfs.go b/container/inittmpfs.go index aad6e1ab..ae337dce 100644 --- a/container/inittmpfs.go +++ b/container/inittmpfs.go @@ -1,7 +1,6 @@ package container import ( - "encoding/gob" "fmt" "math" "os" @@ -11,8 +10,6 @@ import ( "hakurei.app/check" ) -func init() { gob.Register(new(MountTmpfsOp)) } - type TmpfsSizeError int func (e TmpfsSizeError) Error() string { diff --git a/internal/dbus/proc_test.go b/internal/dbus/proc_test.go index 544856ed..b6e5283b 100644 --- a/internal/dbus/proc_test.go +++ b/internal/dbus/proc_test.go @@ -4,8 +4,7 @@ import ( "os" "testing" - "hakurei.app/container" "hakurei.app/internal/helper" ) -func TestMain(m *testing.M) { container.TryArgv0(nil); helper.InternalHelperStub(); os.Exit(m.Run()) } +func TestMain(m *testing.M) { helper.InternalHelperStub(); os.Exit(m.Run()) } diff --git a/internal/helper/stub_test.go b/internal/helper/stub_test.go index 4b438a5b..c662d059 100644 --- a/internal/helper/stub_test.go +++ b/internal/helper/stub_test.go @@ -4,8 +4,7 @@ import ( "os" "testing" - "hakurei.app/container" "hakurei.app/internal/helper" ) -func TestMain(m *testing.M) { container.TryArgv0(nil); helper.InternalHelperStub(); os.Exit(m.Run()) } +func TestMain(m *testing.M) { helper.InternalHelperStub(); os.Exit(m.Run()) } diff --git a/internal/pkg/pkg_test.go b/internal/pkg/pkg_test.go index 39218d96..b23948f8 100644 --- a/internal/pkg/pkg_test.go +++ b/internal/pkg/pkg_test.go @@ -85,8 +85,6 @@ func newRContext(tb testing.TB, c *pkg.Cache) *pkg.RContext { return &r } -func TestMain(m *testing.M) { container.TryArgv0(nil); os.Exit(m.Run()) } - // overrideIdent overrides the ID method of [Artifact]. type overrideIdent struct { id pkg.ID diff --git a/internal/rosa/rosa_test.go b/internal/rosa/rosa_test.go index 86468ea4..76e8a53e 100644 --- a/internal/rosa/rosa_test.go +++ b/internal/rosa/rosa_test.go @@ -10,7 +10,6 @@ import ( "testing" "hakurei.app/check" - "hakurei.app/container" "hakurei.app/internal/pkg" "hakurei.app/internal/rosa" "hakurei.app/message" @@ -28,8 +27,6 @@ var ( ) func TestMain(m *testing.M) { - container.TryArgv0(nil) - code := m.Run() if buildTestCache != nil { buildTestCacheCancel() diff --git a/ldd/exec_test.go b/ldd/exec_test.go index 4621d335..0546b9ad 100644 --- a/ldd/exec_test.go +++ b/ldd/exec_test.go @@ -2,12 +2,10 @@ package ldd_test import ( "errors" - "os" "os/exec" "testing" "hakurei.app/check" - "hakurei.app/container" "hakurei.app/ldd" "hakurei.app/message" ) @@ -42,5 +40,3 @@ func TestExec(t *testing.T) { } }) } - -func TestMain(m *testing.M) { container.TryArgv0(nil); os.Exit(m.Run()) }