From f42ded7acf63e2f3711f6512b701ddeac0e2d7a6 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 20 Apr 2021 09:10:17 -0700 Subject: [PATCH] cmd/tailscale/cli: relax & improve the running-as-CLI check for macOS On macOS, we link the CLI into the GUI executable so it can be included in the Mac App Store build. You then need to run it like: /Applications/Tailscale.app/Contents/MacOS/Tailscale But our old detection of whether you're running that Tailscale binary in CLI mode wasn't accurate and often bit people. For instance, when they made a typo, it then launched in GUI mode and broke their existing GUI connection (starting a new IPNExtension) and took down their network. Signed-off-by: Brad Fitzpatrick --- cmd/tailscale/cli/cli.go | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/cmd/tailscale/cli/cli.go b/cmd/tailscale/cli/cli.go index 1a54bd723..0fa4cf6ad 100644 --- a/cmd/tailscale/cli/cli.go +++ b/cmd/tailscale/cli/cli.go @@ -15,6 +15,7 @@ import ( "os" "os/signal" "runtime" + "strconv" "strings" "syscall" "text/tabwriter" @@ -31,15 +32,37 @@ import ( // CLI based on os.Args, GOOS, the context the process is running in // (pty, parent PID), etc. func ActLikeCLI() bool { - if len(os.Args) < 2 { + // This function is only used on macOS. + if runtime.GOOS != "darwin" { return false } - switch os.Args[1] { - case "up", "down", "status", "netcheck", "ping", "version", - "debug", - "-V", "--version", "-h", "--help": + + // Escape hatch to let people force running the macOS + // GUI Tailscale binary as the CLI. + if v, _ := strconv.ParseBool(os.Getenv("TAILSCALE_BE_CLI")); v { return true } + + // If our parent is launchd, we're definitely not + // being run as a CLI. + if os.Getppid() == 1 { + return false + } + + // Looking at the environment of the GUI Tailscale app (ps eww + // $PID), empirically none of these environment variables are + // present. But all or some of these should be present with + // Terminal.all and bash or zsh. + for _, e := range []string{ + "SHLVL", + "TERM", + "TERM_PROGRAM", + "PS1", + } { + if os.Getenv(e) != "" { + return true + } + } return false }