diff --git a/cmd/prx-helper/main.go b/cmd/prx-helper/main.go new file mode 100644 index 0000000..c4a56fd --- /dev/null +++ b/cmd/prx-helper/main.go @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: MIT + +// Command prx-helper is the privileged core of prx. +// +// It reads a single JSON Plan from stdin, executes it and writes a JSON Result +// to stdout. It refuses to run without root privileges and is intended to be +// launched by the prx CLI through pkexec or sudo. +package main + +import ( + "context" + "encoding/json" + "fmt" + "os" + "os/signal" + "syscall" + + "prx/internal/execx" + "prx/internal/helper" + "prx/internal/proto" +) + +func main() { + if os.Geteuid() != 0 { + fmt.Fprintln(os.Stderr, "prx-helper: must run as root (use pkexec or sudo)") + os.Exit(1) + } + + // Cancelling on SIGINT/SIGTERM lets an in-flight transaction roll back + // instead of being killed part-way through. + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer stop() + + var plan proto.Plan + dec := json.NewDecoder(os.Stdin) + if err := dec.Decode(&plan); err != nil { + fmt.Fprintln(os.Stderr, "prx-helper: invalid plan on stdin: "+err.Error()) + os.Exit(2) + } + + res := helper.Execute(ctx, execx.OSRunner{}, plan) + + enc := json.NewEncoder(os.Stdout) + enc.SetIndent("", " ") + if err := enc.Encode(res); err != nil { + fmt.Fprintln(os.Stderr, "prx-helper: encode result: "+err.Error()) + os.Exit(2) + } + if !res.OK { + os.Exit(1) + } +} diff --git a/cmd/prx/main.go b/cmd/prx/main.go new file mode 100644 index 0000000..2ceb05d --- /dev/null +++ b/cmd/prx/main.go @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +// Command prx is the unprivileged user-facing CLI. +package main + +import ( + "fmt" + "os" + + "prx/internal/cli" +) + +func main() { + if err := cli.Execute(); err != nil { + fmt.Fprintln(os.Stderr, "prx: "+err.Error()) + os.Exit(1) + } +}