|
|
|
|
@ -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 |
|
|
|
|
} |
|
|
|
|
|