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>
This commit is contained in:
cat
2026-08-25 14:53:29 +09:00
parent ac7abbbe3f
commit 1c3761bb53
22 changed files with 32 additions and 72 deletions
-4
View File
@@ -46,7 +46,6 @@ import (
"os/signal" "os/signal"
"syscall" "syscall"
"hakurei.app/container"
"hakurei.app/ext" "hakurei.app/ext"
"hakurei.app/message" "hakurei.app/message"
) )
@@ -59,9 +58,6 @@ var license string
type earlyHardeningErrs struct{ yamaLSM, dumpable error } type earlyHardeningErrs struct{ yamaLSM, dumpable error }
func main() { func main() {
// early init path, skips root check and duplicate PR_SET_DUMPABLE
container.TryArgv0(nil)
log.SetFlags(0) log.SetFlags(0)
log.SetPrefix("hakurei: ") log.SetPrefix("hakurei: ")
msg := message.New(log.Default()) msg := message.New(log.Default())
-3
View File
@@ -37,7 +37,6 @@ import (
"hakurei.app/check" "hakurei.app/check"
"hakurei.app/command" "hakurei.app/command"
"hakurei.app/container"
"hakurei.app/ext" "hakurei.app/ext"
"hakurei.app/fhs" "hakurei.app/fhs"
"hakurei.app/internal/pkg" "hakurei.app/internal/pkg"
@@ -67,8 +66,6 @@ func writeFileExcl(name string, data []byte, perm os.FileMode) error {
} }
func main() { func main() {
container.TryArgv0(nil)
log.SetFlags(0) log.SetFlags(0)
log.SetPrefix("mbf: ") log.SetPrefix("mbf: ")
msg := message.New(log.Default()) msg := message.New(log.Default())
-1
View File
@@ -287,7 +287,6 @@ func unsafeAddArgument(args *fuseArgs, arg string) {
func _main(s ...string) (exitCode int) { func _main(s ...string) (exitCode int) {
msg := message.New(log.Default()) msg := message.New(log.Default())
container.TryArgv0(msg)
runtime.LockOSThread() runtime.LockOSThread()
// don't mask creation mode, kernel already did that // don't mask creation mode, kernel already did that
-3
View File
@@ -1,15 +1,12 @@
package container package container
import ( import (
"encoding/gob"
"fmt" "fmt"
"hakurei.app/check" "hakurei.app/check"
"hakurei.app/fhs" "hakurei.app/fhs"
) )
func init() { gob.Register(new(AutoEtcOp)) }
// Etc is a helper for appending [AutoEtcOp] to [Ops]. // Etc is a helper for appending [AutoEtcOp] to [Ops].
func (f *Ops) Etc(host *check.Absolute, prefix string) *Ops { func (f *Ops) Etc(host *check.Absolute, prefix string) *Ops {
e := &AutoEtcOp{prefix} e := &AutoEtcOp{prefix}
-3
View File
@@ -1,7 +1,6 @@
package container package container
import ( import (
"encoding/gob"
"fmt" "fmt"
"hakurei.app/check" "hakurei.app/check"
@@ -9,8 +8,6 @@ import (
"hakurei.app/message" "hakurei.app/message"
) )
func init() { gob.Register(new(AutoRootOp)) }
// Root is a helper for appending [AutoRootOp] to [Ops]. // Root is a helper for appending [AutoRootOp] to [Ops].
func (f *Ops) Root(host *check.Absolute, flags int) *Ops { func (f *Ops) Root(host *check.Absolute, flags int) *Ops {
*f = append(*f, &AutoRootOp{host, flags, nil}) *f = append(*f, &AutoRootOp{host, flags, nil})
-5
View File
@@ -37,9 +37,6 @@ import (
// Note: this package requires cgo, which is unavailable in the Go playground. // Note: this package requires cgo, which is unavailable in the Go playground.
func Example() { func Example() {
// Must be called early if the current process starts containers.
container.TryArgv0(nil)
// Configure the container. // Configure the container.
z := container.New(context.Background(), nil) z := container.New(context.Background(), nil)
z.Hostname = "hakurei-example" z.Hostname = "hakurei-example"
@@ -876,8 +873,6 @@ var (
var helperCommands []func(c command.Command) var helperCommands []func(c command.Command)
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
container.TryArgv0(nil)
if os.Getenv(envDoCheck) == "1" { if os.Getenv(envDoCheck) == "1" {
c := command.New(os.Stderr, log.Printf, "helper", func(args []string) error { c := command.New(os.Stderr, log.Printf, "helper", func(args []string) error {
log.SetFlags(0) log.SetFlags(0)
+30 -10
View File
@@ -2,6 +2,7 @@ package container
import ( import (
"context" "context"
"encoding/gob"
"errors" "errors"
"fmt" "fmt"
"log" "log"
@@ -130,7 +131,7 @@ type initParams struct {
Verbose bool 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 Init(msg message.Msg) { initEntrypoint(direct{}, msg) }
func initEntrypoint(k syscallDispatcher, msg message.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. // initName is the prefix used by log.std in the init process.
const initName = "init" const initName = "init"
// TryArgv0 calls [Init] if the last element of argv0 is "init". var _ = func() struct{} {
// If a nil msg is passed, the system logger is used instead. for _, v := range []any{
func TryArgv0(msg message.Msg) { (*AutoEtcOp)(nil),
if msg == nil { (*AutoRootOp)(nil),
log.SetPrefix(initName + ": ") (*BindMountOp)(nil),
log.SetFlags(0) (*DaemonOp)(nil),
msg = message.New(log.Default()) (*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) Init(msg)
msg.BeforeExit() msg.BeforeExit()
os.Exit(0) os.Exit(0)
} }
} return struct{}{}
}()
// TryArgv0 is a noop.
//
// Deprecated: init is now implemented as an import side effect.
func TryArgv0(_ message.Msg) {}
-3
View File
@@ -1,7 +1,6 @@
package container package container
import ( import (
"encoding/gob"
"fmt" "fmt"
"os" "os"
"syscall" "syscall"
@@ -10,8 +9,6 @@ import (
"hakurei.app/container/std" "hakurei.app/container/std"
) )
func init() { gob.Register(new(BindMountOp)) }
// Bind is a helper for appending [BindMountOp] to [Ops]. // Bind is a helper for appending [BindMountOp] to [Ops].
func (f *Ops) Bind(source, target *check.Absolute, flags int) *Ops { func (f *Ops) Bind(source, target *check.Absolute, flags int) *Ops {
*f = append(*f, &BindMountOp{nil, source, target, flags}) *f = append(*f, &BindMountOp{nil, source, target, flags})
-3
View File
@@ -2,7 +2,6 @@ package container
import ( import (
"context" "context"
"encoding/gob"
"errors" "errors"
"fmt" "fmt"
"os" "os"
@@ -16,8 +15,6 @@ import (
"hakurei.app/fhs" "hakurei.app/fhs"
) )
func init() { gob.Register(new(DaemonOp)) }
const ( const (
// daemonTimeout is the duration a [DaemonOp] is allowed to block before the // daemonTimeout is the duration a [DaemonOp] is allowed to block before the
// [DaemonOp.Target] marker becomes available. // [DaemonOp.Target] marker becomes available.
-3
View File
@@ -1,7 +1,6 @@
package container package container
import ( import (
"encoding/gob"
"fmt" "fmt"
"path/filepath" "path/filepath"
. "syscall" . "syscall"
@@ -10,8 +9,6 @@ import (
"hakurei.app/fhs" "hakurei.app/fhs"
) )
func init() { gob.Register(new(MountDevOp)) }
// Dev appends an [Op] that mounts a subset of host /dev. // Dev appends an [Op] that mounts a subset of host /dev.
func (f *Ops) Dev(target *check.Absolute, mqueue bool) *Ops { func (f *Ops) Dev(target *check.Absolute, mqueue bool) *Ops {
*f = append(*f, &MountDevOp{target, mqueue, false}) *f = append(*f, &MountDevOp{target, mqueue, false})
-3
View File
@@ -1,15 +1,12 @@
package container package container
import ( import (
"encoding/gob"
"fmt" "fmt"
"os" "os"
"hakurei.app/check" "hakurei.app/check"
) )
func init() { gob.Register(new(MkdirOp)) }
// Mkdir is a helper for appending [MkdirOp] to [Ops]. // Mkdir is a helper for appending [MkdirOp] to [Ops].
func (f *Ops) Mkdir(name *check.Absolute, perm os.FileMode) *Ops { func (f *Ops) Mkdir(name *check.Absolute, perm os.FileMode) *Ops {
*f = append(*f, &MkdirOp{name, perm}) *f = append(*f, &MkdirOp{name, perm})
-3
View File
@@ -1,7 +1,6 @@
package container package container
import ( import (
"encoding/gob"
"fmt" "fmt"
"slices" "slices"
@@ -19,8 +18,6 @@ const (
intermediatePatternOverlayWork = "overlay.work.*" intermediatePatternOverlayWork = "overlay.work.*"
) )
func init() { gob.Register(new(MountOverlayOp)) }
const ( const (
// OverlayEphemeralUnexpectedUpper is set when [MountOverlayOp.Work] is nil // OverlayEphemeralUnexpectedUpper is set when [MountOverlayOp.Work] is nil
// and [MountOverlayOp.Upper] holds an unexpected value. // and [MountOverlayOp.Upper] holds an unexpected value.
-3
View File
@@ -1,7 +1,6 @@
package container package container
import ( import (
"encoding/gob"
"fmt" "fmt"
"syscall" "syscall"
@@ -14,8 +13,6 @@ const (
intermediatePatternTmpfile = "tmp.*" intermediatePatternTmpfile = "tmp.*"
) )
func init() { gob.Register(new(TmpfileOp)) }
// Place is a helper for appending [TmpfileOp] to [Ops]. // Place is a helper for appending [TmpfileOp] to [Ops].
func (f *Ops) Place(name *check.Absolute, data []byte) *Ops { func (f *Ops) Place(name *check.Absolute, data []byte) *Ops {
*f = append(*f, &TmpfileOp{name, data}) *f = append(*f, &TmpfileOp{name, data})
-3
View File
@@ -1,15 +1,12 @@
package container package container
import ( import (
"encoding/gob"
"fmt" "fmt"
. "syscall" . "syscall"
"hakurei.app/check" "hakurei.app/check"
) )
func init() { gob.Register(new(MountProcOp)) }
// Proc is a helper for appending [MountProcOp] to [Ops]. // Proc is a helper for appending [MountProcOp] to [Ops].
func (f *Ops) Proc(target *check.Absolute) *Ops { func (f *Ops) Proc(target *check.Absolute) *Ops {
*f = append(*f, &MountProcOp{target}) *f = append(*f, &MountProcOp{target})
-3
View File
@@ -1,14 +1,11 @@
package container package container
import ( import (
"encoding/gob"
"fmt" "fmt"
"hakurei.app/check" "hakurei.app/check"
) )
func init() { gob.Register(new(RemountOp)) }
// Remount is a helper for appending [RemountOp] to [Ops]. // Remount is a helper for appending [RemountOp] to [Ops].
func (f *Ops) Remount(target *check.Absolute, flags uintptr) *Ops { func (f *Ops) Remount(target *check.Absolute, flags uintptr) *Ops {
*f = append(*f, &RemountOp{target, flags}) *f = append(*f, &RemountOp{target, flags})
-3
View File
@@ -1,15 +1,12 @@
package container package container
import ( import (
"encoding/gob"
"fmt" "fmt"
"path/filepath" "path/filepath"
"hakurei.app/check" "hakurei.app/check"
) )
func init() { gob.Register(new(SymlinkOp)) }
// Link appends an [Op] that creates a symlink in the container filesystem. // Link appends an [Op] that creates a symlink in the container filesystem.
func (f *Ops) Link(target *check.Absolute, linkName string, dereference bool) *Ops { func (f *Ops) Link(target *check.Absolute, linkName string, dereference bool) *Ops {
*f = append(*f, &SymlinkOp{target, linkName, dereference}) *f = append(*f, &SymlinkOp{target, linkName, dereference})
-3
View File
@@ -1,7 +1,6 @@
package container package container
import ( import (
"encoding/gob"
"fmt" "fmt"
"math" "math"
"os" "os"
@@ -11,8 +10,6 @@ import (
"hakurei.app/check" "hakurei.app/check"
) )
func init() { gob.Register(new(MountTmpfsOp)) }
type TmpfsSizeError int type TmpfsSizeError int
func (e TmpfsSizeError) Error() string { func (e TmpfsSizeError) Error() string {
+1 -2
View File
@@ -4,8 +4,7 @@ import (
"os" "os"
"testing" "testing"
"hakurei.app/container"
"hakurei.app/internal/helper" "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()) }
+1 -2
View File
@@ -4,8 +4,7 @@ import (
"os" "os"
"testing" "testing"
"hakurei.app/container"
"hakurei.app/internal/helper" "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()) }
-2
View File
@@ -85,8 +85,6 @@ func newRContext(tb testing.TB, c *pkg.Cache) *pkg.RContext {
return &r return &r
} }
func TestMain(m *testing.M) { container.TryArgv0(nil); os.Exit(m.Run()) }
// overrideIdent overrides the ID method of [Artifact]. // overrideIdent overrides the ID method of [Artifact].
type overrideIdent struct { type overrideIdent struct {
id pkg.ID id pkg.ID
-3
View File
@@ -10,7 +10,6 @@ import (
"testing" "testing"
"hakurei.app/check" "hakurei.app/check"
"hakurei.app/container"
"hakurei.app/internal/pkg" "hakurei.app/internal/pkg"
"hakurei.app/internal/rosa" "hakurei.app/internal/rosa"
"hakurei.app/message" "hakurei.app/message"
@@ -28,8 +27,6 @@ var (
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
container.TryArgv0(nil)
code := m.Run() code := m.Run()
if buildTestCache != nil { if buildTestCache != nil {
buildTestCacheCancel() buildTestCacheCancel()
-4
View File
@@ -2,12 +2,10 @@ package ldd_test
import ( import (
"errors" "errors"
"os"
"os/exec" "os/exec"
"testing" "testing"
"hakurei.app/check" "hakurei.app/check"
"hakurei.app/container"
"hakurei.app/ldd" "hakurei.app/ldd"
"hakurei.app/message" "hakurei.app/message"
) )
@@ -42,5 +40,3 @@ func TestExec(t *testing.T) {
} }
}) })
} }
func TestMain(m *testing.M) { container.TryArgv0(nil); os.Exit(m.Run()) }