aboutsummaryrefslogtreecommitdiffhomepage
path: root/helper/direct.go
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-10-07 15:37:52 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-10-07 15:37:52 +0900
commit85407dd3c09ffbc4c102baa90249ded685badd12 (patch)
treeb4b3cabd25fe317a70c0ea0fcdab555e89f75a47 /helper/direct.go
parent6a2802cf309fb9758756c56ef05c9354d9cb9003 (diff)
helper: helper.Helper interface
For upcoming bwrap implementation of helper.Helper Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
Diffstat (limited to 'helper/direct.go')
-rw-r--r--helper/direct.go93
1 files changed, 93 insertions, 0 deletions
diff --git a/helper/direct.go b/helper/direct.go
new file mode 100644
index 00000000..24f9e75d
--- /dev/null
+++ b/helper/direct.go
@@ -0,0 +1,93 @@
+package helper
+
+import (
+ "errors"
+ "io"
+ "os/exec"
+ "sync"
+)
+
+// direct wraps *exec.Cmd and manages status and args fd.
+// Args is always 3 and status if set is always 4.
+type direct struct {
+ // helper pipes
+ // cannot be nil
+ p *pipes
+
+ // returns an array of arguments passed directly
+ // to the helper process
+ argF func(argsFD, statFD int) []string
+
+ lock sync.RWMutex
+ *exec.Cmd
+}
+
+func (h *direct) StartNotify(ready chan error) error {
+ h.lock.Lock()
+ defer h.lock.Unlock()
+
+ // Check for doubled Start calls before we defer failure cleanup. If the prior
+ // call to Start succeeded, we don't want to spuriously close its pipes.
+ if h.Cmd.Process != nil {
+ return errors.New("exec: already started")
+ }
+
+ h.p.ready = ready
+ if argsFD, statFD, err := h.p.prepareCmd(h.Cmd); err != nil {
+ return err
+ } else {
+ h.Cmd.Args = append(h.Cmd.Args, h.argF(argsFD, statFD)...)
+ }
+
+ if ready != nil {
+ h.Cmd.Env = append(h.Cmd.Env, FortifyHelper+"=1", FortifyStatus+"=1")
+ } else {
+ h.Cmd.Env = append(h.Cmd.Env, FortifyHelper+"=1", FortifyStatus+"=0")
+ }
+
+ if err := h.Cmd.Start(); err != nil {
+ return err
+ }
+ if err := h.p.readyWriteArgs(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (h *direct) Wait() error {
+ h.lock.RLock()
+ defer h.lock.RUnlock()
+
+ if h.Cmd.Process == nil {
+ return errors.New("exec: not started")
+ }
+ if h.Cmd.ProcessState != nil {
+ return errors.New("exec: Wait was already called")
+ }
+
+ defer h.p.mustClosePipes()
+ return h.Cmd.Wait()
+}
+
+func (h *direct) Close() error {
+ return h.p.closeStatus()
+}
+
+func (h *direct) Start() error {
+ return h.StartNotify(nil)
+}
+
+func (h *direct) Unwrap() *exec.Cmd {
+ return h.Cmd
+}
+
+// New initialises a new direct Helper instance with wt as the null-terminated argument writer.
+// Function argF returns an array of arguments passed directly to the child process.
+func New(wt io.WriterTo, name string, argF func(argsFD, statFD int) []string) Helper {
+ if wt == nil {
+ panic("attempted to create helper with invalid argument writer")
+ }
+
+ return &direct{p: &pipes{args: wt}, argF: argF, Cmd: execCommand(name)}
+}