From d7569863b5bdf17b5b174f1cd3f8b7c22474b5d4 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Sun, 14 Feb 2021 21:11:06 -0800 Subject: [PATCH] cmd/tailscaled: fix up install-system-daemon on darwin, add uninstall too Tangentially related to #987, #177, #594, #925, #505 --- cmd/tailscaled/debug.go | 2 ++ cmd/tailscaled/install_darwin.go | 48 ++++++++++++++++++++++++++++---- cmd/tailscaled/tailscaled.go | 27 ++++++++++-------- 3 files changed, 61 insertions(+), 16 deletions(-) diff --git a/cmd/tailscaled/debug.go b/cmd/tailscaled/debug.go index 91ccb070a..d852ad893 100644 --- a/cmd/tailscaled/debug.go +++ b/cmd/tailscaled/debug.go @@ -33,6 +33,8 @@ var debugArgs struct { derpCheck string } +var debugModeFunc = debugMode // so it can be addressable + func debugMode(args []string) error { fs := flag.NewFlagSet("debug", flag.ExitOnError) fs.BoolVar(&debugArgs.monitor, "monitor", false, "If true, run link monitor forever. Precludes all other options.") diff --git a/cmd/tailscaled/install_darwin.go b/cmd/tailscaled/install_darwin.go index 34786df93..7c86cd985 100644 --- a/cmd/tailscaled/install_darwin.go +++ b/cmd/tailscaled/install_darwin.go @@ -5,6 +5,7 @@ package main import ( + "errors" "fmt" "io" "io/ioutil" @@ -14,6 +15,7 @@ import ( func init() { installSystemDaemon = installSystemDaemonDarwin + uninstallSystemDaemon = uninstallSystemDaemonDarwin } // darwinLaunchdPlist is the launchd.plist that's written to @@ -44,9 +46,46 @@ const darwinLaunchdPlist = ` const sysPlist = "/Library/LaunchDaemons/com.tailscale.tailscaled.plist" const targetBin = "/usr/local/bin/tailscaled" -const service = "system/com.tailscale.tailscaled" +const service = "com.tailscale.tailscaled" -func installSystemDaemonDarwin() (err error) { +func uninstallSystemDaemonDarwin(args []string) (ret error) { + if len(args) > 0 { + return errors.New("uninstall subcommand takes no arguments") + } + + plist, err := exec.Command("launchctl", "list", "com.tailscale.tailscaled").Output() + _ = plist // parse it? https://github.com/DHowett/go-plist if we need something. + running := err == nil + + if running { + out, err := exec.Command("launchctl", "stop", "com.tailscale.tailscaled").CombinedOutput() + if err != nil { + fmt.Printf("launchctl stop com.tailscale.tailscaled: %v, %s\n", err, out) + ret = err + } + out, err = exec.Command("launchctl", "unload", sysPlist).CombinedOutput() + if err != nil { + fmt.Printf("launchctl unload %s: %v, %s\n", sysPlist, err, out) + if ret == nil { + ret = err + } + } + } + + err = os.Remove(sysPlist) + if os.IsNotExist(err) { + err = nil + if ret == nil { + ret = err + } + } + return ret +} + +func installSystemDaemonDarwin(args []string) (err error) { + if len(args) > 0 { + return errors.New("install subcommand takes no arguments") + } defer func() { if err != nil && os.Getuid() != 0 { err = fmt.Errorf("%w; try running tailscaled with sudo", err) @@ -84,9 +123,8 @@ func installSystemDaemonDarwin() (err error) { return err } - // Two best effort commands to stop a previous run. - exec.Command("launchctl", "stop", "system/com.tailscale.tailscaled").Run() - exec.Command("launchctl", "unload", sysPlist).Run() + // Best effort: + uninstallSystemDaemonDarwin(nil) if err := ioutil.WriteFile(sysPlist, []byte(darwinLaunchdPlist), 0700); err != nil { return err diff --git a/cmd/tailscaled/tailscaled.go b/cmd/tailscaled/tailscaled.go index 5782fe3c1..e9691a5dc 100644 --- a/cmd/tailscaled/tailscaled.go +++ b/cmd/tailscaled/tailscaled.go @@ -71,7 +71,16 @@ var args struct { verbose int } -var installSystemDaemon func() error // non-nil on some platforms +var ( + installSystemDaemon func([]string) error // non-nil on some platforms + uninstallSystemDaemon func([]string) error // non-nil on some platforms +) + +var subCommands = map[string]*func([]string) error{ + "install-system-daemon": &installSystemDaemon, + "uninstall-system-daemon": &uninstallSystemDaemon, + "debug": &debugModeFunc, +} func main() { // We aren't very performance sensitive, and the parts that are @@ -94,17 +103,13 @@ func main() { flag.BoolVar(&printVersion, "version", false, "print version information and exit") if len(os.Args) > 1 { - switch os.Args[1] { - case "debug": - if err := debugMode(os.Args[2:]); err != nil { - log.Fatal(err) - } - return - case "install-system-daemon": - if f := installSystemDaemon; f == nil { + sub := os.Args[1] + if fp, ok := subCommands[sub]; ok { + if *fp == nil { log.SetFlags(0) - log.Fatalf("install-system-daemon not available on %v", runtime.GOOS) - } else if err := f(); err != nil { + log.Fatalf("%s not available on %v", sub, runtime.GOOS) + } + if err := (*fp)(os.Args[2:]); err != nil { log.SetFlags(0) log.Fatal(err) }