aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/outcome/shim.go
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-12-15 12:32:05 +0900
committerOphestra <cat@gensokyo.uk>2025-12-15 12:32:46 +0900
commitd0a3c6a2f3ac4da3921fa525cf1ee5ea7d68eb1c (patch)
tree057761396cc629e36ed1f58237f95dd41278e916 /internal/outcome/shim.go
parent0c0e3d6fc2bf37eef703e9295fc56ef2a2fc5808 (diff)
internal/outcome: optional shim private dir
This is a private work directory owned by the specific shim. Useful for sockets owned by this instance of the shim and requires no direct assistance from the priv-side process. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'internal/outcome/shim.go')
-rw-r--r--internal/outcome/shim.go57
1 files changed, 57 insertions, 0 deletions
diff --git a/internal/outcome/shim.go b/internal/outcome/shim.go
index bde79be3..59b1236c 100644
--- a/internal/outcome/shim.go
+++ b/internal/outcome/shim.go
@@ -14,6 +14,7 @@ import (
"time"
"hakurei.app/container"
+ "hakurei.app/container/check"
"hakurei.app/container/seccomp"
"hakurei.app/container/std"
"hakurei.app/hst"
@@ -83,6 +84,55 @@ func Shim(msg message.Msg) {
shimEntrypoint(direct{msg})
}
+// A shimPrivate holds state of the private work directory owned by shim.
+type shimPrivate struct {
+ // Path to directory if created.
+ pathname *check.Absolute
+
+ k syscallDispatcher
+ id *stringPair[hst.ID]
+}
+
+// unwrap returns the underlying pathname.
+func (sp *shimPrivate) unwrap() *check.Absolute {
+ if sp.pathname == nil {
+ if a, err := check.NewAbs(sp.k.tempdir()); err != nil {
+ sp.k.fatal(err)
+ panic("unreachable")
+ } else {
+ pathname := a.Append(".hakurei-shim-" + sp.id.String())
+ sp.k.getMsg().Verbosef("creating private work directory %q", pathname)
+ if err = sp.k.mkdir(pathname.String(), 0700); err != nil {
+ sp.k.fatal(err)
+ panic("unreachable")
+ }
+ sp.pathname = pathname
+ return sp.unwrap()
+ }
+ } else {
+ return sp.pathname
+ }
+}
+
+// String returns the absolute pathname to the directory held by shimPrivate.
+func (sp *shimPrivate) String() string { return sp.unwrap().String() }
+
+// destroy removes the directory held by shimPrivate.
+func (sp *shimPrivate) destroy() {
+ defer func() { sp.pathname = nil }()
+ if sp.pathname != nil {
+ sp.k.getMsg().Verbosef("destroying private work directory %q", sp.pathname)
+ if err := sp.k.removeAll(sp.pathname.String()); err != nil {
+ sp.k.getMsg().GetLogger().Println(err)
+ }
+ }
+}
+
+const (
+ // shimPipeWireTimeout is the duration pipewire-pulse is allowed to run before its socket becomes available.
+ shimPipeWireTimeout = 5 * time.Second
+)
+
func shimEntrypoint(k syscallDispatcher) {
msg := k.getMsg()
if msg == nil {
@@ -208,6 +258,7 @@ func shimEntrypoint(k syscallDispatcher) {
ctx, stop := k.notifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
cancelContainer.Store(&stop)
+ sp := shimPrivate{k: k, id: state.id}
z := container.New(ctx, msg)
z.Params = *stateParams.params
z.Stdin, z.Stdout, z.Stderr = os.Stdin, os.Stdout, os.Stderr
@@ -225,9 +276,11 @@ func shimEntrypoint(k syscallDispatcher) {
}
}
printMessageError(f, "cannot start container:", err)
+ sp.destroy()
k.exit(hst.ExitFailure)
}
if err := k.containerServe(z); err != nil {
+ sp.destroy()
printMessageError(func(v ...any) { k.fatal(fmt.Sprintln(v...)) },
"cannot configure container:", err)
}
@@ -236,10 +289,13 @@ func shimEntrypoint(k syscallDispatcher) {
seccomp.Preset(std.PresetStrict, seccomp.AllowMultiarch),
seccomp.AllowMultiarch,
); err != nil {
+ sp.destroy()
k.fatalf("cannot load syscall filter: %v", err)
}
if err := k.containerWait(z); err != nil {
+ sp.destroy()
+
var exitError *exec.ExitError
if !errors.As(err, &exitError) {
if errors.Is(err, context.Canceled) {
@@ -250,4 +306,5 @@ func shimEntrypoint(k syscallDispatcher) {
}
k.exit(exitError.ExitCode())
}
+ sp.destroy()
}