From dbb388719e6fbc9fe778f62888ea2f4b118f6fa9 Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Tue, 18 Aug 2015 16:40:42 +0200 Subject: [PATCH] Retain standard streams over restart (fixes #2155) --- cmd/syncthing/monitor.go | 41 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/cmd/syncthing/monitor.go b/cmd/syncthing/monitor.go index 680f718eb..a5ff1c30c 100644 --- a/cmd/syncthing/monitor.go +++ b/cmd/syncthing/monitor.go @@ -146,9 +146,8 @@ func monitorMain() { // binary as part of the upgrade process. l.Infoln("Restarting monitor...") os.Setenv("STNORESTART", "") - err := exec.Command(args[0], args[1:]...).Start() - if err != nil { - l.Warnln("restart:", err) + if err = restartMonitor(args); err != nil { + l.Warnln("Restart:", err) } return } @@ -227,3 +226,39 @@ func copyStdout(stdout io.Reader, dst io.Writer) { dst.Write([]byte(line)) } } + +func restartMonitor(args []string) error { + if runtime.GOOS != "windows" { + // syscall.Exec is the cleanest way to restart on Unixes as it + // replaces the current process with the new one, keeping the pid and + // controlling terminal and so on + return restartMonitorUnix(args) + } + + // but it isn't supported on Windows, so there we start a normal + // exec.Command and return. + return restartMonitorWindows(args) +} + +func restartMonitorUnix(args []string) error { + if !strings.ContainsRune(args[0], os.PathSeparator) { + // The path to the binary doesn't contain a slash, so it should be + // found in $PATH. + binary, err := exec.LookPath(args[0]) + if err != nil { + return err + } + args[0] = binary + } + + return syscall.Exec(args[0], args, os.Environ()) +} + +func restartMonitorWindows(args []string) error { + cmd := exec.Command(args[0], args[1:]...) + // Retain the standard streams + cmd.Stderr = os.Stderr + cmd.Stdout = os.Stdout + cmd.Stdin = os.Stdin + return cmd.Start() +}