aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-11-10 20:35:59 +0900
committerOphestra <cat@gensokyo.uk>2025-11-10 20:35:59 +0900
commit2f74adc8bdeda2499be0a8b2711f68c342695bf2 (patch)
tree4a4b4f0899e0d56b3ca5c228298f978bc1f984bb
parentd7e0104ae4da25f455630aae044adf165201c9b5 (diff)
container/init: close initial process files on termination
This closes them during the adopt wait delay. This also keeps them alive. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--container/check/absolute_test.go2
-rw-r--r--container/container_test.go1
-rw-r--r--container/fhs/abs.go2
-rw-r--r--container/init.go12
-rw-r--r--container/init_test.go13
-rw-r--r--container/stub/exit_test.go2
6 files changed, 27 insertions, 5 deletions
diff --git a/container/check/absolute_test.go b/container/check/absolute_test.go
index 5cb96d79..466bbacb 100644
--- a/container/check/absolute_test.go
+++ b/container/check/absolute_test.go
@@ -9,7 +9,7 @@ import (
"strings"
"syscall"
"testing"
- _ "unsafe"
+ _ "unsafe" // for go:linkname
. "hakurei.app/container/check"
)
diff --git a/container/container_test.go b/container/container_test.go
index b77ce5f6..5aaa8763 100644
--- a/container/container_test.go
+++ b/container/container_test.go
@@ -722,6 +722,7 @@ func TestMain(m *testing.M) {
func helperNewContainerLibPaths(ctx context.Context, libPaths *[]*check.Absolute, args ...string) (c *container.Container) {
msg := message.New(nil)
+ msg.SwapVerbose(testing.Verbose())
c = container.NewCommand(ctx, msg, absHelperInnerPath, "helper", args...)
c.Env = append(c.Env, envDoCheck+"=1")
c.Bind(check.MustAbs(os.Args[0]), absHelperInnerPath, 0)
diff --git a/container/fhs/abs.go b/container/fhs/abs.go
index af3588ba..6bb72166 100644
--- a/container/fhs/abs.go
+++ b/container/fhs/abs.go
@@ -1,7 +1,7 @@
package fhs
import (
- _ "unsafe"
+ _ "unsafe" // for go:linkname
"hakurei.app/container/check"
)
diff --git a/container/init.go b/container/init.go
index fd513efd..592ef302 100644
--- a/container/init.go
+++ b/container/init.go
@@ -427,6 +427,16 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
}
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 {
case w.wstatus.Exited():
r = w.wstatus.ExitStatus()
@@ -440,8 +450,6 @@ func initEntrypoint(k syscallDispatcher, msg message.Msg) {
r = 255
msg.Verbosef("initial process exited with status %#x", w.wstatus)
}
-
- go func() { time.Sleep(params.AdoptWaitDelay); close(timeout) }()
}
case <-timeout:
diff --git a/container/init_test.go b/container/init_test.go
index 336c7c48..6217537a 100644
--- a/container/init_test.go
+++ b/container/init_test.go
@@ -2070,6 +2070,8 @@ func TestInitEntrypoint(t *testing.T) {
// 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("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("printf", stub.ExpectArgs{"timeout exceeded waiting for lingering processes", ([]any)(nil)}, 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
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("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("printf", stub.ExpectArgs{"timeout exceeded waiting for lingering processes", []any(nil)}, 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("New", stub.ExpectArgs{}, 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("printf", stub.ExpectArgs{"timeout exceeded waiting for lingering processes", ([]any)(nil)}, 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("New", stub.ExpectArgs{}, 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("beforeExit", stub.ExpectArgs{}, 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("New", stub.ExpectArgs{}, 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("beforeExit", stub.ExpectArgs{}, 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("New", stub.ExpectArgs{}, 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("beforeExit", stub.ExpectArgs{}, nil, nil),
call("exit", stub.ExpectArgs{0xff}, nil, nil),
diff --git a/container/stub/exit_test.go b/container/stub/exit_test.go
index 5d850759..e4c4f962 100644
--- a/container/stub/exit_test.go
+++ b/container/stub/exit_test.go
@@ -2,7 +2,7 @@ package stub_test
import (
"testing"
- _ "unsafe"
+ _ "unsafe" // for go:linkname
"hakurei.app/container/stub"
)