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  }