diff options
Diffstat (limited to 'cmd/podman-mac-helper/main.go')
-rw-r--r-- | cmd/podman-mac-helper/main.go | 149 |
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 +} |