aboutsummaryrefslogtreecommitdiffhomepage
path: root/dbus/run.go
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-09-09 03:11:50 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-09-09 03:11:50 +0900
commit357cc4ce4d2888033a8163fe39861c8a88301da6 (patch)
treea6dbdd09fc5ef2dea82ad1c85627b6455c2f3477 /dbus/run.go
parent3242ce340621839d03ecf34bb3ed20d7c6f3cbb3 (diff)
dbus: implement xdg-dbus-proxy wrapper
Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'dbus/run.go')
-rw-r--r--dbus/run.go134
1 files changed, 134 insertions, 0 deletions
diff --git a/dbus/run.go b/dbus/run.go
new file mode 100644
index 00000000..315b31de
--- /dev/null
+++ b/dbus/run.go
@@ -0,0 +1,134 @@
+package dbus
+
+import (
+ "errors"
+ "os"
+ "os/exec"
+)
+
+// Start launches the D-Bus proxy and sets up the Wait method.
+// ready should be buffered and should only be received from once.
+func (p *Proxy) Start(ready *chan bool) error {
+ p.lock.Lock()
+ defer p.lock.Unlock()
+
+ if p.seal == nil {
+ return errors.New("proxy not sealed")
+ }
+
+ // acquire pipes
+ if pr, pw, err := os.Pipe(); err != nil {
+ return err
+ } else {
+ p.statP[0], p.statP[1] = pr, pw
+ }
+ if pr, pw, err := os.Pipe(); err != nil {
+ return err
+ } else {
+ p.argsP[0], p.argsP[1] = pr, pw
+ }
+
+ p.cmd = exec.Command(p.path,
+ // ExtraFiles: If non-nil, entry i becomes file descriptor 3+i.
+ "--fd=3",
+ "--args=4",
+ )
+ p.cmd.Env = []string{}
+ p.cmd.ExtraFiles = []*os.File{p.statP[1], p.argsP[0]}
+ p.cmd.Stdout = os.Stdout
+ p.cmd.Stderr = os.Stderr
+ if err := p.cmd.Start(); err != nil {
+ return err
+ }
+
+ statsP, argsP := p.statP[0], p.argsP[1]
+
+ if _, err := argsP.Write([]byte(*p.seal)); err != nil {
+ if err1 := p.cmd.Process.Kill(); err1 != nil {
+ panic(err1)
+ }
+ return err
+ } else {
+ if err = argsP.Close(); err != nil {
+ if err1 := p.cmd.Process.Kill(); err1 != nil {
+ panic(err1)
+ }
+ return err
+ }
+ }
+
+ wait := make(chan error)
+ go func() {
+ // live out the lifespan of the process
+ wait <- p.cmd.Wait()
+ }()
+
+ read := make(chan error)
+ go func() {
+ n, err := statsP.Read(make([]byte, 1))
+ switch n {
+ case -1:
+ if err1 := p.cmd.Process.Kill(); err1 != nil {
+ panic(err1)
+ }
+ read <- err
+ case 0:
+ read <- err
+ case 1:
+ *ready <- true
+ read <- nil
+ default:
+ panic("unreachable") // unexpected read count
+ }
+ }()
+
+ p.wait = &wait
+ p.read = &read
+ p.ready = ready
+
+ return nil
+}
+
+// Wait waits for xdg-dbus-proxy to exit or fault.
+func (p *Proxy) Wait() error {
+ p.lock.RLock()
+ defer p.lock.RUnlock()
+
+ if p.wait == nil || p.read == nil {
+ return errors.New("proxy not running")
+ }
+
+ defer func() {
+ if err1 := p.statP[0].Close(); err1 != nil && !errors.Is(err1, os.ErrClosed) {
+ panic(err1)
+ }
+ if err1 := p.statP[1].Close(); err1 != nil && !errors.Is(err1, os.ErrClosed) {
+ panic(err1)
+ }
+
+ if err1 := p.argsP[0].Close(); err1 != nil && !errors.Is(err1, os.ErrClosed) {
+ panic(err1)
+ }
+ if err1 := p.argsP[1].Close(); err1 != nil && !errors.Is(err1, os.ErrClosed) {
+ panic(err1)
+ }
+
+ }()
+
+ select {
+ case err := <-*p.wait:
+ *p.ready <- false
+ return err
+ case err := <-*p.read:
+ if err != nil {
+ *p.ready <- false
+ return err
+ }
+ return <-*p.wait
+ }
+}
+
+// Close closes the status file descriptor passed to xdg-dbus-proxy, causing it to stop.
+func (p *Proxy) Close() error {
+ return p.statP[0].Close()
+}