From 12f1bc7c7737848d8ff75a47e19f99a134503a65 Mon Sep 17 00:00:00 2001 From: Andrew Dunham Date: Fri, 4 Oct 2024 16:52:11 -0400 Subject: [PATCH] envknob: support disk-based envknobs on the macsys build Per my investigation just now, the $HOME environment variable is unset on the macsys (standalone macOS GUI) variant, but the current working directory is valid. Look for the environment variable file in that location in addition to inside the home directory. Updates #3707 Signed-off-by: Andrew Dunham Change-Id: I481ae2e0d19b316244373e06865e3b5c3a9f3b88 --- envknob/envknob.go | 76 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/envknob/envknob.go b/envknob/envknob.go index f1925ccf4..59a6d90af 100644 --- a/envknob/envknob.go +++ b/envknob/envknob.go @@ -17,6 +17,7 @@ package envknob import ( "bufio" + "errors" "fmt" "io" "log" @@ -503,7 +504,7 @@ func ApplyDiskConfigError() error { return applyDiskConfigErr } // // On macOS, use one of: // -// - ~/Library/Containers/io.tailscale.ipn.macsys/Data/tailscaled-env.txt +// - /private/var/root/Library/Containers/io.tailscale.ipn.macsys.network-extension/Data/tailscaled-env.txt // for standalone macOS GUI builds // - ~/Library/Containers/io.tailscale.ipn.macos.network-extension/Data/tailscaled-env.txt // for App Store builds @@ -533,44 +534,73 @@ func ApplyDiskConfig() (err error) { return applyKeyValueEnv(f) } - name := getPlatformEnvFile() - if name == "" { + names := getPlatformEnvFiles() + if len(names) == 0 { return nil } - f, err = os.Open(name) - if os.IsNotExist(err) { - return nil - } - if err != nil { - return err + + var errs []error + for _, name := range names { + f, err = os.Open(name) + if os.IsNotExist(err) { + continue + } + if err != nil { + errs = append(errs, err) + continue + } + defer f.Close() + + return applyKeyValueEnv(f) } - defer f.Close() - return applyKeyValueEnv(f) + + // If we have any errors, return them; if all errors are such that + // os.IsNotExist(err) returns true, then errs is empty and we will + // return nil. + return errors.Join(errs...) } -// getPlatformEnvFile returns the current platform's path to an optional -// tailscaled-env.txt file. It returns an empty string if none is defined -// for the platform. -func getPlatformEnvFile() string { +// getPlatformEnvFiles returns a list of paths to the current platform's +// optional tailscaled-env.txt file. It returns an empty list if none is +// defined for the platform. +func getPlatformEnvFiles() []string { switch runtime.GOOS { case "windows": - return filepath.Join(os.Getenv("ProgramData"), "Tailscale", "tailscaled-env.txt") + return []string{ + filepath.Join(os.Getenv("ProgramData"), "Tailscale", "tailscaled-env.txt"), + } case "linux": if distro.Get() == distro.Synology { - return "/etc/tailscale/tailscaled-env.txt" + return []string{"/etc/tailscale/tailscaled-env.txt"} } case "darwin": if version.IsSandboxedMacOS() { // the two GUI variants (App Store or separate download) - // This will be user-visible as ~/Library/Containers/$VARIANT/Data/tailscaled-env.txt - // where $VARIANT is "io.tailscale.ipn.macsys" for macsys (downloadable mac GUI builds) - // or "io.tailscale.ipn.macos.network-extension" for App Store builds. - return filepath.Join(os.Getenv("HOME"), "tailscaled-env.txt") + // On the App Store variant, the home directory is set + // to something like: + // ~/Library/Containers/io.tailscale.ipn.macos.network-extension/Data + // + // On the macsys (downloadable Mac GUI) variant, the + // home directory can be unset, but we have a working + // directory that looks like: + // /private/var/root/Library/Containers/io.tailscale.ipn.macsys.network-extension/Data + // + // Try both and see if we can find the file in either + // location. + var candidates []string + if home := os.Getenv("HOME"); home != "" { + candidates = append(candidates, filepath.Join(home, "tailscaled-env.txt")) + } + if wd, err := os.Getwd(); err == nil { + candidates = append(candidates, filepath.Join(wd, "tailscaled-env.txt")) + } + + return candidates } else { // Open source / homebrew variable, running tailscaled-on-macOS. - return "/etc/tailscale/tailscaled-env.txt" + return []string{"/etc/tailscale/tailscaled-env.txt"} } } - return "" + return nil } // applyKeyValueEnv reads key=value lines r and calls Setenv for each.