From b03170b901b1bb89f815e589750a76ea4a2254bf Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 10 Jan 2022 10:00:15 -0800 Subject: [PATCH] ipn/ipnserver: provide means of setting debug env vars on Windows Fixes #3688 Change-Id: I2f88ca32bf764e2b084fe544d821c43b6a20ffa5 Signed-off-by: Brad Fitzpatrick --- ipn/ipnserver/server.go | 53 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/ipn/ipnserver/server.go b/ipn/ipnserver/server.go index 652911bd5..c96314498 100644 --- a/ipn/ipnserver/server.go +++ b/ipn/ipnserver/server.go @@ -20,6 +20,7 @@ import ( "os/exec" "os/signal" "os/user" + "path/filepath" "runtime" "strconv" "strings" @@ -915,6 +916,14 @@ func BabysitProc(ctx context.Context, args []string, logf logger.Logf) { startTime := time.Now() log.Printf("exec: %#v %v", executable, args) cmd := exec.Command(executable, args...) + if runtime.GOOS == "windows" { + extraEnv, err := loadExtraEnv() + if err != nil { + logf("errors loading extra env file; ignoring: %v", err) + } else { + cmd.Env = append(os.Environ(), extraEnv...) + } + } // Create a pipe object to use as the subproc's stdin. // When the writer goes away, the reader gets EOF. @@ -1184,3 +1193,47 @@ func findTrueNASTaildropDir(name string) (dir string, err error) { } return "", fmt.Errorf("shared folder %q not found", name) } + +func loadExtraEnv() (env []string, err error) { + if runtime.GOOS != "windows" { + return nil, nil + } + name := filepath.Join(os.Getenv("ProgramData"), "Tailscale", "tailscaled-env.txt") + contents, err := os.ReadFile(name) + if os.IsNotExist(err) { + return nil, nil + } + if err != nil { + return nil, err + } + for _, line := range strings.Split(string(contents), "\n") { + line = strings.TrimSpace(line) + if line == "" || line[0] == '#' { + continue + } + k, v, ok := stringsCut(line, "=") + if !ok || k == "" { + continue + } + if strings.HasPrefix(v, `"`) { + var err error + v, err = strconv.Unquote(v) + if err != nil { + return nil, fmt.Errorf("invalid value in line %q: %v", line, err) + } + env = append(env, k+"="+v) + } else { + env = append(env, line) + } + } + return env, nil +} + +// stringsCut is Go 1.18's strings.Cut. +// TODO(bradfitz): delete this when we depend on Go 1.18. +func stringsCut(s, sep string) (before, after string, found bool) { + if i := strings.Index(s, sep); i >= 0 { + return s[:i], s[i+len(sep):], true + } + return s, "", false +}