aboutsummaryrefslogtreecommitdiffhomepage
path: root/internal/system/dbus.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/system/dbus.go')
-rw-r--r--internal/system/dbus.go159
1 files changed, 159 insertions, 0 deletions
diff --git a/internal/system/dbus.go b/internal/system/dbus.go
new file mode 100644
index 00000000..3e4a6e65
--- /dev/null
+++ b/internal/system/dbus.go
@@ -0,0 +1,159 @@
+package system
+
+import (
+ "errors"
+ "fmt"
+ "os"
+
+ "git.ophivana.moe/cat/fortify/dbus"
+ "git.ophivana.moe/cat/fortify/internal/fmsg"
+ "git.ophivana.moe/cat/fortify/internal/state"
+ "git.ophivana.moe/cat/fortify/internal/verbose"
+)
+
+var (
+ ErrDBusConfig = errors.New("dbus config not supplied")
+)
+
+func (sys *I) ProxyDBus(session, system *dbus.Config, sessionPath, systemPath string) error {
+ d := new(DBus)
+
+ // used by waiting goroutine to notify process exit
+ d.done = make(chan struct{})
+
+ // session bus is mandatory
+ if session == nil {
+ return fmsg.WrapError(ErrDBusConfig,
+ "attempted to seal message bus proxy without session bus config")
+ }
+
+ // system bus is optional
+ d.system = system == nil
+
+ // upstream address, downstream socket path
+ var sessionBus, systemBus [2]string
+
+ // resolve upstream bus addresses
+ sessionBus[0], systemBus[0] = dbus.Address()
+
+ // set paths from caller
+ sessionBus[1], systemBus[1] = sessionPath, systemPath
+
+ // create proxy instance
+ d.proxy = dbus.New(sessionBus, systemBus)
+
+ defer func() {
+ if verbose.Get() && d.proxy.Sealed() {
+ verbose.Println("sealed session proxy", session.Args(sessionBus))
+ if system != nil {
+ verbose.Println("sealed system proxy", system.Args(systemBus))
+ }
+ verbose.Println("message bus proxy final args:", d.proxy)
+ }
+ }()
+
+ // queue operation
+ sys.ops = append(sys.ops, d)
+
+ // seal dbus proxy
+ return fmsg.WrapErrorSuffix(d.proxy.Seal(session, system),
+ "cannot seal message bus proxy:")
+}
+
+type DBus struct {
+ proxy *dbus.Proxy
+
+ // whether system bus proxy is enabled
+ system bool
+ // notification from goroutine waiting for dbus.Proxy
+ done chan struct{}
+}
+
+func (d *DBus) Type() state.Enablement {
+ return Process
+}
+
+func (d *DBus) apply(_ *I) error {
+ verbose.Printf("session bus proxy on %q for upstream %q\n", d.proxy.Session()[1], d.proxy.Session()[0])
+ if d.system {
+ verbose.Printf("system bus proxy on %q for upstream %q\n", d.proxy.System()[1], d.proxy.System()[0])
+ }
+
+ // ready channel passed to dbus package
+ ready := make(chan error, 1)
+
+ // background dbus proxy start
+ if err := d.proxy.Start(ready, os.Stderr, true); err != nil {
+ return fmsg.WrapErrorSuffix(err,
+ "cannot start message bus proxy:")
+ }
+ verbose.Println("starting message bus proxy:", d.proxy)
+ if verbose.Get() { // save the extra bwrap arg build when verbose logging is off
+ verbose.Println("message bus proxy bwrap args:", d.proxy.Bwrap())
+ }
+
+ // background wait for proxy instance and notify completion
+ go func() {
+ if err := d.proxy.Wait(); err != nil {
+ fmt.Println("fortify: message bus proxy exited with error:", err)
+ go func() { ready <- err }()
+ } else {
+ verbose.Println("message bus proxy exit")
+ }
+
+ // ensure socket removal so ephemeral directory is empty at revert
+ if err := os.Remove(d.proxy.Session()[1]); err != nil && !errors.Is(err, os.ErrNotExist) {
+ fmt.Println("fortify: cannot remove dangling session bus socket:", err)
+ }
+ if d.system {
+ if err := os.Remove(d.proxy.System()[1]); err != nil && !errors.Is(err, os.ErrNotExist) {
+ fmt.Println("fortify: cannot remove dangling system bus socket:", err)
+ }
+ }
+
+ // notify proxy completion
+ close(d.done)
+ }()
+
+ // ready is not nil if the proxy process faulted
+ if err := <-ready; err != nil {
+ // note that err here is either an I/O error or a predetermined unexpected behaviour error
+ return fmsg.WrapErrorSuffix(err,
+ "message bus proxy fault after start:")
+ }
+ verbose.Println("message bus proxy ready")
+
+ return nil
+}
+
+func (d *DBus) revert(_ *I, _ *Criteria) error {
+ // criteria ignored here since dbus is always process-scoped
+ verbose.Println("terminating message bus proxy")
+
+ if err := d.proxy.Close(); err != nil {
+ if errors.Is(err, os.ErrClosed) {
+ return fmsg.WrapError(err,
+ "message bus proxy already closed")
+ } else {
+ return fmsg.WrapErrorSuffix(err,
+ "cannot stop message bus proxy:")
+ }
+ }
+
+ // block until proxy wait returns
+ <-d.done
+ return nil
+}
+
+func (d *DBus) Is(o Op) bool {
+ d0, ok := o.(*DBus)
+ return ok && d0 != nil && *d == *d0
+}
+
+func (d *DBus) Path() string {
+ return "(dbus proxy)"
+}
+
+func (d *DBus) String() string {
+ return d.proxy.String()
+}