summaryrefslogtreecommitdiff
path: root/cmd/podman-mac-helper/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'cmd/podman-mac-helper/main.go')
-rw-r--r--cmd/podman-mac-helper/main.go149
1 files changed, 149 insertions, 0 deletions
diff --git a/cmd/podman-mac-helper/main.go b/cmd/podman-mac-helper/main.go
new file mode 100644
index 000000000..8d995519f
--- /dev/null
+++ b/cmd/podman-mac-helper/main.go
@@ -0,0 +1,149 @@
+//go:build darwin
+// +build darwin
+
+package main
+
+import (
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "regexp"
+ "strconv"
+ "strings"
+
+ "github.com/pkg/errors"
+ "github.com/spf13/cobra"
+)
+
+const (
+ defaultPrefix = "/usr/local"
+ dockerSock = "/var/run/docker.sock"
+)
+
+var installPrefix string
+
+var rootCmd = &cobra.Command{
+ Use: "podman-mac-helper",
+ Short: "A system helper to manage docker.sock",
+ Long: `podman-mac-helper is a system helper service and tool for managing docker.sock `,
+ CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true},
+ SilenceErrors: true,
+}
+
+// Note, this code is security sensitive since it runs under privilege.
+// Limit actions to what is strictly necessary, and take appropriate
+// safeguards
+//
+// After installation the service call is ran under launchd in a nowait
+// inetd style fashion, so stdin, stdout, and stderr are all pointing to
+// an accepted connection
+//
+// This service is installed once per user and will redirect
+// /var/run/docker to the fixed user-assigned unix socket location.
+//
+// Control communication is restricted to each user specific service via
+// unix file permissions
+
+func main() {
+ if os.Geteuid() != 0 {
+ fmt.Printf("This command must be ran as root via sudo or osascript\n")
+ os.Exit(1)
+ }
+
+ if err := rootCmd.Execute(); err != nil {
+ fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error())
+ }
+}
+
+func getUserInfo(name string) (string, string, string, error) {
+ // We exec id instead of using user.Lookup to remain compat
+ // with CGO disabled.
+ cmd := exec.Command("/usr/bin/id", "-P", name)
+ output, err := cmd.StdoutPipe()
+ if err != nil {
+ return "", "", "", err
+ }
+
+ if err := cmd.Start(); err != nil {
+ return "", "", "", err
+ }
+
+ entry := readCapped(output)
+ elements := strings.Split(entry, ":")
+ if len(elements) < 9 || elements[0] != name {
+ return "", "", "", errors.New("Could not lookup user")
+ }
+
+ return elements[0], elements[2], elements[8], nil
+}
+
+func getUser() (string, string, string, error) {
+ name, found := os.LookupEnv("SUDO_USER")
+ if !found {
+ name, found = os.LookupEnv("USER")
+ if !found {
+ return "", "", "", errors.New("could not determine user")
+ }
+ }
+
+ _, uid, home, err := getUserInfo(name)
+ if err != nil {
+ return "", "", "", fmt.Errorf("could not lookup user: %s", name)
+ }
+ id, err := strconv.Atoi(uid)
+ if err != nil {
+ return "", "", "", fmt.Errorf("invalid uid for user: %s", name)
+ }
+ if id == 0 {
+ return "", "", "", fmt.Errorf("unexpected root user")
+ }
+
+ return name, uid, home, nil
+}
+
+// Used for commands that don't return a proper exit code
+func runDetectErr(name string, args ...string) error {
+ cmd := exec.Command(name, args...)
+ errReader, err := cmd.StderrPipe()
+ if err != nil {
+ return err
+ }
+
+ err = cmd.Start()
+ if err == nil {
+ errString := readCapped(errReader)
+ if len(errString) > 0 {
+ re := regexp.MustCompile(`\r?\n`)
+ err = errors.New(re.ReplaceAllString(errString, ": "))
+ }
+ }
+
+ if werr := cmd.Wait(); werr != nil {
+ err = werr
+ }
+
+ return err
+}
+
+func readCapped(reader io.Reader) string {
+ // Cap output
+ buffer := make([]byte, 2048)
+ n, _ := io.ReadFull(reader, buffer)
+ _, _ = io.Copy(ioutil.Discard, reader)
+ if n > 0 {
+ return string(buffer[:n])
+ }
+
+ return ""
+}
+
+func addPrefixFlag(cmd *cobra.Command) {
+ cmd.Flags().StringVar(&installPrefix, "prefix", defaultPrefix, "Sets the install location prefix")
+}
+
+func silentUsage(cmd *cobra.Command, args []string) {
+ cmd.SilenceUsage = true
+ cmd.SilenceErrors = true
+}