aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOphestra Umiker <cat@ophivana.moe>2024-09-25 14:00:30 +0900
committerOphestra Umiker <cat@ophivana.moe>2024-09-25 14:00:30 +0900
commit8492239cba18c66c2b6dc76eaf3314f11b38b10b (patch)
tree0e97dbe40e3d955c899acb7d7752e763910150eb
parenta8b4b3634b8bef6040601d970a7c178da72b114d (diff)
helper/args: simplify argument parsing and eliminate excess memory copies
Signed-off-by: Ophestra Umiker <cat@ophivana.moe>
-rw-r--r--dbus/dbus.go7
-rw-r--r--helper/args.go97
-rw-r--r--helper/helper.go4
3 files changed, 33 insertions, 75 deletions
diff --git a/dbus/dbus.go b/dbus/dbus.go
index d68dcfa1..70151cfb 100644
--- a/dbus/dbus.go
+++ b/dbus/dbus.go
@@ -54,8 +54,6 @@ func (p *Proxy) Seal(session, system *Config) error {
return errors.New("no configuration to seal")
}
- seal := helper.NewArgs()
-
var args []string
if session != nil {
args = append(args, session.Args(p.session)...)
@@ -63,11 +61,12 @@ func (p *Proxy) Seal(session, system *Config) error {
if system != nil {
args = append(args, system.Args(p.system)...)
}
- if err := seal.Seal(args); err != nil {
+ if seal, err := helper.NewCheckedArgs(args); err != nil {
return err
+ } else {
+ p.seal = seal
}
- p.seal = seal
return nil
}
diff --git a/helper/args.go b/helper/args.go
index 8ef07f4a..fabbbf2e 100644
--- a/helper/args.go
+++ b/helper/args.go
@@ -1,100 +1,59 @@
package helper
import (
- "bytes"
"errors"
- "fmt"
"io"
"strings"
- "sync"
)
var (
ErrContainsNull = errors.New("argument contains null character")
)
-// Args is sealed with a slice of arguments for writing to the helper args FD.
-// The sealing args is checked to not contain null characters.
-// Attempting to seal an instance twice will cause a panic.
-type Args interface {
- Seal(args []string) error
- io.WriterTo
- fmt.Stringer
-}
-
-// argsFD implements Args for helpers expecting null terminated arguments to a file descriptor.
-// argsFD must not be copied after first use.
-type argsFD struct {
- seal []byte
- sync.RWMutex
-}
-
-func (a *argsFD) Seal(args []string) error {
- a.Lock()
- defer a.Unlock()
-
- if a.seal != nil {
- panic("args sealed twice")
- }
-
- seal := bytes.Buffer{}
+type argsFD []string
- n := 0
- for _, arg := range args {
- // reject argument strings containing null
- if hasNull(arg) {
- return ErrContainsNull
+// checks whether any element contains the null character
+// must be called before args use and args must not be modified after call
+func (a argsFD) check() error {
+ for _, arg := range a {
+ for _, b := range arg {
+ if b == '\x00' {
+ return ErrContainsNull
+ }
}
-
- // accumulate buffer size
- n += len(arg) + 1
- }
- seal.Grow(n)
-
- // write null terminated arguments
- for _, arg := range args {
- seal.WriteString(arg)
- seal.WriteByte('\x00')
}
- a.seal = seal.Bytes()
return nil
}
-func (a *argsFD) WriteTo(w io.Writer) (int64, error) {
- a.RLock()
- defer a.RUnlock()
+func (a argsFD) WriteTo(w io.Writer) (int64, error) {
+ // assuming already checked
+
+ nt := 0
+ // write null terminated arguments
+ for _, arg := range a {
+ n, err := w.Write([]byte(arg + "\x00"))
+ nt += n
- if a.seal == nil {
- panic("attempted to activate unsealed args")
+ if err != nil {
+ return int64(nt), err
+ }
}
- n, err := w.Write(a.seal)
- return int64(n), err
+ return int64(nt), nil
}
-func (a *argsFD) String() string {
+func (a argsFD) String() string {
if a == nil {
return "(invalid helper args)"
}
- if a.seal == nil {
- return "(unsealed helper args)"
- }
-
- return strings.ReplaceAll(string(a.seal), "\x00", " ")
-}
-
-func hasNull(s string) bool {
- for _, b := range s {
- if b == '\x00' {
- return true
- }
- }
- return false
+ return strings.Join(a, " ")
}
-// NewArgs returns a new instance of Args
-func NewArgs() Args {
- return new(argsFD)
+// NewCheckedArgs returns a checked argument writer for args.
+// Callers must not retain any references to args.
+func NewCheckedArgs(args []string) (io.WriterTo, error) {
+ a := argsFD(args)
+ return a, a.check()
}
diff --git a/helper/helper.go b/helper/helper.go
index 6f529229..5488ec50 100644
--- a/helper/helper.go
+++ b/helper/helper.go
@@ -19,7 +19,6 @@ var (
// Helper wraps *exec.Cmd and manages status and args fd.
// Args is always 3 and status if set is always 4.
type Helper struct {
- lock sync.RWMutex
args io.WriterTo
statP [2]*os.File
@@ -32,6 +31,7 @@ type Helper struct {
// standard error. If non-nil, entry i becomes file descriptor 5+i.
ExtraFiles []*os.File
+ lock sync.RWMutex
*exec.Cmd
}
@@ -177,7 +177,7 @@ func (h *Helper) Start() error {
func New(wt io.WriterTo, name string, arg ...string) *Helper {
if wt == nil {
- panic("attempted to create helper with nil argument writer")
+ panic("attempted to create helper with invalid argument writer")
}
return &Helper{args: wt, Cmd: exec.Command(name, arg...)}