aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2025-12-15 12:35:43 +0900
committerOphestra <cat@gensokyo.uk>2025-12-15 12:38:39 +0900
commit2e806601693e0262641386ce5430d7e8d84b2a77 (patch)
treebf8cf3cfbe0d3e8e01524a32ef5ab96ac66de5b5
parentd0a3c6a2f3ac4da3921fa525cf1ee5ea7d68eb1c (diff)
internal/outcome: look up pipewire-pulse path
This is for setting up the pipewire-pulse container in shim, for #29. Signed-off-by: Ophestra <cat@gensokyo.uk>
-rw-r--r--internal/outcome/dispatcher.go3
-rw-r--r--internal/outcome/dispatcher_test.go1
-rw-r--r--internal/outcome/outcome.go11
-rw-r--r--internal/outcome/run_test.go10
-rw-r--r--internal/outcome/sppipewire.go27
-rw-r--r--internal/outcome/sppipewire_test.go10
6 files changed, 47 insertions, 15 deletions
diff --git a/internal/outcome/dispatcher.go b/internal/outcome/dispatcher.go
index 0813f819..93adfbb9 100644
--- a/internal/outcome/dispatcher.go
+++ b/internal/outcome/dispatcher.go
@@ -66,6 +66,8 @@ type syscallDispatcher interface {
// lookupGroupId calls [user.LookupGroup] and returns the Gid field of the resulting [user.Group] struct.
lookupGroupId(name string) (string, error)
+ // lookPath provides exec.LookPath.
+ lookPath(file string) (string, error)
// cmdOutput provides the Output method of [exec.Cmd].
cmdOutput(cmd *exec.Cmd) ([]byte, error)
@@ -140,6 +142,7 @@ func (direct) lookupGroupId(name string) (gid string, err error) {
return
}
+func (direct) lookPath(file string) (string, error) { return exec.LookPath(file) }
func (direct) cmdOutput(cmd *exec.Cmd) ([]byte, error) { return cmd.Output() }
func (direct) notifyContext(parent context.Context, signals ...os.Signal) (ctx context.Context, stop context.CancelFunc) {
diff --git a/internal/outcome/dispatcher_test.go b/internal/outcome/dispatcher_test.go
index 4cfa0fa7..84f06c7c 100644
--- a/internal/outcome/dispatcher_test.go
+++ b/internal/outcome/dispatcher_test.go
@@ -707,6 +707,7 @@ func (panicDispatcher) exit(int) { pa
func (panicDispatcher) evalSymlinks(string) (string, error) { panic("unreachable") }
func (panicDispatcher) prctl(uintptr, uintptr, uintptr) error { panic("unreachable") }
func (panicDispatcher) lookupGroupId(string) (string, error) { panic("unreachable") }
+func (panicDispatcher) lookPath(string) (string, error) { panic("unreachable") }
func (panicDispatcher) cmdOutput(*exec.Cmd) ([]byte, error) { panic("unreachable") }
func (panicDispatcher) overflowUid(message.Msg) int { panic("unreachable") }
func (panicDispatcher) overflowGid(message.Msg) int { panic("unreachable") }
diff --git a/internal/outcome/outcome.go b/internal/outcome/outcome.go
index ea01099e..45ef4431 100644
--- a/internal/outcome/outcome.go
+++ b/internal/outcome/outcome.go
@@ -70,7 +70,7 @@ type outcomeState struct {
// Copied from their respective exported values.
mapuid, mapgid *stringPair[int]
- // Copied from [EnvPaths] per-process.
+ // Copied from [env.Paths] per-process.
sc hst.Paths
*env.Paths
@@ -172,6 +172,8 @@ type outcomeStateSys struct {
// Copied from [hst.Config]. Safe for read by spWaylandOp.toSystem only.
directWayland bool
+ // Copied from [hst.Config]. Safe for read by spPipeWireOp.toSystem only.
+ directPipeWire bool
// Copied from [hst.Config]. Safe for read by spPulseOp.toSystem only.
directPulse bool
// Copied header from [hst.Config]. Safe for read by spFilesystemOp.toSystem only.
@@ -187,9 +189,8 @@ type outcomeStateSys struct {
func (s *outcomeState) newSys(config *hst.Config, sys *system.I) *outcomeStateSys {
return &outcomeStateSys{
appId: config.ID, et: config.Enablements.Unwrap(),
- directWayland: config.DirectWayland, directPulse: config.DirectPulse,
- extraPerms: config.ExtraPerms,
- sessionBus: config.SessionBus, systemBus: config.SystemBus,
+ directWayland: config.DirectWayland, directPipeWire: config.DirectPipeWire, directPulse: config.DirectPulse,
+ extraPerms: config.ExtraPerms, sessionBus: config.SessionBus, systemBus: config.SystemBus,
sys: sys, outcomeState: s,
}
}
@@ -295,7 +296,7 @@ func (state *outcomeStateSys) toSystem() error {
// optional via enablements
&spWaylandOp{},
&spX11Op{},
- spPipeWireOp{},
+ &spPipeWireOp{},
&spPulseOp{},
&spDBusOp{},
diff --git a/internal/outcome/run_test.go b/internal/outcome/run_test.go
index 01d487a8..db18e02c 100644
--- a/internal/outcome/run_test.go
+++ b/internal/outcome/run_test.go
@@ -883,6 +883,16 @@ func (k *stubNixOS) lookupGroupId(name string) (string, error) {
}
}
+func (k *stubNixOS) lookPath(file string) (string, error) {
+ switch file {
+ case "pipewire-pulse":
+ return "/run/current-system/sw/bin/pipewire-pulse", nil
+
+ default:
+ panic(fmt.Sprintf("unexpected file %q", file))
+ }
+}
+
func (k *stubNixOS) cmdOutput(cmd *exec.Cmd) ([]byte, error) {
switch cmd.Path {
case "/proc/nonexistent/hsu":
diff --git a/internal/outcome/sppipewire.go b/internal/outcome/sppipewire.go
index b9359f7e..fd99d514 100644
--- a/internal/outcome/sppipewire.go
+++ b/internal/outcome/sppipewire.go
@@ -3,20 +3,33 @@ package outcome
import (
"encoding/gob"
+ "hakurei.app/container/check"
"hakurei.app/hst"
"hakurei.app/internal/pipewire"
)
-func init() { gob.Register(spPipeWireOp{}) }
+const pipewirePulseName = "pipewire-pulse"
+
+func init() { gob.Register(new(spPipeWireOp)) }
// spPipeWireOp exports the PipeWire server to the container via SecurityContext.
// Runs after spRuntimeOp.
-type spPipeWireOp struct{}
+type spPipeWireOp struct {
+ // Path to pipewire-pulse server. Populated during toSystem if DirectPipeWire is false.
+ CompatServerPath *check.Absolute
+}
-func (s spPipeWireOp) toSystem(state *outcomeStateSys) error {
+func (s *spPipeWireOp) toSystem(state *outcomeStateSys) error {
if state.et&hst.EPipeWire == 0 {
return errNotEnabled
}
+ if !state.directPipeWire {
+ if n, err := state.k.lookPath(pipewirePulseName); err != nil {
+ return &hst.AppError{Step: "look up " + pipewirePulseName, Err: err}
+ } else if s.CompatServerPath, err = check.NewAbs(n); err != nil {
+ return err
+ }
+ }
appId := state.appId
if appId == "" {
@@ -27,10 +40,10 @@ func (s spPipeWireOp) toSystem(state *outcomeStateSys) error {
return nil
}
-func (s spPipeWireOp) toContainer(state *outcomeStateParams) error {
- innerPath := state.runtimeDir.Append(pipewire.PW_DEFAULT_REMOTE)
- state.env[pipewire.Remote] = innerPath.String()
- state.params.Bind(state.instancePath().Append("pipewire"), innerPath, 0)
+func (s *spPipeWireOp) toContainer(state *outcomeStateParams) error {
+ innerPath := state.runtimeDir.Append(pipewire.PW_DEFAULT_REMOTE)
+ state.env[pipewire.Remote] = innerPath.String()
+ state.params.Bind(state.instancePath().Append("pipewire"), innerPath, 0)
return nil
}
diff --git a/internal/outcome/sppipewire_test.go b/internal/outcome/sppipewire_test.go
index 35ad8e50..3259915c 100644
--- a/internal/outcome/sppipewire_test.go
+++ b/internal/outcome/sppipewire_test.go
@@ -16,7 +16,7 @@ func TestSpPipeWireOp(t *testing.T) {
checkOpBehaviour(t, []opBehaviourTestCase{
{"not enabled", func(bool, bool) outcomeOp {
- return spPipeWireOp{}
+ return new(spPipeWireOp)
}, func() *hst.Config {
c := hst.Template()
*c.Enablements = 0
@@ -24,8 +24,12 @@ func TestSpPipeWireOp(t *testing.T) {
}, nil, nil, nil, nil, errNotEnabled, nil, nil, nil, nil, nil},
{"success", func(bool, bool) outcomeOp {
- return spPipeWireOp{}
- }, hst.Template, nil, []stub.Call{}, newI().
+ return new(spPipeWireOp)
+ }, func() *hst.Config {
+ c := hst.Template()
+ c.DirectPipeWire = true
+ return c
+ }, nil, []stub.Call{}, newI().
// state.instance
Ephemeral(system.Process, m(wantInstancePrefix), 0711).
// toSystem