cmd/syncthing: Work around binary in current dir restriction (fixes #8499) (#8500)

This commit is contained in:
Simon Frei 2022-08-14 21:25:45 +02:00 committed by GitHub
parent eb81f7400c
commit 5fd6278609
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -83,6 +83,15 @@ func monitorMain(options serveOptions) {
}
args := os.Args
binary := args[0]
if build.IsWindows {
var err error
binary, err = expandExecutableInCurrentDirectory(binary)
if err != nil {
l.Warnln("Error starting the main Syncthing process:", err)
panic("Error starting the main Syncthing process")
}
}
var restarts [restartCounts]time.Time
stopSign := make(chan os.Signal, 1)
@ -104,7 +113,7 @@ func monitorMain(options serveOptions) {
copy(restarts[0:], restarts[1:])
restarts[len(restarts)-1] = time.Now()
cmd := exec.Command(args[0], args[1:]...)
cmd := exec.Command(binary, args[1:]...)
cmd.Env = childEnv
stderr, err := cmd.StderrPipe()
@ -180,7 +189,7 @@ func monitorMain(options serveOptions) {
// Restart the monitor process to release the .old
// binary as part of the upgrade process.
l.Infoln("Restarting monitor...")
if err = restartMonitor(args); err != nil {
if err = restartMonitor(binary, args); err != nil {
l.Warnln("Restart:", err)
}
os.Exit(exitCode)
@ -203,6 +212,21 @@ func monitorMain(options serveOptions) {
}
}
func expandExecutableInCurrentDirectory(args0 string) (string, error) {
// Works around a restriction added in go1.19 that executables in the
// current directory are not resolved when specifying just an executable
// name (like e.g. "syncthing")
if !strings.ContainsRune(args0, os.PathSeparator) {
// Check if it's in PATH
_, err := exec.LookPath(args0)
if err != nil {
// Try to get the path to the current executable
return os.Executable()
}
}
return args0, nil
}
func copyStderr(stderr io.Reader, dst io.Writer) {
br := bufio.NewReader(stderr)
@ -309,7 +333,7 @@ func copyStdout(stdout io.Reader, dst io.Writer) {
}
}
func restartMonitor(args []string) error {
func restartMonitor(binary string, args []string) error {
// Set the STRESTART environment variable to indicate to the next
// process that this is a restart and not initial start. This prevents
// opening the browser on startup.
@ -319,19 +343,20 @@ func restartMonitor(args []string) error {
// 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)
return restartMonitorUnix(binary, args)
}
// but it isn't supported on Windows, so there we start a normal
// exec.Command and return.
return restartMonitorWindows(args)
return restartMonitorWindows(binary, args)
}
func restartMonitorUnix(args []string) error {
if !strings.ContainsRune(args[0], os.PathSeparator) {
func restartMonitorUnix(binary string, args []string) error {
if !strings.ContainsRune(binary, 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])
var err error
binary, err = exec.LookPath(binary)
if err != nil {
return err
}
@ -341,8 +366,8 @@ func restartMonitorUnix(args []string) error {
return syscall.Exec(args[0], args, os.Environ())
}
func restartMonitorWindows(args []string) error {
cmd := exec.Command(args[0], args[1:]...)
func restartMonitorWindows(binary string, args []string) error {
cmd := exec.Command(binary, args[1:]...)
// Retain the standard streams
cmd.Stderr = os.Stderr
cmd.Stdout = os.Stdout