aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-08-25 14:48:27 +0900
committerOphestra <cat@gensokyo.uk>2026-08-25 14:53:29 +0900
commit1c3761bb53c95d75751f95e8f77d9d1e5928b968 (patch)
tree180e272979b83f68e4c32b4f83cd242715a84a72
parentac7abbbe3fa2eea01defb670abc7dc1dc336cf21 (diff)
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 <cat@gensokyo.uk>
-rw-r--r--cmd/hakurei/main.go4
-rw-r--r--cmd/mbf/main.go3
-rw-r--r--cmd/sharefs/fuse.go1
-rw-r--r--container/autoetc.go3
-rw-r--r--container/autoroot.go3
-rw-r--r--container/container_test.go5
-rw-r--r--container/init.go38
-rw-r--r--container/initbind.go3
-rw-r--r--container/initdaemon.go3
-rw-r--r--container/initdev.go3
-rw-r--r--container/initmkdir.go3
-rw-r--r--container/initoverlay.go3
-rw-r--r--container/initplace.go3
-rw-r--r--container/initproc.go3
-rw-r--r--container/initremount.go3
-rw-r--r--container/initsymlink.go3
-rw-r--r--container/inittmpfs.go3
-rw-r--r--internal/dbus/proc_test.go3
-rw-r--r--internal/helper/stub_test.go3
-rw-r--r--internal/pkg/pkg_test.go2
-rw-r--r--internal/rosa/rosa_test.go3
-rw-r--r--ldd/exec_test.go4
22 files changed, 31 insertions, 71 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 {
+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) == 1 && filepath.Base(os.Args[0]) == initName {
log.SetPrefix(initName + ": ")
log.SetFlags(0)
- msg = message.New(log.Default())
- }
+ msg := message.New(log.Default())
- if len(os.Args) > 0 && filepath.Base(os.Args[0]) == initName {
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()) }