github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/cmd/podman-mac-helper/main.go (about) 1 //go:build darwin 2 // +build darwin 3 4 package main 5 6 import ( 7 "fmt" 8 "io" 9 "io/ioutil" 10 "os" 11 "os/exec" 12 "regexp" 13 "strconv" 14 "strings" 15 16 "github.com/pkg/errors" 17 "github.com/spf13/cobra" 18 ) 19 20 const ( 21 defaultPrefix = "/usr/local" 22 dockerSock = "/var/run/docker.sock" 23 ) 24 25 var installPrefix string 26 27 var rootCmd = &cobra.Command{ 28 Use: "podman-mac-helper", 29 Short: "A system helper to manage docker.sock", 30 Long: `podman-mac-helper is a system helper service and tool for managing docker.sock `, 31 CompletionOptions: cobra.CompletionOptions{DisableDefaultCmd: true}, 32 SilenceErrors: true, 33 } 34 35 // Note, this code is security sensitive since it runs under privilege. 36 // Limit actions to what is strictly necessary, and take appropriate 37 // safeguards 38 // 39 // After installation the service call is ran under launchd in a nowait 40 // inetd style fashion, so stdin, stdout, and stderr are all pointing to 41 // an accepted connection 42 // 43 // This service is installed once per user and will redirect 44 // /var/run/docker to the fixed user-assigned unix socket location. 45 // 46 // Control communication is restricted to each user specific service via 47 // unix file permissions 48 49 func main() { 50 if os.Geteuid() != 0 { 51 fmt.Printf("This command must be ran as root via sudo or osascript\n") 52 os.Exit(1) 53 } 54 55 if err := rootCmd.Execute(); err != nil { 56 fmt.Fprintf(os.Stderr, "Error: %s\n", err.Error()) 57 } 58 } 59 60 func getUserInfo(name string) (string, string, string, error) { 61 // We exec id instead of using user.Lookup to remain compat 62 // with CGO disabled. 63 cmd := exec.Command("/usr/bin/id", "-P", name) 64 output, err := cmd.StdoutPipe() 65 if err != nil { 66 return "", "", "", err 67 } 68 69 if err := cmd.Start(); err != nil { 70 return "", "", "", err 71 } 72 73 entry := readCapped(output) 74 elements := strings.Split(entry, ":") 75 if len(elements) < 9 || elements[0] != name { 76 return "", "", "", errors.New("Could not lookup user") 77 } 78 79 return elements[0], elements[2], elements[8], nil 80 } 81 82 func getUser() (string, string, string, error) { 83 name, found := os.LookupEnv("SUDO_USER") 84 if !found { 85 name, found = os.LookupEnv("USER") 86 if !found { 87 return "", "", "", errors.New("could not determine user") 88 } 89 } 90 91 _, uid, home, err := getUserInfo(name) 92 if err != nil { 93 return "", "", "", fmt.Errorf("could not lookup user: %s", name) 94 } 95 id, err := strconv.Atoi(uid) 96 if err != nil { 97 return "", "", "", fmt.Errorf("invalid uid for user: %s", name) 98 } 99 if id == 0 { 100 return "", "", "", fmt.Errorf("unexpected root user") 101 } 102 103 return name, uid, home, nil 104 } 105 106 // Used for commands that don't return a proper exit code 107 func runDetectErr(name string, args ...string) error { 108 cmd := exec.Command(name, args...) 109 errReader, err := cmd.StderrPipe() 110 if err != nil { 111 return err 112 } 113 114 err = cmd.Start() 115 if err == nil { 116 errString := readCapped(errReader) 117 if len(errString) > 0 { 118 re := regexp.MustCompile(`\r?\n`) 119 err = errors.New(re.ReplaceAllString(errString, ": ")) 120 } 121 } 122 123 if werr := cmd.Wait(); werr != nil { 124 err = werr 125 } 126 127 return err 128 } 129 130 func readCapped(reader io.Reader) string { 131 // Cap output 132 buffer := make([]byte, 2048) 133 n, _ := io.ReadFull(reader, buffer) 134 _, _ = io.Copy(ioutil.Discard, reader) 135 if n > 0 { 136 return string(buffer[:n]) 137 } 138 139 return "" 140 } 141 142 func addPrefixFlag(cmd *cobra.Command) { 143 cmd.Flags().StringVar(&installPrefix, "prefix", defaultPrefix, "Sets the install location prefix") 144 } 145 146 func silentUsage(cmd *cobra.Command, args []string) { 147 cmd.SilenceUsage = true 148 cmd.SilenceErrors = true 149 }