container/init: close initial process files on termination
All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 2m29s
Test / Sandbox (race detector) (push) Successful in 4m28s
Test / Hakurei (push) Successful in 4m34s
Test / Hpkg (push) Successful in 4m42s
Test / Hakurei (race detector) (push) Successful in 6m9s
Test / Flake checks (push) Successful in 1m26s

This closes them during the adopt wait delay. This also keeps them alive.

Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
Ophestra 2025-11-10 20:35:59 +09:00
parent d7e0104ae4
commit 2f74adc8bd
Signed by: cat
SSH Key Fingerprint: SHA256:gQ67O0enBZ7UdZypgtspB2FDM1g3GVw8nX0XSdcFw8Q
6 changed files with 27 additions and 5 deletions

View File

@ -9,7 +9,7 @@ import (
"strings" "strings"
"syscall" "syscall"
"testing" "testing"
_ "unsafe" _ "unsafe" // for go:linkname
. "hakurei.app/container/check" . "hakurei.app/container/check"
) )

View File

@ -722,6 +722,7 @@ func TestMain(m *testing.M) {
func helperNewContainerLibPaths(ctx context.Context, libPaths *[]*check.Absolute, args ...string) (c *container.Container) { func helperNewContainerLibPaths(ctx context.Context, libPaths *[]*check.Absolute, args ...string) (c *container.Container) {
msg := message.New(nil) msg := message.New(nil)
msg.SwapVerbose(testing.Verbose())
c = container.NewCommand(ctx, msg, absHelperInnerPath, "helper", args...) c = container.NewCommand(ctx, msg, absHelperInnerPath, "helper", args...)
c.Env = append(c.Env, envDoCheck+"=1") c.Env = append(c.Env, envDoCheck+"=1")
c.Bind(check.MustAbs(os.Args[0]), absHelperInnerPath, 0) c.Bind(check.MustAbs(os.Args[0]), absHelperInnerPath, 0)

View File

@ -1,7 +1,7 @@
package fhs package fhs
import ( import (
_ "unsafe" _ "unsafe" // for go:linkname
"hakurei.app/container/check" "hakurei.app/container/check"
) )

View File

@ -427,6 +427,16 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
} }
if w.wpid == cmd.Process.Pid { if w.wpid == cmd.Process.Pid {
// start timeout early
go func() { time.Sleep(params.AdoptWaitDelay); close(timeout) }()
// close initial process files; this also keeps them alive
for _, f := range extraFiles {
if err := f.Close(); err != nil {
msg.Verbose(err.Error())
}
}
switch { switch {
case w.wstatus.Exited(): case w.wstatus.Exited():
r = w.wstatus.ExitStatus() r = w.wstatus.ExitStatus()
@ -440,8 +450,6 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
r = 255 r = 255
msg.Verbosef("initial process exited with status %#x", w.wstatus) msg.Verbosef("initial process exited with status %#x", w.wstatus)
} }
go func() { time.Sleep(params.AdoptWaitDelay); close(timeout) }()
} }
case <-timeout: case <-timeout:

View File

@ -2070,6 +2070,8 @@ func TestInitEntrypoint(t *testing.T) {
// magicWait4Signal as ret causes wait4 stub to unblock // magicWait4Signal as ret causes wait4 stub to unblock
call("signal", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent", os.Interrupt}, magicWait4Signal, stub.UniqueError(9)), call("signal", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent", os.Interrupt}, magicWait4Signal, stub.UniqueError(9)),
call("printf", stub.ExpectArgs{"cannot forward cancellation: %v", []any{stub.UniqueError(9)}}, nil, nil), call("printf", stub.ExpectArgs{"cannot forward cancellation: %v", []any{stub.UniqueError(9)}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbosef", stub.ExpectArgs{"initial process exited with signal %s", []any{syscall.Signal(0x4e)}}, nil, nil), call("verbosef", stub.ExpectArgs{"initial process exited with signal %s", []any{syscall.Signal(0x4e)}}, nil, nil),
call("printf", stub.ExpectArgs{"timeout exceeded waiting for lingering processes", ([]any)(nil)}, nil, nil), call("printf", stub.ExpectArgs{"timeout exceeded waiting for lingering processes", ([]any)(nil)}, nil, nil),
call("beforeExit", stub.ExpectArgs{}, nil, nil), call("beforeExit", stub.ExpectArgs{}, nil, nil),
@ -2168,6 +2170,8 @@ func TestInitEntrypoint(t *testing.T) {
// magicWait4Signal as ret causes wait4 stub to unblock // magicWait4Signal as ret causes wait4 stub to unblock
call("signal", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent", syscall.SIGQUIT}, magicWait4Signal, stub.UniqueError(0xfe)), call("signal", stub.ExpectArgs{"/run/current-system/sw/bin/bash", []string{"bash", "-c", "false"}, ([]string)(nil), "/.hakurei/nonexistent", syscall.SIGQUIT}, magicWait4Signal, stub.UniqueError(0xfe)),
call("printf", stub.ExpectArgs{"cannot forward signal: %v", []any{stub.UniqueError(0xfe)}}, nil, nil), call("printf", stub.ExpectArgs{"cannot forward signal: %v", []any{stub.UniqueError(0xfe)}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbosef", stub.ExpectArgs{"initial process exited with signal %s", []any{syscall.Signal(0x4e)}}, nil, nil), call("verbosef", stub.ExpectArgs{"initial process exited with signal %s", []any{syscall.Signal(0x4e)}}, nil, nil),
call("printf", stub.ExpectArgs{"timeout exceeded waiting for lingering processes", []any(nil)}, nil, nil), call("printf", stub.ExpectArgs{"timeout exceeded waiting for lingering processes", []any(nil)}, nil, nil),
call("beforeExit", stub.ExpectArgs{}, nil, nil), call("beforeExit", stub.ExpectArgs{}, nil, nil),
@ -2353,6 +2357,8 @@ func TestInitEntrypoint(t *testing.T) {
call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(5)}}, nil, nil), call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(5)}}, nil, nil),
call("New", stub.ExpectArgs{}, nil, nil), call("New", stub.ExpectArgs{}, nil, nil),
call("notify", stub.ExpectArgs{nil, []os.Signal{CancelSignal, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT}}, nil, nil), call("notify", stub.ExpectArgs{nil, []os.Signal{CancelSignal, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbosef", stub.ExpectArgs{"initial process exited with signal %s", []any{syscall.Signal(0x4e)}}, nil, nil), call("verbosef", stub.ExpectArgs{"initial process exited with signal %s", []any{syscall.Signal(0x4e)}}, nil, nil),
call("printf", stub.ExpectArgs{"timeout exceeded waiting for lingering processes", ([]any)(nil)}, nil, nil), call("printf", stub.ExpectArgs{"timeout exceeded waiting for lingering processes", ([]any)(nil)}, nil, nil),
call("beforeExit", stub.ExpectArgs{}, nil, nil), call("beforeExit", stub.ExpectArgs{}, nil, nil),
@ -2446,6 +2452,8 @@ func TestInitEntrypoint(t *testing.T) {
call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(3)}}, nil, nil), call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(3)}}, nil, nil),
call("New", stub.ExpectArgs{}, nil, nil), call("New", stub.ExpectArgs{}, nil, nil),
call("notify", stub.ExpectArgs{nil, []os.Signal{CancelSignal, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT}}, nil, nil), call("notify", stub.ExpectArgs{nil, []os.Signal{CancelSignal, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbosef", stub.ExpectArgs{"initial process exited with signal %s", []any{syscall.Signal(0x4e)}}, nil, nil), call("verbosef", stub.ExpectArgs{"initial process exited with signal %s", []any{syscall.Signal(0x4e)}}, nil, nil),
call("beforeExit", stub.ExpectArgs{}, nil, nil), call("beforeExit", stub.ExpectArgs{}, nil, nil),
call("exit", stub.ExpectArgs{0xce}, nil, nil), call("exit", stub.ExpectArgs{0xce}, nil, nil),
@ -2582,6 +2590,8 @@ func TestInitEntrypoint(t *testing.T) {
call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(1)}}, nil, nil), call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(1)}}, nil, nil),
call("New", stub.ExpectArgs{}, nil, nil), call("New", stub.ExpectArgs{}, nil, nil),
call("notify", stub.ExpectArgs{nil, []os.Signal{CancelSignal, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT}}, nil, nil), call("notify", stub.ExpectArgs{nil, []os.Signal{CancelSignal, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbosef", stub.ExpectArgs{"initial process exited with code %d", []any{1}}, nil, nil), call("verbosef", stub.ExpectArgs{"initial process exited with code %d", []any{1}}, nil, nil),
call("beforeExit", stub.ExpectArgs{}, nil, nil), call("beforeExit", stub.ExpectArgs{}, nil, nil),
call("exit", stub.ExpectArgs{1}, nil, nil), call("exit", stub.ExpectArgs{1}, nil, nil),
@ -2722,6 +2732,9 @@ func TestInitEntrypoint(t *testing.T) {
call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(0)}}, nil, nil), call("printf", stub.ExpectArgs{"cannot close setup pipe: %v", []any{stub.UniqueError(0)}}, nil, nil),
call("New", stub.ExpectArgs{}, nil, nil), call("New", stub.ExpectArgs{}, nil, nil),
call("notify", stub.ExpectArgs{nil, []os.Signal{CancelSignal, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT}}, nil, nil), call("notify", stub.ExpectArgs{nil, []os.Signal{CancelSignal, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbose", stub.ExpectArgs{[]any{os.ErrInvalid.Error()}}, nil, nil),
call("verbosef", stub.ExpectArgs{"initial process exited with status %#x", []any{syscall.WaitStatus(0xfade007f)}}, nil, nil), call("verbosef", stub.ExpectArgs{"initial process exited with status %#x", []any{syscall.WaitStatus(0xfade007f)}}, nil, nil),
call("beforeExit", stub.ExpectArgs{}, nil, nil), call("beforeExit", stub.ExpectArgs{}, nil, nil),
call("exit", stub.ExpectArgs{0xff}, nil, nil), call("exit", stub.ExpectArgs{0xff}, nil, nil),

View File

@ -2,7 +2,7 @@ package stub_test
import ( import (
"testing" "testing"
_ "unsafe" _ "unsafe" // for go:linkname
"hakurei.app/container/stub" "hakurei.app/container/stub"
) )